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>
41fa9e4066Sahrens #include <sys/zfs_ioctl.h>
42ea8dc4b6Seschrock #include <sys/zio.h>
4306eeb2adSek #include <strings.h>
44fa9e4066Sahrens 
45fa9e4066Sahrens #include "zfs_namecheck.h"
46fa9e4066Sahrens #include "libzfs_impl.h"
47fa9e4066Sahrens 
48fa9e4066Sahrens /*
49fa9e4066Sahrens  * Validate the given pool name, optionally putting an extended error message in
50fa9e4066Sahrens  * 'buf'.
51fa9e4066Sahrens  */
5299653d4eSeschrock static boolean_t
5399653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
54fa9e4066Sahrens {
55fa9e4066Sahrens 	namecheck_err_t why;
56fa9e4066Sahrens 	char what;
57b468a217Seschrock 	int ret;
58b468a217Seschrock 
59b468a217Seschrock 	ret = pool_namecheck(pool, &why, &what);
60b468a217Seschrock 
61b468a217Seschrock 	/*
62b468a217Seschrock 	 * The rules for reserved pool names were extended at a later point.
63b468a217Seschrock 	 * But we need to support users with existing pools that may now be
64b468a217Seschrock 	 * invalid.  So we only check for this expanded set of names during a
65b468a217Seschrock 	 * create (or import), and only in userland.
66b468a217Seschrock 	 */
67b468a217Seschrock 	if (ret == 0 && !isopen &&
68b468a217Seschrock 	    (strncmp(pool, "mirror", 6) == 0 ||
69b468a217Seschrock 	    strncmp(pool, "raidz", 5) == 0 ||
70b468a217Seschrock 	    strncmp(pool, "spare", 5) == 0)) {
7199653d4eSeschrock 		zfs_error_aux(hdl,
7299653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "name is reserved"));
7399653d4eSeschrock 		return (B_FALSE);
74b468a217Seschrock 	}
75b468a217Seschrock 
76fa9e4066Sahrens 
77b468a217Seschrock 	if (ret != 0) {
7899653d4eSeschrock 		if (hdl != NULL) {
79fa9e4066Sahrens 			switch (why) {
80b81d61a6Slling 			case NAME_ERR_TOOLONG:
8199653d4eSeschrock 				zfs_error_aux(hdl,
82b81d61a6Slling 				    dgettext(TEXT_DOMAIN, "name is too long"));
83b81d61a6Slling 				break;
84b81d61a6Slling 
85fa9e4066Sahrens 			case NAME_ERR_INVALCHAR:
8699653d4eSeschrock 				zfs_error_aux(hdl,
87fa9e4066Sahrens 				    dgettext(TEXT_DOMAIN, "invalid character "
88fa9e4066Sahrens 				    "'%c' in pool name"), what);
89fa9e4066Sahrens 				break;
90fa9e4066Sahrens 
91fa9e4066Sahrens 			case NAME_ERR_NOLETTER:
9299653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
9399653d4eSeschrock 				    "name must begin with a letter"));
94fa9e4066Sahrens 				break;
95fa9e4066Sahrens 
96fa9e4066Sahrens 			case NAME_ERR_RESERVED:
9799653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
9899653d4eSeschrock 				    "name is reserved"));
99fa9e4066Sahrens 				break;
100fa9e4066Sahrens 
101fa9e4066Sahrens 			case NAME_ERR_DISKLIKE:
10299653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
10399653d4eSeschrock 				    "pool name is reserved"));
104fa9e4066Sahrens 				break;
1055ad82045Snd 
1065ad82045Snd 			case NAME_ERR_LEADING_SLASH:
1075ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1085ad82045Snd 				    "leading slash in name"));
1095ad82045Snd 				break;
1105ad82045Snd 
1115ad82045Snd 			case NAME_ERR_EMPTY_COMPONENT:
1125ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1135ad82045Snd 				    "empty component in name"));
1145ad82045Snd 				break;
1155ad82045Snd 
1165ad82045Snd 			case NAME_ERR_TRAILING_SLASH:
1175ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1185ad82045Snd 				    "trailing slash in name"));
1195ad82045Snd 				break;
1205ad82045Snd 
1215ad82045Snd 			case NAME_ERR_MULTIPLE_AT:
1225ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1235ad82045Snd 				    "multiple '@' delimiters in name"));
1245ad82045Snd 				break;
1255ad82045Snd 
126fa9e4066Sahrens 			}
127fa9e4066Sahrens 		}
12899653d4eSeschrock 		return (B_FALSE);
129fa9e4066Sahrens 	}
130fa9e4066Sahrens 
13199653d4eSeschrock 	return (B_TRUE);
132fa9e4066Sahrens }
133fa9e4066Sahrens 
134fa9e4066Sahrens /*
135fa9e4066Sahrens  * Open a handle to the given pool, even if the pool is currently in the FAULTED
136fa9e4066Sahrens  * state.
137fa9e4066Sahrens  */
138fa9e4066Sahrens zpool_handle_t *
13999653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
140fa9e4066Sahrens {
141fa9e4066Sahrens 	zpool_handle_t *zhp;
14294de1d4cSeschrock 	boolean_t missing;
143fa9e4066Sahrens 
144fa9e4066Sahrens 	/*
145fa9e4066Sahrens 	 * Make sure the pool name is valid.
146fa9e4066Sahrens 	 */
14799653d4eSeschrock 	if (!zpool_name_valid(hdl, B_TRUE, pool)) {
148ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_INVALIDNAME,
14999653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
15099653d4eSeschrock 		    pool);
151fa9e4066Sahrens 		return (NULL);
152fa9e4066Sahrens 	}
153fa9e4066Sahrens 
15499653d4eSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
15599653d4eSeschrock 		return (NULL);
156fa9e4066Sahrens 
15799653d4eSeschrock 	zhp->zpool_hdl = hdl;
158fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
159fa9e4066Sahrens 
16094de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
16194de1d4cSeschrock 		zpool_close(zhp);
16294de1d4cSeschrock 		return (NULL);
16394de1d4cSeschrock 	}
16494de1d4cSeschrock 
16594de1d4cSeschrock 	if (missing) {
16694de1d4cSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
16794de1d4cSeschrock 		    "no such pool"));
168ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_NOENT,
16994de1d4cSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
17094de1d4cSeschrock 		    pool);
17194de1d4cSeschrock 		zpool_close(zhp);
17294de1d4cSeschrock 		return (NULL);
173fa9e4066Sahrens 	}
174fa9e4066Sahrens 
175fa9e4066Sahrens 	return (zhp);
176fa9e4066Sahrens }
177fa9e4066Sahrens 
178fa9e4066Sahrens /*
179fa9e4066Sahrens  * Like the above, but silent on error.  Used when iterating over pools (because
180fa9e4066Sahrens  * the configuration cache may be out of date).
181fa9e4066Sahrens  */
18294de1d4cSeschrock int
18394de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret)
184fa9e4066Sahrens {
185fa9e4066Sahrens 	zpool_handle_t *zhp;
18694de1d4cSeschrock 	boolean_t missing;
187fa9e4066Sahrens 
18894de1d4cSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
18994de1d4cSeschrock 		return (-1);
190fa9e4066Sahrens 
19199653d4eSeschrock 	zhp->zpool_hdl = hdl;
192fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
193fa9e4066Sahrens 
19494de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
19594de1d4cSeschrock 		zpool_close(zhp);
19694de1d4cSeschrock 		return (-1);
197fa9e4066Sahrens 	}
198fa9e4066Sahrens 
19994de1d4cSeschrock 	if (missing) {
20094de1d4cSeschrock 		zpool_close(zhp);
20194de1d4cSeschrock 		*ret = NULL;
20294de1d4cSeschrock 		return (0);
20394de1d4cSeschrock 	}
20494de1d4cSeschrock 
20594de1d4cSeschrock 	*ret = zhp;
20694de1d4cSeschrock 	return (0);
207fa9e4066Sahrens }
208fa9e4066Sahrens 
209fa9e4066Sahrens /*
210fa9e4066Sahrens  * Similar to zpool_open_canfail(), but refuses to open pools in the faulted
211fa9e4066Sahrens  * state.
212fa9e4066Sahrens  */
213fa9e4066Sahrens zpool_handle_t *
21499653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool)
215fa9e4066Sahrens {
216fa9e4066Sahrens 	zpool_handle_t *zhp;
217fa9e4066Sahrens 
21899653d4eSeschrock 	if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
219fa9e4066Sahrens 		return (NULL);
220fa9e4066Sahrens 
221fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
222ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
22399653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
224fa9e4066Sahrens 		zpool_close(zhp);
225fa9e4066Sahrens 		return (NULL);
226fa9e4066Sahrens 	}
227fa9e4066Sahrens 
228fa9e4066Sahrens 	return (zhp);
229fa9e4066Sahrens }
230fa9e4066Sahrens 
231fa9e4066Sahrens /*
232fa9e4066Sahrens  * Close the handle.  Simply frees the memory associated with the handle.
233fa9e4066Sahrens  */
234fa9e4066Sahrens void
235fa9e4066Sahrens zpool_close(zpool_handle_t *zhp)
236fa9e4066Sahrens {
237fa9e4066Sahrens 	if (zhp->zpool_config)
238fa9e4066Sahrens 		nvlist_free(zhp->zpool_config);
239088e9d47Seschrock 	if (zhp->zpool_old_config)
240088e9d47Seschrock 		nvlist_free(zhp->zpool_old_config);
241fa9e4066Sahrens 	free(zhp);
242fa9e4066Sahrens }
243fa9e4066Sahrens 
244fa9e4066Sahrens /*
245fa9e4066Sahrens  * Return the name of the pool.
246fa9e4066Sahrens  */
247fa9e4066Sahrens const char *
248fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp)
249fa9e4066Sahrens {
250fa9e4066Sahrens 	return (zhp->zpool_name);
251fa9e4066Sahrens }
252fa9e4066Sahrens 
253fa9e4066Sahrens /*
254fa9e4066Sahrens  * Return the GUID of the pool.
255fa9e4066Sahrens  */
256fa9e4066Sahrens uint64_t
257fa9e4066Sahrens zpool_get_guid(zpool_handle_t *zhp)
258fa9e4066Sahrens {
259fa9e4066Sahrens 	uint64_t guid;
260fa9e4066Sahrens 
261fa9e4066Sahrens 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID,
262fa9e4066Sahrens 	    &guid) == 0);
263fa9e4066Sahrens 	return (guid);
264fa9e4066Sahrens }
265fa9e4066Sahrens 
26699653d4eSeschrock /*
26799653d4eSeschrock  * Return the version of the pool.
26899653d4eSeschrock  */
26999653d4eSeschrock uint64_t
27099653d4eSeschrock zpool_get_version(zpool_handle_t *zhp)
27199653d4eSeschrock {
27299653d4eSeschrock 	uint64_t version;
27399653d4eSeschrock 
27499653d4eSeschrock 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_VERSION,
27599653d4eSeschrock 	    &version) == 0);
27699653d4eSeschrock 
27799653d4eSeschrock 	return (version);
27899653d4eSeschrock }
27999653d4eSeschrock 
280fa9e4066Sahrens /*
281fa9e4066Sahrens  * Return the amount of space currently consumed by the pool.
282fa9e4066Sahrens  */
283fa9e4066Sahrens uint64_t
284fa9e4066Sahrens zpool_get_space_used(zpool_handle_t *zhp)
285fa9e4066Sahrens {
286fa9e4066Sahrens 	nvlist_t *nvroot;
287fa9e4066Sahrens 	vdev_stat_t *vs;
288fa9e4066Sahrens 	uint_t vsc;
289fa9e4066Sahrens 
290fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
291fa9e4066Sahrens 	    &nvroot) == 0);
292fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
293fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
294fa9e4066Sahrens 
295fa9e4066Sahrens 	return (vs->vs_alloc);
296fa9e4066Sahrens }
297fa9e4066Sahrens 
298fa9e4066Sahrens /*
299fa9e4066Sahrens  * Return the total space in the pool.
300fa9e4066Sahrens  */
301fa9e4066Sahrens uint64_t
302fa9e4066Sahrens zpool_get_space_total(zpool_handle_t *zhp)
303fa9e4066Sahrens {
304fa9e4066Sahrens 	nvlist_t *nvroot;
305fa9e4066Sahrens 	vdev_stat_t *vs;
306fa9e4066Sahrens 	uint_t vsc;
307fa9e4066Sahrens 
308fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
309fa9e4066Sahrens 	    &nvroot) == 0);
310fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
311fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
312fa9e4066Sahrens 
313fa9e4066Sahrens 	return (vs->vs_space);
314fa9e4066Sahrens }
315fa9e4066Sahrens 
316fa9e4066Sahrens /*
317fa9e4066Sahrens  * Return the alternate root for this pool, if any.
318fa9e4066Sahrens  */
319fa9e4066Sahrens int
320fa9e4066Sahrens zpool_get_root(zpool_handle_t *zhp, char *buf, size_t buflen)
321fa9e4066Sahrens {
322fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
323fa9e4066Sahrens 
324fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
32599653d4eSeschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 ||
326e9dbad6fSeschrock 	    zc.zc_value[0] == '\0')
327fa9e4066Sahrens 		return (-1);
328fa9e4066Sahrens 
329e9dbad6fSeschrock 	(void) strlcpy(buf, zc.zc_value, buflen);
330fa9e4066Sahrens 
331fa9e4066Sahrens 	return (0);
332fa9e4066Sahrens }
333fa9e4066Sahrens 
334fa9e4066Sahrens /*
335fa9e4066Sahrens  * Return the state of the pool (ACTIVE or UNAVAILABLE)
336fa9e4066Sahrens  */
337fa9e4066Sahrens int
338fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp)
339fa9e4066Sahrens {
340fa9e4066Sahrens 	return (zhp->zpool_state);
341fa9e4066Sahrens }
342fa9e4066Sahrens 
343fa9e4066Sahrens /*
344fa9e4066Sahrens  * Create the named pool, using the provided vdev list.  It is assumed
345fa9e4066Sahrens  * that the consumer has already validated the contents of the nvlist, so we
346fa9e4066Sahrens  * don't have to worry about error semantics.
347fa9e4066Sahrens  */
348fa9e4066Sahrens int
34999653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
35099653d4eSeschrock     const char *altroot)
351fa9e4066Sahrens {
352fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
35399653d4eSeschrock 	char msg[1024];
354fa9e4066Sahrens 
35599653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
35699653d4eSeschrock 	    "cannot create '%s'"), pool);
357fa9e4066Sahrens 
35899653d4eSeschrock 	if (!zpool_name_valid(hdl, B_FALSE, pool))
35999653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
360fa9e4066Sahrens 
36199653d4eSeschrock 	if (altroot != NULL && altroot[0] != '/')
362ece3d9b3Slling 		return (zfs_error_fmt(hdl, EZFS_BADPATH,
36399653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), altroot));
364fa9e4066Sahrens 
365e9dbad6fSeschrock 	if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
36699653d4eSeschrock 		return (-1);
36799653d4eSeschrock 
368fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
369fa9e4066Sahrens 
370fa9e4066Sahrens 	if (altroot != NULL)
371e9dbad6fSeschrock 		(void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value));
372fa9e4066Sahrens 
37399653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CREATE, &zc) != 0) {
374e9dbad6fSeschrock 		zcmd_free_nvlists(&zc);
375fa9e4066Sahrens 
37699653d4eSeschrock 		switch (errno) {
377fa9e4066Sahrens 		case EBUSY:
378fa9e4066Sahrens 			/*
379fa9e4066Sahrens 			 * This can happen if the user has specified the same
380fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
381fa9e4066Sahrens 			 * until we try to add it and see we already have a
382fa9e4066Sahrens 			 * label.
383fa9e4066Sahrens 			 */
38499653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
38599653d4eSeschrock 			    "one or more vdevs refer to the same device"));
38699653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
387fa9e4066Sahrens 
388fa9e4066Sahrens 		case EOVERFLOW:
389fa9e4066Sahrens 			/*
39099653d4eSeschrock 			 * This occurs when one of the devices is below
391fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
392fa9e4066Sahrens 			 * device was the problem device since there's no
393fa9e4066Sahrens 			 * reliable way to determine device size from userland.
394fa9e4066Sahrens 			 */
395fa9e4066Sahrens 			{
396fa9e4066Sahrens 				char buf[64];
397fa9e4066Sahrens 
398fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
399fa9e4066Sahrens 
40099653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
40199653d4eSeschrock 				    "one or more devices is less than the "
40299653d4eSeschrock 				    "minimum size (%s)"), buf);
403fa9e4066Sahrens 			}
40499653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
405fa9e4066Sahrens 
406fa9e4066Sahrens 		case ENOSPC:
40799653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
40899653d4eSeschrock 			    "one or more devices is out of space"));
40999653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
410fa9e4066Sahrens 
411fa9e4066Sahrens 		default:
41299653d4eSeschrock 			return (zpool_standard_error(hdl, errno, msg));
413fa9e4066Sahrens 		}
414fa9e4066Sahrens 	}
415fa9e4066Sahrens 
416e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
417fa9e4066Sahrens 
418fa9e4066Sahrens 	/*
419fa9e4066Sahrens 	 * If this is an alternate root pool, then we automatically set the
420e9dbad6fSeschrock 	 * mountpoint of the root dataset to be '/'.
421fa9e4066Sahrens 	 */
422fa9e4066Sahrens 	if (altroot != NULL) {
423fa9e4066Sahrens 		zfs_handle_t *zhp;
424fa9e4066Sahrens 
42599653d4eSeschrock 		verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_ANY)) != NULL);
426e9dbad6fSeschrock 		verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
427e9dbad6fSeschrock 		    "/") == 0);
428fa9e4066Sahrens 
429fa9e4066Sahrens 		zfs_close(zhp);
430fa9e4066Sahrens 	}
431fa9e4066Sahrens 
432fa9e4066Sahrens 	return (0);
433fa9e4066Sahrens }
434fa9e4066Sahrens 
435fa9e4066Sahrens /*
436fa9e4066Sahrens  * Destroy the given pool.  It is up to the caller to ensure that there are no
437fa9e4066Sahrens  * datasets left in the pool.
438fa9e4066Sahrens  */
439fa9e4066Sahrens int
440fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp)
441fa9e4066Sahrens {
442fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
443fa9e4066Sahrens 	zfs_handle_t *zfp = NULL;
44499653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
44599653d4eSeschrock 	char msg[1024];
446fa9e4066Sahrens 
447fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_ACTIVE &&
44899653d4eSeschrock 	    (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
44999653d4eSeschrock 	    ZFS_TYPE_FILESYSTEM)) == NULL)
450fa9e4066Sahrens 		return (-1);
451fa9e4066Sahrens 
4525ad82045Snd 	if (zpool_remove_zvol_links(zhp) != 0)
453fa9e4066Sahrens 		return (-1);
454fa9e4066Sahrens 
455fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
456fa9e4066Sahrens 
45799653d4eSeschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
45899653d4eSeschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
45999653d4eSeschrock 		    "cannot destroy '%s'"), zhp->zpool_name);
460fa9e4066Sahrens 
46199653d4eSeschrock 		if (errno == EROFS) {
46299653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
46399653d4eSeschrock 			    "one or more devices is read only"));
46499653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
46599653d4eSeschrock 		} else {
46699653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
467fa9e4066Sahrens 		}
468fa9e4066Sahrens 
469fa9e4066Sahrens 		if (zfp)
470fa9e4066Sahrens 			zfs_close(zfp);
471fa9e4066Sahrens 		return (-1);
472fa9e4066Sahrens 	}
473fa9e4066Sahrens 
474fa9e4066Sahrens 	if (zfp) {
475fa9e4066Sahrens 		remove_mountpoint(zfp);
476fa9e4066Sahrens 		zfs_close(zfp);
477fa9e4066Sahrens 	}
478fa9e4066Sahrens 
479fa9e4066Sahrens 	return (0);
480fa9e4066Sahrens }
481fa9e4066Sahrens 
482fa9e4066Sahrens /*
483fa9e4066Sahrens  * Add the given vdevs to the pool.  The caller must have already performed the
484fa9e4066Sahrens  * necessary verification to ensure that the vdev specification is well-formed.
485fa9e4066Sahrens  */
486fa9e4066Sahrens int
487fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
488fa9e4066Sahrens {
489e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
49099653d4eSeschrock 	int ret;
49199653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
49299653d4eSeschrock 	char msg[1024];
49399653d4eSeschrock 	nvlist_t **spares;
49499653d4eSeschrock 	uint_t nspares;
49599653d4eSeschrock 
49699653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
49799653d4eSeschrock 	    "cannot add to '%s'"), zhp->zpool_name);
49899653d4eSeschrock 
49999653d4eSeschrock 	if (zpool_get_version(zhp) < ZFS_VERSION_SPARES &&
50099653d4eSeschrock 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
50199653d4eSeschrock 	    &spares, &nspares) == 0) {
50299653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
50399653d4eSeschrock 		    "upgraded to add hot spares"));
50499653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
50599653d4eSeschrock 	}
506fa9e4066Sahrens 
507e9dbad6fSeschrock 	if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
50899653d4eSeschrock 		return (-1);
509fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
510fa9e4066Sahrens 
51199653d4eSeschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ADD, &zc) != 0) {
512fa9e4066Sahrens 		switch (errno) {
513fa9e4066Sahrens 		case EBUSY:
514fa9e4066Sahrens 			/*
515fa9e4066Sahrens 			 * This can happen if the user has specified the same
516fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
517fa9e4066Sahrens 			 * until we try to add it and see we already have a
518fa9e4066Sahrens 			 * label.
519fa9e4066Sahrens 			 */
52099653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
52199653d4eSeschrock 			    "one or more vdevs refer to the same device"));
52299653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
523fa9e4066Sahrens 			break;
524fa9e4066Sahrens 
525fa9e4066Sahrens 		case EOVERFLOW:
526fa9e4066Sahrens 			/*
527fa9e4066Sahrens 			 * This occurrs when one of the devices is below
528fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
529fa9e4066Sahrens 			 * device was the problem device since there's no
530fa9e4066Sahrens 			 * reliable way to determine device size from userland.
531fa9e4066Sahrens 			 */
532fa9e4066Sahrens 			{
533fa9e4066Sahrens 				char buf[64];
534fa9e4066Sahrens 
535fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
536fa9e4066Sahrens 
53799653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
53899653d4eSeschrock 				    "device is less than the minimum "
53999653d4eSeschrock 				    "size (%s)"), buf);
540fa9e4066Sahrens 			}
54199653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
54299653d4eSeschrock 			break;
54399653d4eSeschrock 
54499653d4eSeschrock 		case ENOTSUP:
54599653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
54699653d4eSeschrock 			    "pool must be upgraded to add raidz2 vdevs"));
54799653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, msg);
548fa9e4066Sahrens 			break;
549fa9e4066Sahrens 
550fa9e4066Sahrens 		default:
55199653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
552fa9e4066Sahrens 		}
553fa9e4066Sahrens 
55499653d4eSeschrock 		ret = -1;
55599653d4eSeschrock 	} else {
55699653d4eSeschrock 		ret = 0;
557fa9e4066Sahrens 	}
558fa9e4066Sahrens 
559e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
560fa9e4066Sahrens 
56199653d4eSeschrock 	return (ret);
562fa9e4066Sahrens }
563fa9e4066Sahrens 
564fa9e4066Sahrens /*
565fa9e4066Sahrens  * Exports the pool from the system.  The caller must ensure that there are no
566fa9e4066Sahrens  * mounted datasets in the pool.
567fa9e4066Sahrens  */
568fa9e4066Sahrens int
569fa9e4066Sahrens zpool_export(zpool_handle_t *zhp)
570fa9e4066Sahrens {
571fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
572fa9e4066Sahrens 
573fa9e4066Sahrens 	if (zpool_remove_zvol_links(zhp) != 0)
574fa9e4066Sahrens 		return (-1);
575fa9e4066Sahrens 
576fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
577fa9e4066Sahrens 
57899653d4eSeschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_EXPORT, &zc) != 0)
579ece3d9b3Slling 		return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
58099653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot export '%s'"),
58199653d4eSeschrock 		    zhp->zpool_name));
582fa9e4066Sahrens 
583fa9e4066Sahrens 	return (0);
584fa9e4066Sahrens }
585fa9e4066Sahrens 
586fa9e4066Sahrens /*
587fa9e4066Sahrens  * Import the given pool using the known configuration.  The configuration
588fa9e4066Sahrens  * should have come from zpool_find_import().  The 'newname' and 'altroot'
589fa9e4066Sahrens  * parameters control whether the pool is imported with a different name or with
590fa9e4066Sahrens  * an alternate root, respectively.
591fa9e4066Sahrens  */
592fa9e4066Sahrens int
59399653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
59499653d4eSeschrock     const char *altroot)
595fa9e4066Sahrens {
596e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
597fa9e4066Sahrens 	char *thename;
598fa9e4066Sahrens 	char *origname;
599fa9e4066Sahrens 	int ret;
600fa9e4066Sahrens 
601fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
602fa9e4066Sahrens 	    &origname) == 0);
603fa9e4066Sahrens 
604fa9e4066Sahrens 	if (newname != NULL) {
60599653d4eSeschrock 		if (!zpool_name_valid(hdl, B_FALSE, newname))
606ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_INVALIDNAME,
60799653d4eSeschrock 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
60899653d4eSeschrock 			    newname));
609fa9e4066Sahrens 		thename = (char *)newname;
610fa9e4066Sahrens 	} else {
611fa9e4066Sahrens 		thename = origname;
612fa9e4066Sahrens 	}
613fa9e4066Sahrens 
61499653d4eSeschrock 	if (altroot != NULL && altroot[0] != '/')
615ece3d9b3Slling 		return (zfs_error_fmt(hdl, EZFS_BADPATH,
61699653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "bad alternate root '%s'"),
61799653d4eSeschrock 		    altroot));
618fa9e4066Sahrens 
619fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
620fa9e4066Sahrens 
621fa9e4066Sahrens 	if (altroot != NULL)
622e9dbad6fSeschrock 		(void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value));
623fa9e4066Sahrens 	else
624e9dbad6fSeschrock 		zc.zc_value[0] = '\0';
625fa9e4066Sahrens 
626fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
627ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
628fa9e4066Sahrens 
629e9dbad6fSeschrock 	if (zcmd_write_src_nvlist(hdl, &zc, config, NULL) != 0)
63099653d4eSeschrock 		return (-1);
631fa9e4066Sahrens 
632fa9e4066Sahrens 	ret = 0;
63399653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
634fa9e4066Sahrens 		char desc[1024];
635fa9e4066Sahrens 		if (newname == NULL)
636fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
637fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
638fa9e4066Sahrens 			    thename);
639fa9e4066Sahrens 		else
640fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
641fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
642fa9e4066Sahrens 			    origname, thename);
643fa9e4066Sahrens 
644fa9e4066Sahrens 		switch (errno) {
645ea8dc4b6Seschrock 		case ENOTSUP:
646ea8dc4b6Seschrock 			/*
647ea8dc4b6Seschrock 			 * Unsupported version.
648ea8dc4b6Seschrock 			 */
64999653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, desc);
650ea8dc4b6Seschrock 			break;
651ea8dc4b6Seschrock 
652b5989ec7Seschrock 		case EINVAL:
653b5989ec7Seschrock 			(void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
654b5989ec7Seschrock 			break;
655b5989ec7Seschrock 
656fa9e4066Sahrens 		default:
65799653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, desc);
658fa9e4066Sahrens 		}
659fa9e4066Sahrens 
660fa9e4066Sahrens 		ret = -1;
661fa9e4066Sahrens 	} else {
662fa9e4066Sahrens 		zpool_handle_t *zhp;
663fa9e4066Sahrens 		/*
664fa9e4066Sahrens 		 * This should never fail, but play it safe anyway.
665fa9e4066Sahrens 		 */
66694de1d4cSeschrock 		if (zpool_open_silent(hdl, thename, &zhp) != 0) {
66794de1d4cSeschrock 			ret = -1;
66894de1d4cSeschrock 		} else if (zhp != NULL) {
669fa9e4066Sahrens 			ret = zpool_create_zvol_links(zhp);
670fa9e4066Sahrens 			zpool_close(zhp);
671fa9e4066Sahrens 		}
672fa9e4066Sahrens 	}
673fa9e4066Sahrens 
674e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
675fa9e4066Sahrens 	return (ret);
676fa9e4066Sahrens }
677fa9e4066Sahrens 
678fa9e4066Sahrens /*
679fa9e4066Sahrens  * Scrub the pool.
680fa9e4066Sahrens  */
681fa9e4066Sahrens int
682fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type)
683fa9e4066Sahrens {
684fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
685fa9e4066Sahrens 	char msg[1024];
68699653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
687fa9e4066Sahrens 
688fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
689fa9e4066Sahrens 	zc.zc_cookie = type;
690fa9e4066Sahrens 
69199653d4eSeschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_SCRUB, &zc) == 0)
692fa9e4066Sahrens 		return (0);
693fa9e4066Sahrens 
694fa9e4066Sahrens 	(void) snprintf(msg, sizeof (msg),
695fa9e4066Sahrens 	    dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name);
696fa9e4066Sahrens 
69799653d4eSeschrock 	if (errno == EBUSY)
69899653d4eSeschrock 		return (zfs_error(hdl, EZFS_RESILVERING, msg));
69999653d4eSeschrock 	else
70099653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
701fa9e4066Sahrens }
702fa9e4066Sahrens 
703a43d325bSek /*
704a43d325bSek  * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
705a43d325bSek  * spare; but FALSE if its an INUSE spare.
706a43d325bSek  */
70799653d4eSeschrock static nvlist_t *
70899653d4eSeschrock vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid,
709a43d325bSek     boolean_t *avail_spare)
710ea8dc4b6Seschrock {
711ea8dc4b6Seschrock 	uint_t c, children;
712ea8dc4b6Seschrock 	nvlist_t **child;
71399653d4eSeschrock 	uint64_t theguid, present;
714ea8dc4b6Seschrock 	char *path;
715ea8dc4b6Seschrock 	uint64_t wholedisk = 0;
71699653d4eSeschrock 	nvlist_t *ret;
717ea8dc4b6Seschrock 
71899653d4eSeschrock 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0);
719ea8dc4b6Seschrock 
720ea8dc4b6Seschrock 	if (search == NULL &&
721ea8dc4b6Seschrock 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &present) == 0) {
722ea8dc4b6Seschrock 		/*
723ea8dc4b6Seschrock 		 * If the device has never been present since import, the only
724ea8dc4b6Seschrock 		 * reliable way to match the vdev is by GUID.
725ea8dc4b6Seschrock 		 */
72699653d4eSeschrock 		if (theguid == guid)
72799653d4eSeschrock 			return (nv);
728ea8dc4b6Seschrock 	} else if (search != NULL &&
729ea8dc4b6Seschrock 	    nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
730ea8dc4b6Seschrock 		(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
731ea8dc4b6Seschrock 		    &wholedisk);
732ea8dc4b6Seschrock 		if (wholedisk) {
733ea8dc4b6Seschrock 			/*
734ea8dc4b6Seschrock 			 * For whole disks, the internal path has 's0', but the
735ea8dc4b6Seschrock 			 * path passed in by the user doesn't.
736ea8dc4b6Seschrock 			 */
737ea8dc4b6Seschrock 			if (strlen(search) == strlen(path) - 2 &&
738ea8dc4b6Seschrock 			    strncmp(search, path, strlen(search)) == 0)
73999653d4eSeschrock 				return (nv);
740ea8dc4b6Seschrock 		} else if (strcmp(search, path) == 0) {
74199653d4eSeschrock 			return (nv);
742ea8dc4b6Seschrock 		}
743ea8dc4b6Seschrock 	}
744ea8dc4b6Seschrock 
745ea8dc4b6Seschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
746ea8dc4b6Seschrock 	    &child, &children) != 0)
74799653d4eSeschrock 		return (NULL);
748ea8dc4b6Seschrock 
749ea8dc4b6Seschrock 	for (c = 0; c < children; c++)
75099653d4eSeschrock 		if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
751a43d325bSek 		    avail_spare)) != NULL)
752ea8dc4b6Seschrock 			return (ret);
753ea8dc4b6Seschrock 
75499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
75599653d4eSeschrock 	    &child, &children) == 0) {
75699653d4eSeschrock 		for (c = 0; c < children; c++) {
75799653d4eSeschrock 			if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
758a43d325bSek 			    avail_spare)) != NULL) {
759a43d325bSek 				*avail_spare = B_TRUE;
76099653d4eSeschrock 				return (ret);
76199653d4eSeschrock 			}
76299653d4eSeschrock 		}
76399653d4eSeschrock 	}
76499653d4eSeschrock 
76599653d4eSeschrock 	return (NULL);
766ea8dc4b6Seschrock }
767ea8dc4b6Seschrock 
76899653d4eSeschrock nvlist_t *
769a43d325bSek zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare)
770ea8dc4b6Seschrock {
771ea8dc4b6Seschrock 	char buf[MAXPATHLEN];
772ea8dc4b6Seschrock 	const char *search;
773ea8dc4b6Seschrock 	char *end;
774ea8dc4b6Seschrock 	nvlist_t *nvroot;
775ea8dc4b6Seschrock 	uint64_t guid;
776ea8dc4b6Seschrock 
7770917b783Seschrock 	guid = strtoull(path, &end, 10);
778ea8dc4b6Seschrock 	if (guid != 0 && *end == '\0') {
779ea8dc4b6Seschrock 		search = NULL;
780ea8dc4b6Seschrock 	} else if (path[0] != '/') {
781ea8dc4b6Seschrock 		(void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path);
782ea8dc4b6Seschrock 		search = buf;
783ea8dc4b6Seschrock 	} else {
784ea8dc4b6Seschrock 		search = path;
785ea8dc4b6Seschrock 	}
786ea8dc4b6Seschrock 
787ea8dc4b6Seschrock 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
788ea8dc4b6Seschrock 	    &nvroot) == 0);
789ea8dc4b6Seschrock 
790a43d325bSek 	*avail_spare = B_FALSE;
791a43d325bSek 	return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare));
792a43d325bSek }
793a43d325bSek 
794a43d325bSek /*
795a43d325bSek  * Returns TRUE if the given guid corresponds to a spare (INUSE or not).
796a43d325bSek  */
797a43d325bSek static boolean_t
798a43d325bSek is_spare(zpool_handle_t *zhp, uint64_t guid)
799a43d325bSek {
800a43d325bSek 	uint64_t spare_guid;
801a43d325bSek 	nvlist_t *nvroot;
802a43d325bSek 	nvlist_t **spares;
803a43d325bSek 	uint_t nspares;
804a43d325bSek 	int i;
805a43d325bSek 
806a43d325bSek 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
807a43d325bSek 	    &nvroot) == 0);
808a43d325bSek 	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
809a43d325bSek 	    &spares, &nspares) == 0) {
810a43d325bSek 		for (i = 0; i < nspares; i++) {
811a43d325bSek 			verify(nvlist_lookup_uint64(spares[i],
812a43d325bSek 			    ZPOOL_CONFIG_GUID, &spare_guid) == 0);
813a43d325bSek 			if (guid == spare_guid)
814a43d325bSek 				return (B_TRUE);
815a43d325bSek 		}
816a43d325bSek 	}
817a43d325bSek 
818a43d325bSek 	return (B_FALSE);
819ea8dc4b6Seschrock }
820ea8dc4b6Seschrock 
821fa9e4066Sahrens /*
822fa9e4066Sahrens  * Bring the specified vdev online
823fa9e4066Sahrens  */
824fa9e4066Sahrens int
825fa9e4066Sahrens zpool_vdev_online(zpool_handle_t *zhp, const char *path)
826fa9e4066Sahrens {
827fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
828fa9e4066Sahrens 	char msg[1024];
82999653d4eSeschrock 	nvlist_t *tgt;
830a43d325bSek 	boolean_t avail_spare;
83199653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
832fa9e4066Sahrens 
833ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
834ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot online %s"), path);
835ea8dc4b6Seschrock 
836fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
837a43d325bSek 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL)
83899653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
839fa9e4066Sahrens 
84099653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
841fa9e4066Sahrens 
842a43d325bSek 	if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE)
843a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
844a43d325bSek 
84599653d4eSeschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ONLINE, &zc) == 0)
84699653d4eSeschrock 		return (0);
847fa9e4066Sahrens 
84899653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
849fa9e4066Sahrens }
850fa9e4066Sahrens 
851fa9e4066Sahrens /*
852fa9e4066Sahrens  * Take the specified vdev offline
853fa9e4066Sahrens  */
854fa9e4066Sahrens int
855441d80aaSlling zpool_vdev_offline(zpool_handle_t *zhp, const char *path, int istmp)
856fa9e4066Sahrens {
857fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
858fa9e4066Sahrens 	char msg[1024];
85999653d4eSeschrock 	nvlist_t *tgt;
860a43d325bSek 	boolean_t avail_spare;
86199653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
862fa9e4066Sahrens 
863ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
864ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
865ea8dc4b6Seschrock 
866fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
867a43d325bSek 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL)
86899653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
86999653d4eSeschrock 
87099653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
871fa9e4066Sahrens 
872a43d325bSek 	if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE)
873a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
874a43d325bSek 
875441d80aaSlling 	zc.zc_cookie = istmp;
876441d80aaSlling 
87799653d4eSeschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_OFFLINE, &zc) == 0)
878fa9e4066Sahrens 		return (0);
879fa9e4066Sahrens 
880fa9e4066Sahrens 	switch (errno) {
88199653d4eSeschrock 	case EBUSY:
882fa9e4066Sahrens 
883fa9e4066Sahrens 		/*
884fa9e4066Sahrens 		 * There are no other replicas of this device.
885fa9e4066Sahrens 		 */
88699653d4eSeschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
887fa9e4066Sahrens 
88899653d4eSeschrock 	default:
88999653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
890fa9e4066Sahrens 	}
89199653d4eSeschrock }
89299653d4eSeschrock 
89399653d4eSeschrock /*
89499653d4eSeschrock  * Returns TRUE if the given nvlist is a vdev that was originally swapped in as
89599653d4eSeschrock  * a hot spare.
89699653d4eSeschrock  */
89799653d4eSeschrock static boolean_t
89899653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which)
89999653d4eSeschrock {
90099653d4eSeschrock 	nvlist_t **child;
90199653d4eSeschrock 	uint_t c, children;
90299653d4eSeschrock 	char *type;
90399653d4eSeschrock 
90499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child,
90599653d4eSeschrock 	    &children) == 0) {
90699653d4eSeschrock 		verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE,
90799653d4eSeschrock 		    &type) == 0);
90899653d4eSeschrock 
90999653d4eSeschrock 		if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
91099653d4eSeschrock 		    children == 2 && child[which] == tgt)
91199653d4eSeschrock 			return (B_TRUE);
91299653d4eSeschrock 
91399653d4eSeschrock 		for (c = 0; c < children; c++)
91499653d4eSeschrock 			if (is_replacing_spare(child[c], tgt, which))
91599653d4eSeschrock 				return (B_TRUE);
91699653d4eSeschrock 	}
91799653d4eSeschrock 
91899653d4eSeschrock 	return (B_FALSE);
919fa9e4066Sahrens }
920fa9e4066Sahrens 
921fa9e4066Sahrens /*
922fa9e4066Sahrens  * Attach new_disk (fully described by nvroot) to old_disk.
923fa9e4066Sahrens  * If 'replacing' is specified, tne new disk will replace the old one.
924fa9e4066Sahrens  */
925fa9e4066Sahrens int
926fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp,
927fa9e4066Sahrens     const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
928fa9e4066Sahrens {
929fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
930fa9e4066Sahrens 	char msg[1024];
931fa9e4066Sahrens 	int ret;
93299653d4eSeschrock 	nvlist_t *tgt;
933a43d325bSek 	boolean_t avail_spare;
93499653d4eSeschrock 	uint64_t val;
93599653d4eSeschrock 	char *path;
93699653d4eSeschrock 	nvlist_t **child;
93799653d4eSeschrock 	uint_t children;
93899653d4eSeschrock 	nvlist_t *config_root;
93999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
940fa9e4066Sahrens 
941ea8dc4b6Seschrock 	if (replacing)
942ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
943ea8dc4b6Seschrock 		    "cannot replace %s with %s"), old_disk, new_disk);
944ea8dc4b6Seschrock 	else
945ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
946ea8dc4b6Seschrock 		    "cannot attach %s to %s"), new_disk, old_disk);
947ea8dc4b6Seschrock 
948fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
949a43d325bSek 	if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare)) == 0)
95099653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
95199653d4eSeschrock 
952a43d325bSek 	if (avail_spare)
95399653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
95499653d4eSeschrock 
95599653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
956fa9e4066Sahrens 	zc.zc_cookie = replacing;
957fa9e4066Sahrens 
95899653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
95999653d4eSeschrock 	    &child, &children) != 0 || children != 1) {
96099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
96199653d4eSeschrock 		    "new device must be a single disk"));
96299653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
96399653d4eSeschrock 	}
96499653d4eSeschrock 
96599653d4eSeschrock 	verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
96699653d4eSeschrock 	    ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
96799653d4eSeschrock 
96899653d4eSeschrock 	/*
96999653d4eSeschrock 	 * If the target is a hot spare that has been swapped in, we can only
97099653d4eSeschrock 	 * replace it with another hot spare.
97199653d4eSeschrock 	 */
97299653d4eSeschrock 	if (replacing &&
97399653d4eSeschrock 	    nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
97499653d4eSeschrock 	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
975a43d325bSek 	    (zpool_find_vdev(zhp, path, &avail_spare) == NULL ||
976a43d325bSek 	    !avail_spare) && is_replacing_spare(config_root, tgt, 1)) {
97799653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
97899653d4eSeschrock 		    "can only be replaced by another hot spare"));
97999653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
98099653d4eSeschrock 	}
98199653d4eSeschrock 
98299653d4eSeschrock 	/*
98399653d4eSeschrock 	 * If we are attempting to replace a spare, it canot be applied to an
98499653d4eSeschrock 	 * already spared device.
98599653d4eSeschrock 	 */
98699653d4eSeschrock 	if (replacing &&
98799653d4eSeschrock 	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
988a43d325bSek 	    zpool_find_vdev(zhp, path, &avail_spare) != NULL && avail_spare &&
98999653d4eSeschrock 	    is_replacing_spare(config_root, tgt, 0)) {
99099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
99199653d4eSeschrock 		    "device has already been replaced with a spare"));
99299653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
99399653d4eSeschrock 	}
99499653d4eSeschrock 
995e9dbad6fSeschrock 	if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
99699653d4eSeschrock 		return (-1);
997fa9e4066Sahrens 
99899653d4eSeschrock 	ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ATTACH, &zc);
999fa9e4066Sahrens 
1000e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1001fa9e4066Sahrens 
1002fa9e4066Sahrens 	if (ret == 0)
1003fa9e4066Sahrens 		return (0);
1004fa9e4066Sahrens 
1005fa9e4066Sahrens 	switch (errno) {
1006ea8dc4b6Seschrock 	case ENOTSUP:
1007fa9e4066Sahrens 		/*
1008fa9e4066Sahrens 		 * Can't attach to or replace this type of vdev.
1009fa9e4066Sahrens 		 */
1010fa9e4066Sahrens 		if (replacing)
101199653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
101299653d4eSeschrock 			    "cannot replace a replacing device"));
1013fa9e4066Sahrens 		else
101499653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
101599653d4eSeschrock 			    "can only attach to mirrors and top-level "
101699653d4eSeschrock 			    "disks"));
101799653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADTARGET, msg);
1018fa9e4066Sahrens 		break;
1019fa9e4066Sahrens 
1020ea8dc4b6Seschrock 	case EINVAL:
1021fa9e4066Sahrens 		/*
1022fa9e4066Sahrens 		 * The new device must be a single disk.
1023fa9e4066Sahrens 		 */
102499653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
102599653d4eSeschrock 		    "new device must be a single disk"));
102699653d4eSeschrock 		(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
1027fa9e4066Sahrens 		break;
1028fa9e4066Sahrens 
1029ea8dc4b6Seschrock 	case EBUSY:
103099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
103199653d4eSeschrock 		    new_disk);
103299653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
1033fa9e4066Sahrens 		break;
1034fa9e4066Sahrens 
1035ea8dc4b6Seschrock 	case EOVERFLOW:
1036fa9e4066Sahrens 		/*
1037fa9e4066Sahrens 		 * The new device is too small.
1038fa9e4066Sahrens 		 */
103999653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
104099653d4eSeschrock 		    "device is too small"));
104199653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
1042fa9e4066Sahrens 		break;
1043fa9e4066Sahrens 
1044ea8dc4b6Seschrock 	case EDOM:
1045fa9e4066Sahrens 		/*
1046fa9e4066Sahrens 		 * The new device has a different alignment requirement.
1047fa9e4066Sahrens 		 */
104899653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
104999653d4eSeschrock 		    "devices have different sector alignment"));
105099653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
1051fa9e4066Sahrens 		break;
1052fa9e4066Sahrens 
1053ea8dc4b6Seschrock 	case ENAMETOOLONG:
1054fa9e4066Sahrens 		/*
1055fa9e4066Sahrens 		 * The resulting top-level vdev spec won't fit in the label.
1056fa9e4066Sahrens 		 */
105799653d4eSeschrock 		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
1058fa9e4066Sahrens 		break;
1059fa9e4066Sahrens 
1060ea8dc4b6Seschrock 	default:
106199653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
1062fa9e4066Sahrens 	}
1063fa9e4066Sahrens 
106499653d4eSeschrock 	return (-1);
1065fa9e4066Sahrens }
1066fa9e4066Sahrens 
1067fa9e4066Sahrens /*
1068fa9e4066Sahrens  * Detach the specified device.
1069fa9e4066Sahrens  */
1070fa9e4066Sahrens int
1071fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
1072fa9e4066Sahrens {
1073fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1074fa9e4066Sahrens 	char msg[1024];
107599653d4eSeschrock 	nvlist_t *tgt;
1076a43d325bSek 	boolean_t avail_spare;
107799653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1078fa9e4066Sahrens 
1079ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
1080ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
1081ea8dc4b6Seschrock 
1082fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1083a43d325bSek 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0)
108499653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
1085fa9e4066Sahrens 
1086a43d325bSek 	if (avail_spare)
108799653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
108899653d4eSeschrock 
108999653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
109099653d4eSeschrock 
109199653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_DETACH, &zc) == 0)
1092fa9e4066Sahrens 		return (0);
1093fa9e4066Sahrens 
1094fa9e4066Sahrens 	switch (errno) {
1095fa9e4066Sahrens 
1096ea8dc4b6Seschrock 	case ENOTSUP:
1097fa9e4066Sahrens 		/*
1098fa9e4066Sahrens 		 * Can't detach from this type of vdev.
1099fa9e4066Sahrens 		 */
110099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
110199653d4eSeschrock 		    "applicable to mirror and replacing vdevs"));
110299653d4eSeschrock 		(void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg);
1103fa9e4066Sahrens 		break;
1104fa9e4066Sahrens 
1105ea8dc4b6Seschrock 	case EBUSY:
1106fa9e4066Sahrens 		/*
1107fa9e4066Sahrens 		 * There are no other replicas of this device.
1108fa9e4066Sahrens 		 */
110999653d4eSeschrock 		(void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
1110fa9e4066Sahrens 		break;
1111fa9e4066Sahrens 
1112ea8dc4b6Seschrock 	default:
111399653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
1114ea8dc4b6Seschrock 	}
1115ea8dc4b6Seschrock 
111699653d4eSeschrock 	return (-1);
111799653d4eSeschrock }
111899653d4eSeschrock 
111999653d4eSeschrock /*
112099653d4eSeschrock  * Remove the given device.  Currently, this is supported only for hot spares.
112199653d4eSeschrock  */
112299653d4eSeschrock int
112399653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
112499653d4eSeschrock {
112599653d4eSeschrock 	zfs_cmd_t zc = { 0 };
112699653d4eSeschrock 	char msg[1024];
112799653d4eSeschrock 	nvlist_t *tgt;
1128a43d325bSek 	boolean_t avail_spare;
112999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
113099653d4eSeschrock 
113199653d4eSeschrock 	(void) snprintf(msg, sizeof (msg),
113299653d4eSeschrock 	    dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
113399653d4eSeschrock 
113499653d4eSeschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1135a43d325bSek 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0)
113699653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
113799653d4eSeschrock 
1138a43d325bSek 	if (!avail_spare) {
113999653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
114039c23413Seschrock 		    "only inactive hot spares can be removed"));
114199653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
114299653d4eSeschrock 	}
114399653d4eSeschrock 
114499653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
114599653d4eSeschrock 
114699653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
114799653d4eSeschrock 		return (0);
114899653d4eSeschrock 
114999653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
1150ea8dc4b6Seschrock }
1151ea8dc4b6Seschrock 
1152ea8dc4b6Seschrock /*
1153ea8dc4b6Seschrock  * Clear the errors for the pool, or the particular device if specified.
1154ea8dc4b6Seschrock  */
1155ea8dc4b6Seschrock int
1156ea8dc4b6Seschrock zpool_clear(zpool_handle_t *zhp, const char *path)
1157ea8dc4b6Seschrock {
1158ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
1159ea8dc4b6Seschrock 	char msg[1024];
116099653d4eSeschrock 	nvlist_t *tgt;
1161a43d325bSek 	boolean_t avail_spare;
116299653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1163ea8dc4b6Seschrock 
1164ea8dc4b6Seschrock 	if (path)
1165ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
1166ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
1167e9dbad6fSeschrock 		    path);
1168ea8dc4b6Seschrock 	else
1169ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
1170ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
1171ea8dc4b6Seschrock 		    zhp->zpool_name);
1172ea8dc4b6Seschrock 
1173ea8dc4b6Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
117499653d4eSeschrock 	if (path) {
1175a43d325bSek 		if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0)
117699653d4eSeschrock 			return (zfs_error(hdl, EZFS_NODEVICE, msg));
1177ea8dc4b6Seschrock 
1178a43d325bSek 		if (avail_spare)
117999653d4eSeschrock 			return (zfs_error(hdl, EZFS_ISSPARE, msg));
1180ea8dc4b6Seschrock 
118199653d4eSeschrock 		verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
118299653d4eSeschrock 		    &zc.zc_guid) == 0);
1183fa9e4066Sahrens 	}
1184fa9e4066Sahrens 
118599653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
118699653d4eSeschrock 		return (0);
118799653d4eSeschrock 
118899653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
1189fa9e4066Sahrens }
1190fa9e4066Sahrens 
1191f3861e1aSahl /*
1192f3861e1aSahl  * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool>
1193f3861e1aSahl  * hierarchy.
1194f3861e1aSahl  */
1195f3861e1aSahl int
1196f3861e1aSahl zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *),
1197f3861e1aSahl     void *data)
1198fa9e4066Sahrens {
1199f3861e1aSahl 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1200f3861e1aSahl 	char (*paths)[MAXPATHLEN];
1201f3861e1aSahl 	size_t size = 4;
1202f3861e1aSahl 	int curr, fd, base, ret = 0;
1203f3861e1aSahl 	DIR *dirp;
1204f3861e1aSahl 	struct dirent *dp;
1205f3861e1aSahl 	struct stat st;
1206f3861e1aSahl 
1207f3861e1aSahl 	if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0)
1208f3861e1aSahl 		return (errno == ENOENT ? 0 : -1);
1209f3861e1aSahl 
1210f3861e1aSahl 	if (fstatat(base, zhp->zpool_name, &st, 0) != 0) {
1211f3861e1aSahl 		int err = errno;
1212f3861e1aSahl 		(void) close(base);
1213f3861e1aSahl 		return (err == ENOENT ? 0 : -1);
1214f3861e1aSahl 	}
1215fa9e4066Sahrens 
1216fa9e4066Sahrens 	/*
1217f3861e1aSahl 	 * Oddly this wasn't a directory -- ignore that failure since we
1218f3861e1aSahl 	 * know there are no links lower in the (non-existant) hierarchy.
1219fa9e4066Sahrens 	 */
1220f3861e1aSahl 	if (!S_ISDIR(st.st_mode)) {
1221f3861e1aSahl 		(void) close(base);
1222f3861e1aSahl 		return (0);
1223fa9e4066Sahrens 	}
1224fa9e4066Sahrens 
1225f3861e1aSahl 	if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) {
1226f3861e1aSahl 		(void) close(base);
1227f3861e1aSahl 		return (-1);
1228f3861e1aSahl 	}
1229f3861e1aSahl 
1230f3861e1aSahl 	(void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0]));
1231f3861e1aSahl 	curr = 0;
1232f3861e1aSahl 
1233f3861e1aSahl 	while (curr >= 0) {
1234f3861e1aSahl 		if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0)
1235f3861e1aSahl 			goto err;
1236f3861e1aSahl 
1237f3861e1aSahl 		if (S_ISDIR(st.st_mode)) {
1238f3861e1aSahl 			if ((fd = openat(base, paths[curr], O_RDONLY)) < 0)
1239f3861e1aSahl 				goto err;
1240f3861e1aSahl 
1241f3861e1aSahl 			if ((dirp = fdopendir(fd)) == NULL) {
1242f3861e1aSahl 				(void) close(fd);
1243f3861e1aSahl 				goto err;
1244f3861e1aSahl 			}
1245f3861e1aSahl 
1246f3861e1aSahl 			while ((dp = readdir(dirp)) != NULL) {
1247f3861e1aSahl 				if (dp->d_name[0] == '.')
1248f3861e1aSahl 					continue;
1249f3861e1aSahl 
1250f3861e1aSahl 				if (curr + 1 == size) {
1251f3861e1aSahl 					paths = zfs_realloc(hdl, paths,
1252f3861e1aSahl 					    size * sizeof (paths[0]),
1253f3861e1aSahl 					    size * 2 * sizeof (paths[0]));
1254f3861e1aSahl 					if (paths == NULL) {
1255f3861e1aSahl 						(void) closedir(dirp);
1256f3861e1aSahl 						(void) close(fd);
1257f3861e1aSahl 						goto err;
1258f3861e1aSahl 					}
1259f3861e1aSahl 
1260f3861e1aSahl 					size *= 2;
1261f3861e1aSahl 				}
1262f3861e1aSahl 
1263f3861e1aSahl 				(void) strlcpy(paths[curr + 1], paths[curr],
1264f3861e1aSahl 				    sizeof (paths[curr + 1]));
1265f3861e1aSahl 				(void) strlcat(paths[curr], "/",
1266f3861e1aSahl 				    sizeof (paths[curr]));
1267f3861e1aSahl 				(void) strlcat(paths[curr], dp->d_name,
1268f3861e1aSahl 				    sizeof (paths[curr]));
1269f3861e1aSahl 				curr++;
1270f3861e1aSahl 			}
1271f3861e1aSahl 
1272f3861e1aSahl 			(void) closedir(dirp);
1273f3861e1aSahl 
1274f3861e1aSahl 		} else {
1275f3861e1aSahl 			if ((ret = cb(paths[curr], data)) != 0)
1276f3861e1aSahl 				break;
1277f3861e1aSahl 		}
1278f3861e1aSahl 
1279f3861e1aSahl 		curr--;
1280f3861e1aSahl 	}
1281f3861e1aSahl 
1282f3861e1aSahl 	free(paths);
1283f3861e1aSahl 	(void) close(base);
1284f3861e1aSahl 
1285f3861e1aSahl 	return (ret);
1286f3861e1aSahl 
1287f3861e1aSahl err:
1288f3861e1aSahl 	free(paths);
1289f3861e1aSahl 	(void) close(base);
1290f3861e1aSahl 	return (-1);
1291f3861e1aSahl }
1292f3861e1aSahl 
1293f3861e1aSahl typedef struct zvol_cb {
1294f3861e1aSahl 	zpool_handle_t *zcb_pool;
1295f3861e1aSahl 	boolean_t zcb_create;
1296f3861e1aSahl } zvol_cb_t;
1297f3861e1aSahl 
1298f3861e1aSahl /*ARGSUSED*/
1299f3861e1aSahl static int
1300f3861e1aSahl do_zvol_create(zfs_handle_t *zhp, void *data)
1301f3861e1aSahl {
1302f3861e1aSahl 	int ret;
1303f3861e1aSahl 
1304f3861e1aSahl 	if (ZFS_IS_VOLUME(zhp))
1305f3861e1aSahl 		(void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
1306f3861e1aSahl 
1307f3861e1aSahl 	ret = zfs_iter_children(zhp, do_zvol_create, NULL);
1308fa9e4066Sahrens 
1309fa9e4066Sahrens 	zfs_close(zhp);
1310f3861e1aSahl 
1311fa9e4066Sahrens 	return (ret);
1312fa9e4066Sahrens }
1313fa9e4066Sahrens 
1314fa9e4066Sahrens /*
1315fa9e4066Sahrens  * Iterate over all zvols in the pool and make any necessary minor nodes.
1316fa9e4066Sahrens  */
1317fa9e4066Sahrens int
1318fa9e4066Sahrens zpool_create_zvol_links(zpool_handle_t *zhp)
1319fa9e4066Sahrens {
1320fa9e4066Sahrens 	zfs_handle_t *zfp;
1321fa9e4066Sahrens 	int ret;
1322fa9e4066Sahrens 
1323fa9e4066Sahrens 	/*
1324fa9e4066Sahrens 	 * If the pool is unavailable, just return success.
1325fa9e4066Sahrens 	 */
132699653d4eSeschrock 	if ((zfp = make_dataset_handle(zhp->zpool_hdl,
132799653d4eSeschrock 	    zhp->zpool_name)) == NULL)
1328fa9e4066Sahrens 		return (0);
1329fa9e4066Sahrens 
1330f3861e1aSahl 	ret = zfs_iter_children(zfp, do_zvol_create, NULL);
1331fa9e4066Sahrens 
1332fa9e4066Sahrens 	zfs_close(zfp);
1333fa9e4066Sahrens 	return (ret);
1334fa9e4066Sahrens }
1335fa9e4066Sahrens 
1336f3861e1aSahl static int
1337f3861e1aSahl do_zvol_remove(const char *dataset, void *data)
1338f3861e1aSahl {
1339f3861e1aSahl 	zpool_handle_t *zhp = data;
1340f3861e1aSahl 
1341f3861e1aSahl 	return (zvol_remove_link(zhp->zpool_hdl, dataset));
1342f3861e1aSahl }
1343f3861e1aSahl 
1344fa9e4066Sahrens /*
1345f3861e1aSahl  * Iterate over all zvols in the pool and remove any minor nodes.  We iterate
1346f3861e1aSahl  * by examining the /dev links so that a corrupted pool doesn't impede this
1347f3861e1aSahl  * operation.
1348fa9e4066Sahrens  */
1349fa9e4066Sahrens int
1350fa9e4066Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp)
1351fa9e4066Sahrens {
1352f3861e1aSahl 	return (zpool_iter_zvol(zhp, do_zvol_remove, zhp));
1353fa9e4066Sahrens }
1354c67d9675Seschrock 
1355c67d9675Seschrock /*
1356c67d9675Seschrock  * Convert from a devid string to a path.
1357c67d9675Seschrock  */
1358c67d9675Seschrock static char *
1359c67d9675Seschrock devid_to_path(char *devid_str)
1360c67d9675Seschrock {
1361c67d9675Seschrock 	ddi_devid_t devid;
1362c67d9675Seschrock 	char *minor;
1363c67d9675Seschrock 	char *path;
1364c67d9675Seschrock 	devid_nmlist_t *list = NULL;
1365c67d9675Seschrock 	int ret;
1366c67d9675Seschrock 
1367c67d9675Seschrock 	if (devid_str_decode(devid_str, &devid, &minor) != 0)
1368c67d9675Seschrock 		return (NULL);
1369c67d9675Seschrock 
1370c67d9675Seschrock 	ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list);
1371c67d9675Seschrock 
1372c67d9675Seschrock 	devid_str_free(minor);
1373c67d9675Seschrock 	devid_free(devid);
1374c67d9675Seschrock 
1375c67d9675Seschrock 	if (ret != 0)
1376c67d9675Seschrock 		return (NULL);
1377c67d9675Seschrock 
137899653d4eSeschrock 	if ((path = strdup(list[0].devname)) == NULL)
137999653d4eSeschrock 		return (NULL);
138099653d4eSeschrock 
1381c67d9675Seschrock 	devid_free_nmlist(list);
1382c67d9675Seschrock 
1383c67d9675Seschrock 	return (path);
1384c67d9675Seschrock }
1385c67d9675Seschrock 
1386c67d9675Seschrock /*
1387c67d9675Seschrock  * Convert from a path to a devid string.
1388c67d9675Seschrock  */
1389c67d9675Seschrock static char *
1390c67d9675Seschrock path_to_devid(const char *path)
1391c67d9675Seschrock {
1392c67d9675Seschrock 	int fd;
1393c67d9675Seschrock 	ddi_devid_t devid;
1394c67d9675Seschrock 	char *minor, *ret;
1395c67d9675Seschrock 
1396c67d9675Seschrock 	if ((fd = open(path, O_RDONLY)) < 0)
1397c67d9675Seschrock 		return (NULL);
1398c67d9675Seschrock 
1399c67d9675Seschrock 	minor = NULL;
1400c67d9675Seschrock 	ret = NULL;
1401c67d9675Seschrock 	if (devid_get(fd, &devid) == 0) {
1402c67d9675Seschrock 		if (devid_get_minor_name(fd, &minor) == 0)
1403c67d9675Seschrock 			ret = devid_str_encode(devid, minor);
1404c67d9675Seschrock 		if (minor != NULL)
1405c67d9675Seschrock 			devid_str_free(minor);
1406c67d9675Seschrock 		devid_free(devid);
1407c67d9675Seschrock 	}
1408c67d9675Seschrock 	(void) close(fd);
1409c67d9675Seschrock 
1410c67d9675Seschrock 	return (ret);
1411c67d9675Seschrock }
1412c67d9675Seschrock 
1413c67d9675Seschrock /*
1414c67d9675Seschrock  * Issue the necessary ioctl() to update the stored path value for the vdev.  We
1415c67d9675Seschrock  * ignore any failure here, since a common case is for an unprivileged user to
1416c67d9675Seschrock  * type 'zpool status', and we'll display the correct information anyway.
1417c67d9675Seschrock  */
1418c67d9675Seschrock static void
1419c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
1420c67d9675Seschrock {
1421c67d9675Seschrock 	zfs_cmd_t zc = { 0 };
1422c67d9675Seschrock 
1423c67d9675Seschrock 	(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1424e9dbad6fSeschrock 	(void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
1425c67d9675Seschrock 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1426ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
1427c67d9675Seschrock 
142899653d4eSeschrock 	(void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
1429c67d9675Seschrock }
1430c67d9675Seschrock 
1431c67d9675Seschrock /*
1432c67d9675Seschrock  * Given a vdev, return the name to display in iostat.  If the vdev has a path,
1433c67d9675Seschrock  * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
1434c67d9675Seschrock  * We also check if this is a whole disk, in which case we strip off the
1435c67d9675Seschrock  * trailing 's0' slice name.
1436c67d9675Seschrock  *
1437c67d9675Seschrock  * This routine is also responsible for identifying when disks have been
1438c67d9675Seschrock  * reconfigured in a new location.  The kernel will have opened the device by
1439c67d9675Seschrock  * devid, but the path will still refer to the old location.  To catch this, we
1440c67d9675Seschrock  * first do a path -> devid translation (which is fast for the common case).  If
1441c67d9675Seschrock  * the devid matches, we're done.  If not, we do a reverse devid -> path
1442c67d9675Seschrock  * translation and issue the appropriate ioctl() to update the path of the vdev.
1443c67d9675Seschrock  * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any
1444c67d9675Seschrock  * of these checks.
1445c67d9675Seschrock  */
1446c67d9675Seschrock char *
144799653d4eSeschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv)
1448c67d9675Seschrock {
1449c67d9675Seschrock 	char *path, *devid;
1450ea8dc4b6Seschrock 	uint64_t value;
1451ea8dc4b6Seschrock 	char buf[64];
1452c67d9675Seschrock 
1453ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1454ea8dc4b6Seschrock 	    &value) == 0) {
1455ea8dc4b6Seschrock 		verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1456ea8dc4b6Seschrock 		    &value) == 0);
14575ad82045Snd 		(void) snprintf(buf, sizeof (buf), "%llu",
14585ad82045Snd 		    (u_longlong_t)value);
1459ea8dc4b6Seschrock 		path = buf;
1460ea8dc4b6Seschrock 	} else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
1461c67d9675Seschrock 
1462c67d9675Seschrock 		if (zhp != NULL &&
1463c67d9675Seschrock 		    nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
1464c67d9675Seschrock 			/*
1465c67d9675Seschrock 			 * Determine if the current path is correct.
1466c67d9675Seschrock 			 */
1467c67d9675Seschrock 			char *newdevid = path_to_devid(path);
1468c67d9675Seschrock 
1469c67d9675Seschrock 			if (newdevid == NULL ||
1470c67d9675Seschrock 			    strcmp(devid, newdevid) != 0) {
1471c67d9675Seschrock 				char *newpath;
1472c67d9675Seschrock 
1473c67d9675Seschrock 				if ((newpath = devid_to_path(devid)) != NULL) {
1474c67d9675Seschrock 					/*
1475c67d9675Seschrock 					 * Update the path appropriately.
1476c67d9675Seschrock 					 */
1477c67d9675Seschrock 					set_path(zhp, nv, newpath);
147899653d4eSeschrock 					if (nvlist_add_string(nv,
147999653d4eSeschrock 					    ZPOOL_CONFIG_PATH, newpath) == 0)
148099653d4eSeschrock 						verify(nvlist_lookup_string(nv,
148199653d4eSeschrock 						    ZPOOL_CONFIG_PATH,
148299653d4eSeschrock 						    &path) == 0);
1483c67d9675Seschrock 					free(newpath);
1484c67d9675Seschrock 				}
1485c67d9675Seschrock 			}
1486c67d9675Seschrock 
148799653d4eSeschrock 			if (newdevid)
148899653d4eSeschrock 				devid_str_free(newdevid);
1489c67d9675Seschrock 		}
1490c67d9675Seschrock 
1491c67d9675Seschrock 		if (strncmp(path, "/dev/dsk/", 9) == 0)
1492c67d9675Seschrock 			path += 9;
1493c67d9675Seschrock 
1494c67d9675Seschrock 		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
1495ea8dc4b6Seschrock 		    &value) == 0 && value) {
149699653d4eSeschrock 			char *tmp = zfs_strdup(hdl, path);
149799653d4eSeschrock 			if (tmp == NULL)
149899653d4eSeschrock 				return (NULL);
1499c67d9675Seschrock 			tmp[strlen(path) - 2] = '\0';
1500c67d9675Seschrock 			return (tmp);
1501c67d9675Seschrock 		}
1502c67d9675Seschrock 	} else {
1503c67d9675Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
150499653d4eSeschrock 
150599653d4eSeschrock 		/*
150699653d4eSeschrock 		 * If it's a raidz device, we need to stick in the parity level.
150799653d4eSeschrock 		 */
150899653d4eSeschrock 		if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
150999653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
151099653d4eSeschrock 			    &value) == 0);
151199653d4eSeschrock 			(void) snprintf(buf, sizeof (buf), "%s%llu", path,
15125ad82045Snd 			    (u_longlong_t)value);
151399653d4eSeschrock 			path = buf;
151499653d4eSeschrock 		}
1515c67d9675Seschrock 	}
1516c67d9675Seschrock 
151799653d4eSeschrock 	return (zfs_strdup(hdl, path));
1518c67d9675Seschrock }
1519ea8dc4b6Seschrock 
1520ea8dc4b6Seschrock static int
1521ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b)
1522ea8dc4b6Seschrock {
1523ea8dc4b6Seschrock 	return (memcmp(a, b, sizeof (zbookmark_t)));
1524ea8dc4b6Seschrock }
1525ea8dc4b6Seschrock 
1526ea8dc4b6Seschrock /*
1527ea8dc4b6Seschrock  * Retrieve the persistent error log, uniquify the members, and return to the
1528ea8dc4b6Seschrock  * caller.
1529ea8dc4b6Seschrock  */
1530ea8dc4b6Seschrock int
153155434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
1532ea8dc4b6Seschrock {
1533ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
1534ea8dc4b6Seschrock 	uint64_t count;
1535e9dbad6fSeschrock 	zbookmark_t *zb = NULL;
153655434c77Sek 	int i;
1537ea8dc4b6Seschrock 
1538ea8dc4b6Seschrock 	/*
1539ea8dc4b6Seschrock 	 * Retrieve the raw error list from the kernel.  If the number of errors
1540ea8dc4b6Seschrock 	 * has increased, allocate more space and continue until we get the
1541ea8dc4b6Seschrock 	 * entire list.
1542ea8dc4b6Seschrock 	 */
1543ea8dc4b6Seschrock 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
1544ea8dc4b6Seschrock 	    &count) == 0);
1545e9dbad6fSeschrock 	if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
15465ad82045Snd 	    count * sizeof (zbookmark_t))) == (uintptr_t)NULL)
154799653d4eSeschrock 		return (-1);
1548e9dbad6fSeschrock 	zc.zc_nvlist_dst_size = count;
1549ea8dc4b6Seschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
1550ea8dc4b6Seschrock 	for (;;) {
155199653d4eSeschrock 		if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
155299653d4eSeschrock 		    &zc) != 0) {
1553e9dbad6fSeschrock 			free((void *)(uintptr_t)zc.zc_nvlist_dst);
1554ea8dc4b6Seschrock 			if (errno == ENOMEM) {
1555*bf561db0Svb 				count = zc.zc_nvlist_dst_size;
1556e9dbad6fSeschrock 				if ((zc.zc_nvlist_dst = (uintptr_t)
1557*bf561db0Svb 				    zfs_alloc(zhp->zpool_hdl, count *
1558*bf561db0Svb 				    sizeof (zbookmark_t))) == (uintptr_t)NULL)
155999653d4eSeschrock 					return (-1);
1560ea8dc4b6Seschrock 			} else {
1561ea8dc4b6Seschrock 				return (-1);
1562ea8dc4b6Seschrock 			}
1563ea8dc4b6Seschrock 		} else {
1564ea8dc4b6Seschrock 			break;
1565ea8dc4b6Seschrock 		}
1566ea8dc4b6Seschrock 	}
1567ea8dc4b6Seschrock 
1568ea8dc4b6Seschrock 	/*
1569ea8dc4b6Seschrock 	 * Sort the resulting bookmarks.  This is a little confusing due to the
1570ea8dc4b6Seschrock 	 * implementation of ZFS_IOC_ERROR_LOG.  The bookmarks are copied last
1571e9dbad6fSeschrock 	 * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks
1572ea8dc4b6Seschrock 	 * _not_ copied as part of the process.  So we point the start of our
1573ea8dc4b6Seschrock 	 * array appropriate and decrement the total number of elements.
1574ea8dc4b6Seschrock 	 */
1575e9dbad6fSeschrock 	zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) +
1576e9dbad6fSeschrock 	    zc.zc_nvlist_dst_size;
1577e9dbad6fSeschrock 	count -= zc.zc_nvlist_dst_size;
1578ea8dc4b6Seschrock 
1579ea8dc4b6Seschrock 	qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare);
1580ea8dc4b6Seschrock 
158155434c77Sek 	verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0);
1582ea8dc4b6Seschrock 
1583ea8dc4b6Seschrock 	/*
158455434c77Sek 	 * Fill in the nverrlistp with nvlist's of dataset and object numbers.
1585ea8dc4b6Seschrock 	 */
1586ea8dc4b6Seschrock 	for (i = 0; i < count; i++) {
1587ea8dc4b6Seschrock 		nvlist_t *nv;
1588ea8dc4b6Seschrock 
1589c0a81264Sek 		/* ignoring zb_blkid and zb_level for now */
1590c0a81264Sek 		if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
1591c0a81264Sek 		    zb[i-1].zb_object == zb[i].zb_object)
1592ea8dc4b6Seschrock 			continue;
1593ea8dc4b6Seschrock 
159455434c77Sek 		if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0)
159555434c77Sek 			goto nomem;
159655434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET,
159755434c77Sek 		    zb[i].zb_objset) != 0) {
159855434c77Sek 			nvlist_free(nv);
159999653d4eSeschrock 			goto nomem;
1600ea8dc4b6Seschrock 		}
160155434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT,
160255434c77Sek 		    zb[i].zb_object) != 0) {
160355434c77Sek 			nvlist_free(nv);
160455434c77Sek 			goto nomem;
160555434c77Sek 		}
160655434c77Sek 		if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
160755434c77Sek 			nvlist_free(nv);
160855434c77Sek 			goto nomem;
160955434c77Sek 		}
161055434c77Sek 		nvlist_free(nv);
1611ea8dc4b6Seschrock 	}
1612ea8dc4b6Seschrock 
16133ccfa83cSahrens 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
1614ea8dc4b6Seschrock 	return (0);
161599653d4eSeschrock 
161699653d4eSeschrock nomem:
1617e9dbad6fSeschrock 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
161899653d4eSeschrock 	return (no_memory(zhp->zpool_hdl));
1619ea8dc4b6Seschrock }
1620eaca9bbdSeschrock 
1621eaca9bbdSeschrock /*
1622eaca9bbdSeschrock  * Upgrade a ZFS pool to the latest on-disk version.
1623eaca9bbdSeschrock  */
1624eaca9bbdSeschrock int
1625eaca9bbdSeschrock zpool_upgrade(zpool_handle_t *zhp)
1626eaca9bbdSeschrock {
1627eaca9bbdSeschrock 	zfs_cmd_t zc = { 0 };
162899653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1629eaca9bbdSeschrock 
1630eaca9bbdSeschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
163199653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
1632ece3d9b3Slling 		return (zpool_standard_error_fmt(hdl, errno,
163399653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
163499653d4eSeschrock 		    zhp->zpool_name));
1635eaca9bbdSeschrock 
1636eaca9bbdSeschrock 	return (0);
1637eaca9bbdSeschrock }
163806eeb2adSek 
163906eeb2adSek /*
164006eeb2adSek  * Log command history.
164106eeb2adSek  *
164206eeb2adSek  * 'pool' is B_TRUE if we are logging a command for 'zpool'; B_FALSE
164306eeb2adSek  * otherwise ('zfs').  'pool_create' is B_TRUE if we are logging the creation
164406eeb2adSek  * of the pool; B_FALSE otherwise.  'path' is the pathanme containing the
164506eeb2adSek  * poolname.  'argc' and 'argv' are used to construct the command string.
164606eeb2adSek  */
164706eeb2adSek void
164806eeb2adSek zpool_log_history(libzfs_handle_t *hdl, int argc, char **argv, const char *path,
164906eeb2adSek     boolean_t pool, boolean_t pool_create)
165006eeb2adSek {
165106eeb2adSek 	char cmd_buf[HIS_MAX_RECORD_LEN];
165206eeb2adSek 	char *dspath;
165306eeb2adSek 	zfs_cmd_t zc = { 0 };
165406eeb2adSek 	int i;
165506eeb2adSek 
165606eeb2adSek 	/* construct the command string */
165706eeb2adSek 	(void) strcpy(cmd_buf, pool ? "zpool" : "zfs");
165806eeb2adSek 	for (i = 0; i < argc; i++) {
165906eeb2adSek 		if (strlen(cmd_buf) + 1 + strlen(argv[i]) > HIS_MAX_RECORD_LEN)
166006eeb2adSek 			break;
166106eeb2adSek 		(void) strcat(cmd_buf, " ");
166206eeb2adSek 		(void) strcat(cmd_buf, argv[i]);
166306eeb2adSek 	}
166406eeb2adSek 
166506eeb2adSek 	/* figure out the poolname */
166606eeb2adSek 	dspath = strpbrk(path, "/@");
166706eeb2adSek 	if (dspath == NULL) {
166806eeb2adSek 		(void) strcpy(zc.zc_name, path);
166906eeb2adSek 	} else {
167006eeb2adSek 		(void) strncpy(zc.zc_name, path, dspath - path);
167106eeb2adSek 		zc.zc_name[dspath-path] = '\0';
167206eeb2adSek 	}
167306eeb2adSek 
167406eeb2adSek 	zc.zc_history = (uint64_t)(uintptr_t)cmd_buf;
167506eeb2adSek 	zc.zc_history_len = strlen(cmd_buf);
167606eeb2adSek 
167706eeb2adSek 	/* overloading zc_history_offset */
167806eeb2adSek 	zc.zc_history_offset = pool_create;
167906eeb2adSek 
168006eeb2adSek 	(void) ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_LOG_HISTORY, &zc);
168106eeb2adSek }
168206eeb2adSek 
168306eeb2adSek /*
168406eeb2adSek  * Perform ioctl to get some command history of a pool.
168506eeb2adSek  *
168606eeb2adSek  * 'buf' is the buffer to fill up to 'len' bytes.  'off' is the
168706eeb2adSek  * logical offset of the history buffer to start reading from.
168806eeb2adSek  *
168906eeb2adSek  * Upon return, 'off' is the next logical offset to read from and
169006eeb2adSek  * 'len' is the actual amount of bytes read into 'buf'.
169106eeb2adSek  */
169206eeb2adSek static int
169306eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len)
169406eeb2adSek {
169506eeb2adSek 	zfs_cmd_t zc = { 0 };
169606eeb2adSek 	libzfs_handle_t *hdl = zhp->zpool_hdl;
169706eeb2adSek 
169806eeb2adSek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
169906eeb2adSek 
170006eeb2adSek 	zc.zc_history = (uint64_t)(uintptr_t)buf;
170106eeb2adSek 	zc.zc_history_len = *len;
170206eeb2adSek 	zc.zc_history_offset = *off;
170306eeb2adSek 
170406eeb2adSek 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) {
170506eeb2adSek 		switch (errno) {
170606eeb2adSek 		case EPERM:
1707ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_PERM,
1708ece3d9b3Slling 			    dgettext(TEXT_DOMAIN,
170906eeb2adSek 			    "cannot show history for pool '%s'"),
171006eeb2adSek 			    zhp->zpool_name));
171106eeb2adSek 		case ENOENT:
1712ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_NOHISTORY,
171306eeb2adSek 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
171406eeb2adSek 			    "'%s'"), zhp->zpool_name));
171506eeb2adSek 		default:
1716ece3d9b3Slling 			return (zpool_standard_error_fmt(hdl, errno,
171706eeb2adSek 			    dgettext(TEXT_DOMAIN,
171806eeb2adSek 			    "cannot get history for '%s'"), zhp->zpool_name));
171906eeb2adSek 		}
172006eeb2adSek 	}
172106eeb2adSek 
172206eeb2adSek 	*len = zc.zc_history_len;
172306eeb2adSek 	*off = zc.zc_history_offset;
172406eeb2adSek 
172506eeb2adSek 	return (0);
172606eeb2adSek }
172706eeb2adSek 
172806eeb2adSek /*
172906eeb2adSek  * Process the buffer of nvlists, unpacking and storing each nvlist record
173006eeb2adSek  * into 'records'.  'leftover' is set to the number of bytes that weren't
173106eeb2adSek  * processed as there wasn't a complete record.
173206eeb2adSek  */
173306eeb2adSek static int
173406eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
173506eeb2adSek     nvlist_t ***records, uint_t *numrecords)
173606eeb2adSek {
173706eeb2adSek 	uint64_t reclen;
173806eeb2adSek 	nvlist_t *nv;
173906eeb2adSek 	int i;
174006eeb2adSek 
174106eeb2adSek 	while (bytes_read > sizeof (reclen)) {
174206eeb2adSek 
174306eeb2adSek 		/* get length of packed record (stored as little endian) */
174406eeb2adSek 		for (i = 0, reclen = 0; i < sizeof (reclen); i++)
174506eeb2adSek 			reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i);
174606eeb2adSek 
174706eeb2adSek 		if (bytes_read < sizeof (reclen) + reclen)
174806eeb2adSek 			break;
174906eeb2adSek 
175006eeb2adSek 		/* unpack record */
175106eeb2adSek 		if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0)
175206eeb2adSek 			return (ENOMEM);
175306eeb2adSek 		bytes_read -= sizeof (reclen) + reclen;
175406eeb2adSek 		buf += sizeof (reclen) + reclen;
175506eeb2adSek 
175606eeb2adSek 		/* add record to nvlist array */
175706eeb2adSek 		(*numrecords)++;
175806eeb2adSek 		if (ISP2(*numrecords + 1)) {
175906eeb2adSek 			*records = realloc(*records,
176006eeb2adSek 			    *numrecords * 2 * sizeof (nvlist_t *));
176106eeb2adSek 		}
176206eeb2adSek 		(*records)[*numrecords - 1] = nv;
176306eeb2adSek 	}
176406eeb2adSek 
176506eeb2adSek 	*leftover = bytes_read;
176606eeb2adSek 	return (0);
176706eeb2adSek }
176806eeb2adSek 
176906eeb2adSek #define	HIS_BUF_LEN	(128*1024)
177006eeb2adSek 
177106eeb2adSek /*
177206eeb2adSek  * Retrieve the command history of a pool.
177306eeb2adSek  */
177406eeb2adSek int
177506eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
177606eeb2adSek {
177706eeb2adSek 	char buf[HIS_BUF_LEN];
177806eeb2adSek 	uint64_t off = 0;
177906eeb2adSek 	nvlist_t **records = NULL;
178006eeb2adSek 	uint_t numrecords = 0;
178106eeb2adSek 	int err, i;
178206eeb2adSek 
178306eeb2adSek 	do {
178406eeb2adSek 		uint64_t bytes_read = sizeof (buf);
178506eeb2adSek 		uint64_t leftover;
178606eeb2adSek 
178706eeb2adSek 		if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
178806eeb2adSek 			break;
178906eeb2adSek 
179006eeb2adSek 		/* if nothing else was read in, we're at EOF, just return */
179106eeb2adSek 		if (!bytes_read)
179206eeb2adSek 			break;
179306eeb2adSek 
179406eeb2adSek 		if ((err = zpool_history_unpack(buf, bytes_read,
179506eeb2adSek 		    &leftover, &records, &numrecords)) != 0)
179606eeb2adSek 			break;
179706eeb2adSek 		off -= leftover;
179806eeb2adSek 
179906eeb2adSek 		/* CONSTCOND */
180006eeb2adSek 	} while (1);
180106eeb2adSek 
180206eeb2adSek 	if (!err) {
180306eeb2adSek 		verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
180406eeb2adSek 		verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD,
180506eeb2adSek 		    records, numrecords) == 0);
180606eeb2adSek 	}
180706eeb2adSek 	for (i = 0; i < numrecords; i++)
180806eeb2adSek 		nvlist_free(records[i]);
180906eeb2adSek 	free(records);
181006eeb2adSek 
181106eeb2adSek 	return (err);
181206eeb2adSek }
181355434c77Sek 
181455434c77Sek void
181555434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
181655434c77Sek     char *pathname, size_t len)
181755434c77Sek {
181855434c77Sek 	zfs_cmd_t zc = { 0 };
181955434c77Sek 	boolean_t mounted = B_FALSE;
182055434c77Sek 	char *mntpnt = NULL;
182155434c77Sek 	char dsname[MAXNAMELEN];
182255434c77Sek 
182355434c77Sek 	if (dsobj == 0) {
182455434c77Sek 		/* special case for the MOS */
182555434c77Sek 		(void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj);
182655434c77Sek 		return;
182755434c77Sek 	}
182855434c77Sek 
182955434c77Sek 	/* get the dataset's name */
183055434c77Sek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
183155434c77Sek 	zc.zc_obj = dsobj;
183255434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd,
183355434c77Sek 	    ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) {
183455434c77Sek 		/* just write out a path of two object numbers */
183555434c77Sek 		(void) snprintf(pathname, len, "<0x%llx>:<0x%llx>",
183655434c77Sek 		    dsobj, obj);
183755434c77Sek 		return;
183855434c77Sek 	}
183955434c77Sek 	(void) strlcpy(dsname, zc.zc_value, sizeof (dsname));
184055434c77Sek 
184155434c77Sek 	/* find out if the dataset is mounted */
184255434c77Sek 	mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt);
184355434c77Sek 
184455434c77Sek 	/* get the corrupted object's path */
184555434c77Sek 	(void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
184655434c77Sek 	zc.zc_obj = obj;
184755434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH,
184855434c77Sek 	    &zc) == 0) {
184955434c77Sek 		if (mounted) {
185055434c77Sek 			(void) snprintf(pathname, len, "%s%s", mntpnt,
185155434c77Sek 			    zc.zc_value);
185255434c77Sek 		} else {
185355434c77Sek 			(void) snprintf(pathname, len, "%s:%s",
185455434c77Sek 			    dsname, zc.zc_value);
185555434c77Sek 		}
185655434c77Sek 	} else {
185755434c77Sek 		(void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj);
185855434c77Sek 	}
185955434c77Sek 	free(mntpnt);
186055434c77Sek }
1861