1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock  * 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  */
21f3861e1aSahl 
22fa9e4066Sahrens /*
23798d5834Sgw  * 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 
29fa9e4066Sahrens #include <assert.h>
30fa9e4066Sahrens #include <ctype.h>
31fa9e4066Sahrens #include <errno.h>
32fa9e4066Sahrens #include <libdevinfo.h>
33fa9e4066Sahrens #include <libintl.h>
34fa9e4066Sahrens #include <math.h>
35fa9e4066Sahrens #include <stdio.h>
36fa9e4066Sahrens #include <stdlib.h>
37fa9e4066Sahrens #include <strings.h>
38fa9e4066Sahrens #include <unistd.h>
39fa9e4066Sahrens #include <zone.h>
4099653d4eSeschrock #include <fcntl.h>
41fa9e4066Sahrens #include <sys/mntent.h>
42fa9e4066Sahrens #include <sys/mnttab.h>
43b12a1c38Slling #include <sys/mount.h>
44fa9e4066Sahrens 
45fa9e4066Sahrens #include <sys/spa.h>
46fa9e4066Sahrens #include <sys/zio.h>
47e9dbad6fSeschrock #include <sys/zap.h>
48fa9e4066Sahrens #include <libzfs.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include "zfs_namecheck.h"
51fa9e4066Sahrens #include "zfs_prop.h"
52fa9e4066Sahrens #include "libzfs_impl.h"
53fa9e4066Sahrens 
54*cdf5b4caSmmusante static int zvol_create_link_common(libzfs_handle_t *, const char *, int);
55*cdf5b4caSmmusante 
56fa9e4066Sahrens /*
57fa9e4066Sahrens  * Given a single type (not a mask of types), return the type in a human
58fa9e4066Sahrens  * readable form.
59fa9e4066Sahrens  */
60fa9e4066Sahrens const char *
61fa9e4066Sahrens zfs_type_to_name(zfs_type_t type)
62fa9e4066Sahrens {
63fa9e4066Sahrens 	switch (type) {
64fa9e4066Sahrens 	case ZFS_TYPE_FILESYSTEM:
65fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "filesystem"));
66fa9e4066Sahrens 	case ZFS_TYPE_SNAPSHOT:
67fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "snapshot"));
68fa9e4066Sahrens 	case ZFS_TYPE_VOLUME:
69fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "volume"));
70fa9e4066Sahrens 	}
71fa9e4066Sahrens 
72fa9e4066Sahrens 	return (NULL);
73fa9e4066Sahrens }
74fa9e4066Sahrens 
75fa9e4066Sahrens /*
76fa9e4066Sahrens  * Given a path and mask of ZFS types, return a string describing this dataset.
77fa9e4066Sahrens  * This is used when we fail to open a dataset and we cannot get an exact type.
78fa9e4066Sahrens  * We guess what the type would have been based on the path and the mask of
79fa9e4066Sahrens  * acceptable types.
80fa9e4066Sahrens  */
81fa9e4066Sahrens static const char *
82fa9e4066Sahrens path_to_str(const char *path, int types)
83fa9e4066Sahrens {
84fa9e4066Sahrens 	/*
85fa9e4066Sahrens 	 * When given a single type, always report the exact type.
86fa9e4066Sahrens 	 */
87fa9e4066Sahrens 	if (types == ZFS_TYPE_SNAPSHOT)
88fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "snapshot"));
89fa9e4066Sahrens 	if (types == ZFS_TYPE_FILESYSTEM)
90fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "filesystem"));
91fa9e4066Sahrens 	if (types == ZFS_TYPE_VOLUME)
92fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "volume"));
93fa9e4066Sahrens 
94fa9e4066Sahrens 	/*
95fa9e4066Sahrens 	 * The user is requesting more than one type of dataset.  If this is the
96fa9e4066Sahrens 	 * case, consult the path itself.  If we're looking for a snapshot, and
97fa9e4066Sahrens 	 * a '@' is found, then report it as "snapshot".  Otherwise, remove the
98fa9e4066Sahrens 	 * snapshot attribute and try again.
99fa9e4066Sahrens 	 */
100fa9e4066Sahrens 	if (types & ZFS_TYPE_SNAPSHOT) {
101fa9e4066Sahrens 		if (strchr(path, '@') != NULL)
102fa9e4066Sahrens 			return (dgettext(TEXT_DOMAIN, "snapshot"));
103fa9e4066Sahrens 		return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT));
104fa9e4066Sahrens 	}
105fa9e4066Sahrens 
106fa9e4066Sahrens 
107fa9e4066Sahrens 	/*
108fa9e4066Sahrens 	 * The user has requested either filesystems or volumes.
109fa9e4066Sahrens 	 * We have no way of knowing a priori what type this would be, so always
110fa9e4066Sahrens 	 * report it as "filesystem" or "volume", our two primitive types.
111fa9e4066Sahrens 	 */
112fa9e4066Sahrens 	if (types & ZFS_TYPE_FILESYSTEM)
113fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "filesystem"));
114fa9e4066Sahrens 
115fa9e4066Sahrens 	assert(types & ZFS_TYPE_VOLUME);
116fa9e4066Sahrens 	return (dgettext(TEXT_DOMAIN, "volume"));
117fa9e4066Sahrens }
118fa9e4066Sahrens 
119fa9e4066Sahrens /*
120fa9e4066Sahrens  * Validate a ZFS path.  This is used even before trying to open the dataset, to
121fa9e4066Sahrens  * provide a more meaningful error message.  We place a more useful message in
122fa9e4066Sahrens  * 'buf' detailing exactly why the name was not valid.
123fa9e4066Sahrens  */
124fa9e4066Sahrens static int
12599653d4eSeschrock zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type)
126fa9e4066Sahrens {
127fa9e4066Sahrens 	namecheck_err_t why;
128fa9e4066Sahrens 	char what;
129fa9e4066Sahrens 
130fa9e4066Sahrens 	if (dataset_namecheck(path, &why, &what) != 0) {
13199653d4eSeschrock 		if (hdl != NULL) {
132fa9e4066Sahrens 			switch (why) {
133b81d61a6Slling 			case NAME_ERR_TOOLONG:
13499653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
13599653d4eSeschrock 				    "name is too long"));
136b81d61a6Slling 				break;
137b81d61a6Slling 
138fa9e4066Sahrens 			case NAME_ERR_LEADING_SLASH:
13999653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
14099653d4eSeschrock 				    "leading slash in name"));
141fa9e4066Sahrens 				break;
142fa9e4066Sahrens 
143fa9e4066Sahrens 			case NAME_ERR_EMPTY_COMPONENT:
14499653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
14599653d4eSeschrock 				    "empty component in name"));
146fa9e4066Sahrens 				break;
147fa9e4066Sahrens 
148fa9e4066Sahrens 			case NAME_ERR_TRAILING_SLASH:
14999653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
15099653d4eSeschrock 				    "trailing slash in name"));
151fa9e4066Sahrens 				break;
152fa9e4066Sahrens 
153fa9e4066Sahrens 			case NAME_ERR_INVALCHAR:
15499653d4eSeschrock 				zfs_error_aux(hdl,
155fa9e4066Sahrens 				    dgettext(TEXT_DOMAIN, "invalid character "
15699653d4eSeschrock 				    "'%c' in name"), what);
157fa9e4066Sahrens 				break;
158fa9e4066Sahrens 
159fa9e4066Sahrens 			case NAME_ERR_MULTIPLE_AT:
16099653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
16199653d4eSeschrock 				    "multiple '@' delimiters in name"));
162fa9e4066Sahrens 				break;
1635ad82045Snd 
1645ad82045Snd 			case NAME_ERR_NOLETTER:
1655ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1665ad82045Snd 				    "pool doesn't begin with a letter"));
1675ad82045Snd 				break;
1685ad82045Snd 
1695ad82045Snd 			case NAME_ERR_RESERVED:
1705ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1715ad82045Snd 				    "name is reserved"));
1725ad82045Snd 				break;
1735ad82045Snd 
1745ad82045Snd 			case NAME_ERR_DISKLIKE:
1755ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1765ad82045Snd 				    "reserved disk name"));
1775ad82045Snd 				break;
178fa9e4066Sahrens 			}
179fa9e4066Sahrens 		}
180fa9e4066Sahrens 
181fa9e4066Sahrens 		return (0);
182fa9e4066Sahrens 	}
183fa9e4066Sahrens 
184fa9e4066Sahrens 	if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
18599653d4eSeschrock 		if (hdl != NULL)
18699653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
18799653d4eSeschrock 			    "snapshot delimiter '@' in filesystem name"));
188fa9e4066Sahrens 		return (0);
189fa9e4066Sahrens 	}
190fa9e4066Sahrens 
1911d452cf5Sahrens 	if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
1921d452cf5Sahrens 		if (hdl != NULL)
1931d452cf5Sahrens 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
194d7d4af51Smmusante 			    "missing '@' delimiter in snapshot name"));
1951d452cf5Sahrens 		return (0);
1961d452cf5Sahrens 	}
1971d452cf5Sahrens 
19899653d4eSeschrock 	return (-1);
199fa9e4066Sahrens }
200fa9e4066Sahrens 
201fa9e4066Sahrens int
202fa9e4066Sahrens zfs_name_valid(const char *name, zfs_type_t type)
203fa9e4066Sahrens {
20499653d4eSeschrock 	return (zfs_validate_name(NULL, name, type));
205fa9e4066Sahrens }
206fa9e4066Sahrens 
207e9dbad6fSeschrock /*
208e9dbad6fSeschrock  * This function takes the raw DSL properties, and filters out the user-defined
209e9dbad6fSeschrock  * properties into a separate nvlist.
210e9dbad6fSeschrock  */
211e9dbad6fSeschrock static int
212e9dbad6fSeschrock process_user_props(zfs_handle_t *zhp)
213e9dbad6fSeschrock {
214e9dbad6fSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
215e9dbad6fSeschrock 	nvpair_t *elem;
216e9dbad6fSeschrock 	nvlist_t *propval;
217e9dbad6fSeschrock 
218e9dbad6fSeschrock 	nvlist_free(zhp->zfs_user_props);
219e9dbad6fSeschrock 
220e9dbad6fSeschrock 	if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0)
221e9dbad6fSeschrock 		return (no_memory(hdl));
222e9dbad6fSeschrock 
223e9dbad6fSeschrock 	elem = NULL;
224e9dbad6fSeschrock 	while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) {
225e9dbad6fSeschrock 		if (!zfs_prop_user(nvpair_name(elem)))
226e9dbad6fSeschrock 			continue;
227e9dbad6fSeschrock 
228e9dbad6fSeschrock 		verify(nvpair_value_nvlist(elem, &propval) == 0);
229e9dbad6fSeschrock 		if (nvlist_add_nvlist(zhp->zfs_user_props,
230e9dbad6fSeschrock 		    nvpair_name(elem), propval) != 0)
231e9dbad6fSeschrock 			return (no_memory(hdl));
232e9dbad6fSeschrock 	}
233e9dbad6fSeschrock 
234e9dbad6fSeschrock 	return (0);
235e9dbad6fSeschrock }
236e9dbad6fSeschrock 
237fa9e4066Sahrens /*
238fa9e4066Sahrens  * Utility function to gather stats (objset and zpl) for the given object.
239fa9e4066Sahrens  */
240fa9e4066Sahrens static int
241fa9e4066Sahrens get_stats(zfs_handle_t *zhp)
242fa9e4066Sahrens {
243fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
244e9dbad6fSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
245fa9e4066Sahrens 
246fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
247fa9e4066Sahrens 
248e9dbad6fSeschrock 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
24999653d4eSeschrock 		return (-1);
2507f7322feSeschrock 
25199653d4eSeschrock 	while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
2527f7322feSeschrock 		if (errno == ENOMEM) {
253e9dbad6fSeschrock 			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
254e9dbad6fSeschrock 				zcmd_free_nvlists(&zc);
25599653d4eSeschrock 				return (-1);
256e9dbad6fSeschrock 			}
2577f7322feSeschrock 		} else {
258e9dbad6fSeschrock 			zcmd_free_nvlists(&zc);
2597f7322feSeschrock 			return (-1);
2607f7322feSeschrock 		}
2617f7322feSeschrock 	}
262fa9e4066Sahrens 
263a2eea2e1Sahrens 	zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */
264fa9e4066Sahrens 
265e9dbad6fSeschrock 	(void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root));
266ea8dc4b6Seschrock 
26799653d4eSeschrock 	if (zhp->zfs_props) {
26899653d4eSeschrock 		nvlist_free(zhp->zfs_props);
26999653d4eSeschrock 		zhp->zfs_props = NULL;
27099653d4eSeschrock 	}
27199653d4eSeschrock 
272e9dbad6fSeschrock 	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) {
273e9dbad6fSeschrock 		zcmd_free_nvlists(&zc);
27499653d4eSeschrock 		return (-1);
27599653d4eSeschrock 	}
276fa9e4066Sahrens 
277e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
278fa9e4066Sahrens 
279e9dbad6fSeschrock 	if (process_user_props(zhp) != 0)
280e9dbad6fSeschrock 		return (-1);
28199653d4eSeschrock 
282fa9e4066Sahrens 	return (0);
283fa9e4066Sahrens }
284fa9e4066Sahrens 
285fa9e4066Sahrens /*
286fa9e4066Sahrens  * Refresh the properties currently stored in the handle.
287fa9e4066Sahrens  */
288fa9e4066Sahrens void
289fa9e4066Sahrens zfs_refresh_properties(zfs_handle_t *zhp)
290fa9e4066Sahrens {
291fa9e4066Sahrens 	(void) get_stats(zhp);
292fa9e4066Sahrens }
293fa9e4066Sahrens 
294fa9e4066Sahrens /*
295fa9e4066Sahrens  * Makes a handle from the given dataset name.  Used by zfs_open() and
296fa9e4066Sahrens  * zfs_iter_* to create child handles on the fly.
297fa9e4066Sahrens  */
298fa9e4066Sahrens zfs_handle_t *
29999653d4eSeschrock make_dataset_handle(libzfs_handle_t *hdl, const char *path)
300fa9e4066Sahrens {
30199653d4eSeschrock 	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
30299653d4eSeschrock 
30399653d4eSeschrock 	if (zhp == NULL)
30499653d4eSeschrock 		return (NULL);
30599653d4eSeschrock 
30699653d4eSeschrock 	zhp->zfs_hdl = hdl;
307fa9e4066Sahrens 
30831fd60d3Sahrens top:
309fa9e4066Sahrens 	(void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
310fa9e4066Sahrens 
311fa9e4066Sahrens 	if (get_stats(zhp) != 0) {
312fa9e4066Sahrens 		free(zhp);
313fa9e4066Sahrens 		return (NULL);
314fa9e4066Sahrens 	}
315fa9e4066Sahrens 
31631fd60d3Sahrens 	if (zhp->zfs_dmustats.dds_inconsistent) {
31731fd60d3Sahrens 		zfs_cmd_t zc = { 0 };
31831fd60d3Sahrens 
31931fd60d3Sahrens 		/*
32031fd60d3Sahrens 		 * If it is dds_inconsistent, then we've caught it in
32131fd60d3Sahrens 		 * the middle of a 'zfs receive' or 'zfs destroy', and
32231fd60d3Sahrens 		 * it is inconsistent from the ZPL's point of view, so
32331fd60d3Sahrens 		 * can't be mounted.  However, it could also be that we
32431fd60d3Sahrens 		 * have crashed in the middle of one of those
32531fd60d3Sahrens 		 * operations, in which case we need to get rid of the
32631fd60d3Sahrens 		 * inconsistent state.  We do that by either rolling
32731fd60d3Sahrens 		 * back to the previous snapshot (which will fail if
32831fd60d3Sahrens 		 * there is none), or destroying the filesystem.  Note
32931fd60d3Sahrens 		 * that if we are still in the middle of an active
33031fd60d3Sahrens 		 * 'receive' or 'destroy', then the rollback and destroy
33131fd60d3Sahrens 		 * will fail with EBUSY and we will drive on as usual.
33231fd60d3Sahrens 		 */
33331fd60d3Sahrens 
33431fd60d3Sahrens 		(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
33531fd60d3Sahrens 
336a2eea2e1Sahrens 		if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) {
33799653d4eSeschrock 			(void) zvol_remove_link(hdl, zhp->zfs_name);
33831fd60d3Sahrens 			zc.zc_objset_type = DMU_OST_ZVOL;
33931fd60d3Sahrens 		} else {
34031fd60d3Sahrens 			zc.zc_objset_type = DMU_OST_ZFS;
34131fd60d3Sahrens 		}
34231fd60d3Sahrens 
34331fd60d3Sahrens 		/* If we can successfully roll it back, reget the stats */
34499653d4eSeschrock 		if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0)
34531fd60d3Sahrens 			goto top;
34631fd60d3Sahrens 		/*
34731fd60d3Sahrens 		 * If we can sucessfully destroy it, pretend that it
34831fd60d3Sahrens 		 * never existed.
34931fd60d3Sahrens 		 */
35099653d4eSeschrock 		if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) {
35131fd60d3Sahrens 			free(zhp);
35231fd60d3Sahrens 			errno = ENOENT;
35331fd60d3Sahrens 			return (NULL);
35431fd60d3Sahrens 		}
35531fd60d3Sahrens 	}
35631fd60d3Sahrens 
357fa9e4066Sahrens 	/*
358fa9e4066Sahrens 	 * We've managed to open the dataset and gather statistics.  Determine
359fa9e4066Sahrens 	 * the high-level type.
360fa9e4066Sahrens 	 */
361a2eea2e1Sahrens 	if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
362a2eea2e1Sahrens 		zhp->zfs_head_type = ZFS_TYPE_VOLUME;
363a2eea2e1Sahrens 	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
364a2eea2e1Sahrens 		zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
365a2eea2e1Sahrens 	else
366a2eea2e1Sahrens 		abort();
367a2eea2e1Sahrens 
368fa9e4066Sahrens 	if (zhp->zfs_dmustats.dds_is_snapshot)
369fa9e4066Sahrens 		zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
370fa9e4066Sahrens 	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
371fa9e4066Sahrens 		zhp->zfs_type = ZFS_TYPE_VOLUME;
372fa9e4066Sahrens 	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
373fa9e4066Sahrens 		zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
374fa9e4066Sahrens 	else
37599653d4eSeschrock 		abort();	/* we should never see any other types */
376fa9e4066Sahrens 
377fa9e4066Sahrens 	return (zhp);
378fa9e4066Sahrens }
379fa9e4066Sahrens 
380fa9e4066Sahrens /*
381fa9e4066Sahrens  * Opens the given snapshot, filesystem, or volume.   The 'types'
382fa9e4066Sahrens  * argument is a mask of acceptable types.  The function will print an
383fa9e4066Sahrens  * appropriate error message and return NULL if it can't be opened.
384fa9e4066Sahrens  */
385fa9e4066Sahrens zfs_handle_t *
38699653d4eSeschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types)
387fa9e4066Sahrens {
388fa9e4066Sahrens 	zfs_handle_t *zhp;
38999653d4eSeschrock 	char errbuf[1024];
39099653d4eSeschrock 
39199653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf),
39299653d4eSeschrock 	    dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
393fa9e4066Sahrens 
394fa9e4066Sahrens 	/*
39599653d4eSeschrock 	 * Validate the name before we even try to open it.
396fa9e4066Sahrens 	 */
39799653d4eSeschrock 	if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) {
39899653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
39999653d4eSeschrock 		    "invalid dataset name"));
40099653d4eSeschrock 		(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
401fa9e4066Sahrens 		return (NULL);
402fa9e4066Sahrens 	}
403fa9e4066Sahrens 
404fa9e4066Sahrens 	/*
405fa9e4066Sahrens 	 * Try to get stats for the dataset, which will tell us if it exists.
406fa9e4066Sahrens 	 */
407fa9e4066Sahrens 	errno = 0;
40899653d4eSeschrock 	if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
409ece3d9b3Slling 		(void) zfs_standard_error(hdl, errno, errbuf);
410fa9e4066Sahrens 		return (NULL);
411fa9e4066Sahrens 	}
412fa9e4066Sahrens 
413fa9e4066Sahrens 	if (!(types & zhp->zfs_type)) {
41499653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
41594de1d4cSeschrock 		zfs_close(zhp);
416fa9e4066Sahrens 		return (NULL);
417fa9e4066Sahrens 	}
418fa9e4066Sahrens 
419fa9e4066Sahrens 	return (zhp);
420fa9e4066Sahrens }
421fa9e4066Sahrens 
422fa9e4066Sahrens /*
423fa9e4066Sahrens  * Release a ZFS handle.  Nothing to do but free the associated memory.
424fa9e4066Sahrens  */
425fa9e4066Sahrens void
426fa9e4066Sahrens zfs_close(zfs_handle_t *zhp)
427fa9e4066Sahrens {
428fa9e4066Sahrens 	if (zhp->zfs_mntopts)
429fa9e4066Sahrens 		free(zhp->zfs_mntopts);
430e9dbad6fSeschrock 	nvlist_free(zhp->zfs_props);
431e9dbad6fSeschrock 	nvlist_free(zhp->zfs_user_props);
432fa9e4066Sahrens 	free(zhp);
433fa9e4066Sahrens }
434fa9e4066Sahrens 
435fa9e4066Sahrens /*
436fa9e4066Sahrens  * Given a numeric suffix, convert the value into a number of bits that the
437fa9e4066Sahrens  * resulting value must be shifted.
438fa9e4066Sahrens  */
439fa9e4066Sahrens static int
44099653d4eSeschrock str2shift(libzfs_handle_t *hdl, const char *buf)
441fa9e4066Sahrens {
442fa9e4066Sahrens 	const char *ends = "BKMGTPEZ";
443fa9e4066Sahrens 	int i;
444fa9e4066Sahrens 
445fa9e4066Sahrens 	if (buf[0] == '\0')
446fa9e4066Sahrens 		return (0);
447fa9e4066Sahrens 	for (i = 0; i < strlen(ends); i++) {
448fa9e4066Sahrens 		if (toupper(buf[0]) == ends[i])
449fa9e4066Sahrens 			break;
450fa9e4066Sahrens 	}
451fa9e4066Sahrens 	if (i == strlen(ends)) {
45299653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
45399653d4eSeschrock 		    "invalid numeric suffix '%s'"), buf);
454fa9e4066Sahrens 		return (-1);
455fa9e4066Sahrens 	}
456fa9e4066Sahrens 
457fa9e4066Sahrens 	/*
458fa9e4066Sahrens 	 * We want to allow trailing 'b' characters for 'GB' or 'Mb'.  But don't
459fa9e4066Sahrens 	 * allow 'BB' - that's just weird.
460fa9e4066Sahrens 	 */
461fa9e4066Sahrens 	if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
46299653d4eSeschrock 	    toupper(buf[0]) != 'B'))
463fa9e4066Sahrens 		return (10*i);
464fa9e4066Sahrens 
46599653d4eSeschrock 	zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
46699653d4eSeschrock 	    "invalid numeric suffix '%s'"), buf);
467fa9e4066Sahrens 	return (-1);
468fa9e4066Sahrens }
469fa9e4066Sahrens 
470fa9e4066Sahrens /*
471fa9e4066Sahrens  * Convert a string of the form '100G' into a real number.  Used when setting
472fa9e4066Sahrens  * properties or creating a volume.  'buf' is used to place an extended error
473fa9e4066Sahrens  * message for the caller to use.
474fa9e4066Sahrens  */
475fa9e4066Sahrens static int
47699653d4eSeschrock nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)
477fa9e4066Sahrens {
478fa9e4066Sahrens 	char *end;
479fa9e4066Sahrens 	int shift;
480fa9e4066Sahrens 
481fa9e4066Sahrens 	*num = 0;
482fa9e4066Sahrens 
483fa9e4066Sahrens 	/* Check to see if this looks like a number.  */
484fa9e4066Sahrens 	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
48599653d4eSeschrock 		if (hdl)
48699653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
48799653d4eSeschrock 			    "bad numeric value '%s'"), value);
488fa9e4066Sahrens 		return (-1);
489fa9e4066Sahrens 	}
490fa9e4066Sahrens 
491fa9e4066Sahrens 	/* Rely on stroll() to process the numeric portion.  */
492fa9e4066Sahrens 	errno = 0;
493fa9e4066Sahrens 	*num = strtoll(value, &end, 10);
494fa9e4066Sahrens 
495fa9e4066Sahrens 	/*
496fa9e4066Sahrens 	 * Check for ERANGE, which indicates that the value is too large to fit
497fa9e4066Sahrens 	 * in a 64-bit value.
498fa9e4066Sahrens 	 */
499fa9e4066Sahrens 	if (errno == ERANGE) {
50099653d4eSeschrock 		if (hdl)
50199653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
50299653d4eSeschrock 			    "numeric value is too large"));
503fa9e4066Sahrens 		return (-1);
504fa9e4066Sahrens 	}
505fa9e4066Sahrens 
506fa9e4066Sahrens 	/*
507fa9e4066Sahrens 	 * If we have a decimal value, then do the computation with floating
508fa9e4066Sahrens 	 * point arithmetic.  Otherwise, use standard arithmetic.
509fa9e4066Sahrens 	 */
510fa9e4066Sahrens 	if (*end == '.') {
511fa9e4066Sahrens 		double fval = strtod(value, &end);
512fa9e4066Sahrens 
51399653d4eSeschrock 		if ((shift = str2shift(hdl, end)) == -1)
514fa9e4066Sahrens 			return (-1);
515fa9e4066Sahrens 
516fa9e4066Sahrens 		fval *= pow(2, shift);
517fa9e4066Sahrens 
518fa9e4066Sahrens 		if (fval > UINT64_MAX) {
51999653d4eSeschrock 			if (hdl)
52099653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
52199653d4eSeschrock 				    "numeric value is too large"));
522fa9e4066Sahrens 			return (-1);
523fa9e4066Sahrens 		}
524fa9e4066Sahrens 
525fa9e4066Sahrens 		*num = (uint64_t)fval;
526fa9e4066Sahrens 	} else {
52799653d4eSeschrock 		if ((shift = str2shift(hdl, end)) == -1)
528fa9e4066Sahrens 			return (-1);
529fa9e4066Sahrens 
530fa9e4066Sahrens 		/* Check for overflow */
531fa9e4066Sahrens 		if (shift >= 64 || (*num << shift) >> shift != *num) {
53299653d4eSeschrock 			if (hdl)
53399653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
53499653d4eSeschrock 				    "numeric value is too large"));
535fa9e4066Sahrens 			return (-1);
536fa9e4066Sahrens 		}
537fa9e4066Sahrens 
538fa9e4066Sahrens 		*num <<= shift;
539fa9e4066Sahrens 	}
540fa9e4066Sahrens 
541fa9e4066Sahrens 	return (0);
542fa9e4066Sahrens }
543fa9e4066Sahrens 
544fa9e4066Sahrens int
545e9dbad6fSeschrock zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val)
546fa9e4066Sahrens {
547e9dbad6fSeschrock 	return (nicestrtonum(hdl, str, val));
548fa9e4066Sahrens }
549fa9e4066Sahrens 
550fa9e4066Sahrens /*
551e9dbad6fSeschrock  * The prop_parse_*() functions are designed to allow flexibility in callers
552e9dbad6fSeschrock  * when setting properties.  At the DSL layer, all properties are either 64-bit
553e9dbad6fSeschrock  * numbers or strings.  We want the user to be able to ignore this fact and
554e9dbad6fSeschrock  * specify properties as native values (boolean, for example) or as strings (to
555e9dbad6fSeschrock  * simplify command line utilities).  This also handles converting index types
556e9dbad6fSeschrock  * (compression, checksum, etc) from strings to their on-disk index.
557fa9e4066Sahrens  */
558fa9e4066Sahrens 
559e9dbad6fSeschrock static int
560e9dbad6fSeschrock prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val)
561e9dbad6fSeschrock {
562e9dbad6fSeschrock 	uint64_t ret;
56399653d4eSeschrock 
564e9dbad6fSeschrock 	switch (nvpair_type(elem)) {
565e9dbad6fSeschrock 	case DATA_TYPE_STRING:
566e9dbad6fSeschrock 		{
567e9dbad6fSeschrock 			char *value;
568798d5834Sgw 			verify(nvpair_value_string(elem, &value) == 0);
569fa9e4066Sahrens 
570e9dbad6fSeschrock 			if (strcmp(value, "on") == 0) {
571e9dbad6fSeschrock 				ret = 1;
572e9dbad6fSeschrock 			} else if (strcmp(value, "off") == 0) {
573e9dbad6fSeschrock 				ret = 0;
574e9dbad6fSeschrock 			} else {
575e9dbad6fSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
576e9dbad6fSeschrock 				    "property '%s' must be 'on' or 'off'"),
577e9dbad6fSeschrock 				    nvpair_name(elem));
578e9dbad6fSeschrock 				return (-1);
579e9dbad6fSeschrock 			}
580e9dbad6fSeschrock 			break;
581e9dbad6fSeschrock 		}
582fa9e4066Sahrens 
583e9dbad6fSeschrock 	case DATA_TYPE_UINT64:
584e9dbad6fSeschrock 		{
585798d5834Sgw 			verify(nvpair_value_uint64(elem, &ret) == 0);
586e9dbad6fSeschrock 			if (ret > 1) {
587e9dbad6fSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
588e9dbad6fSeschrock 				    "'%s' must be a boolean value"),
589e9dbad6fSeschrock 				    nvpair_name(elem));
590e9dbad6fSeschrock 				return (-1);
591e9dbad6fSeschrock 			}
592e9dbad6fSeschrock 			break;
593fa9e4066Sahrens 		}
594fa9e4066Sahrens 
595e9dbad6fSeschrock 	case DATA_TYPE_BOOLEAN_VALUE:
596e9dbad6fSeschrock 		{
597e9dbad6fSeschrock 			boolean_t value;
598798d5834Sgw 			verify(nvpair_value_boolean_value(elem, &value) == 0);
599e9dbad6fSeschrock 			ret = value;
600fa9e4066Sahrens 			break;
601fa9e4066Sahrens 		}
602fa9e4066Sahrens 
603e9dbad6fSeschrock 	default:
604e9dbad6fSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
605e9dbad6fSeschrock 		    "'%s' must be a boolean value"),
606e9dbad6fSeschrock 		    nvpair_name(elem));
607e9dbad6fSeschrock 		return (-1);
608e9dbad6fSeschrock 	}
609fa9e4066Sahrens 
610e9dbad6fSeschrock 	*val = ret;
611e9dbad6fSeschrock 	return (0);
612e9dbad6fSeschrock }
613fa9e4066Sahrens 
614e9dbad6fSeschrock static int
615e9dbad6fSeschrock prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop,
616e9dbad6fSeschrock     uint64_t *val)
617e9dbad6fSeschrock {
618e9dbad6fSeschrock 	uint64_t ret;
619e9dbad6fSeschrock 	boolean_t isnone = B_FALSE;
620e9dbad6fSeschrock 
621e9dbad6fSeschrock 	switch (nvpair_type(elem)) {
622e9dbad6fSeschrock 	case DATA_TYPE_STRING:
623e9dbad6fSeschrock 		{
624e9dbad6fSeschrock 			char *value;
625e9dbad6fSeschrock 			(void) nvpair_value_string(elem, &value);
626e9dbad6fSeschrock 			if (strcmp(value, "none") == 0) {
627e9dbad6fSeschrock 				isnone = B_TRUE;
628e9dbad6fSeschrock 				ret = 0;
629e9dbad6fSeschrock 			} else if (nicestrtonum(hdl, value, &ret) != 0) {
630e9dbad6fSeschrock 				return (-1);
631fa9e4066Sahrens 			}
632e9dbad6fSeschrock 			break;
633fa9e4066Sahrens 		}
634fa9e4066Sahrens 
635e9dbad6fSeschrock 	case DATA_TYPE_UINT64:
636e9dbad6fSeschrock 		(void) nvpair_value_uint64(elem, &ret);
637fa9e4066Sahrens 		break;
638fa9e4066Sahrens 
639e9dbad6fSeschrock 	default:
640e9dbad6fSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
641e9dbad6fSeschrock 		    "'%s' must be a number"),
642e9dbad6fSeschrock 		    nvpair_name(elem));
643e9dbad6fSeschrock 		return (-1);
644e9dbad6fSeschrock 	}
645e9dbad6fSeschrock 
646e9dbad6fSeschrock 	/*
647e9dbad6fSeschrock 	 * Quota special: force 'none' and don't allow 0.
648e9dbad6fSeschrock 	 */
649e9dbad6fSeschrock 	if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) {
650e9dbad6fSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
651e9dbad6fSeschrock 		    "use 'none' to disable quota"));
652e9dbad6fSeschrock 		return (-1);
653e9dbad6fSeschrock 	}
654e9dbad6fSeschrock 
655e9dbad6fSeschrock 	*val = ret;
656e9dbad6fSeschrock 	return (0);
657e9dbad6fSeschrock }
658e9dbad6fSeschrock 
659e9dbad6fSeschrock static int
660e9dbad6fSeschrock prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop,
661e9dbad6fSeschrock     uint64_t *val)
662e9dbad6fSeschrock {
663e9dbad6fSeschrock 	char *propname = nvpair_name(elem);
664e9dbad6fSeschrock 	char *value;
665e9dbad6fSeschrock 
666e9dbad6fSeschrock 	if (nvpair_type(elem) != DATA_TYPE_STRING) {
667e9dbad6fSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
668e9dbad6fSeschrock 		    "'%s' must be a string"), propname);
669e9dbad6fSeschrock 		return (-1);
670e9dbad6fSeschrock 	}
671e9dbad6fSeschrock 
672e9dbad6fSeschrock 	(void) nvpair_value_string(elem, &value);
673e9dbad6fSeschrock 
674e9dbad6fSeschrock 	if (zfs_prop_string_to_index(prop, value, val) != 0) {
675e9dbad6fSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
676e9dbad6fSeschrock 		    "'%s' must be one of '%s'"), propname,
677e9dbad6fSeschrock 		    zfs_prop_values(prop));
678e9dbad6fSeschrock 		return (-1);
679e9dbad6fSeschrock 	}
680e9dbad6fSeschrock 
681e9dbad6fSeschrock 	return (0);
682e9dbad6fSeschrock }
683e9dbad6fSeschrock 
684b1b8ab34Slling /*
685b1b8ab34Slling  * Check if the bootfs name has the same pool name as it is set to.
686b1b8ab34Slling  * Assuming bootfs is a valid dataset name.
687b1b8ab34Slling  */
688b1b8ab34Slling static boolean_t
689b1b8ab34Slling bootfs_poolname_valid(char *pool, char *bootfs)
690b1b8ab34Slling {
691b1b8ab34Slling 	char ch, *pname;
692b1b8ab34Slling 
693b1b8ab34Slling 	/* get the pool name from the bootfs name */
694b1b8ab34Slling 	pname = bootfs;
695b1b8ab34Slling 	while (*bootfs && !isspace(*bootfs) && *bootfs != '/')
696b1b8ab34Slling 		bootfs++;
697b1b8ab34Slling 
698b1b8ab34Slling 	ch = *bootfs;
699b1b8ab34Slling 	*bootfs = 0;
700b1b8ab34Slling 
701b1b8ab34Slling 	if (strcmp(pool, pname) == 0) {
702b1b8ab34Slling 		*bootfs = ch;
703b1b8ab34Slling 		return (B_TRUE);
704b1b8ab34Slling 	}
705b1b8ab34Slling 
706b1b8ab34Slling 	*bootfs = ch;
707b1b8ab34Slling 	return (B_FALSE);
708b1b8ab34Slling }
709b1b8ab34Slling 
710e9dbad6fSeschrock /*
711e9dbad6fSeschrock  * Given an nvlist of properties to set, validates that they are correct, and
712e9dbad6fSeschrock  * parses any numeric properties (index, boolean, etc) if they are specified as
713e9dbad6fSeschrock  * strings.
714e9dbad6fSeschrock  */
715b1b8ab34Slling nvlist_t *
716b1b8ab34Slling zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name,
717b1b8ab34Slling     nvlist_t *nvl, uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
718e9dbad6fSeschrock {
719e9dbad6fSeschrock 	nvpair_t *elem;
720e9dbad6fSeschrock 	const char *propname;
721e9dbad6fSeschrock 	zfs_prop_t prop;
722e9dbad6fSeschrock 	uint64_t intval;
723e9dbad6fSeschrock 	char *strval;
724e9dbad6fSeschrock 	nvlist_t *ret;
725b1b8ab34Slling 	int isuser;
726e9dbad6fSeschrock 
727e9dbad6fSeschrock 	if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
728e9dbad6fSeschrock 		(void) no_memory(hdl);
729e9dbad6fSeschrock 		return (NULL);
730e9dbad6fSeschrock 	}
731e9dbad6fSeschrock 
732e9dbad6fSeschrock 	if (type == ZFS_TYPE_SNAPSHOT) {
733e9dbad6fSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
734d7d4af51Smmusante 		    "snapshot properties cannot be modified"));
735e9dbad6fSeschrock 		(void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
736e9dbad6fSeschrock 		goto error;
737e9dbad6fSeschrock 	}
738e9dbad6fSeschrock 
739e9dbad6fSeschrock 	elem = NULL;
740e9dbad6fSeschrock 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
741e9dbad6fSeschrock 		propname = nvpair_name(elem);
742e9dbad6fSeschrock 
743fa9e4066Sahrens 		/*
744e9dbad6fSeschrock 		 * Make sure this property is valid and applies to this type.
745fa9e4066Sahrens 		 */
746b1b8ab34Slling 		if ((prop = zfs_name_to_prop_common(propname, type))
747b1b8ab34Slling 		    == ZFS_PROP_INVAL) {
748b1b8ab34Slling 			isuser = zfs_prop_user(propname);
749b1b8ab34Slling 			if (!isuser || (isuser && (type & ZFS_TYPE_POOL))) {
75099653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
751e9dbad6fSeschrock 				    "invalid property '%s'"),
752e9dbad6fSeschrock 				    propname);
753e9dbad6fSeschrock 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
754e9dbad6fSeschrock 				goto error;
755e9dbad6fSeschrock 			} else {
756e9dbad6fSeschrock 				/*
757e9dbad6fSeschrock 				 * If this is a user property, make sure it's a
758e9dbad6fSeschrock 				 * string, and that it's less than
759e9dbad6fSeschrock 				 * ZAP_MAXNAMELEN.
760e9dbad6fSeschrock 				 */
761e9dbad6fSeschrock 				if (nvpair_type(elem) != DATA_TYPE_STRING) {
762e9dbad6fSeschrock 					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
763e9dbad6fSeschrock 					    "'%s' must be a string"),
764e9dbad6fSeschrock 					    propname);
765e9dbad6fSeschrock 					(void) zfs_error(hdl, EZFS_BADPROP,
766e9dbad6fSeschrock 					    errbuf);
767e9dbad6fSeschrock 					goto error;
768e9dbad6fSeschrock 				}
769fa9e4066Sahrens 
770e9dbad6fSeschrock 				if (strlen(nvpair_name(elem)) >=
771e9dbad6fSeschrock 				    ZAP_MAXNAMELEN) {
772e9dbad6fSeschrock 					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
773e9dbad6fSeschrock 					    "property name '%s' is too long"),
774e9dbad6fSeschrock 					    propname);
775e9dbad6fSeschrock 					(void) zfs_error(hdl, EZFS_BADPROP,
776e9dbad6fSeschrock 					    errbuf);
777e9dbad6fSeschrock 					goto error;
778fa9e4066Sahrens 				}
779fa9e4066Sahrens 			}
780fa9e4066Sahrens 
781e9dbad6fSeschrock 			(void) nvpair_value_string(elem, &strval);
782e9dbad6fSeschrock 			if (nvlist_add_string(ret, propname, strval) != 0) {
783e9dbad6fSeschrock 				(void) no_memory(hdl);
784e9dbad6fSeschrock 				goto error;
785e9dbad6fSeschrock 			}
786e9dbad6fSeschrock 			continue;
787e9dbad6fSeschrock 		}
788e9dbad6fSeschrock 
789e9dbad6fSeschrock 		/*
790e9dbad6fSeschrock 		 * Normalize the name, to get rid of shorthand abbrevations.
791e9dbad6fSeschrock 		 */
792e9dbad6fSeschrock 		propname = zfs_prop_to_name(prop);
793e9dbad6fSeschrock 
794e9dbad6fSeschrock 		if (!zfs_prop_valid_for_type(prop, type)) {
795e9dbad6fSeschrock 			zfs_error_aux(hdl,
796e9dbad6fSeschrock 			    dgettext(TEXT_DOMAIN, "'%s' does not "
797e9dbad6fSeschrock 			    "apply to datasets of this type"), propname);
798e9dbad6fSeschrock 			(void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
799e9dbad6fSeschrock 			goto error;
800e9dbad6fSeschrock 		}
801e9dbad6fSeschrock 
802e9dbad6fSeschrock 		if (zfs_prop_readonly(prop) &&
803e9dbad6fSeschrock 		    (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) {
804e9dbad6fSeschrock 			zfs_error_aux(hdl,
805e9dbad6fSeschrock 			    dgettext(TEXT_DOMAIN, "'%s' is readonly"),
806e9dbad6fSeschrock 			    propname);
807e9dbad6fSeschrock 			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
808e9dbad6fSeschrock 			goto error;
809e9dbad6fSeschrock 		}
810e9dbad6fSeschrock 
811e9dbad6fSeschrock 		/*
812e9dbad6fSeschrock 		 * Convert any properties to the internal DSL value types.
813e9dbad6fSeschrock 		 */
814e9dbad6fSeschrock 		strval = NULL;
815e9dbad6fSeschrock 		switch (zfs_prop_get_type(prop)) {
816e9dbad6fSeschrock 		case prop_type_boolean:
817e9dbad6fSeschrock 			if (prop_parse_boolean(hdl, elem, &intval) != 0) {
818e9dbad6fSeschrock 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
819e9dbad6fSeschrock 				goto error;
820e9dbad6fSeschrock 			}
821e9dbad6fSeschrock 			break;
822e9dbad6fSeschrock 
823e9dbad6fSeschrock 		case prop_type_string:
824e9dbad6fSeschrock 			if (nvpair_type(elem) != DATA_TYPE_STRING) {
82599653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
826e9dbad6fSeschrock 				    "'%s' must be a string"),
827e9dbad6fSeschrock 				    propname);
828e9dbad6fSeschrock 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
829e9dbad6fSeschrock 				goto error;
830e9dbad6fSeschrock 			}
831e9dbad6fSeschrock 			(void) nvpair_value_string(elem, &strval);
832e9dbad6fSeschrock 			if (strlen(strval) >= ZFS_MAXPROPLEN) {
833e9dbad6fSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
834e9dbad6fSeschrock 				    "'%s' is too long"), propname);
835e9dbad6fSeschrock 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
836e9dbad6fSeschrock 				goto error;
837fa9e4066Sahrens 			}
838fa9e4066Sahrens 			break;
839fa9e4066Sahrens 
840e9dbad6fSeschrock 		case prop_type_number:
841e9dbad6fSeschrock 			if (prop_parse_number(hdl, elem, prop, &intval) != 0) {
842e9dbad6fSeschrock 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
843e9dbad6fSeschrock 				goto error;
844fa9e4066Sahrens 			}
845e9dbad6fSeschrock 			break;
846fa9e4066Sahrens 
847e9dbad6fSeschrock 		case prop_type_index:
848e9dbad6fSeschrock 			if (prop_parse_index(hdl, elem, prop, &intval) != 0) {
849e9dbad6fSeschrock 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
850e9dbad6fSeschrock 				goto error;
851fa9e4066Sahrens 			}
852fa9e4066Sahrens 			break;
853fa9e4066Sahrens 
854e9dbad6fSeschrock 		default:
855e9dbad6fSeschrock 			abort();
856e9dbad6fSeschrock 		}
857e9dbad6fSeschrock 
858e9dbad6fSeschrock 		/*
859e9dbad6fSeschrock 		 * Add the result to our return set of properties.
860e9dbad6fSeschrock 		 */
861e9dbad6fSeschrock 		if (strval) {
862e9dbad6fSeschrock 			if (nvlist_add_string(ret, propname, strval) != 0) {
863e9dbad6fSeschrock 				(void) no_memory(hdl);
864e9dbad6fSeschrock 				goto error;
865fa9e4066Sahrens 			}
866e9dbad6fSeschrock 		} else if (nvlist_add_uint64(ret, propname, intval) != 0) {
867e9dbad6fSeschrock 			(void) no_memory(hdl);
868e9dbad6fSeschrock 			goto error;
869e9dbad6fSeschrock 		}
870fa9e4066Sahrens 
871e9dbad6fSeschrock 		/*
872e9dbad6fSeschrock 		 * Perform some additional checks for specific properties.
873e9dbad6fSeschrock 		 */
874e9dbad6fSeschrock 		switch (prop) {
875e9dbad6fSeschrock 		case ZFS_PROP_RECORDSIZE:
876e9dbad6fSeschrock 		case ZFS_PROP_VOLBLOCKSIZE:
877e9dbad6fSeschrock 			/* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */
878e9dbad6fSeschrock 			if (intval < SPA_MINBLOCKSIZE ||
879e9dbad6fSeschrock 			    intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) {
88099653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
881e9dbad6fSeschrock 				    "'%s' must be power of 2 from %u "
882e9dbad6fSeschrock 				    "to %uk"), propname,
883e9dbad6fSeschrock 				    (uint_t)SPA_MINBLOCKSIZE,
884e9dbad6fSeschrock 				    (uint_t)SPA_MAXBLOCKSIZE >> 10);
885e9dbad6fSeschrock 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
886e9dbad6fSeschrock 				goto error;
887fa9e4066Sahrens 			}
888fa9e4066Sahrens 			break;
889fa9e4066Sahrens 
890f3861e1aSahl 		case ZFS_PROP_SHAREISCSI:
891f3861e1aSahl 			if (strcmp(strval, "off") != 0 &&
892f3861e1aSahl 			    strcmp(strval, "on") != 0 &&
893f3861e1aSahl 			    strcmp(strval, "type=disk") != 0) {
894f3861e1aSahl 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
895f3861e1aSahl 				    "'%s' must be 'on', 'off', or 'type=disk'"),
896f3861e1aSahl 				    propname);
897f3861e1aSahl 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
898f3861e1aSahl 				goto error;
899f3861e1aSahl 			}
900f3861e1aSahl 
901f3861e1aSahl 			break;
902f3861e1aSahl 
903e9dbad6fSeschrock 		case ZFS_PROP_MOUNTPOINT:
904e9dbad6fSeschrock 			if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
905e9dbad6fSeschrock 			    strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
906e9dbad6fSeschrock 				break;
907fa9e4066Sahrens 
908e9dbad6fSeschrock 			if (strval[0] != '/') {
90999653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
910e9dbad6fSeschrock 				    "'%s' must be an absolute path, "
911e9dbad6fSeschrock 				    "'none', or 'legacy'"), propname);
912e9dbad6fSeschrock 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
913e9dbad6fSeschrock 				goto error;
914fa9e4066Sahrens 			}
915f3861e1aSahl 			/*FALLTHRU*/
916fa9e4066Sahrens 
917f3861e1aSahl 		case ZFS_PROP_SHARENFS:
918f3861e1aSahl 			/*
919f3861e1aSahl 			 * For the mountpoint and sharenfs properties, check if
920f3861e1aSahl 			 * it can be set in a global/non-global zone based on
921f3861e1aSahl 			 * the zoned property value:
922f3861e1aSahl 			 *
923f3861e1aSahl 			 *		global zone	    non-global zone
924f3861e1aSahl 			 * --------------------------------------------------
925f3861e1aSahl 			 * zoned=on	mountpoint (no)	    mountpoint (yes)
926f3861e1aSahl 			 *		sharenfs (no)	    sharenfs (no)
927f3861e1aSahl 			 *
928f3861e1aSahl 			 * zoned=off	mountpoint (yes)	N/A
929f3861e1aSahl 			 *		sharenfs (yes)
930f3861e1aSahl 			 */
931e9dbad6fSeschrock 			if (zoned) {
932e9dbad6fSeschrock 				if (getzoneid() == GLOBAL_ZONEID) {
933e9dbad6fSeschrock 					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
934e9dbad6fSeschrock 					    "'%s' cannot be set on "
935e9dbad6fSeschrock 					    "dataset in a non-global zone"),
936e9dbad6fSeschrock 					    propname);
937e9dbad6fSeschrock 					(void) zfs_error(hdl, EZFS_ZONED,
938e9dbad6fSeschrock 					    errbuf);
939e9dbad6fSeschrock 					goto error;
940e9dbad6fSeschrock 				} else if (prop == ZFS_PROP_SHARENFS) {
941e9dbad6fSeschrock 					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
942e9dbad6fSeschrock 					    "'%s' cannot be set in "
943e9dbad6fSeschrock 					    "a non-global zone"), propname);
944e9dbad6fSeschrock 					(void) zfs_error(hdl, EZFS_ZONED,
945e9dbad6fSeschrock 					    errbuf);
946e9dbad6fSeschrock 					goto error;
947fa9e4066Sahrens 				}
948e9dbad6fSeschrock 			} else if (getzoneid() != GLOBAL_ZONEID) {
949e9dbad6fSeschrock 				/*
950e9dbad6fSeschrock 				 * If zoned property is 'off', this must be in
951e9dbad6fSeschrock 				 * a globle zone. If not, something is wrong.
952e9dbad6fSeschrock 				 */
953e9dbad6fSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
954e9dbad6fSeschrock 				    "'%s' cannot be set while dataset "
955e9dbad6fSeschrock 				    "'zoned' property is set"), propname);
956e9dbad6fSeschrock 				(void) zfs_error(hdl, EZFS_ZONED, errbuf);
957e9dbad6fSeschrock 				goto error;
958fa9e4066Sahrens 			}
959f3861e1aSahl 
960f3861e1aSahl 			break;
961b1b8ab34Slling 
962b1b8ab34Slling 		case ZFS_PROP_BOOTFS:
963b1b8ab34Slling 			/*
964b1b8ab34Slling 			 * bootfs property value has to be a dataset name and
965b1b8ab34Slling 			 * the dataset has to be in the same pool as it sets to.
966b1b8ab34Slling 			 */
967b1b8ab34Slling 			if (strval[0] != '\0' && (!zfs_name_valid(strval,
968b1b8ab34Slling 			    ZFS_TYPE_FILESYSTEM) || !bootfs_poolname_valid(
969b1b8ab34Slling 			    pool_name, strval))) {
970b1b8ab34Slling 
971b1b8ab34Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
972b1b8ab34Slling 				    "is an invalid name"), strval);
973b1b8ab34Slling 				(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
974b1b8ab34Slling 				goto error;
975b1b8ab34Slling 			}
976b1b8ab34Slling 			break;
977e9dbad6fSeschrock 		}
978fa9e4066Sahrens 
979e9dbad6fSeschrock 		/*
980e9dbad6fSeschrock 		 * For changes to existing volumes, we have some additional
981e9dbad6fSeschrock 		 * checks to enforce.
982e9dbad6fSeschrock 		 */
983e9dbad6fSeschrock 		if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
984e9dbad6fSeschrock 			uint64_t volsize = zfs_prop_get_int(zhp,
985e9dbad6fSeschrock 			    ZFS_PROP_VOLSIZE);
986e9dbad6fSeschrock 			uint64_t blocksize = zfs_prop_get_int(zhp,
987e9dbad6fSeschrock 			    ZFS_PROP_VOLBLOCKSIZE);
988e9dbad6fSeschrock 			char buf[64];
989e9dbad6fSeschrock 
990e9dbad6fSeschrock 			switch (prop) {
991e9dbad6fSeschrock 			case ZFS_PROP_RESERVATION:
992e9dbad6fSeschrock 				if (intval > volsize) {
993e9dbad6fSeschrock 					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
994e9dbad6fSeschrock 					    "'%s' is greater than current "
995e9dbad6fSeschrock 					    "volume size"), propname);
996e9dbad6fSeschrock 					(void) zfs_error(hdl, EZFS_BADPROP,
997e9dbad6fSeschrock 					    errbuf);
998e9dbad6fSeschrock 					goto error;
999e9dbad6fSeschrock 				}
1000e9dbad6fSeschrock 				break;
1001e9dbad6fSeschrock 
1002e9dbad6fSeschrock 			case ZFS_PROP_VOLSIZE:
1003e9dbad6fSeschrock 				if (intval % blocksize != 0) {
1004e9dbad6fSeschrock 					zfs_nicenum(blocksize, buf,
1005e9dbad6fSeschrock 					    sizeof (buf));
1006e9dbad6fSeschrock 					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1007e9dbad6fSeschrock 					    "'%s' must be a multiple of "
1008e9dbad6fSeschrock 					    "volume block size (%s)"),
1009e9dbad6fSeschrock 					    propname, buf);
1010e9dbad6fSeschrock 					(void) zfs_error(hdl, EZFS_BADPROP,
1011e9dbad6fSeschrock 					    errbuf);
1012e9dbad6fSeschrock 					goto error;
1013e9dbad6fSeschrock 				}
1014e9dbad6fSeschrock 
1015e9dbad6fSeschrock 				if (intval == 0) {
1016e9dbad6fSeschrock 					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1017e9dbad6fSeschrock 					    "'%s' cannot be zero"),
1018e9dbad6fSeschrock 					    propname);
1019e9dbad6fSeschrock 					(void) zfs_error(hdl, EZFS_BADPROP,
1020e9dbad6fSeschrock 					    errbuf);
1021e9dbad6fSeschrock 					goto error;
1022e9dbad6fSeschrock 				}
1023f3861e1aSahl 				break;
1024fa9e4066Sahrens 			}
1025e9dbad6fSeschrock 		}
1026e9dbad6fSeschrock 	}
1027fa9e4066Sahrens 
1028e9dbad6fSeschrock 	/*
1029e9dbad6fSeschrock 	 * If this is an existing volume, and someone is setting the volsize,
1030e9dbad6fSeschrock 	 * make sure that it matches the reservation, or add it if necessary.
1031e9dbad6fSeschrock 	 */
1032e9dbad6fSeschrock 	if (zhp != NULL && type == ZFS_TYPE_VOLUME &&
1033e9dbad6fSeschrock 	    nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1034e9dbad6fSeschrock 	    &intval) == 0) {
1035e9dbad6fSeschrock 		uint64_t old_volsize = zfs_prop_get_int(zhp,
1036e9dbad6fSeschrock 		    ZFS_PROP_VOLSIZE);
1037e9dbad6fSeschrock 		uint64_t old_reservation = zfs_prop_get_int(zhp,
1038e9dbad6fSeschrock 		    ZFS_PROP_RESERVATION);
1039e9dbad6fSeschrock 		uint64_t new_reservation;
1040e9dbad6fSeschrock 
1041e9dbad6fSeschrock 		if (old_volsize == old_reservation &&
1042e9dbad6fSeschrock 		    nvlist_lookup_uint64(ret,
1043e9dbad6fSeschrock 		    zfs_prop_to_name(ZFS_PROP_RESERVATION),
1044e9dbad6fSeschrock 		    &new_reservation) != 0) {
1045e9dbad6fSeschrock 			if (nvlist_add_uint64(ret,
1046e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_RESERVATION),
1047e9dbad6fSeschrock 			    intval) != 0) {
1048e9dbad6fSeschrock 				(void) no_memory(hdl);
1049e9dbad6fSeschrock 				goto error;
1050e9dbad6fSeschrock 			}
1051fa9e4066Sahrens 		}
1052fa9e4066Sahrens 	}
1053fa9e4066Sahrens 
1054e9dbad6fSeschrock 	return (ret);
1055fa9e4066Sahrens 
1056e9dbad6fSeschrock error:
1057e9dbad6fSeschrock 	nvlist_free(ret);
1058e9dbad6fSeschrock 	return (NULL);
1059fa9e4066Sahrens }
1060fa9e4066Sahrens 
1061fa9e4066Sahrens /*
1062fa9e4066Sahrens  * Given a property name and value, set the property for the given dataset.
1063fa9e4066Sahrens  */
1064fa9e4066Sahrens int
1065e9dbad6fSeschrock zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
1066fa9e4066Sahrens {
1067fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1068e9dbad6fSeschrock 	int ret = -1;
1069e9dbad6fSeschrock 	prop_changelist_t *cl = NULL;
107099653d4eSeschrock 	char errbuf[1024];
107199653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
1072e9dbad6fSeschrock 	nvlist_t *nvl = NULL, *realprops;
1073e9dbad6fSeschrock 	zfs_prop_t prop;
107499653d4eSeschrock 
107599653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf),
1076e9dbad6fSeschrock 	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
107799653d4eSeschrock 	    zhp->zfs_name);
107899653d4eSeschrock 
1079e9dbad6fSeschrock 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
1080e9dbad6fSeschrock 	    nvlist_add_string(nvl, propname, propval) != 0) {
1081e9dbad6fSeschrock 		(void) no_memory(hdl);
1082e9dbad6fSeschrock 		goto error;
1083fa9e4066Sahrens 	}
1084fa9e4066Sahrens 
1085b1b8ab34Slling 	if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, NULL, nvl,
1086e9dbad6fSeschrock 	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL)
1087e9dbad6fSeschrock 		goto error;
1088e9dbad6fSeschrock 	nvlist_free(nvl);
1089e9dbad6fSeschrock 	nvl = realprops;
1090e9dbad6fSeschrock 
1091e9dbad6fSeschrock 	prop = zfs_name_to_prop(propname);
1092e9dbad6fSeschrock 
1093fa9e4066Sahrens 	if ((cl = changelist_gather(zhp, prop, 0)) == NULL)
1094e9dbad6fSeschrock 		goto error;
1095fa9e4066Sahrens 
1096fa9e4066Sahrens 	if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
109799653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
109899653d4eSeschrock 		    "child dataset with inherited mountpoint is used "
109999653d4eSeschrock 		    "in a non-global zone"));
110099653d4eSeschrock 		ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1101fa9e4066Sahrens 		goto error;
1102fa9e4066Sahrens 	}
1103fa9e4066Sahrens 
1104fa9e4066Sahrens 	if ((ret = changelist_prefix(cl)) != 0)
1105fa9e4066Sahrens 		goto error;
1106fa9e4066Sahrens 
1107fa9e4066Sahrens 	/*
1108fa9e4066Sahrens 	 * Execute the corresponding ioctl() to set this property.
1109fa9e4066Sahrens 	 */
1110fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1111fa9e4066Sahrens 
1112e9dbad6fSeschrock 	if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0)
1113e9dbad6fSeschrock 		goto error;
1114e9dbad6fSeschrock 
1115e9dbad6fSeschrock 	ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc);
1116fa9e4066Sahrens 
1117fa9e4066Sahrens 	if (ret != 0) {
1118fa9e4066Sahrens 		switch (errno) {
1119fa9e4066Sahrens 
1120fa9e4066Sahrens 		case ENOSPC:
1121fa9e4066Sahrens 			/*
1122fa9e4066Sahrens 			 * For quotas and reservations, ENOSPC indicates
1123fa9e4066Sahrens 			 * something different; setting a quota or reservation
1124fa9e4066Sahrens 			 * doesn't use any disk space.
1125fa9e4066Sahrens 			 */
1126fa9e4066Sahrens 			switch (prop) {
1127fa9e4066Sahrens 			case ZFS_PROP_QUOTA:
112899653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
112999653d4eSeschrock 				    "size is less than current used or "
113099653d4eSeschrock 				    "reserved space"));
113199653d4eSeschrock 				(void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1132fa9e4066Sahrens 				break;
1133fa9e4066Sahrens 
1134fa9e4066Sahrens 			case ZFS_PROP_RESERVATION:
113599653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
113699653d4eSeschrock 				    "size is greater than available space"));
113799653d4eSeschrock 				(void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1138fa9e4066Sahrens 				break;
1139fa9e4066Sahrens 
1140fa9e4066Sahrens 			default:
114199653d4eSeschrock 				(void) zfs_standard_error(hdl, errno, errbuf);
1142fa9e4066Sahrens 				break;
1143fa9e4066Sahrens 			}
1144fa9e4066Sahrens 			break;
1145fa9e4066Sahrens 
1146fa9e4066Sahrens 		case EBUSY:
114799653d4eSeschrock 			if (prop == ZFS_PROP_VOLBLOCKSIZE)
114899653d4eSeschrock 				(void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf);
114999653d4eSeschrock 			else
1150e9dbad6fSeschrock 				(void) zfs_standard_error(hdl, EBUSY, errbuf);
1151fa9e4066Sahrens 			break;
1152fa9e4066Sahrens 
11532a79c5feSlling 		case EROFS:
115499653d4eSeschrock 			(void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
11552a79c5feSlling 			break;
11562a79c5feSlling 
1157c9431fa1Sahl 		case ENOTSUP:
1158c9431fa1Sahl 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1159c9431fa1Sahl 			    "pool must be upgraded to allow gzip compression"));
1160c9431fa1Sahl 			(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
1161c9431fa1Sahl 			break;
1162c9431fa1Sahl 
1163fa9e4066Sahrens 		case EOVERFLOW:
1164fa9e4066Sahrens 			/*
1165fa9e4066Sahrens 			 * This platform can't address a volume this big.
1166fa9e4066Sahrens 			 */
1167fa9e4066Sahrens #ifdef _ILP32
1168fa9e4066Sahrens 			if (prop == ZFS_PROP_VOLSIZE) {
116999653d4eSeschrock 				(void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
1170fa9e4066Sahrens 				break;
1171fa9e4066Sahrens 			}
1172fa9e4066Sahrens #endif
117399653d4eSeschrock 			/* FALLTHROUGH */
1174fa9e4066Sahrens 		default:
117599653d4eSeschrock 			(void) zfs_standard_error(hdl, errno, errbuf);
1176fa9e4066Sahrens 		}
1177fa9e4066Sahrens 	} else {
1178fa9e4066Sahrens 		/*
1179fa9e4066Sahrens 		 * Refresh the statistics so the new property value
1180fa9e4066Sahrens 		 * is reflected.
1181fa9e4066Sahrens 		 */
1182e9dbad6fSeschrock 		if ((ret = changelist_postfix(cl)) == 0)
1183e9dbad6fSeschrock 			(void) get_stats(zhp);
1184fa9e4066Sahrens 	}
1185fa9e4066Sahrens 
1186fa9e4066Sahrens error:
1187e9dbad6fSeschrock 	nvlist_free(nvl);
1188e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1189e9dbad6fSeschrock 	if (cl)
1190e9dbad6fSeschrock 		changelist_free(cl);
1191fa9e4066Sahrens 	return (ret);
1192fa9e4066Sahrens }
1193fa9e4066Sahrens 
1194fa9e4066Sahrens /*
1195fa9e4066Sahrens  * Given a property, inherit the value from the parent dataset.
1196fa9e4066Sahrens  */
1197fa9e4066Sahrens int
1198e9dbad6fSeschrock zfs_prop_inherit(zfs_handle_t *zhp, const char *propname)
1199fa9e4066Sahrens {
1200fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1201fa9e4066Sahrens 	int ret;
1202fa9e4066Sahrens 	prop_changelist_t *cl;
120399653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
120499653d4eSeschrock 	char errbuf[1024];
1205e9dbad6fSeschrock 	zfs_prop_t prop;
120699653d4eSeschrock 
120799653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
120899653d4eSeschrock 	    "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
1209fa9e4066Sahrens 
1210e9dbad6fSeschrock 	if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) {
1211e9dbad6fSeschrock 		/*
1212e9dbad6fSeschrock 		 * For user properties, the amount of work we have to do is very
1213e9dbad6fSeschrock 		 * small, so just do it here.
1214e9dbad6fSeschrock 		 */
1215e9dbad6fSeschrock 		if (!zfs_prop_user(propname)) {
1216e9dbad6fSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1217e9dbad6fSeschrock 			    "invalid property"));
1218e9dbad6fSeschrock 			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
1219e9dbad6fSeschrock 		}
1220e9dbad6fSeschrock 
1221e9dbad6fSeschrock 		(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1222e9dbad6fSeschrock 		(void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1223e9dbad6fSeschrock 
1224e9dbad6fSeschrock 		if (ioctl(zhp->zfs_hdl->libzfs_fd,
1225e9dbad6fSeschrock 		    ZFS_IOC_SET_PROP, &zc) != 0)
1226e9dbad6fSeschrock 			return (zfs_standard_error(hdl, errno, errbuf));
1227e9dbad6fSeschrock 
1228e9dbad6fSeschrock 		return (0);
1229e9dbad6fSeschrock 	}
1230e9dbad6fSeschrock 
1231fa9e4066Sahrens 	/*
1232fa9e4066Sahrens 	 * Verify that this property is inheritable.
1233fa9e4066Sahrens 	 */
123499653d4eSeschrock 	if (zfs_prop_readonly(prop))
123599653d4eSeschrock 		return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
1236fa9e4066Sahrens 
123799653d4eSeschrock 	if (!zfs_prop_inheritable(prop))
123899653d4eSeschrock 		return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
1239fa9e4066Sahrens 
1240fa9e4066Sahrens 	/*
1241fa9e4066Sahrens 	 * Check to see if the value applies to this type
1242fa9e4066Sahrens 	 */
124399653d4eSeschrock 	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
124499653d4eSeschrock 		return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
1245fa9e4066Sahrens 
1246bf7c2d40Srm 	/*
1247bf7c2d40Srm 	 * Normalize the name, to get rid of shorthand abbrevations.
1248bf7c2d40Srm 	 */
1249bf7c2d40Srm 	propname = zfs_prop_to_name(prop);
1250fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1251e9dbad6fSeschrock 	(void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1252fa9e4066Sahrens 
1253fa9e4066Sahrens 	if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
1254fa9e4066Sahrens 	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
125599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
125699653d4eSeschrock 		    "dataset is used in a non-global zone"));
125799653d4eSeschrock 		return (zfs_error(hdl, EZFS_ZONED, errbuf));
1258fa9e4066Sahrens 	}
1259fa9e4066Sahrens 
1260fa9e4066Sahrens 	/*
1261fa9e4066Sahrens 	 * Determine datasets which will be affected by this change, if any.
1262fa9e4066Sahrens 	 */
1263fa9e4066Sahrens 	if ((cl = changelist_gather(zhp, prop, 0)) == NULL)
1264fa9e4066Sahrens 		return (-1);
1265fa9e4066Sahrens 
1266fa9e4066Sahrens 	if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
126799653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
126899653d4eSeschrock 		    "child dataset with inherited mountpoint is used "
126999653d4eSeschrock 		    "in a non-global zone"));
127099653d4eSeschrock 		ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1271fa9e4066Sahrens 		goto error;
1272fa9e4066Sahrens 	}
1273fa9e4066Sahrens 
1274fa9e4066Sahrens 	if ((ret = changelist_prefix(cl)) != 0)
1275fa9e4066Sahrens 		goto error;
1276fa9e4066Sahrens 
127799653d4eSeschrock 	if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd,
127899653d4eSeschrock 	    ZFS_IOC_SET_PROP, &zc)) != 0) {
127999653d4eSeschrock 		return (zfs_standard_error(hdl, errno, errbuf));
1280fa9e4066Sahrens 	} else {
1281fa9e4066Sahrens 
1282efc555ebSnd 		if ((ret = changelist_postfix(cl)) != 0)
1283fa9e4066Sahrens 			goto error;
1284fa9e4066Sahrens 
1285fa9e4066Sahrens 		/*
1286fa9e4066Sahrens 		 * Refresh the statistics so the new property is reflected.
1287fa9e4066Sahrens 		 */
1288fa9e4066Sahrens 		(void) get_stats(zhp);
1289fa9e4066Sahrens 	}
1290fa9e4066Sahrens 
1291fa9e4066Sahrens error:
1292fa9e4066Sahrens 	changelist_free(cl);
1293fa9e4066Sahrens 	return (ret);
1294fa9e4066Sahrens }
1295fa9e4066Sahrens 
1296b1b8ab34Slling void
1297fa9e4066Sahrens nicebool(int value, char *buf, size_t buflen)
1298fa9e4066Sahrens {
1299fa9e4066Sahrens 	if (value)
1300fa9e4066Sahrens 		(void) strlcpy(buf, "on", buflen);
1301fa9e4066Sahrens 	else
1302fa9e4066Sahrens 		(void) strlcpy(buf, "off", buflen);
1303fa9e4066Sahrens }
1304fa9e4066Sahrens 
13057f7322feSeschrock /*
13067f7322feSeschrock  * True DSL properties are stored in an nvlist.  The following two functions
13077f7322feSeschrock  * extract them appropriately.
13087f7322feSeschrock  */
13097f7322feSeschrock static uint64_t
13107f7322feSeschrock getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
13117f7322feSeschrock {
13127f7322feSeschrock 	nvlist_t *nv;
13137f7322feSeschrock 	uint64_t value;
13147f7322feSeschrock 
1315a2eea2e1Sahrens 	*source = NULL;
13167f7322feSeschrock 	if (nvlist_lookup_nvlist(zhp->zfs_props,
13177f7322feSeschrock 	    zfs_prop_to_name(prop), &nv) == 0) {
13187f7322feSeschrock 		verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0);
1319a2eea2e1Sahrens 		(void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source);
13207f7322feSeschrock 	} else {
13217f7322feSeschrock 		value = zfs_prop_default_numeric(prop);
13227f7322feSeschrock 		*source = "";
13237f7322feSeschrock 	}
13247f7322feSeschrock 
13257f7322feSeschrock 	return (value);
13267f7322feSeschrock }
13277f7322feSeschrock 
13287f7322feSeschrock static char *
13297f7322feSeschrock getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
13307f7322feSeschrock {
13317f7322feSeschrock 	nvlist_t *nv;
13327f7322feSeschrock 	char *value;
13337f7322feSeschrock 
1334a2eea2e1Sahrens 	*source = NULL;
13357f7322feSeschrock 	if (nvlist_lookup_nvlist(zhp->zfs_props,
13367f7322feSeschrock 	    zfs_prop_to_name(prop), &nv) == 0) {
13377f7322feSeschrock 		verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0);
1338a2eea2e1Sahrens 		(void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source);
13397f7322feSeschrock 	} else {
13407f7322feSeschrock 		if ((value = (char *)zfs_prop_default_string(prop)) == NULL)
13417f7322feSeschrock 			value = "";
13427f7322feSeschrock 		*source = "";
13437f7322feSeschrock 	}
13447f7322feSeschrock 
13457f7322feSeschrock 	return (value);
13467f7322feSeschrock }
13477f7322feSeschrock 
1348fa9e4066Sahrens /*
1349fa9e4066Sahrens  * Internal function for getting a numeric property.  Both zfs_prop_get() and
1350fa9e4066Sahrens  * zfs_prop_get_int() are built using this interface.
1351fa9e4066Sahrens  *
1352fa9e4066Sahrens  * Certain properties can be overridden using 'mount -o'.  In this case, scan
1353fa9e4066Sahrens  * the contents of the /etc/mnttab entry, searching for the appropriate options.
1354fa9e4066Sahrens  * If they differ from the on-disk values, report the current values and mark
1355fa9e4066Sahrens  * the source "temporary".
1356fa9e4066Sahrens  */
135799653d4eSeschrock static int
1358fa9e4066Sahrens get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
135999653d4eSeschrock     char **source, uint64_t *val)
1360fa9e4066Sahrens {
1361fa9e4066Sahrens 	struct mnttab mnt;
13623ccfa83cSahrens 	char *mntopt_on = NULL;
13633ccfa83cSahrens 	char *mntopt_off = NULL;
1364fa9e4066Sahrens 
1365fa9e4066Sahrens 	*source = NULL;
1366fa9e4066Sahrens 
13673ccfa83cSahrens 	switch (prop) {
13683ccfa83cSahrens 	case ZFS_PROP_ATIME:
13693ccfa83cSahrens 		mntopt_on = MNTOPT_ATIME;
13703ccfa83cSahrens 		mntopt_off = MNTOPT_NOATIME;
13713ccfa83cSahrens 		break;
13723ccfa83cSahrens 
13733ccfa83cSahrens 	case ZFS_PROP_DEVICES:
13743ccfa83cSahrens 		mntopt_on = MNTOPT_DEVICES;
13753ccfa83cSahrens 		mntopt_off = MNTOPT_NODEVICES;
13763ccfa83cSahrens 		break;
13773ccfa83cSahrens 
13783ccfa83cSahrens 	case ZFS_PROP_EXEC:
13793ccfa83cSahrens 		mntopt_on = MNTOPT_EXEC;
13803ccfa83cSahrens 		mntopt_off = MNTOPT_NOEXEC;
13813ccfa83cSahrens 		break;
13823ccfa83cSahrens 
13833ccfa83cSahrens 	case ZFS_PROP_READONLY:
13843ccfa83cSahrens 		mntopt_on = MNTOPT_RO;
13853ccfa83cSahrens 		mntopt_off = MNTOPT_RW;
13863ccfa83cSahrens 		break;
13873ccfa83cSahrens 
13883ccfa83cSahrens 	case ZFS_PROP_SETUID:
13893ccfa83cSahrens 		mntopt_on = MNTOPT_SETUID;
13903ccfa83cSahrens 		mntopt_off = MNTOPT_NOSETUID;
13913ccfa83cSahrens 		break;
13923ccfa83cSahrens 
13933ccfa83cSahrens 	case ZFS_PROP_XATTR:
13943ccfa83cSahrens 		mntopt_on = MNTOPT_XATTR;
13953ccfa83cSahrens 		mntopt_off = MNTOPT_NOXATTR;
13963ccfa83cSahrens 		break;
13973ccfa83cSahrens 	}
13983ccfa83cSahrens 
13993bb79becSeschrock 	/*
14003bb79becSeschrock 	 * Because looking up the mount options is potentially expensive
14013bb79becSeschrock 	 * (iterating over all of /etc/mnttab), we defer its calculation until
14023bb79becSeschrock 	 * we're looking up a property which requires its presence.
14033bb79becSeschrock 	 */
14043bb79becSeschrock 	if (!zhp->zfs_mntcheck &&
14053ccfa83cSahrens 	    (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
14063ccfa83cSahrens 		struct mnttab entry, search = { 0 };
14073ccfa83cSahrens 		FILE *mnttab = zhp->zfs_hdl->libzfs_mnttab;
14083bb79becSeschrock 
14093bb79becSeschrock 		search.mnt_special = (char *)zhp->zfs_name;
14103bb79becSeschrock 		search.mnt_fstype = MNTTYPE_ZFS;
14113ccfa83cSahrens 		rewind(mnttab);
14123bb79becSeschrock 
14133ccfa83cSahrens 		if (getmntany(mnttab, &entry, &search) == 0) {
14143ccfa83cSahrens 			zhp->zfs_mntopts = zfs_strdup(zhp->zfs_hdl,
14153ccfa83cSahrens 			    entry.mnt_mntopts);
14163ccfa83cSahrens 			if (zhp->zfs_mntopts == NULL)
14173ccfa83cSahrens 				return (-1);
14183ccfa83cSahrens 		}
14193bb79becSeschrock 
14203bb79becSeschrock 		zhp->zfs_mntcheck = B_TRUE;
14213bb79becSeschrock 	}
14223bb79becSeschrock 
1423fa9e4066Sahrens 	if (zhp->zfs_mntopts == NULL)
1424fa9e4066Sahrens 		mnt.mnt_mntopts = "";
1425fa9e4066Sahrens 	else
1426fa9e4066Sahrens 		mnt.mnt_mntopts = zhp->zfs_mntopts;
1427fa9e4066Sahrens 
1428fa9e4066Sahrens 	switch (prop) {
1429fa9e4066Sahrens 	case ZFS_PROP_ATIME:
1430fa9e4066Sahrens 	case ZFS_PROP_DEVICES:
1431fa9e4066Sahrens 	case ZFS_PROP_EXEC:
14323ccfa83cSahrens 	case ZFS_PROP_READONLY:
14333ccfa83cSahrens 	case ZFS_PROP_SETUID:
14343ccfa83cSahrens 	case ZFS_PROP_XATTR:
143599653d4eSeschrock 		*val = getprop_uint64(zhp, prop, source);
1436fa9e4066Sahrens 
14373ccfa83cSahrens 		if (hasmntopt(&mnt, mntopt_on) && !*val) {
143899653d4eSeschrock 			*val = B_TRUE;
1439fa9e4066Sahrens 			if (src)
1440fa9e4066Sahrens 				*src = ZFS_SRC_TEMPORARY;
14413ccfa83cSahrens 		} else if (hasmntopt(&mnt, mntopt_off) && *val) {
144299653d4eSeschrock 			*val = B_FALSE;
1443fa9e4066Sahrens 			if (src)
1444fa9e4066Sahrens 				*src = ZFS_SRC_TEMPORARY;
1445fa9e4066Sahrens 		}
144699653d4eSeschrock 		break;
1447fa9e4066Sahrens 
1448fa9e4066Sahrens 	case ZFS_PROP_RECORDSIZE:
1449fa9e4066Sahrens 	case ZFS_PROP_COMPRESSION:
14507f7322feSeschrock 	case ZFS_PROP_ZONED:
1451a2eea2e1Sahrens 	case ZFS_PROP_CREATION:
1452a2eea2e1Sahrens 	case ZFS_PROP_COMPRESSRATIO:
1453a2eea2e1Sahrens 	case ZFS_PROP_REFERENCED:
1454a2eea2e1Sahrens 	case ZFS_PROP_USED:
1455a2eea2e1Sahrens 	case ZFS_PROP_CREATETXG:
1456a2eea2e1Sahrens 	case ZFS_PROP_AVAILABLE:
1457a2eea2e1Sahrens 	case ZFS_PROP_VOLSIZE:
1458a2eea2e1Sahrens 	case ZFS_PROP_VOLBLOCKSIZE:
1459fda77a98Srm 		*val = getprop_uint64(zhp, prop, source);
1460fda77a98Srm 		break;
1461fda77a98Srm 
14623ccfa83cSahrens 	case ZFS_PROP_CANMOUNT:
146399653d4eSeschrock 		*val = getprop_uint64(zhp, prop, source);
1464fda77a98Srm 		if (*val == 0)
1465fda77a98Srm 			*source = zhp->zfs_name;
1466fda77a98Srm 		else
1467fda77a98Srm 			*source = "";	/* default */
146899653d4eSeschrock 		break;
1469fa9e4066Sahrens 
1470fa9e4066Sahrens 	case ZFS_PROP_QUOTA:
1471fa9e4066Sahrens 	case ZFS_PROP_RESERVATION:
1472a2eea2e1Sahrens 		*val = getprop_uint64(zhp, prop, source);
1473a2eea2e1Sahrens 		if (*val == 0)
1474fa9e4066Sahrens 			*source = "";	/* default */
1475fa9e4066Sahrens 		else
1476fa9e4066Sahrens 			*source = zhp->zfs_name;
147799653d4eSeschrock 		break;
1478fa9e4066Sahrens 
1479fa9e4066Sahrens 	case ZFS_PROP_MOUNTED:
148099653d4eSeschrock 		*val = (zhp->zfs_mntopts != NULL);
148199653d4eSeschrock 		break;
1482fa9e4066Sahrens 
148339c23413Seschrock 	case ZFS_PROP_NUMCLONES:
148439c23413Seschrock 		*val = zhp->zfs_dmustats.dds_num_clones;
148539c23413Seschrock 		break;
148639c23413Seschrock 
1487fa9e4066Sahrens 	default:
148899653d4eSeschrock 		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
148999653d4eSeschrock 		    "cannot get non-numeric property"));
149099653d4eSeschrock 		return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
149199653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "internal error")));
1492fa9e4066Sahrens 	}
1493fa9e4066Sahrens 
1494fa9e4066Sahrens 	return (0);
1495fa9e4066Sahrens }
1496fa9e4066Sahrens 
1497fa9e4066Sahrens /*
1498fa9e4066Sahrens  * Calculate the source type, given the raw source string.
1499fa9e4066Sahrens  */
1500fa9e4066Sahrens static void
1501fa9e4066Sahrens get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source,
1502fa9e4066Sahrens     char *statbuf, size_t statlen)
1503fa9e4066Sahrens {
1504fa9e4066Sahrens 	if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY)
1505fa9e4066Sahrens 		return;
1506fa9e4066Sahrens 
1507fa9e4066Sahrens 	if (source == NULL) {
1508fa9e4066Sahrens 		*srctype = ZFS_SRC_NONE;
1509fa9e4066Sahrens 	} else if (source[0] == '\0') {
1510fa9e4066Sahrens 		*srctype = ZFS_SRC_DEFAULT;
1511fa9e4066Sahrens 	} else {
1512fa9e4066Sahrens 		if (strcmp(source, zhp->zfs_name) == 0) {
1513fa9e4066Sahrens 			*srctype = ZFS_SRC_LOCAL;
1514fa9e4066Sahrens 		} else {
1515fa9e4066Sahrens 			(void) strlcpy(statbuf, source, statlen);
1516fa9e4066Sahrens 			*srctype = ZFS_SRC_INHERITED;
1517fa9e4066Sahrens 		}
1518fa9e4066Sahrens 	}
1519fa9e4066Sahrens 
1520fa9e4066Sahrens }
1521fa9e4066Sahrens 
1522fa9e4066Sahrens /*
1523fa9e4066Sahrens  * Retrieve a property from the given object.  If 'literal' is specified, then
1524fa9e4066Sahrens  * numbers are left as exact values.  Otherwise, numbers are converted to a
1525fa9e4066Sahrens  * human-readable form.
1526fa9e4066Sahrens  *
1527fa9e4066Sahrens  * Returns 0 on success, or -1 on error.
1528fa9e4066Sahrens  */
1529fa9e4066Sahrens int
1530fa9e4066Sahrens zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
153199653d4eSeschrock     zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
1532fa9e4066Sahrens {
1533fa9e4066Sahrens 	char *source = NULL;
1534fa9e4066Sahrens 	uint64_t val;
1535fa9e4066Sahrens 	char *str;
1536fa9e4066Sahrens 	const char *root;
1537e9dbad6fSeschrock 	const char *strval;
1538fa9e4066Sahrens 
1539fa9e4066Sahrens 	/*
1540fa9e4066Sahrens 	 * Check to see if this property applies to our object
1541fa9e4066Sahrens 	 */
1542fa9e4066Sahrens 	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
1543fa9e4066Sahrens 		return (-1);
1544fa9e4066Sahrens 
1545fa9e4066Sahrens 	if (src)
1546fa9e4066Sahrens 		*src = ZFS_SRC_NONE;
1547fa9e4066Sahrens 
1548fa9e4066Sahrens 	switch (prop) {
1549fa9e4066Sahrens 	case ZFS_PROP_ATIME:
1550fa9e4066Sahrens 	case ZFS_PROP_READONLY:
1551fa9e4066Sahrens 	case ZFS_PROP_SETUID:
1552fa9e4066Sahrens 	case ZFS_PROP_ZONED:
1553fa9e4066Sahrens 	case ZFS_PROP_DEVICES:
1554fa9e4066Sahrens 	case ZFS_PROP_EXEC:
1555e9dbad6fSeschrock 	case ZFS_PROP_CANMOUNT:
15567b55fa8eSck 	case ZFS_PROP_XATTR:
1557fa9e4066Sahrens 		/*
1558fa9e4066Sahrens 		 * Basic boolean values are built on top of
1559fa9e4066Sahrens 		 * get_numeric_property().
1560fa9e4066Sahrens 		 */
156199653d4eSeschrock 		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
156299653d4eSeschrock 			return (-1);
156399653d4eSeschrock 		nicebool(val, propbuf, proplen);
1564fa9e4066Sahrens 
1565fa9e4066Sahrens 		break;
1566fa9e4066Sahrens 
1567fa9e4066Sahrens 	case ZFS_PROP_AVAILABLE:
1568fa9e4066Sahrens 	case ZFS_PROP_RECORDSIZE:
1569fa9e4066Sahrens 	case ZFS_PROP_CREATETXG:
1570fa9e4066Sahrens 	case ZFS_PROP_REFERENCED:
1571fa9e4066Sahrens 	case ZFS_PROP_USED:
1572fa9e4066Sahrens 	case ZFS_PROP_VOLSIZE:
1573fa9e4066Sahrens 	case ZFS_PROP_VOLBLOCKSIZE:
157439c23413Seschrock 	case ZFS_PROP_NUMCLONES:
1575fa9e4066Sahrens 		/*
1576fa9e4066Sahrens 		 * Basic numeric values are built on top of
1577fa9e4066Sahrens 		 * get_numeric_property().
1578fa9e4066Sahrens 		 */
157999653d4eSeschrock 		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
158099653d4eSeschrock 			return (-1);
1581fa9e4066Sahrens 		if (literal)
15825ad82045Snd 			(void) snprintf(propbuf, proplen, "%llu",
1583b1b8ab34Slling 			    (u_longlong_t)val);
1584fa9e4066Sahrens 		else
1585fa9e4066Sahrens 			zfs_nicenum(val, propbuf, proplen);
1586fa9e4066Sahrens 		break;
1587fa9e4066Sahrens 
1588fa9e4066Sahrens 	case ZFS_PROP_COMPRESSION:
1589fa9e4066Sahrens 	case ZFS_PROP_CHECKSUM:
1590fa9e4066Sahrens 	case ZFS_PROP_SNAPDIR:
1591fa9e4066Sahrens 	case ZFS_PROP_ACLMODE:
1592fa9e4066Sahrens 	case ZFS_PROP_ACLINHERIT:
1593d0ad202dSahrens 	case ZFS_PROP_COPIES:
15947f7322feSeschrock 		val = getprop_uint64(zhp, prop, &source);
1595e9dbad6fSeschrock 		verify(zfs_prop_index_to_string(prop, val, &strval) == 0);
1596e9dbad6fSeschrock 		(void) strlcpy(propbuf, strval, proplen);
1597fa9e4066Sahrens 		break;
1598fa9e4066Sahrens 
1599fa9e4066Sahrens 	case ZFS_PROP_CREATION:
1600fa9e4066Sahrens 		/*
1601fa9e4066Sahrens 		 * 'creation' is a time_t stored in the statistics.  We convert
1602fa9e4066Sahrens 		 * this into a string unless 'literal' is specified.
1603fa9e4066Sahrens 		 */
1604fa9e4066Sahrens 		{
1605a2eea2e1Sahrens 			val = getprop_uint64(zhp, prop, &source);
1606a2eea2e1Sahrens 			time_t time = (time_t)val;
1607fa9e4066Sahrens 			struct tm t;
1608fa9e4066Sahrens 
1609fa9e4066Sahrens 			if (literal ||
1610fa9e4066Sahrens 			    localtime_r(&time, &t) == NULL ||
1611fa9e4066Sahrens 			    strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
1612fa9e4066Sahrens 			    &t) == 0)
1613a2eea2e1Sahrens 				(void) snprintf(propbuf, proplen, "%llu", val);
1614fa9e4066Sahrens 		}
1615fa9e4066Sahrens 		break;
1616fa9e4066Sahrens 
1617fa9e4066Sahrens 	case ZFS_PROP_MOUNTPOINT:
1618fa9e4066Sahrens 		/*
1619fa9e4066Sahrens 		 * Getting the precise mountpoint can be tricky.
1620fa9e4066Sahrens 		 *
1621fa9e4066Sahrens 		 *  - for 'none' or 'legacy', return those values.
1622fa9e4066Sahrens 		 *  - for default mountpoints, construct it as /zfs/<dataset>
1623fa9e4066Sahrens 		 *  - for inherited mountpoints, we want to take everything
1624fa9e4066Sahrens 		 *    after our ancestor and append it to the inherited value.
1625fa9e4066Sahrens 		 *
1626fa9e4066Sahrens 		 * If the pool has an alternate root, we want to prepend that
1627fa9e4066Sahrens 		 * root to any values we return.
1628fa9e4066Sahrens 		 */
1629ea8dc4b6Seschrock 		root = zhp->zfs_root;
16307f7322feSeschrock 		str = getprop_string(zhp, prop, &source);
1631fa9e4066Sahrens 
16327f7322feSeschrock 		if (str[0] == '\0') {
1633fa9e4066Sahrens 			(void) snprintf(propbuf, proplen, "%s/zfs/%s",
1634fa9e4066Sahrens 			    root, zhp->zfs_name);
16357f7322feSeschrock 		} else if (str[0] == '/') {
16367f7322feSeschrock 			const char *relpath = zhp->zfs_name + strlen(source);
1637fa9e4066Sahrens 
1638fa9e4066Sahrens 			if (relpath[0] == '/')
1639fa9e4066Sahrens 				relpath++;
16407f7322feSeschrock 			if (str[1] == '\0')
16417f7322feSeschrock 				str++;
1642fa9e4066Sahrens 
1643fa9e4066Sahrens 			if (relpath[0] == '\0')
1644fa9e4066Sahrens 				(void) snprintf(propbuf, proplen, "%s%s",
16457f7322feSeschrock 				    root, str);
1646fa9e4066Sahrens 			else
1647fa9e4066Sahrens 				(void) snprintf(propbuf, proplen, "%s%s%s%s",
16487f7322feSeschrock 				    root, str, relpath[0] == '@' ? "" : "/",
1649fa9e4066Sahrens 				    relpath);
1650fa9e4066Sahrens 		} else {
1651fa9e4066Sahrens 			/* 'legacy' or 'none' */
16527f7322feSeschrock 			(void) strlcpy(propbuf, str, proplen);
1653fa9e4066Sahrens 		}
1654fa9e4066Sahrens 
1655fa9e4066Sahrens 		break;
1656fa9e4066Sahrens 
1657fa9e4066Sahrens 	case ZFS_PROP_SHARENFS:
1658f3861e1aSahl 	case ZFS_PROP_SHAREISCSI:
1659f3861e1aSahl 	case ZFS_PROP_ISCSIOPTIONS:
16607f7322feSeschrock 		(void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
16617f7322feSeschrock 		    proplen);
1662fa9e4066Sahrens 		break;
1663fa9e4066Sahrens 
1664fa9e4066Sahrens 	case ZFS_PROP_ORIGIN:
1665a2eea2e1Sahrens 		(void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
1666fa9e4066Sahrens 		    proplen);
1667fa9e4066Sahrens 		/*
1668fa9e4066Sahrens 		 * If there is no parent at all, return failure to indicate that
1669fa9e4066Sahrens 		 * it doesn't apply to this dataset.
1670fa9e4066Sahrens 		 */
1671fa9e4066Sahrens 		if (propbuf[0] == '\0')
1672fa9e4066Sahrens 			return (-1);
1673fa9e4066Sahrens 		break;
1674fa9e4066Sahrens 
1675fa9e4066Sahrens 	case ZFS_PROP_QUOTA:
1676fa9e4066Sahrens 	case ZFS_PROP_RESERVATION:
167799653d4eSeschrock 		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
167899653d4eSeschrock 			return (-1);
1679fa9e4066Sahrens 
1680fa9e4066Sahrens 		/*
1681fa9e4066Sahrens 		 * If quota or reservation is 0, we translate this into 'none'
1682fa9e4066Sahrens 		 * (unless literal is set), and indicate that it's the default
1683fa9e4066Sahrens 		 * value.  Otherwise, we print the number nicely and indicate
1684fa9e4066Sahrens 		 * that its set locally.
1685fa9e4066Sahrens 		 */
1686fa9e4066Sahrens 		if (val == 0) {
1687fa9e4066Sahrens 			if (literal)
1688fa9e4066Sahrens 				(void) strlcpy(propbuf, "0", proplen);
1689fa9e4066Sahrens 			else
1690fa9e4066Sahrens 				(void) strlcpy(propbuf, "none", proplen);
1691fa9e4066Sahrens 		} else {
1692fa9e4066Sahrens 			if (literal)
16935ad82045Snd 				(void) snprintf(propbuf, proplen, "%llu",
1694b1b8ab34Slling 				    (u_longlong_t)val);
1695fa9e4066Sahrens 			else
1696fa9e4066Sahrens 				zfs_nicenum(val, propbuf, proplen);
1697fa9e4066Sahrens 		}
1698fa9e4066Sahrens 		break;
1699fa9e4066Sahrens 
1700fa9e4066Sahrens 	case ZFS_PROP_COMPRESSRATIO:
170199653d4eSeschrock 		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
170299653d4eSeschrock 			return (-1);
17035ad82045Snd 		(void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t)
17045ad82045Snd 		    val / 100, (longlong_t)val % 100);
1705fa9e4066Sahrens 		break;
1706fa9e4066Sahrens 
1707fa9e4066Sahrens 	case ZFS_PROP_TYPE:
1708fa9e4066Sahrens 		switch (zhp->zfs_type) {
1709fa9e4066Sahrens 		case ZFS_TYPE_FILESYSTEM:
1710fa9e4066Sahrens 			str = "filesystem";
1711fa9e4066Sahrens 			break;
1712fa9e4066Sahrens 		case ZFS_TYPE_VOLUME:
1713fa9e4066Sahrens 			str = "volume";
1714fa9e4066Sahrens 			break;
1715fa9e4066Sahrens 		case ZFS_TYPE_SNAPSHOT:
1716fa9e4066Sahrens 			str = "snapshot";
1717fa9e4066Sahrens 			break;
1718fa9e4066Sahrens 		default:
171999653d4eSeschrock 			abort();
1720fa9e4066Sahrens 		}
1721fa9e4066Sahrens 		(void) snprintf(propbuf, proplen, "%s", str);
1722fa9e4066Sahrens 		break;
1723fa9e4066Sahrens 
1724fa9e4066Sahrens 	case ZFS_PROP_MOUNTED:
1725fa9e4066Sahrens 		/*
1726fa9e4066Sahrens 		 * The 'mounted' property is a pseudo-property that described
1727fa9e4066Sahrens 		 * whether the filesystem is currently mounted.  Even though
1728fa9e4066Sahrens 		 * it's a boolean value, the typical values of "on" and "off"
1729fa9e4066Sahrens 		 * don't make sense, so we translate to "yes" and "no".
1730fa9e4066Sahrens 		 */
173199653d4eSeschrock 		if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
173299653d4eSeschrock 		    src, &source, &val) != 0)
173399653d4eSeschrock 			return (-1);
173499653d4eSeschrock 		if (val)
1735fa9e4066Sahrens 			(void) strlcpy(propbuf, "yes", proplen);
1736fa9e4066Sahrens 		else
1737fa9e4066Sahrens 			(void) strlcpy(propbuf, "no", proplen);
1738fa9e4066Sahrens 		break;
1739fa9e4066Sahrens 
1740fa9e4066Sahrens 	case ZFS_PROP_NAME:
1741fa9e4066Sahrens 		/*
1742fa9e4066Sahrens 		 * The 'name' property is a pseudo-property derived from the
1743fa9e4066Sahrens 		 * dataset name.  It is presented as a real property to simplify
1744fa9e4066Sahrens 		 * consumers.
1745fa9e4066Sahrens 		 */
1746fa9e4066Sahrens 		(void) strlcpy(propbuf, zhp->zfs_name, proplen);
1747fa9e4066Sahrens 		break;
1748fa9e4066Sahrens 
1749fa9e4066Sahrens 	default:
175099653d4eSeschrock 		abort();
1751fa9e4066Sahrens 	}
1752fa9e4066Sahrens 
1753fa9e4066Sahrens 	get_source(zhp, src, source, statbuf, statlen);
1754fa9e4066Sahrens 
1755fa9e4066Sahrens 	return (0);
1756fa9e4066Sahrens }
1757fa9e4066Sahrens 
1758fa9e4066Sahrens /*
1759fa9e4066Sahrens  * Utility function to get the given numeric property.  Does no validation that
1760fa9e4066Sahrens  * the given property is the appropriate type; should only be used with
1761fa9e4066Sahrens  * hard-coded property types.
1762fa9e4066Sahrens  */
1763fa9e4066Sahrens uint64_t
1764fa9e4066Sahrens zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
1765fa9e4066Sahrens {
1766fa9e4066Sahrens 	char *source;
1767fa9e4066Sahrens 	zfs_source_t sourcetype = ZFS_SRC_NONE;
176899653d4eSeschrock 	uint64_t val;
176999653d4eSeschrock 
177099653d4eSeschrock 	(void) get_numeric_property(zhp, prop, &sourcetype, &source, &val);
1771fa9e4066Sahrens 
177299653d4eSeschrock 	return (val);
1773fa9e4066Sahrens }
1774fa9e4066Sahrens 
1775fa9e4066Sahrens /*
1776fa9e4066Sahrens  * Similar to zfs_prop_get(), but returns the value as an integer.
1777fa9e4066Sahrens  */
1778fa9e4066Sahrens int
1779fa9e4066Sahrens zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
1780fa9e4066Sahrens     zfs_source_t *src, char *statbuf, size_t statlen)
1781fa9e4066Sahrens {
1782fa9e4066Sahrens 	char *source;
1783fa9e4066Sahrens 
1784fa9e4066Sahrens 	/*
1785fa9e4066Sahrens 	 * Check to see if this property applies to our object
1786fa9e4066Sahrens 	 */
1787fa9e4066Sahrens 	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
1788ece3d9b3Slling 		return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
178999653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
179099653d4eSeschrock 		    zfs_prop_to_name(prop)));
1791fa9e4066Sahrens 
1792fa9e4066Sahrens 	if (src)
1793fa9e4066Sahrens 		*src = ZFS_SRC_NONE;
1794fa9e4066Sahrens 
179599653d4eSeschrock 	if (get_numeric_property(zhp, prop, src, &source, value) != 0)
179699653d4eSeschrock 		return (-1);
1797fa9e4066Sahrens 
1798fa9e4066Sahrens 	get_source(zhp, src, source, statbuf, statlen);
1799fa9e4066Sahrens 
1800fa9e4066Sahrens 	return (0);
1801fa9e4066Sahrens }
1802fa9e4066Sahrens 
1803fa9e4066Sahrens /*
1804fa9e4066Sahrens  * Returns the name of the given zfs handle.
1805fa9e4066Sahrens  */
1806fa9e4066Sahrens const char *
1807fa9e4066Sahrens zfs_get_name(const zfs_handle_t *zhp)
1808fa9e4066Sahrens {
1809fa9e4066Sahrens 	return (zhp->zfs_name);
1810fa9e4066Sahrens }
1811fa9e4066Sahrens 
1812fa9e4066Sahrens /*
1813fa9e4066Sahrens  * Returns the type of the given zfs handle.
1814fa9e4066Sahrens  */
1815fa9e4066Sahrens zfs_type_t
1816fa9e4066Sahrens zfs_get_type(const zfs_handle_t *zhp)
1817fa9e4066Sahrens {
1818fa9e4066Sahrens 	return (zhp->zfs_type);
1819fa9e4066Sahrens }
1820fa9e4066Sahrens 
1821fa9e4066Sahrens /*
18227f7322feSeschrock  * Iterate over all child filesystems
1823fa9e4066Sahrens  */
1824fa9e4066Sahrens int
18257f7322feSeschrock zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
1826fa9e4066Sahrens {
1827fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1828fa9e4066Sahrens 	zfs_handle_t *nzhp;
1829fa9e4066Sahrens 	int ret;
1830fa9e4066Sahrens 
1831fa9e4066Sahrens 	for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
183299653d4eSeschrock 	    ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
1833fa9e4066Sahrens 	    (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
1834fa9e4066Sahrens 		/*
1835fa9e4066Sahrens 		 * Ignore private dataset names.
1836fa9e4066Sahrens 		 */
1837fa9e4066Sahrens 		if (dataset_name_hidden(zc.zc_name))
1838fa9e4066Sahrens 			continue;
1839fa9e4066Sahrens 
1840fa9e4066Sahrens 		/*
1841fa9e4066Sahrens 		 * Silently ignore errors, as the only plausible explanation is
1842fa9e4066Sahrens 		 * that the pool has since been removed.
1843fa9e4066Sahrens 		 */
184499653d4eSeschrock 		if ((nzhp = make_dataset_handle(zhp->zfs_hdl,
184599653d4eSeschrock 		    zc.zc_name)) == NULL)
1846fa9e4066Sahrens 			continue;
1847fa9e4066Sahrens 
1848fa9e4066Sahrens 		if ((ret = func(nzhp, data)) != 0)
1849fa9e4066Sahrens 			return (ret);
1850fa9e4066Sahrens 	}
1851fa9e4066Sahrens 
1852fa9e4066Sahrens 	/*
1853fa9e4066Sahrens 	 * An errno value of ESRCH indicates normal completion.  If ENOENT is
1854fa9e4066Sahrens 	 * returned, then the underlying dataset has been removed since we
1855fa9e4066Sahrens 	 * obtained the handle.
1856fa9e4066Sahrens 	 */
1857fa9e4066Sahrens 	if (errno != ESRCH && errno != ENOENT)
185899653d4eSeschrock 		return (zfs_standard_error(zhp->zfs_hdl, errno,
185999653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot iterate filesystems")));
1860fa9e4066Sahrens 
18617f7322feSeschrock 	return (0);
18627f7322feSeschrock }
18637f7322feSeschrock 
18647f7322feSeschrock /*
18657f7322feSeschrock  * Iterate over all snapshots
18667f7322feSeschrock  */
18677f7322feSeschrock int
18687f7322feSeschrock zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
18697f7322feSeschrock {
18707f7322feSeschrock 	zfs_cmd_t zc = { 0 };
18717f7322feSeschrock 	zfs_handle_t *nzhp;
18727f7322feSeschrock 	int ret;
1873fa9e4066Sahrens 
1874fa9e4066Sahrens 	for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
187599653d4eSeschrock 	    ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT,
187699653d4eSeschrock 	    &zc) == 0;
1877fa9e4066Sahrens 	    (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
1878fa9e4066Sahrens 
187999653d4eSeschrock 		if ((nzhp = make_dataset_handle(zhp->zfs_hdl,
188099653d4eSeschrock 		    zc.zc_name)) == NULL)
1881fa9e4066Sahrens 			continue;
1882fa9e4066Sahrens 
1883fa9e4066Sahrens 		if ((ret = func(nzhp, data)) != 0)
1884fa9e4066Sahrens 			return (ret);
1885fa9e4066Sahrens 	}
1886fa9e4066Sahrens 
1887fa9e4066Sahrens 	/*
1888fa9e4066Sahrens 	 * An errno value of ESRCH indicates normal completion.  If ENOENT is
1889fa9e4066Sahrens 	 * returned, then the underlying dataset has been removed since we
1890fa9e4066Sahrens 	 * obtained the handle.  Silently ignore this case, and return success.
1891fa9e4066Sahrens 	 */
1892fa9e4066Sahrens 	if (errno != ESRCH && errno != ENOENT)
189399653d4eSeschrock 		return (zfs_standard_error(zhp->zfs_hdl, errno,
189499653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot iterate filesystems")));
1895fa9e4066Sahrens 
1896fa9e4066Sahrens 	return (0);
1897fa9e4066Sahrens }
1898fa9e4066Sahrens 
18997f7322feSeschrock /*
19007f7322feSeschrock  * Iterate over all children, snapshots and filesystems
19017f7322feSeschrock  */
19027f7322feSeschrock int
19037f7322feSeschrock zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
19047f7322feSeschrock {
19057f7322feSeschrock 	int ret;
19067f7322feSeschrock 
19077f7322feSeschrock 	if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0)
19087f7322feSeschrock 		return (ret);
19097f7322feSeschrock 
19107f7322feSeschrock 	return (zfs_iter_snapshots(zhp, func, data));
19117f7322feSeschrock }
19127f7322feSeschrock 
1913fa9e4066Sahrens /*
1914fa9e4066Sahrens  * Given a complete name, return just the portion that refers to the parent.
1915fa9e4066Sahrens  * Can return NULL if this is a pool.
1916fa9e4066Sahrens  */
1917fa9e4066Sahrens static int
1918fa9e4066Sahrens parent_name(const char *path, char *buf, size_t buflen)
1919fa9e4066Sahrens {
1920fa9e4066Sahrens 	char *loc;
1921fa9e4066Sahrens 
1922fa9e4066Sahrens 	if ((loc = strrchr(path, '/')) == NULL)
1923fa9e4066Sahrens 		return (-1);
1924fa9e4066Sahrens 
1925fa9e4066Sahrens 	(void) strncpy(buf, path, MIN(buflen, loc - path));
1926fa9e4066Sahrens 	buf[loc - path] = '\0';
1927fa9e4066Sahrens 
1928fa9e4066Sahrens 	return (0);
1929fa9e4066Sahrens }
1930fa9e4066Sahrens 
1931fa9e4066Sahrens /*
1932e9dbad6fSeschrock  * Checks to make sure that the given path has a parent, and that it exists.  We
1933e9dbad6fSeschrock  * also fetch the 'zoned' property, which is used to validate property settings
1934e9dbad6fSeschrock  * when creating new datasets.
1935fa9e4066Sahrens  */
1936fa9e4066Sahrens static int
1937e9dbad6fSeschrock check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned)
1938fa9e4066Sahrens {
1939fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1940fa9e4066Sahrens 	char parent[ZFS_MAXNAMELEN];
1941fa9e4066Sahrens 	char *slash;
19427f7322feSeschrock 	zfs_handle_t *zhp;
194399653d4eSeschrock 	char errbuf[1024];
194499653d4eSeschrock 
194599653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'",
194699653d4eSeschrock 	    path);
1947fa9e4066Sahrens 
1948fa9e4066Sahrens 	/* get parent, and check to see if this is just a pool */
1949fa9e4066Sahrens 	if (parent_name(path, parent, sizeof (parent)) != 0) {
195099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
195199653d4eSeschrock 		    "missing dataset name"));
195299653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
1953fa9e4066Sahrens 	}
1954fa9e4066Sahrens 
1955fa9e4066Sahrens 	/* check to see if the pool exists */
1956fa9e4066Sahrens 	if ((slash = strchr(parent, '/')) == NULL)
1957fa9e4066Sahrens 		slash = parent + strlen(parent);
1958fa9e4066Sahrens 	(void) strncpy(zc.zc_name, parent, slash - parent);
1959fa9e4066Sahrens 	zc.zc_name[slash - parent] = '\0';
196099653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
1961fa9e4066Sahrens 	    errno == ENOENT) {
196299653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
196399653d4eSeschrock 		    "no such pool '%s'"), zc.zc_name);
196499653d4eSeschrock 		return (zfs_error(hdl, EZFS_NOENT, errbuf));
1965fa9e4066Sahrens 	}
1966fa9e4066Sahrens 
1967fa9e4066Sahrens 	/* check to see if the parent dataset exists */
196899653d4eSeschrock 	if ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
1969fa9e4066Sahrens 		switch (errno) {
1970fa9e4066Sahrens 		case ENOENT:
197199653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
197299653d4eSeschrock 			    "parent does not exist"));
197399653d4eSeschrock 			return (zfs_error(hdl, EZFS_NOENT, errbuf));
1974fa9e4066Sahrens 
1975fa9e4066Sahrens 		default:
197699653d4eSeschrock 			return (zfs_standard_error(hdl, errno, errbuf));
1977fa9e4066Sahrens 		}
1978fa9e4066Sahrens 	}
1979fa9e4066Sahrens 
1980e9dbad6fSeschrock 	*zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
1981fa9e4066Sahrens 	/* we are in a non-global zone, but parent is in the global zone */
1982e9dbad6fSeschrock 	if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) {
198399653d4eSeschrock 		(void) zfs_standard_error(hdl, EPERM, errbuf);
19847f7322feSeschrock 		zfs_close(zhp);
1985fa9e4066Sahrens 		return (-1);
1986fa9e4066Sahrens 	}
1987fa9e4066Sahrens 
1988fa9e4066Sahrens 	/* make sure parent is a filesystem */
19897f7322feSeschrock 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
199099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
199199653d4eSeschrock 		    "parent is not a filesystem"));
199299653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
19937f7322feSeschrock 		zfs_close(zhp);
1994fa9e4066Sahrens 		return (-1);
1995fa9e4066Sahrens 	}
1996fa9e4066Sahrens 
19977f7322feSeschrock 	zfs_close(zhp);
1998fa9e4066Sahrens 	return (0);
1999fa9e4066Sahrens }
2000fa9e4066Sahrens 
2001fa9e4066Sahrens /*
2002e9dbad6fSeschrock  * Create a new filesystem or volume.
2003fa9e4066Sahrens  */
2004fa9e4066Sahrens int
200599653d4eSeschrock zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
2006e9dbad6fSeschrock     nvlist_t *props)
2007fa9e4066Sahrens {
2008fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2009fa9e4066Sahrens 	int ret;
2010fa9e4066Sahrens 	uint64_t size = 0;
2011fa9e4066Sahrens 	uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
201299653d4eSeschrock 	char errbuf[1024];
2013e9dbad6fSeschrock 	uint64_t zoned;
201499653d4eSeschrock 
201599653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
201699653d4eSeschrock 	    "cannot create '%s'"), path);
2017fa9e4066Sahrens 
2018fa9e4066Sahrens 	/* validate the path, taking care to note the extended error message */
201999653d4eSeschrock 	if (!zfs_validate_name(hdl, path, type))
202099653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2021fa9e4066Sahrens 
2022fa9e4066Sahrens 	/* validate parents exist */
2023e9dbad6fSeschrock 	if (check_parents(hdl, path, &zoned) != 0)
2024fa9e4066Sahrens 		return (-1);
2025fa9e4066Sahrens 
2026fa9e4066Sahrens 	/*
2027fa9e4066Sahrens 	 * The failure modes when creating a dataset of a different type over
2028fa9e4066Sahrens 	 * one that already exists is a little strange.  In particular, if you
2029fa9e4066Sahrens 	 * try to create a dataset on top of an existing dataset, the ioctl()
2030fa9e4066Sahrens 	 * will return ENOENT, not EEXIST.  To prevent this from happening, we
2031fa9e4066Sahrens 	 * first try to see if the dataset exists.
2032fa9e4066Sahrens 	 */
2033fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name));
203499653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) {
203599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
203699653d4eSeschrock 		    "dataset already exists"));
203799653d4eSeschrock 		return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2038fa9e4066Sahrens 	}
2039fa9e4066Sahrens 
2040fa9e4066Sahrens 	if (type == ZFS_TYPE_VOLUME)
2041fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZVOL;
2042fa9e4066Sahrens 	else
2043fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZFS;
2044fa9e4066Sahrens 
2045b1b8ab34Slling 	if (props && (props = zfs_validate_properties(hdl, type, NULL, props,
2046b1b8ab34Slling 	    zoned, NULL, errbuf)) == 0)
2047e9dbad6fSeschrock 		return (-1);
2048e9dbad6fSeschrock 
2049fa9e4066Sahrens 	if (type == ZFS_TYPE_VOLUME) {
20505c5460e9Seschrock 		/*
20515c5460e9Seschrock 		 * If we are creating a volume, the size and block size must
20525c5460e9Seschrock 		 * satisfy a few restraints.  First, the blocksize must be a
20535c5460e9Seschrock 		 * valid block size between SPA_{MIN,MAX}BLOCKSIZE.  Second, the
20545c5460e9Seschrock 		 * volsize must be a multiple of the block size, and cannot be
20555c5460e9Seschrock 		 * zero.
20565c5460e9Seschrock 		 */
2057e9dbad6fSeschrock 		if (props == NULL || nvlist_lookup_uint64(props,
2058e9dbad6fSeschrock 		    zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
2059e9dbad6fSeschrock 			nvlist_free(props);
206099653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2061e9dbad6fSeschrock 			    "missing volume size"));
2062e9dbad6fSeschrock 			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2063e9dbad6fSeschrock 		}
2064e9dbad6fSeschrock 
2065e9dbad6fSeschrock 		if ((ret = nvlist_lookup_uint64(props,
2066e9dbad6fSeschrock 		    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
2067e9dbad6fSeschrock 		    &blocksize)) != 0) {
2068e9dbad6fSeschrock 			if (ret == ENOENT) {
2069e9dbad6fSeschrock 				blocksize = zfs_prop_default_numeric(
2070e9dbad6fSeschrock 				    ZFS_PROP_VOLBLOCKSIZE);
2071e9dbad6fSeschrock 			} else {
2072e9dbad6fSeschrock 				nvlist_free(props);
2073e9dbad6fSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2074e9dbad6fSeschrock 				    "missing volume block size"));
2075e9dbad6fSeschrock 				return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2076e9dbad6fSeschrock 			}
2077fa9e4066Sahrens 		}
2078fa9e4066Sahrens 
2079e9dbad6fSeschrock 		if (size == 0) {
2080e9dbad6fSeschrock 			nvlist_free(props);
208199653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2082e9dbad6fSeschrock 			    "volume size cannot be zero"));
2083e9dbad6fSeschrock 			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
20845c5460e9Seschrock 		}
20855c5460e9Seschrock 
20865c5460e9Seschrock 		if (size % blocksize != 0) {
2087e9dbad6fSeschrock 			nvlist_free(props);
208899653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2089e9dbad6fSeschrock 			    "volume size must be a multiple of volume block "
2090e9dbad6fSeschrock 			    "size"));
2091e9dbad6fSeschrock 			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
20925c5460e9Seschrock 		}
2093fa9e4066Sahrens 	}
2094fa9e4066Sahrens 
2095e9dbad6fSeschrock 	if (props &&
2096e9dbad6fSeschrock 	    zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0)
2097e9dbad6fSeschrock 		return (-1);
2098e9dbad6fSeschrock 	nvlist_free(props);
2099e9dbad6fSeschrock 
2100fa9e4066Sahrens 	/* create the dataset */
210199653d4eSeschrock 	ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
2102fa9e4066Sahrens 
2103b1b8ab34Slling 	if (ret == 0 && type == ZFS_TYPE_VOLUME) {
210499653d4eSeschrock 		ret = zvol_create_link(hdl, path);
2105b1b8ab34Slling 		if (ret) {
2106b1b8ab34Slling 			(void) zfs_standard_error(hdl, errno,
2107b1b8ab34Slling 			    dgettext(TEXT_DOMAIN,
2108b1b8ab34Slling 			    "Volume successfully created, but device links "
2109b1b8ab34Slling 			    "were not created"));
2110b1b8ab34Slling 			zcmd_free_nvlists(&zc);
2111b1b8ab34Slling 			return (-1);
2112b1b8ab34Slling 		}
2113b1b8ab34Slling 	}
2114fa9e4066Sahrens 
2115e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
2116e9dbad6fSeschrock 
2117fa9e4066Sahrens 	/* check for failure */
2118fa9e4066Sahrens 	if (ret != 0) {
2119fa9e4066Sahrens 		char parent[ZFS_MAXNAMELEN];
2120fa9e4066Sahrens 		(void) parent_name(path, parent, sizeof (parent));
2121fa9e4066Sahrens 
2122fa9e4066Sahrens 		switch (errno) {
2123fa9e4066Sahrens 		case ENOENT:
212499653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
212599653d4eSeschrock 			    "no such parent '%s'"), parent);
212699653d4eSeschrock 			return (zfs_error(hdl, EZFS_NOENT, errbuf));
2127fa9e4066Sahrens 
2128fa9e4066Sahrens 		case EINVAL:
212999653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2130d7d4af51Smmusante 			    "parent '%s' is not a filesystem"), parent);
213199653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2132fa9e4066Sahrens 
2133fa9e4066Sahrens 		case EDOM:
213499653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2135e9dbad6fSeschrock 			    "volume block size must be power of 2 from "
2136e9dbad6fSeschrock 			    "%u to %uk"),
2137fa9e4066Sahrens 			    (uint_t)SPA_MINBLOCKSIZE,
2138fa9e4066Sahrens 			    (uint_t)SPA_MAXBLOCKSIZE >> 10);
213999653d4eSeschrock 
2140e9dbad6fSeschrock 			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
214199653d4eSeschrock 
2142fa9e4066Sahrens #ifdef _ILP32
2143fa9e4066Sahrens 		case EOVERFLOW:
2144fa9e4066Sahrens 			/*
2145fa9e4066Sahrens 			 * This platform can't address a volume this big.
2146fa9e4066Sahrens 			 */
214799653d4eSeschrock 			if (type == ZFS_TYPE_VOLUME)
214899653d4eSeschrock 				return (zfs_error(hdl, EZFS_VOLTOOBIG,
214999653d4eSeschrock 				    errbuf));
2150fa9e4066Sahrens #endif
215199653d4eSeschrock 			/* FALLTHROUGH */
2152fa9e4066Sahrens 		default:
215399653d4eSeschrock 			return (zfs_standard_error(hdl, errno, errbuf));
2154fa9e4066Sahrens 		}
2155fa9e4066Sahrens 	}
2156fa9e4066Sahrens 
2157fa9e4066Sahrens 	return (0);
2158fa9e4066Sahrens }
2159fa9e4066Sahrens 
2160fa9e4066Sahrens /*
2161fa9e4066Sahrens  * Destroys the given dataset.  The caller must make sure that the filesystem
2162fa9e4066Sahrens  * isn't mounted, and that there are no active dependents.
2163fa9e4066Sahrens  */
2164fa9e4066Sahrens int
2165fa9e4066Sahrens zfs_destroy(zfs_handle_t *zhp)
2166fa9e4066Sahrens {
2167fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2168fa9e4066Sahrens 
2169fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2170fa9e4066Sahrens 
2171e9dbad6fSeschrock 	if (ZFS_IS_VOLUME(zhp)) {
2172f3861e1aSahl 		/*
2173f3861e1aSahl 		 * Unconditionally unshare this zvol ignoring failure as it
2174f3861e1aSahl 		 * indicates only that the volume wasn't shared initially.
2175f3861e1aSahl 		 */
2176f3861e1aSahl 		(void) zfs_unshare_iscsi(zhp);
2177f3861e1aSahl 
217899653d4eSeschrock 		if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0)
2179fa9e4066Sahrens 			return (-1);
2180fa9e4066Sahrens 
2181fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZVOL;
2182fa9e4066Sahrens 	} else {
2183fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZFS;
2184fa9e4066Sahrens 	}
2185fa9e4066Sahrens 
2186f3861e1aSahl 	if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) {
2187ece3d9b3Slling 		return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
218899653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
218999653d4eSeschrock 		    zhp->zfs_name));
21901d452cf5Sahrens 	}
2191fa9e4066Sahrens 
2192fa9e4066Sahrens 	remove_mountpoint(zhp);
2193fa9e4066Sahrens 
2194fa9e4066Sahrens 	return (0);
2195fa9e4066Sahrens }
2196fa9e4066Sahrens 
21971d452cf5Sahrens struct destroydata {
21981d452cf5Sahrens 	char *snapname;
21991d452cf5Sahrens 	boolean_t gotone;
22003ccfa83cSahrens 	boolean_t closezhp;
22011d452cf5Sahrens };
22021d452cf5Sahrens 
22031d452cf5Sahrens static int
22041d452cf5Sahrens zfs_remove_link_cb(zfs_handle_t *zhp, void *arg)
22051d452cf5Sahrens {
22061d452cf5Sahrens 	struct destroydata *dd = arg;
22071d452cf5Sahrens 	zfs_handle_t *szhp;
22081d452cf5Sahrens 	char name[ZFS_MAXNAMELEN];
22093ccfa83cSahrens 	boolean_t closezhp = dd->closezhp;
22103ccfa83cSahrens 	int rv;
22111d452cf5Sahrens 
2212e9dbad6fSeschrock 	(void) strlcpy(name, zhp->zfs_name, sizeof (name));
2213e9dbad6fSeschrock 	(void) strlcat(name, "@", sizeof (name));
2214e9dbad6fSeschrock 	(void) strlcat(name, dd->snapname, sizeof (name));
22151d452cf5Sahrens 
22161d452cf5Sahrens 	szhp = make_dataset_handle(zhp->zfs_hdl, name);
22171d452cf5Sahrens 	if (szhp) {
22181d452cf5Sahrens 		dd->gotone = B_TRUE;
22191d452cf5Sahrens 		zfs_close(szhp);
22201d452cf5Sahrens 	}
22211d452cf5Sahrens 
22221d452cf5Sahrens 	if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
22231d452cf5Sahrens 		(void) zvol_remove_link(zhp->zfs_hdl, name);
22241d452cf5Sahrens 		/*
22251d452cf5Sahrens 		 * NB: this is simply a best-effort.  We don't want to
22261d452cf5Sahrens 		 * return an error, because then we wouldn't visit all
22271d452cf5Sahrens 		 * the volumes.
22281d452cf5Sahrens 		 */
22291d452cf5Sahrens 	}
22301d452cf5Sahrens 
22313ccfa83cSahrens 	dd->closezhp = B_TRUE;
22323ccfa83cSahrens 	rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg);
22333ccfa83cSahrens 	if (closezhp)
22343ccfa83cSahrens 		zfs_close(zhp);
22353ccfa83cSahrens 	return (rv);
22361d452cf5Sahrens }
22371d452cf5Sahrens 
22381d452cf5Sahrens /*
22391d452cf5Sahrens  * Destroys all snapshots with the given name in zhp & descendants.
22401d452cf5Sahrens  */
22411d452cf5Sahrens int
22421d452cf5Sahrens zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname)
22431d452cf5Sahrens {
22441d452cf5Sahrens 	zfs_cmd_t zc = { 0 };
22451d452cf5Sahrens 	int ret;
22461d452cf5Sahrens 	struct destroydata dd = { 0 };
22471d452cf5Sahrens 
22481d452cf5Sahrens 	dd.snapname = snapname;
22491d452cf5Sahrens 	(void) zfs_remove_link_cb(zhp, &dd);
22501d452cf5Sahrens 
22511d452cf5Sahrens 	if (!dd.gotone) {
2252ece3d9b3Slling 		return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
22531d452cf5Sahrens 		    dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
22541d452cf5Sahrens 		    zhp->zfs_name, snapname));
22551d452cf5Sahrens 	}
22561d452cf5Sahrens 
22571d452cf5Sahrens 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2258e9dbad6fSeschrock 	(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
22591d452cf5Sahrens 
22601d452cf5Sahrens 	ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc);
22611d452cf5Sahrens 	if (ret != 0) {
22621d452cf5Sahrens 		char errbuf[1024];
22631d452cf5Sahrens 
22641d452cf5Sahrens 		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
22651d452cf5Sahrens 		    "cannot destroy '%s@%s'"), zc.zc_name, snapname);
22661d452cf5Sahrens 
22671d452cf5Sahrens 		switch (errno) {
22681d452cf5Sahrens 		case EEXIST:
22691d452cf5Sahrens 			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
22701d452cf5Sahrens 			    "snapshot is cloned"));
22711d452cf5Sahrens 			return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf));
22721d452cf5Sahrens 
22731d452cf5Sahrens 		default:
22741d452cf5Sahrens 			return (zfs_standard_error(zhp->zfs_hdl, errno,
22751d452cf5Sahrens 			    errbuf));
22761d452cf5Sahrens 		}
22771d452cf5Sahrens 	}
22781d452cf5Sahrens 
22791d452cf5Sahrens 	return (0);
22801d452cf5Sahrens }
22811d452cf5Sahrens 
2282fa9e4066Sahrens /*
2283fa9e4066Sahrens  * Clones the given dataset.  The target must be of the same type as the source.
2284fa9e4066Sahrens  */
2285fa9e4066Sahrens int
2286e9dbad6fSeschrock zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
2287fa9e4066Sahrens {
2288fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2289fa9e4066Sahrens 	char parent[ZFS_MAXNAMELEN];
2290fa9e4066Sahrens 	int ret;
229199653d4eSeschrock 	char errbuf[1024];
229299653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
2293e9dbad6fSeschrock 	zfs_type_t type;
2294e9dbad6fSeschrock 	uint64_t zoned;
2295fa9e4066Sahrens 
2296fa9e4066Sahrens 	assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
2297fa9e4066Sahrens 
229899653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
229999653d4eSeschrock 	    "cannot create '%s'"), target);
230099653d4eSeschrock 
2301fa9e4066Sahrens 	/* validate the target name */
230299653d4eSeschrock 	if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM))
230399653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2304fa9e4066Sahrens 
2305fa9e4066Sahrens 	/* validate parents exist */
2306e9dbad6fSeschrock 	if (check_parents(hdl, target, &zoned) != 0)
2307fa9e4066Sahrens 		return (-1);
2308fa9e4066Sahrens 
2309fa9e4066Sahrens 	(void) parent_name(target, parent, sizeof (parent));
2310fa9e4066Sahrens 
2311fa9e4066Sahrens 	/* do the clone */
2312e9dbad6fSeschrock 	if (ZFS_IS_VOLUME(zhp)) {
2313fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZVOL;
23145f8e1617Snn 		type = ZFS_TYPE_VOLUME;
2315e9dbad6fSeschrock 	} else {
2316fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZFS;
23175f8e1617Snn 		type = ZFS_TYPE_FILESYSTEM;
2318e9dbad6fSeschrock 	}
2319e9dbad6fSeschrock 
2320e9dbad6fSeschrock 	if (props) {
2321b1b8ab34Slling 		if ((props = zfs_validate_properties(hdl, type, NULL, props,
2322b1b8ab34Slling 		    zoned, zhp, errbuf)) == NULL)
2323e9dbad6fSeschrock 			return (-1);
2324e9dbad6fSeschrock 
2325e9dbad6fSeschrock 		if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) {
2326e9dbad6fSeschrock 			nvlist_free(props);
2327e9dbad6fSeschrock 			return (-1);
2328e9dbad6fSeschrock 		}
2329e9dbad6fSeschrock 
2330e9dbad6fSeschrock 		nvlist_free(props);
2331e9dbad6fSeschrock 	}
2332fa9e4066Sahrens 
2333fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
2334e9dbad6fSeschrock 	(void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value));
233599653d4eSeschrock 	ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
2336fa9e4066Sahrens 
2337e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
2338e9dbad6fSeschrock 
2339fa9e4066Sahrens 	if (ret != 0) {
2340fa9e4066Sahrens 		switch (errno) {
2341fa9e4066Sahrens 
2342fa9e4066Sahrens 		case ENOENT:
2343fa9e4066Sahrens 			/*
2344fa9e4066Sahrens 			 * The parent doesn't exist.  We should have caught this
2345fa9e4066Sahrens 			 * above, but there may a race condition that has since
2346fa9e4066Sahrens 			 * destroyed the parent.
2347fa9e4066Sahrens 			 *
2348fa9e4066Sahrens 			 * At this point, we don't know whether it's the source
2349fa9e4066Sahrens 			 * that doesn't exist anymore, or whether the target
2350fa9e4066Sahrens 			 * dataset doesn't exist.
2351fa9e4066Sahrens 			 */
235299653d4eSeschrock 			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
235399653d4eSeschrock 			    "no such parent '%s'"), parent);
235499653d4eSeschrock 			return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
2355fa9e4066Sahrens 
235699653d4eSeschrock 		case EXDEV:
235799653d4eSeschrock 			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
235899653d4eSeschrock 			    "source and target pools differ"));
235999653d4eSeschrock 			return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
236099653d4eSeschrock 			    errbuf));
2361fa9e4066Sahrens 
236299653d4eSeschrock 		default:
236399653d4eSeschrock 			return (zfs_standard_error(zhp->zfs_hdl, errno,
236499653d4eSeschrock 			    errbuf));
236599653d4eSeschrock 		}
2366e9dbad6fSeschrock 	} else if (ZFS_IS_VOLUME(zhp)) {
236799653d4eSeschrock 		ret = zvol_create_link(zhp->zfs_hdl, target);
236899653d4eSeschrock 	}
2369fa9e4066Sahrens 
237099653d4eSeschrock 	return (ret);
237199653d4eSeschrock }
237299653d4eSeschrock 
237399653d4eSeschrock typedef struct promote_data {
237499653d4eSeschrock 	char cb_mountpoint[MAXPATHLEN];
237599653d4eSeschrock 	const char *cb_target;
237699653d4eSeschrock 	const char *cb_errbuf;
237799653d4eSeschrock 	uint64_t cb_pivot_txg;
237899653d4eSeschrock } promote_data_t;
237999653d4eSeschrock 
238099653d4eSeschrock static int
238199653d4eSeschrock promote_snap_cb(zfs_handle_t *zhp, void *data)
238299653d4eSeschrock {
238399653d4eSeschrock 	promote_data_t *pd = data;
238499653d4eSeschrock 	zfs_handle_t *szhp;
238599653d4eSeschrock 	char snapname[MAXPATHLEN];
23863ccfa83cSahrens 	int rv = 0;
238799653d4eSeschrock 
238899653d4eSeschrock 	/* We don't care about snapshots after the pivot point */
23893ccfa83cSahrens 	if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) {
23903ccfa83cSahrens 		zfs_close(zhp);
239199653d4eSeschrock 		return (0);
23923ccfa83cSahrens 	}
239399653d4eSeschrock 
23940b69c2f0Sahrens 	/* Remove the device link if it's a zvol. */
2395e9dbad6fSeschrock 	if (ZFS_IS_VOLUME(zhp))
23960b69c2f0Sahrens 		(void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name);
239799653d4eSeschrock 
239899653d4eSeschrock 	/* Check for conflicting names */
2399e9dbad6fSeschrock 	(void) strlcpy(snapname, pd->cb_target, sizeof (snapname));
2400e9dbad6fSeschrock 	(void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname));
240199653d4eSeschrock 	szhp = make_dataset_handle(zhp->zfs_hdl, snapname);
240299653d4eSeschrock 	if (szhp != NULL) {
240399653d4eSeschrock 		zfs_close(szhp);
240499653d4eSeschrock 		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
240599653d4eSeschrock 		    "snapshot name '%s' from origin \n"
240699653d4eSeschrock 		    "conflicts with '%s' from target"),
240799653d4eSeschrock 		    zhp->zfs_name, snapname);
24083ccfa83cSahrens 		rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf);
240999653d4eSeschrock 	}
24103ccfa83cSahrens 	zfs_close(zhp);
24113ccfa83cSahrens 	return (rv);
241299653d4eSeschrock }
241399653d4eSeschrock 
24140b69c2f0Sahrens static int
24150b69c2f0Sahrens promote_snap_done_cb(zfs_handle_t *zhp, void *data)
24160b69c2f0Sahrens {
24170b69c2f0Sahrens 	promote_data_t *pd = data;
24180b69c2f0Sahrens 
24190b69c2f0Sahrens 	/* We don't care about snapshots after the pivot point */
24203ccfa83cSahrens 	if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) {
24213ccfa83cSahrens 		/* Create the device link if it's a zvol. */
24223ccfa83cSahrens 		if (ZFS_IS_VOLUME(zhp))
24233ccfa83cSahrens 			(void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
24243ccfa83cSahrens 	}
24250b69c2f0Sahrens 
24263ccfa83cSahrens 	zfs_close(zhp);
24270b69c2f0Sahrens 	return (0);
24280b69c2f0Sahrens }
24290b69c2f0Sahrens 
243099653d4eSeschrock /*
243199653d4eSeschrock  * Promotes the given clone fs to be the clone parent.
243299653d4eSeschrock  */
243399653d4eSeschrock int
243499653d4eSeschrock zfs_promote(zfs_handle_t *zhp)
243599653d4eSeschrock {
243699653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
243799653d4eSeschrock 	zfs_cmd_t zc = { 0 };
243899653d4eSeschrock 	char parent[MAXPATHLEN];
243999653d4eSeschrock 	char *cp;
244099653d4eSeschrock 	int ret;
244199653d4eSeschrock 	zfs_handle_t *pzhp;
244299653d4eSeschrock 	promote_data_t pd;
244399653d4eSeschrock 	char errbuf[1024];
244499653d4eSeschrock 
244599653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
244699653d4eSeschrock 	    "cannot promote '%s'"), zhp->zfs_name);
244799653d4eSeschrock 
244899653d4eSeschrock 	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
244999653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
245099653d4eSeschrock 		    "snapshots can not be promoted"));
245199653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
245299653d4eSeschrock 	}
245399653d4eSeschrock 
2454e9dbad6fSeschrock 	(void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent));
245599653d4eSeschrock 	if (parent[0] == '\0') {
245699653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
245799653d4eSeschrock 		    "not a cloned filesystem"));
245899653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
245999653d4eSeschrock 	}
246099653d4eSeschrock 	cp = strchr(parent, '@');
246199653d4eSeschrock 	*cp = '\0';
246299653d4eSeschrock 
246399653d4eSeschrock 	/* Walk the snapshots we will be moving */
246499653d4eSeschrock 	pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT);
246599653d4eSeschrock 	if (pzhp == NULL)
246699653d4eSeschrock 		return (-1);
246799653d4eSeschrock 	pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG);
246899653d4eSeschrock 	zfs_close(pzhp);
246999653d4eSeschrock 	pd.cb_target = zhp->zfs_name;
247099653d4eSeschrock 	pd.cb_errbuf = errbuf;
247199653d4eSeschrock 	pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY);
247299653d4eSeschrock 	if (pzhp == NULL)
247399653d4eSeschrock 		return (-1);
247499653d4eSeschrock 	(void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint,
247599653d4eSeschrock 	    sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE);
247699653d4eSeschrock 	ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd);
24770b69c2f0Sahrens 	if (ret != 0) {
24780b69c2f0Sahrens 		zfs_close(pzhp);
247999653d4eSeschrock 		return (-1);
24800b69c2f0Sahrens 	}
248199653d4eSeschrock 
248299653d4eSeschrock 	/* issue the ioctl */
2483e9dbad6fSeschrock 	(void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of,
2484e9dbad6fSeschrock 	    sizeof (zc.zc_value));
248599653d4eSeschrock 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
248699653d4eSeschrock 	ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc);
248799653d4eSeschrock 
248899653d4eSeschrock 	if (ret != 0) {
24890b69c2f0Sahrens 		int save_errno = errno;
24900b69c2f0Sahrens 
24910b69c2f0Sahrens 		(void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd);
24920b69c2f0Sahrens 		zfs_close(pzhp);
249399653d4eSeschrock 
24940b69c2f0Sahrens 		switch (save_errno) {
249599653d4eSeschrock 		case EEXIST:
2496fa9e4066Sahrens 			/*
249799653d4eSeschrock 			 * There is a conflicting snapshot name.  We
249899653d4eSeschrock 			 * should have caught this above, but they could
249999653d4eSeschrock 			 * have renamed something in the mean time.
2500fa9e4066Sahrens 			 */
250199653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
250299653d4eSeschrock 			    "conflicting snapshot name from parent '%s'"),
250399653d4eSeschrock 			    parent);
250499653d4eSeschrock 			return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2505fa9e4066Sahrens 
2506fa9e4066Sahrens 		default:
25070b69c2f0Sahrens 			return (zfs_standard_error(hdl, save_errno, errbuf));
2508fa9e4066Sahrens 		}
25090b69c2f0Sahrens 	} else {
25100b69c2f0Sahrens 		(void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd);
2511fa9e4066Sahrens 	}
2512fa9e4066Sahrens 
25130b69c2f0Sahrens 	zfs_close(pzhp);
2514fa9e4066Sahrens 	return (ret);
2515fa9e4066Sahrens }
2516fa9e4066Sahrens 
2517*cdf5b4caSmmusante struct createdata {
2518*cdf5b4caSmmusante 	const char *cd_snapname;
2519*cdf5b4caSmmusante 	int cd_ifexists;
2520*cdf5b4caSmmusante };
2521*cdf5b4caSmmusante 
25221d452cf5Sahrens static int
25231d452cf5Sahrens zfs_create_link_cb(zfs_handle_t *zhp, void *arg)
25241d452cf5Sahrens {
2525*cdf5b4caSmmusante 	struct createdata *cd = arg;
2526e9dbad6fSeschrock 	int ret;
25271d452cf5Sahrens 
25281d452cf5Sahrens 	if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
25291d452cf5Sahrens 		char name[MAXPATHLEN];
25301d452cf5Sahrens 
2531e9dbad6fSeschrock 		(void) strlcpy(name, zhp->zfs_name, sizeof (name));
2532e9dbad6fSeschrock 		(void) strlcat(name, "@", sizeof (name));
2533*cdf5b4caSmmusante 		(void) strlcat(name, cd->cd_snapname, sizeof (name));
2534*cdf5b4caSmmusante 		(void) zvol_create_link_common(zhp->zfs_hdl, name,
2535*cdf5b4caSmmusante 		    cd->cd_ifexists);
25361d452cf5Sahrens 		/*
25371d452cf5Sahrens 		 * NB: this is simply a best-effort.  We don't want to
25381d452cf5Sahrens 		 * return an error, because then we wouldn't visit all
25391d452cf5Sahrens 		 * the volumes.
25401d452cf5Sahrens 		 */
25411d452cf5Sahrens 	}
2542e9dbad6fSeschrock 
2543*cdf5b4caSmmusante 	ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, cd);
2544e9dbad6fSeschrock 
2545e9dbad6fSeschrock 	zfs_close(zhp);
2546e9dbad6fSeschrock 
2547e9dbad6fSeschrock 	return (ret);
25481d452cf5Sahrens }
25491d452cf5Sahrens 
2550fa9e4066Sahrens /*
255172bdce51Sahl  * Takes a snapshot of the given dataset.
2552fa9e4066Sahrens  */
2553fa9e4066Sahrens int
25541d452cf5Sahrens zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
2555fa9e4066Sahrens {
2556fa9e4066Sahrens 	const char *delim;
2557fa9e4066Sahrens 	char *parent;
2558fa9e4066Sahrens 	zfs_handle_t *zhp;
2559fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2560fa9e4066Sahrens 	int ret;
256199653d4eSeschrock 	char errbuf[1024];
2562fa9e4066Sahrens 
256399653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
256499653d4eSeschrock 	    "cannot snapshot '%s'"), path);
256599653d4eSeschrock 
256699653d4eSeschrock 	/* validate the target name */
256799653d4eSeschrock 	if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT))
256899653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2569fa9e4066Sahrens 
2570fa9e4066Sahrens 	/* make sure the parent exists and is of the appropriate type */
25711d452cf5Sahrens 	delim = strchr(path, '@');
257299653d4eSeschrock 	if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL)
257399653d4eSeschrock 		return (-1);
2574fa9e4066Sahrens 	(void) strncpy(parent, path, delim - path);
2575fa9e4066Sahrens 	parent[delim - path] = '\0';
2576fa9e4066Sahrens 
257799653d4eSeschrock 	if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM |
2578fa9e4066Sahrens 	    ZFS_TYPE_VOLUME)) == NULL) {
2579fa9e4066Sahrens 		free(parent);
2580fa9e4066Sahrens 		return (-1);
2581fa9e4066Sahrens 	}
2582fa9e4066Sahrens 
25831d452cf5Sahrens 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2584e9dbad6fSeschrock 	(void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value));
25851d452cf5Sahrens 	zc.zc_cookie = recursive;
25861d452cf5Sahrens 	ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc);
2587fa9e4066Sahrens 
25881d452cf5Sahrens 	/*
25891d452cf5Sahrens 	 * if it was recursive, the one that actually failed will be in
25901d452cf5Sahrens 	 * zc.zc_name.
25911d452cf5Sahrens 	 */
25921d452cf5Sahrens 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2593e9dbad6fSeschrock 	    "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value);
25941d452cf5Sahrens 	if (ret == 0 && recursive) {
2595*cdf5b4caSmmusante 		struct createdata cd;
2596*cdf5b4caSmmusante 
2597*cdf5b4caSmmusante 		cd.cd_snapname = delim + 1;
2598*cdf5b4caSmmusante 		cd.cd_ifexists = B_FALSE;
2599*cdf5b4caSmmusante 		(void) zfs_iter_filesystems(zhp, zfs_create_link_cb, &cd);
26001d452cf5Sahrens 	}
2601fa9e4066Sahrens 	if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) {
260299653d4eSeschrock 		ret = zvol_create_link(zhp->zfs_hdl, path);
26031d452cf5Sahrens 		if (ret != 0) {
260499653d4eSeschrock 			(void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY,
260599653d4eSeschrock 			    &zc);
26061d452cf5Sahrens 		}
2607fa9e4066Sahrens 	}
2608fa9e4066Sahrens 
260999653d4eSeschrock 	if (ret != 0)
261099653d4eSeschrock 		(void) zfs_standard_error(hdl, errno, errbuf);
2611fa9e4066Sahrens 
2612fa9e4066Sahrens 	free(parent);
2613fa9e4066Sahrens 	zfs_close(zhp);
2614fa9e4066Sahrens 
2615fa9e4066Sahrens 	return (ret);
2616fa9e4066Sahrens }
2617fa9e4066Sahrens 
2618fa9e4066Sahrens /*
261972bdce51Sahl  * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
262072bdce51Sahl  * NULL) to the file descriptor specified by outfd.
2621fa9e4066Sahrens  */
2622fa9e4066Sahrens int
262372bdce51Sahl zfs_send(zfs_handle_t *zhp, const char *fromsnap, int outfd)
2624fa9e4066Sahrens {
2625fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
262699653d4eSeschrock 	char errbuf[1024];
2627a2eea2e1Sahrens 	libzfs_handle_t *hdl = zhp->zfs_hdl;
262899653d4eSeschrock 
262972bdce51Sahl 	assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
2630fa9e4066Sahrens 
2631a2eea2e1Sahrens 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2632a2eea2e1Sahrens 	if (fromsnap)
2633a2eea2e1Sahrens 		(void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name));
263472bdce51Sahl 	zc.zc_cookie = outfd;
263572bdce51Sahl 
263672bdce51Sahl 	if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc) != 0) {
263772bdce51Sahl 		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
263872bdce51Sahl 		    "cannot send '%s'"), zhp->zfs_name);
2639fa9e4066Sahrens 
2640fa9e4066Sahrens 		switch (errno) {
2641fa9e4066Sahrens 
2642fa9e4066Sahrens 		case EXDEV:
264399653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2644d7d4af51Smmusante 			    "not an earlier snapshot from the same fs"));
264599653d4eSeschrock 			return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
2646fa9e4066Sahrens 
2647fa9e4066Sahrens 		case EDQUOT:
2648fa9e4066Sahrens 		case EFBIG:
2649fa9e4066Sahrens 		case EIO:
2650fa9e4066Sahrens 		case ENOLINK:
2651fa9e4066Sahrens 		case ENOSPC:
2652fa9e4066Sahrens 		case ENOSTR:
2653fa9e4066Sahrens 		case ENXIO:
2654fa9e4066Sahrens 		case EPIPE:
2655fa9e4066Sahrens 		case ERANGE:
2656fa9e4066Sahrens 		case EFAULT:
2657fa9e4066Sahrens 		case EROFS:
265899653d4eSeschrock 			zfs_error_aux(hdl, strerror(errno));
265999653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
2660fa9e4066Sahrens 
2661fa9e4066Sahrens 		default:
266299653d4eSeschrock 			return (zfs_standard_error(hdl, errno, errbuf));
2663fa9e4066Sahrens 		}
2664fa9e4066Sahrens 	}
2665fa9e4066Sahrens 
266672bdce51Sahl 	return (0);
2667fa9e4066Sahrens }
2668fa9e4066Sahrens 
2669a2eea2e1Sahrens /*
2670a2eea2e1Sahrens  * Create ancestors of 'target', but not target itself, and not
2671a2eea2e1Sahrens  * ancestors whose names are shorter than prefixlen.  Die if
2672a2eea2e1Sahrens  * prefixlen-ancestor does not exist.
2673a2eea2e1Sahrens  */
2674a2eea2e1Sahrens static int
2675a2eea2e1Sahrens create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
2676a2eea2e1Sahrens {
2677a2eea2e1Sahrens 	zfs_handle_t *h;
2678a2eea2e1Sahrens 	char *cp;
2679a2eea2e1Sahrens 
2680a2eea2e1Sahrens 	/* make sure prefix exists */
2681a2eea2e1Sahrens 	cp = strchr(target + prefixlen, '/');
2682a2eea2e1Sahrens 	*cp = '\0';
2683a2eea2e1Sahrens 	h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2684a2eea2e1Sahrens 	*cp = '/';
2685a2eea2e1Sahrens 	if (h == NULL)
2686a2eea2e1Sahrens 		return (-1);
2687a2eea2e1Sahrens 	zfs_close(h);
2688a2eea2e1Sahrens 
2689a2eea2e1Sahrens 	/*
2690a2eea2e1Sahrens 	 * Attempt to create, mount, and share any ancestor filesystems,
2691a2eea2e1Sahrens 	 * up to the prefixlen-long one.
2692a2eea2e1Sahrens 	 */
2693a2eea2e1Sahrens 	for (cp = target + prefixlen + 1;
2694a2eea2e1Sahrens 	    cp = strchr(cp, '/'); *cp = '/', cp++) {
2695a2eea2e1Sahrens 		const char *opname;
2696a2eea2e1Sahrens 
2697a2eea2e1Sahrens 		*cp = '\0';
2698a2eea2e1Sahrens 
2699a2eea2e1Sahrens 		h = make_dataset_handle(hdl, target);
2700a2eea2e1Sahrens 		if (h) {
2701a2eea2e1Sahrens 			/* it already exists, nothing to do here */
2702a2eea2e1Sahrens 			zfs_close(h);
2703a2eea2e1Sahrens 			continue;
2704a2eea2e1Sahrens 		}
2705a2eea2e1Sahrens 
2706a2eea2e1Sahrens 		opname = dgettext(TEXT_DOMAIN, "create");
2707a2eea2e1Sahrens 		if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
2708a2eea2e1Sahrens 		    NULL) != 0)
2709a2eea2e1Sahrens 			goto ancestorerr;
2710a2eea2e1Sahrens 
2711a2eea2e1Sahrens 		opname = dgettext(TEXT_DOMAIN, "open");
2712a2eea2e1Sahrens 		h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2713a2eea2e1Sahrens 		if (h == NULL)
2714a2eea2e1Sahrens 			goto ancestorerr;
2715a2eea2e1Sahrens 
2716a2eea2e1Sahrens 		opname = dgettext(TEXT_DOMAIN, "mount");
2717a2eea2e1Sahrens 		if (zfs_mount(h, NULL, 0) != 0)
2718a2eea2e1Sahrens 			goto ancestorerr;
2719a2eea2e1Sahrens 
2720a2eea2e1Sahrens 		opname = dgettext(TEXT_DOMAIN, "share");
2721a2eea2e1Sahrens 		if (zfs_share(h) != 0)
2722a2eea2e1Sahrens 			goto ancestorerr;
2723a2eea2e1Sahrens 
2724a2eea2e1Sahrens 		zfs_close(h);
2725a2eea2e1Sahrens 
2726a2eea2e1Sahrens 		continue;
2727a2eea2e1Sahrens ancestorerr:
2728a2eea2e1Sahrens 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2729a2eea2e1Sahrens 		    "failed to %s ancestor '%s'"), opname, target);
2730a2eea2e1Sahrens 		return (-1);
2731a2eea2e1Sahrens 	}
2732a2eea2e1Sahrens 
2733a2eea2e1Sahrens 	return (0);
2734a2eea2e1Sahrens }
2735a2eea2e1Sahrens 
2736fa9e4066Sahrens /*
273772bdce51Sahl  * Restores a backup of tosnap from the file descriptor specified by infd.
2738fa9e4066Sahrens  */
2739fa9e4066Sahrens int
274099653d4eSeschrock zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
274172bdce51Sahl     int verbose, int dryrun, boolean_t force, int infd)
2742fa9e4066Sahrens {
2743fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2744fa9e4066Sahrens 	time_t begin_time;
2745a2eea2e1Sahrens 	int ioctl_err, err, bytes, size, choplen;
2746fa9e4066Sahrens 	char *cp;
2747fa9e4066Sahrens 	dmu_replay_record_t drr;
2748fa9e4066Sahrens 	struct drr_begin *drrb = &zc.zc_begin_record;
274999653d4eSeschrock 	char errbuf[1024];
275098579b20Snd 	prop_changelist_t *clp;
2751a2eea2e1Sahrens 	char chopprefix[ZFS_MAXNAMELEN];
2752fa9e4066Sahrens 
2753fa9e4066Sahrens 	begin_time = time(NULL);
2754fa9e4066Sahrens 
275599653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
275699653d4eSeschrock 	    "cannot receive"));
275799653d4eSeschrock 
2758fa9e4066Sahrens 	/* read in the BEGIN record */
2759fa9e4066Sahrens 	cp = (char *)&drr;
2760fa9e4066Sahrens 	bytes = 0;
2761fa9e4066Sahrens 	do {
276272bdce51Sahl 		size = read(infd, cp, sizeof (drr) - bytes);
27639b4f025eSahrens 		cp += size;
27649b4f025eSahrens 		bytes += size;
27659b4f025eSahrens 	} while (size > 0);
2766fa9e4066Sahrens 
27679b4f025eSahrens 	if (size < 0 || bytes != sizeof (drr)) {
276899653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
276999653d4eSeschrock 		    "stream (failed to read first record)"));
277099653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2771fa9e4066Sahrens 	}
2772fa9e4066Sahrens 
2773fa9e4066Sahrens 	zc.zc_begin_record = drr.drr_u.drr_begin;
2774fa9e4066Sahrens 
2775fa9e4066Sahrens 	if (drrb->drr_magic != DMU_BACKUP_MAGIC &&
2776fa9e4066Sahrens 	    drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) {
277799653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
277899653d4eSeschrock 		    "stream (bad magic number)"));
277999653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2780fa9e4066Sahrens 	}
2781fa9e4066Sahrens 
2782fa9e4066Sahrens 	if (drrb->drr_version != DMU_BACKUP_VERSION &&
2783fa9e4066Sahrens 	    drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) {
278499653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version "
278599653d4eSeschrock 		    "0x%llx is supported (stream is version 0x%llx)"),
2786fa9e4066Sahrens 		    DMU_BACKUP_VERSION, drrb->drr_version);
278799653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2788fa9e4066Sahrens 	}
2789fa9e4066Sahrens 
2790a2eea2e1Sahrens 	if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) {
2791a2eea2e1Sahrens 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
2792b1b8ab34Slling 		    "stream (bad snapshot name)"));
2793a2eea2e1Sahrens 		return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2794a2eea2e1Sahrens 	}
2795fa9e4066Sahrens 	/*
2796a2eea2e1Sahrens 	 * Determine how much of the snapshot name stored in the stream
2797a2eea2e1Sahrens 	 * we are going to tack on to the name they specified on the
2798a2eea2e1Sahrens 	 * command line, and how much we are going to chop off.
2799a2eea2e1Sahrens 	 *
2800a2eea2e1Sahrens 	 * If they specified a snapshot, chop the entire name stored in
2801a2eea2e1Sahrens 	 * the stream.
2802fa9e4066Sahrens 	 */
2803a2eea2e1Sahrens 	(void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname);
2804fa9e4066Sahrens 	if (isprefix) {
2805a2eea2e1Sahrens 		/*
2806a2eea2e1Sahrens 		 * They specified a fs with -d, we want to tack on
2807a2eea2e1Sahrens 		 * everything but the pool name stored in the stream
2808a2eea2e1Sahrens 		 */
2809a2eea2e1Sahrens 		if (strchr(tosnap, '@')) {
2810a2eea2e1Sahrens 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
2811a2eea2e1Sahrens 			    "argument - snapshot not allowed with -d"));
2812a2eea2e1Sahrens 			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2813fa9e4066Sahrens 		}
2814a2eea2e1Sahrens 		cp = strchr(chopprefix, '/');
2815fa9e4066Sahrens 		if (cp == NULL)
2816a2eea2e1Sahrens 			cp = strchr(chopprefix, '@');
2817a2eea2e1Sahrens 		*cp = '\0';
2818fa9e4066Sahrens 	} else if (strchr(tosnap, '@') == NULL) {
2819fa9e4066Sahrens 		/*
2820a2eea2e1Sahrens 		 * If they specified a filesystem without -d, we want to
2821a2eea2e1Sahrens 		 * tack on everything after the fs specified in the
2822a2eea2e1Sahrens 		 * first name from the stream.
2823fa9e4066Sahrens 		 */
2824a2eea2e1Sahrens 		cp = strchr(chopprefix, '@');
2825a2eea2e1Sahrens 		*cp = '\0';
2826fa9e4066Sahrens 	}
2827a2eea2e1Sahrens 	choplen = strlen(chopprefix);
2828a2eea2e1Sahrens 
2829a2eea2e1Sahrens 	/*
2830a2eea2e1Sahrens 	 * Determine name of destination snapshot, store in zc_value.
2831a2eea2e1Sahrens 	 */
2832a2eea2e1Sahrens 	(void) strcpy(zc.zc_value, tosnap);
2833a2eea2e1Sahrens 	(void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen,
2834a2eea2e1Sahrens 	    sizeof (zc.zc_value));
28353ccfa83cSahrens 	if (!zfs_validate_name(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT))
28363ccfa83cSahrens 		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2837fa9e4066Sahrens 
2838a2eea2e1Sahrens 	(void) strcpy(zc.zc_name, zc.zc_value);
2839fa9e4066Sahrens 	if (drrb->drr_fromguid) {
2840fa9e4066Sahrens 		/* incremental backup stream */
2841a2eea2e1Sahrens 		zfs_handle_t *h;
2842fa9e4066Sahrens 
2843a2eea2e1Sahrens 		/* do the recvbackup ioctl to the containing fs */
2844a2eea2e1Sahrens 		*strchr(zc.zc_name, '@') = '\0';
2845fa9e4066Sahrens 
2846fa9e4066Sahrens 		/* make sure destination fs exists */
284799653d4eSeschrock 		h = zfs_open(hdl, zc.zc_name,
284899653d4eSeschrock 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
284999653d4eSeschrock 		if (h == NULL)
2850fa9e4066Sahrens 			return (-1);
28519b4f025eSahrens 		if (!dryrun) {
285298579b20Snd 			/*
285398579b20Snd 			 * We need to unmount all the dependents of the dataset
285498579b20Snd 			 * and the dataset itself. If it's a volume
285598579b20Snd 			 * then remove device link.
285698579b20Snd 			 */
28579b4f025eSahrens 			if (h->zfs_type == ZFS_TYPE_FILESYSTEM) {
285898579b20Snd 				clp = changelist_gather(h, ZFS_PROP_NAME, 0);
285998579b20Snd 				if (clp == NULL)
286098579b20Snd 					return (-1);
286198579b20Snd 				if (changelist_prefix(clp) != 0) {
286298579b20Snd 					changelist_free(clp);
286398579b20Snd 					return (-1);
286498579b20Snd 				}
28659b4f025eSahrens 			} else {
286699653d4eSeschrock 				(void) zvol_remove_link(hdl, h->zfs_name);
28679b4f025eSahrens 			}
28689b4f025eSahrens 		}
2869fa9e4066Sahrens 		zfs_close(h);
2870fa9e4066Sahrens 	} else {
2871fa9e4066Sahrens 		/* full backup stream */
2872fa9e4066Sahrens 
2873a2eea2e1Sahrens 		/* Make sure destination fs does not exist */
2874a2eea2e1Sahrens 		*strchr(zc.zc_name, '@') = '\0';
2875a2eea2e1Sahrens 		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) {
287699653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2877a2eea2e1Sahrens 			    "destination '%s' exists"), zc.zc_name);
287899653d4eSeschrock 			return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2879fa9e4066Sahrens 		}
2880fa9e4066Sahrens 
2881a2eea2e1Sahrens 		if (strchr(zc.zc_name, '/') == NULL) {
28829b4f025eSahrens 			/*
2883a2eea2e1Sahrens 			 * they're trying to do a recv into a
2884a2eea2e1Sahrens 			 * nonexistant topmost filesystem.
28859b4f025eSahrens 			 */
288699653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2887a2eea2e1Sahrens 			    "destination does not exist"), zc.zc_name);
288899653d4eSeschrock 			return (zfs_error(hdl, EZFS_EXISTS, errbuf));
28899b4f025eSahrens 		}
28909b4f025eSahrens 
28919b4f025eSahrens 		/* Do the recvbackup ioctl to the fs's parent. */
2892a2eea2e1Sahrens 		*strrchr(zc.zc_name, '/') = '\0';
2893a2eea2e1Sahrens 
2894a2eea2e1Sahrens 		if (isprefix && (err = create_parents(hdl,
2895a2eea2e1Sahrens 		    zc.zc_value, strlen(tosnap))) != 0) {
2896a2eea2e1Sahrens 			return (zfs_error(hdl, EZFS_BADRESTORE, errbuf));
2897a2eea2e1Sahrens 		}
2898a2eea2e1Sahrens 
2899fa9e4066Sahrens 	}
2900fa9e4066Sahrens 
290172bdce51Sahl 	zc.zc_cookie = infd;
2902e9dbad6fSeschrock 	zc.zc_guid = force;
2903fa9e4066Sahrens 	if (verbose) {
2904f2a3c691Sahrens 		(void) printf("%s %s stream of %s into %s\n",
2905f2a3c691Sahrens 		    dryrun ? "would receive" : "receiving",
2906fa9e4066Sahrens 		    drrb->drr_fromguid ? "incremental" : "full",
2907fa9e4066Sahrens 		    drr.drr_u.drr_begin.drr_toname,
2908e9dbad6fSeschrock 		    zc.zc_value);
2909fa9e4066Sahrens 		(void) fflush(stdout);
2910fa9e4066Sahrens 	}
2911fa9e4066Sahrens 	if (dryrun)
2912fa9e4066Sahrens 		return (0);
291399653d4eSeschrock 	err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc);
29149b4f025eSahrens 	if (ioctl_err != 0) {
2915fa9e4066Sahrens 		switch (errno) {
2916fa9e4066Sahrens 		case ENODEV:
291799653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
291899653d4eSeschrock 			    "most recent snapshot does not match incremental "
291999653d4eSeschrock 			    "source"));
292099653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
2921fa9e4066Sahrens 			break;
2922fa9e4066Sahrens 		case ETXTBSY:
292399653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
292499653d4eSeschrock 			    "destination has been modified since most recent "
292599653d4eSeschrock 			    "snapshot"));
292699653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
2927fa9e4066Sahrens 			break;
2928fa9e4066Sahrens 		case EEXIST:
2929fa9e4066Sahrens 			if (drrb->drr_fromguid == 0) {
2930fa9e4066Sahrens 				/* it's the containing fs that exists */
2931e9dbad6fSeschrock 				cp = strchr(zc.zc_value, '@');
2932fa9e4066Sahrens 				*cp = '\0';
2933fa9e4066Sahrens 			}
293499653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
293599653d4eSeschrock 			    "destination already exists"));
2936ece3d9b3Slling 			(void) zfs_error_fmt(hdl, EZFS_EXISTS,
2937ece3d9b3Slling 			    dgettext(TEXT_DOMAIN, "cannot restore to %s"),
2938ece3d9b3Slling 			    zc.zc_value);
2939fa9e4066Sahrens 			break;
2940fa9e4066Sahrens 		case EINVAL:
294199653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
29429b4f025eSahrens 			break;
2943ea8dc4b6Seschrock 		case ECKSUM:
294499653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
294599653d4eSeschrock 			    "invalid stream (checksum mismatch)"));
294699653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
2947fa9e4066Sahrens 			break;
2948fa9e4066Sahrens 		default:
294999653d4eSeschrock 			(void) zfs_standard_error(hdl, errno, errbuf);
2950fa9e4066Sahrens 		}
2951fa9e4066Sahrens 	}
2952fa9e4066Sahrens 
2953fa9e4066Sahrens 	/*
29549b4f025eSahrens 	 * Mount or recreate the /dev links for the target filesystem
29559b4f025eSahrens 	 * (if created, or if we tore them down to do an incremental
29569b4f025eSahrens 	 * restore), and the /dev links for the new snapshot (if
295798579b20Snd 	 * created). Also mount any children of the target filesystem
295898579b20Snd 	 * if we did an incremental receive.
2959fa9e4066Sahrens 	 */
2960e9dbad6fSeschrock 	cp = strchr(zc.zc_value, '@');
29619b4f025eSahrens 	if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) {
2962fa9e4066Sahrens 		zfs_handle_t *h;
2963fa9e4066Sahrens 
2964fa9e4066Sahrens 		*cp = '\0';
2965e9dbad6fSeschrock 		h = zfs_open(hdl, zc.zc_value,
2966fa9e4066Sahrens 		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
29679b4f025eSahrens 		*cp = '@';
2968fa9e4066Sahrens 		if (h) {
296998579b20Snd 			if (h->zfs_type == ZFS_TYPE_VOLUME) {
297099653d4eSeschrock 				err = zvol_create_link(hdl, h->zfs_name);
2971ea8dc4b6Seschrock 				if (err == 0 && ioctl_err == 0)
297299653d4eSeschrock 					err = zvol_create_link(hdl,
2973e9dbad6fSeschrock 					    zc.zc_value);
297498579b20Snd 			} else {
297598579b20Snd 				if (drrb->drr_fromguid) {
297698579b20Snd 					err = changelist_postfix(clp);
297798579b20Snd 					changelist_free(clp);
297898579b20Snd 				} else {
297998579b20Snd 					err = zfs_mount(h, NULL, 0);
298098579b20Snd 				}
29819b4f025eSahrens 			}
298298579b20Snd 		zfs_close(h);
2983fa9e4066Sahrens 		}
2984fa9e4066Sahrens 	}
2985fa9e4066Sahrens 
29869b4f025eSahrens 	if (err || ioctl_err)
29879b4f025eSahrens 		return (-1);
2988fa9e4066Sahrens 
2989fa9e4066Sahrens 	if (verbose) {
2990fa9e4066Sahrens 		char buf1[64];
2991fa9e4066Sahrens 		char buf2[64];
2992fa9e4066Sahrens 		uint64_t bytes = zc.zc_cookie;
2993fa9e4066Sahrens 		time_t delta = time(NULL) - begin_time;
2994fa9e4066Sahrens 		if (delta == 0)
2995fa9e4066Sahrens 			delta = 1;
2996fa9e4066Sahrens 		zfs_nicenum(bytes, buf1, sizeof (buf1));
2997fa9e4066Sahrens 		zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
2998fa9e4066Sahrens 
2999f2a3c691Sahrens 		(void) printf("received %sb stream in %lu seconds (%sb/sec)\n",
3000fa9e4066Sahrens 		    buf1, delta, buf2);
3001fa9e4066Sahrens 	}
300298579b20Snd 
3003fa9e4066Sahrens 	return (0);
3004fa9e4066Sahrens }
3005fa9e4066Sahrens 
3006fa9e4066Sahrens /*
3007b12a1c38Slling  * Destroy any more recent snapshots.  We invoke this callback on any dependents
3008b12a1c38Slling  * of the snapshot first.  If the 'cb_dependent' member is non-zero, then this
3009b12a1c38Slling  * is a dependent and we should just destroy it without checking the transaction
3010b12a1c38Slling  * group.
3011fa9e4066Sahrens  */
3012b12a1c38Slling typedef struct rollback_data {
3013b12a1c38Slling 	const char	*cb_target;		/* the snapshot */
3014b12a1c38Slling 	uint64_t	cb_create;		/* creation time reference */
3015b12a1c38Slling 	prop_changelist_t *cb_clp;		/* changelist pointer */
3016b12a1c38Slling 	int		cb_error;
301799653d4eSeschrock 	boolean_t	cb_dependent;
3018b12a1c38Slling } rollback_data_t;
3019b12a1c38Slling 
3020b12a1c38Slling static int
3021b12a1c38Slling rollback_destroy(zfs_handle_t *zhp, void *data)
3022b12a1c38Slling {
3023b12a1c38Slling 	rollback_data_t *cbp = data;
3024b12a1c38Slling 
3025b12a1c38Slling 	if (!cbp->cb_dependent) {
3026b12a1c38Slling 		if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 &&
3027b12a1c38Slling 		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
3028b12a1c38Slling 		    zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
3029b12a1c38Slling 		    cbp->cb_create) {
3030b12a1c38Slling 
303199653d4eSeschrock 			cbp->cb_dependent = B_TRUE;
30323bb79becSeschrock 			if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy,
30333bb79becSeschrock 			    cbp) != 0)
30343bb79becSeschrock 				cbp->cb_error = 1;
303599653d4eSeschrock 			cbp->cb_dependent = B_FALSE;
3036b12a1c38Slling 
3037b12a1c38Slling 			if (zfs_destroy(zhp) != 0)
3038b12a1c38Slling 				cbp->cb_error = 1;
3039b12a1c38Slling 			else
3040b12a1c38Slling 				changelist_remove(zhp, cbp->cb_clp);
3041b12a1c38Slling 		}
3042b12a1c38Slling 	} else {
3043b12a1c38Slling 		if (zfs_destroy(zhp) != 0)
3044b12a1c38Slling 			cbp->cb_error = 1;
3045b12a1c38Slling 		else
3046b12a1c38Slling 			changelist_remove(zhp, cbp->cb_clp);
3047b12a1c38Slling 	}
3048b12a1c38Slling 
3049b12a1c38Slling 	zfs_close(zhp);
3050b12a1c38Slling 	return (0);
3051b12a1c38Slling }
3052b12a1c38Slling 
3053b12a1c38Slling /*
3054b12a1c38Slling  * Rollback the dataset to its latest snapshot.
3055b12a1c38Slling  */
3056b12a1c38Slling static int
3057b12a1c38Slling do_rollback(zfs_handle_t *zhp)
3058fa9e4066Sahrens {
3059fa9e4066Sahrens 	int ret;
3060fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
3061fa9e4066Sahrens 
3062fa9e4066Sahrens 	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
3063fa9e4066Sahrens 	    zhp->zfs_type == ZFS_TYPE_VOLUME);
3064fa9e4066Sahrens 
3065fa9e4066Sahrens 	if (zhp->zfs_type == ZFS_TYPE_VOLUME &&
306699653d4eSeschrock 	    zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0)
3067fa9e4066Sahrens 		return (-1);
3068fa9e4066Sahrens 
3069fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3070fa9e4066Sahrens 
3071e9dbad6fSeschrock 	if (ZFS_IS_VOLUME(zhp))
3072fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZVOL;
3073fa9e4066Sahrens 	else
3074fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZFS;
3075fa9e4066Sahrens 
3076fa9e4066Sahrens 	/*
3077fa9e4066Sahrens 	 * We rely on the consumer to verify that there are no newer snapshots
3078fa9e4066Sahrens 	 * for the given dataset.  Given these constraints, we can simply pass
3079fa9e4066Sahrens 	 * the name on to the ioctl() call.  There is still an unlikely race
3080fa9e4066Sahrens 	 * condition where the user has taken a snapshot since we verified that
3081fa9e4066Sahrens 	 * this was the most recent.
3082fa9e4066Sahrens 	 */
308399653d4eSeschrock 	if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK,
308499653d4eSeschrock 	    &zc)) != 0) {
3085ece3d9b3Slling 		(void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
308699653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
308799653d4eSeschrock 		    zhp->zfs_name);
3088fa9e4066Sahrens 	} else if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
308999653d4eSeschrock 		ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
3090fa9e4066Sahrens 	}
3091fa9e4066Sahrens 
3092fa9e4066Sahrens 	return (ret);
3093fa9e4066Sahrens }
3094fa9e4066Sahrens 
3095b12a1c38Slling /*
3096b12a1c38Slling  * Given a dataset, rollback to a specific snapshot, discarding any
3097b12a1c38Slling  * data changes since then and making it the active dataset.
3098b12a1c38Slling  *
3099b12a1c38Slling  * Any snapshots more recent than the target are destroyed, along with
3100b12a1c38Slling  * their dependents.
3101b12a1c38Slling  */
3102b12a1c38Slling int
3103b12a1c38Slling zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag)
3104b12a1c38Slling {
3105b12a1c38Slling 	int ret;
3106b12a1c38Slling 	rollback_data_t cb = { 0 };
3107b12a1c38Slling 	prop_changelist_t *clp;
3108b12a1c38Slling 
3109b12a1c38Slling 	/*
3110b12a1c38Slling 	 * Unmount all dependendents of the dataset and the dataset itself.
3111b12a1c38Slling 	 * The list we need to gather is the same as for doing rename
3112b12a1c38Slling 	 */
3113b12a1c38Slling 	clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0);
3114b12a1c38Slling 	if (clp == NULL)
3115b12a1c38Slling 		return (-1);
3116b12a1c38Slling 
3117b12a1c38Slling 	if ((ret = changelist_prefix(clp)) != 0)
3118b12a1c38Slling 		goto out;
3119b12a1c38Slling 
3120b12a1c38Slling 	/*
3121b12a1c38Slling 	 * Destroy all recent snapshots and its dependends.
3122b12a1c38Slling 	 */
3123b12a1c38Slling 	cb.cb_target = snap->zfs_name;
3124b12a1c38Slling 	cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
3125b12a1c38Slling 	cb.cb_clp = clp;
3126b12a1c38Slling 	(void) zfs_iter_children(zhp, rollback_destroy, &cb);
3127b12a1c38Slling 
3128b12a1c38Slling 	if ((ret = cb.cb_error) != 0) {
3129b12a1c38Slling 		(void) changelist_postfix(clp);
3130b12a1c38Slling 		goto out;
3131b12a1c38Slling 	}
3132b12a1c38Slling 
3133b12a1c38Slling 	/*
3134b12a1c38Slling 	 * Now that we have verified that the snapshot is the latest,
3135b12a1c38Slling 	 * rollback to the given snapshot.
3136b12a1c38Slling 	 */
3137b12a1c38Slling 	ret = do_rollback(zhp);
3138b12a1c38Slling 
3139b12a1c38Slling 	if (ret != 0) {
3140b12a1c38Slling 		(void) changelist_postfix(clp);
3141b12a1c38Slling 		goto out;
3142b12a1c38Slling 	}
3143b12a1c38Slling 
3144b12a1c38Slling 	/*
3145b12a1c38Slling 	 * We only want to re-mount the filesystem if it was mounted in the
3146b12a1c38Slling 	 * first place.
3147b12a1c38Slling 	 */
3148b12a1c38Slling 	ret = changelist_postfix(clp);
3149b12a1c38Slling 
3150b12a1c38Slling out:
3151b12a1c38Slling 	changelist_free(clp);
3152b12a1c38Slling 	return (ret);
3153b12a1c38Slling }
3154b12a1c38Slling 
3155fa9e4066Sahrens /*
3156fa9e4066Sahrens  * Iterate over all dependents for a given dataset.  This includes both
3157fa9e4066Sahrens  * hierarchical dependents (children) and data dependents (snapshots and
3158fa9e4066Sahrens  * clones).  The bulk of the processing occurs in get_dependents() in
3159fa9e4066Sahrens  * libzfs_graph.c.
3160fa9e4066Sahrens  */
3161fa9e4066Sahrens int
31623bb79becSeschrock zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
31633bb79becSeschrock     zfs_iter_f func, void *data)
3164fa9e4066Sahrens {
3165fa9e4066Sahrens 	char **dependents;
3166fa9e4066Sahrens 	size_t count;
3167fa9e4066Sahrens 	int i;
3168fa9e4066Sahrens 	zfs_handle_t *child;
3169fa9e4066Sahrens 	int ret = 0;
3170fa9e4066Sahrens 
31713bb79becSeschrock 	if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name,
31723bb79becSeschrock 	    &dependents, &count) != 0)
31733bb79becSeschrock 		return (-1);
31743bb79becSeschrock 
3175fa9e4066Sahrens 	for (i = 0; i < count; i++) {
317699653d4eSeschrock 		if ((child = make_dataset_handle(zhp->zfs_hdl,
317799653d4eSeschrock 		    dependents[i])) == NULL)
3178fa9e4066Sahrens 			continue;
3179fa9e4066Sahrens 
3180fa9e4066Sahrens 		if ((ret = func(child, data)) != 0)
3181fa9e4066Sahrens 			break;
3182fa9e4066Sahrens 	}
3183fa9e4066Sahrens 
3184fa9e4066Sahrens 	for (i = 0; i < count; i++)
3185fa9e4066Sahrens 		free(dependents[i]);
3186fa9e4066Sahrens 	free(dependents);
3187fa9e4066Sahrens 
3188fa9e4066Sahrens 	return (ret);
3189fa9e4066Sahrens }
3190fa9e4066Sahrens 
3191fa9e4066Sahrens /*
3192fa9e4066Sahrens  * Renames the given dataset.
3193fa9e4066Sahrens  */
3194fa9e4066Sahrens int
3195*cdf5b4caSmmusante zfs_rename(zfs_handle_t *zhp, const char *target, int recursive)
3196fa9e4066Sahrens {
3197fa9e4066Sahrens 	int ret;
3198fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
3199fa9e4066Sahrens 	char *delim;
3200*cdf5b4caSmmusante 	prop_changelist_t *cl = NULL;
3201*cdf5b4caSmmusante 	zfs_handle_t *zhrp = NULL;
3202*cdf5b4caSmmusante 	char *parentname = NULL;
3203fa9e4066Sahrens 	char parent[ZFS_MAXNAMELEN];
320499653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
320599653d4eSeschrock 	char errbuf[1024];
3206fa9e4066Sahrens 
3207fa9e4066Sahrens 	/* if we have the same exact name, just return success */
3208fa9e4066Sahrens 	if (strcmp(zhp->zfs_name, target) == 0)
3209fa9e4066Sahrens 		return (0);
3210fa9e4066Sahrens 
321199653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
321299653d4eSeschrock 	    "cannot rename to '%s'"), target);
321399653d4eSeschrock 
3214fa9e4066Sahrens 	/*
3215fa9e4066Sahrens 	 * Make sure the target name is valid
3216fa9e4066Sahrens 	 */
3217fa9e4066Sahrens 	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
321898579b20Snd 		if ((strchr(target, '@') == NULL) ||
321998579b20Snd 		    *target == '@') {
322098579b20Snd 			/*
322198579b20Snd 			 * Snapshot target name is abbreviated,
322298579b20Snd 			 * reconstruct full dataset name
322398579b20Snd 			 */
322498579b20Snd 			(void) strlcpy(parent, zhp->zfs_name,
322598579b20Snd 			    sizeof (parent));
322698579b20Snd 			delim = strchr(parent, '@');
322798579b20Snd 			if (strchr(target, '@') == NULL)
322898579b20Snd 				*(++delim) = '\0';
322998579b20Snd 			else
323098579b20Snd 				*delim = '\0';
323198579b20Snd 			(void) strlcat(parent, target, sizeof (parent));
323298579b20Snd 			target = parent;
323398579b20Snd 		} else {
323498579b20Snd 			/*
323598579b20Snd 			 * Make sure we're renaming within the same dataset.
323698579b20Snd 			 */
323798579b20Snd 			delim = strchr(target, '@');
323898579b20Snd 			if (strncmp(zhp->zfs_name, target, delim - target)
323998579b20Snd 			    != 0 || zhp->zfs_name[delim - target] != '@') {
324098579b20Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
324198579b20Snd 				    "snapshots must be part of same "
324298579b20Snd 				    "dataset"));
324398579b20Snd 				return (zfs_error(hdl, EZFS_CROSSTARGET,
3244b1b8ab34Slling 				    errbuf));
324598579b20Snd 			}
3246fa9e4066Sahrens 		}
324798579b20Snd 		if (!zfs_validate_name(hdl, target, zhp->zfs_type))
324898579b20Snd 			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3249fa9e4066Sahrens 	} else {
3250*cdf5b4caSmmusante 		if (recursive) {
3251*cdf5b4caSmmusante 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3252*cdf5b4caSmmusante 			    "recursive rename must be a snapshot"));
3253*cdf5b4caSmmusante 			return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3254*cdf5b4caSmmusante 		}
3255*cdf5b4caSmmusante 
325698579b20Snd 		if (!zfs_validate_name(hdl, target, zhp->zfs_type))
325798579b20Snd 			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3258e9dbad6fSeschrock 		uint64_t unused;
3259e9dbad6fSeschrock 
3260fa9e4066Sahrens 		/* validate parents */
3261e9dbad6fSeschrock 		if (check_parents(hdl, target, &unused) != 0)
3262fa9e4066Sahrens 			return (-1);
3263fa9e4066Sahrens 
3264fa9e4066Sahrens 		(void) parent_name(target, parent, sizeof (parent));
3265fa9e4066Sahrens 
3266fa9e4066Sahrens 		/* make sure we're in the same pool */
3267fa9e4066Sahrens 		verify((delim = strchr(target, '/')) != NULL);
3268fa9e4066Sahrens 		if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
3269fa9e4066Sahrens 		    zhp->zfs_name[delim - target] != '/') {
327099653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
327199653d4eSeschrock 			    "datasets must be within same pool"));
327299653d4eSeschrock 			return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
3273fa9e4066Sahrens 		}
3274f2fdf992Snd 
3275f2fdf992Snd 		/* new name cannot be a child of the current dataset name */
3276f2fdf992Snd 		if (strncmp(parent, zhp->zfs_name,
3277b1b8ab34Slling 		    strlen(zhp->zfs_name)) == 0) {
3278f2fdf992Snd 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3279f2fdf992Snd 			    "New dataset name cannot be a descendent of "
3280f2fdf992Snd 			    "current dataset name"));
3281f2fdf992Snd 			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3282f2fdf992Snd 		}
3283fa9e4066Sahrens 	}
3284fa9e4066Sahrens 
328599653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf),
328699653d4eSeschrock 	    dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
328799653d4eSeschrock 
3288fa9e4066Sahrens 	if (getzoneid() == GLOBAL_ZONEID &&
3289fa9e4066Sahrens 	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
329099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
329199653d4eSeschrock 		    "dataset is used in a non-global zone"));
329299653d4eSeschrock 		return (zfs_error(hdl, EZFS_ZONED, errbuf));
3293fa9e4066Sahrens 	}
3294fa9e4066Sahrens 
3295*cdf5b4caSmmusante 	if (recursive) {
3296*cdf5b4caSmmusante 		struct destroydata dd;
3297fa9e4066Sahrens 
3298*cdf5b4caSmmusante 		parentname = strdup(zhp->zfs_name);
3299*cdf5b4caSmmusante 		delim = strchr(parentname, '@');
3300*cdf5b4caSmmusante 		*delim = '\0';
3301*cdf5b4caSmmusante 		zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_ANY);
3302*cdf5b4caSmmusante 		if (zhrp == NULL) {
3303*cdf5b4caSmmusante 			return (-1);
3304*cdf5b4caSmmusante 		}
3305fa9e4066Sahrens 
3306*cdf5b4caSmmusante 		dd.snapname = delim + 1;
3307*cdf5b4caSmmusante 		dd.gotone = B_FALSE;
3308*cdf5b4caSmmusante 		dd.closezhp = B_FALSE;
3309*cdf5b4caSmmusante 
3310*cdf5b4caSmmusante 		/* We remove any zvol links prior to renaming them */
3311*cdf5b4caSmmusante 		ret = zfs_iter_filesystems(zhrp, zfs_remove_link_cb, &dd);
3312*cdf5b4caSmmusante 		if (ret) {
3313*cdf5b4caSmmusante 			goto error;
3314*cdf5b4caSmmusante 		}
3315*cdf5b4caSmmusante 	} else {
3316*cdf5b4caSmmusante 		if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL)
3317*cdf5b4caSmmusante 			return (-1);
3318*cdf5b4caSmmusante 
3319*cdf5b4caSmmusante 		if (changelist_haszonedchild(cl)) {
3320*cdf5b4caSmmusante 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3321*cdf5b4caSmmusante 			    "child dataset with inherited mountpoint is used "
3322*cdf5b4caSmmusante 			    "in a non-global zone"));
3323*cdf5b4caSmmusante 			(void) zfs_error(hdl, EZFS_ZONED, errbuf);
3324*cdf5b4caSmmusante 			goto error;
3325*cdf5b4caSmmusante 		}
3326*cdf5b4caSmmusante 
3327*cdf5b4caSmmusante 		if ((ret = changelist_prefix(cl)) != 0)
3328*cdf5b4caSmmusante 			goto error;
3329*cdf5b4caSmmusante 	}
3330fa9e4066Sahrens 
3331e9dbad6fSeschrock 	if (ZFS_IS_VOLUME(zhp))
3332fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZVOL;
3333fa9e4066Sahrens 	else
3334fa9e4066Sahrens 		zc.zc_objset_type = DMU_OST_ZFS;
3335fa9e4066Sahrens 
333698579b20Snd 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3337e9dbad6fSeschrock 	(void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
333898579b20Snd 
3339*cdf5b4caSmmusante 	zc.zc_cookie = recursive;
3340*cdf5b4caSmmusante 
334199653d4eSeschrock 	if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) {
3342*cdf5b4caSmmusante 		/*
3343*cdf5b4caSmmusante 		 * if it was recursive, the one that actually failed will
3344*cdf5b4caSmmusante 		 * be in zc.zc_name
3345*cdf5b4caSmmusante 		 */
3346*cdf5b4caSmmusante 		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3347*cdf5b4caSmmusante 		    "cannot rename to '%s'"), zc.zc_name);
3348*cdf5b4caSmmusante 
3349*cdf5b4caSmmusante 		if (recursive && errno == EEXIST) {
3350*cdf5b4caSmmusante 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3351*cdf5b4caSmmusante 			    "a child dataset already has a snapshot "
3352*cdf5b4caSmmusante 			    "with the new name"));
3353*cdf5b4caSmmusante 			(void) zfs_error(hdl, EZFS_CROSSTARGET, errbuf);
3354*cdf5b4caSmmusante 		} else {
3355*cdf5b4caSmmusante 			(void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
3356*cdf5b4caSmmusante 		}
3357fa9e4066Sahrens 
3358fa9e4066Sahrens 		/*
3359fa9e4066Sahrens 		 * On failure, we still want to remount any filesystems that
3360fa9e4066Sahrens 		 * were previously mounted, so we don't alter the system state.
3361fa9e4066Sahrens 		 */
3362*cdf5b4caSmmusante 		if (recursive) {
3363*cdf5b4caSmmusante 			struct createdata cd;
3364*cdf5b4caSmmusante 
3365*cdf5b4caSmmusante 			/* only create links for datasets that had existed */
3366*cdf5b4caSmmusante 			cd.cd_snapname = delim + 1;
3367*cdf5b4caSmmusante 			cd.cd_ifexists = B_TRUE;
3368*cdf5b4caSmmusante 			(void) zfs_iter_filesystems(zhrp, zfs_create_link_cb,
3369*cdf5b4caSmmusante 			    &cd);
3370*cdf5b4caSmmusante 		} else {
3371*cdf5b4caSmmusante 			(void) changelist_postfix(cl);
3372*cdf5b4caSmmusante 		}
3373fa9e4066Sahrens 	} else {
3374*cdf5b4caSmmusante 		if (recursive) {
3375*cdf5b4caSmmusante 			struct createdata cd;
3376*cdf5b4caSmmusante 
3377*cdf5b4caSmmusante 			/* only create links for datasets that had existed */
3378*cdf5b4caSmmusante 			cd.cd_snapname = strchr(target, '@') + 1;
3379*cdf5b4caSmmusante 			cd.cd_ifexists = B_TRUE;
3380*cdf5b4caSmmusante 			ret = zfs_iter_filesystems(zhrp, zfs_create_link_cb,
3381*cdf5b4caSmmusante 			    &cd);
3382*cdf5b4caSmmusante 		} else {
3383*cdf5b4caSmmusante 			changelist_rename(cl, zfs_get_name(zhp), target);
3384*cdf5b4caSmmusante 			ret = changelist_postfix(cl);
3385*cdf5b4caSmmusante 		}
3386fa9e4066Sahrens 	}
3387fa9e4066Sahrens 
3388fa9e4066Sahrens error:
3389*cdf5b4caSmmusante 	if (parentname) {
3390*cdf5b4caSmmusante 		free(parentname);
3391*cdf5b4caSmmusante 	}
3392*cdf5b4caSmmusante 	if (zhrp) {
3393*cdf5b4caSmmusante 		zfs_close(zhrp);
3394*cdf5b4caSmmusante 	}
3395*cdf5b4caSmmusante 	if (cl) {
3396*cdf5b4caSmmusante 		changelist_free(cl);
3397*cdf5b4caSmmusante 	}
3398fa9e4066Sahrens 	return (ret);
3399fa9e4066Sahrens }
3400fa9e4066Sahrens 
3401fa9e4066Sahrens /*
3402fa9e4066Sahrens  * Given a zvol dataset, issue the ioctl to create the appropriate minor node,
3403fa9e4066Sahrens  * poke devfsadm to create the /dev link, and then wait for the link to appear.
3404fa9e4066Sahrens  */
3405fa9e4066Sahrens int
340699653d4eSeschrock zvol_create_link(libzfs_handle_t *hdl, const char *dataset)
3407*cdf5b4caSmmusante {
3408*cdf5b4caSmmusante 	return (zvol_create_link_common(hdl, dataset, B_FALSE));
3409*cdf5b4caSmmusante }
3410*cdf5b4caSmmusante 
3411*cdf5b4caSmmusante static int
3412*cdf5b4caSmmusante zvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists)
3413fa9e4066Sahrens {
3414fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
341599653d4eSeschrock 	di_devlink_handle_t dhdl;
3416fa9e4066Sahrens 
3417fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
3418fa9e4066Sahrens 
3419fa9e4066Sahrens 	/*
3420fa9e4066Sahrens 	 * Issue the appropriate ioctl.
3421fa9e4066Sahrens 	 */
342299653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) {
3423fa9e4066Sahrens 		switch (errno) {
3424fa9e4066Sahrens 		case EEXIST:
3425fa9e4066Sahrens 			/*
3426fa9e4066Sahrens 			 * Silently ignore the case where the link already
3427fa9e4066Sahrens 			 * exists.  This allows 'zfs volinit' to be run multiple
3428fa9e4066Sahrens 			 * times without errors.
3429fa9e4066Sahrens 			 */
3430fa9e4066Sahrens 			return (0);
3431fa9e4066Sahrens 
3432*cdf5b4caSmmusante 		case ENOENT:
3433*cdf5b4caSmmusante 			/*
3434*cdf5b4caSmmusante 			 * Dataset does not exist in the kernel.  If we
3435*cdf5b4caSmmusante 			 * don't care (see zfs_rename), then ignore the
3436*cdf5b4caSmmusante 			 * error quietly.
3437*cdf5b4caSmmusante 			 */
3438*cdf5b4caSmmusante 			if (ifexists) {
3439*cdf5b4caSmmusante 				return (0);
3440*cdf5b4caSmmusante 			}
3441*cdf5b4caSmmusante 
3442*cdf5b4caSmmusante 			/* FALLTHROUGH */
3443*cdf5b4caSmmusante 
3444fa9e4066Sahrens 		default:
3445ece3d9b3Slling 			return (zfs_standard_error_fmt(hdl, errno,
344699653d4eSeschrock 			    dgettext(TEXT_DOMAIN, "cannot create device links "
344799653d4eSeschrock 			    "for '%s'"), dataset));
3448fa9e4066Sahrens 		}
3449fa9e4066Sahrens 	}
3450fa9e4066Sahrens 
3451fa9e4066Sahrens 	/*
3452fa9e4066Sahrens 	 * Call devfsadm and wait for the links to magically appear.
3453fa9e4066Sahrens 	 */
345499653d4eSeschrock 	if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) {
345599653d4eSeschrock 		zfs_error_aux(hdl, strerror(errno));
3456ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_DEVLINKS,
345799653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot create device links "
345899653d4eSeschrock 		    "for '%s'"), dataset);
345999653d4eSeschrock 		(void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc);
3460fa9e4066Sahrens 		return (-1);
3461fa9e4066Sahrens 	} else {
346299653d4eSeschrock 		(void) di_devlink_fini(&dhdl);
3463fa9e4066Sahrens 	}
3464fa9e4066Sahrens 
3465fa9e4066Sahrens 	return (0);
3466fa9e4066Sahrens }
3467fa9e4066Sahrens 
3468fa9e4066Sahrens /*
3469fa9e4066Sahrens  * Remove a minor node for the given zvol and the associated /dev links.
3470fa9e4066Sahrens  */
3471fa9e4066Sahrens int
347299653d4eSeschrock zvol_remove_link(libzfs_handle_t *hdl, const char *dataset)
3473fa9e4066Sahrens {
3474fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
3475fa9e4066Sahrens 
3476fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
3477fa9e4066Sahrens 
347899653d4eSeschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) {
3479fa9e4066Sahrens 		switch (errno) {
3480fa9e4066Sahrens 		case ENXIO:
3481fa9e4066Sahrens 			/*
3482fa9e4066Sahrens 			 * Silently ignore the case where the link no longer
3483fa9e4066Sahrens 			 * exists, so that 'zfs volfini' can be run multiple
3484fa9e4066Sahrens 			 * times without errors.
3485fa9e4066Sahrens 			 */
3486fa9e4066Sahrens 			return (0);
3487fa9e4066Sahrens 
3488fa9e4066Sahrens 		default:
3489ece3d9b3Slling 			return (zfs_standard_error_fmt(hdl, errno,
349099653d4eSeschrock 			    dgettext(TEXT_DOMAIN, "cannot remove device "
349199653d4eSeschrock 			    "links for '%s'"), dataset));
3492fa9e4066Sahrens 		}
3493fa9e4066Sahrens 	}
3494fa9e4066Sahrens 
3495fa9e4066Sahrens 	return (0);
3496fa9e4066Sahrens }
3497e9dbad6fSeschrock 
3498e9dbad6fSeschrock nvlist_t *
3499e9dbad6fSeschrock zfs_get_user_props(zfs_handle_t *zhp)
3500e9dbad6fSeschrock {
3501e9dbad6fSeschrock 	return (zhp->zfs_user_props);
3502e9dbad6fSeschrock }
3503e9dbad6fSeschrock 
3504e9dbad6fSeschrock /*
3505e9dbad6fSeschrock  * Given a comma-separated list of properties, contruct a property list
3506e9dbad6fSeschrock  * containing both user-defined and native properties.  This function will
3507e9dbad6fSeschrock  * return a NULL list if 'all' is specified, which can later be expanded on a
3508e9dbad6fSeschrock  * per-dataset basis by zfs_expand_proplist().
3509e9dbad6fSeschrock  */
3510e9dbad6fSeschrock int
3511b1b8ab34Slling zfs_get_proplist_common(libzfs_handle_t *hdl, char *fields,
3512b1b8ab34Slling     zfs_proplist_t **listp, zfs_type_t type)
3513e9dbad6fSeschrock {
3514e9dbad6fSeschrock 	size_t len;
3515e9dbad6fSeschrock 	char *s, *p;
3516e9dbad6fSeschrock 	char c;
3517e9dbad6fSeschrock 	zfs_prop_t prop;
3518e9dbad6fSeschrock 	zfs_proplist_t *entry;
3519e9dbad6fSeschrock 	zfs_proplist_t **last;
3520e9dbad6fSeschrock 
3521e9dbad6fSeschrock 	*listp = NULL;
3522e9dbad6fSeschrock 	last = listp;
3523e9dbad6fSeschrock 
3524e9dbad6fSeschrock 	/*
3525e9dbad6fSeschrock 	 * If 'all' is specified, return a NULL list.
3526e9dbad6fSeschrock 	 */
3527e9dbad6fSeschrock 	if (strcmp(fields, "all") == 0)
3528e9dbad6fSeschrock 		return (0);
3529e9dbad6fSeschrock 
3530e9dbad6fSeschrock 	/*
3531e9dbad6fSeschrock 	 * If no fields were specified, return an error.
3532e9dbad6fSeschrock 	 */
3533e9dbad6fSeschrock 	if (fields[0] == '\0') {
3534e9dbad6fSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3535e9dbad6fSeschrock 		    "no properties specified"));
3536e9dbad6fSeschrock 		return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
3537e9dbad6fSeschrock 		    "bad property list")));
3538e9dbad6fSeschrock 	}
3539e9dbad6fSeschrock 
3540e9dbad6fSeschrock 	/*
3541e9dbad6fSeschrock 	 * It would be nice to use getsubopt() here, but the inclusion of column
3542e9dbad6fSeschrock 	 * aliases makes this more effort than it's worth.
3543e9dbad6fSeschrock 	 */
3544e9dbad6fSeschrock 	s = fields;
3545e9dbad6fSeschrock 	while (*s != '\0') {
3546e9dbad6fSeschrock 		if ((p = strchr(s, ',')) == NULL) {
3547e9dbad6fSeschrock 			len = strlen(s);
3548e9dbad6fSeschrock 			p = s + len;
3549e9dbad6fSeschrock 		} else {
3550e9dbad6fSeschrock 			len = p - s;
3551e9dbad6fSeschrock 		}
3552e9dbad6fSeschrock 
3553e9dbad6fSeschrock 		/*
3554e9dbad6fSeschrock 		 * Check for empty options.
3555e9dbad6fSeschrock 		 */
3556e9dbad6fSeschrock 		if (len == 0) {
3557e9dbad6fSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3558e9dbad6fSeschrock 			    "empty property name"));
3559e9dbad6fSeschrock 			return (zfs_error(hdl, EZFS_BADPROP,
3560e9dbad6fSeschrock 			    dgettext(TEXT_DOMAIN, "bad property list")));
3561e9dbad6fSeschrock 		}
3562e9dbad6fSeschrock 
3563e9dbad6fSeschrock 		/*
3564e9dbad6fSeschrock 		 * Check all regular property names.
3565e9dbad6fSeschrock 		 */
3566e9dbad6fSeschrock 		c = s[len];
3567e9dbad6fSeschrock 		s[len] = '\0';
3568b1b8ab34Slling 		prop = zfs_name_to_prop_common(s, type);
3569b1b8ab34Slling 
3570b1b8ab34Slling 		if (prop != ZFS_PROP_INVAL &&
3571b1b8ab34Slling 		    !zfs_prop_valid_for_type(prop, type))
3572b1b8ab34Slling 			prop = ZFS_PROP_INVAL;
3573e9dbad6fSeschrock 
3574e9dbad6fSeschrock 		/*
3575b1b8ab34Slling 		 * When no property table entry can be found, return failure if
3576b1b8ab34Slling 		 * this is a pool property or if this isn't a user-defined
3577b1b8ab34Slling 		 * dataset property,
3578e9dbad6fSeschrock 		 */
3579b1b8ab34Slling 		if (prop == ZFS_PROP_INVAL &&
3580b1b8ab34Slling 		    (type & ZFS_TYPE_POOL || !zfs_prop_user(s))) {
3581e9dbad6fSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3582e9dbad6fSeschrock 			    "invalid property '%s'"), s);
3583e9dbad6fSeschrock 			return (zfs_error(hdl, EZFS_BADPROP,
3584e9dbad6fSeschrock 			    dgettext(TEXT_DOMAIN, "bad property list")));
3585e9dbad6fSeschrock 		}
3586e9dbad6fSeschrock 
3587e9dbad6fSeschrock 		if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL)
3588e9dbad6fSeschrock 			return (-1);
3589e9dbad6fSeschrock 
3590e9dbad6fSeschrock 		entry->pl_prop = prop;
3591e9dbad6fSeschrock 		if (prop == ZFS_PROP_INVAL) {
3592e9dbad6fSeschrock 			if ((entry->pl_user_prop =
3593e9dbad6fSeschrock 			    zfs_strdup(hdl, s)) == NULL) {
3594e9dbad6fSeschrock 				free(entry);
3595e9dbad6fSeschrock 				return (-1);
3596e9dbad6fSeschrock 			}
3597e9dbad6fSeschrock 			entry->pl_width = strlen(s);
3598e9dbad6fSeschrock 		} else {
3599e9dbad6fSeschrock 			entry->pl_width = zfs_prop_width(prop,
3600e9dbad6fSeschrock 			    &entry->pl_fixed);
3601e9dbad6fSeschrock 		}
3602e9dbad6fSeschrock 
3603e9dbad6fSeschrock 		*last = entry;
3604e9dbad6fSeschrock 		last = &entry->pl_next;
3605e9dbad6fSeschrock 
3606e9dbad6fSeschrock 		s = p;
3607e9dbad6fSeschrock 		if (c == ',')
3608e9dbad6fSeschrock 			s++;
3609e9dbad6fSeschrock 	}
3610e9dbad6fSeschrock 
3611e9dbad6fSeschrock 	return (0);
3612e9dbad6fSeschrock }
3613e9dbad6fSeschrock 
3614b1b8ab34Slling int
3615b1b8ab34Slling zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp)
3616b1b8ab34Slling {
3617b1b8ab34Slling 	return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_ANY));
3618b1b8ab34Slling }
3619b1b8ab34Slling 
3620e9dbad6fSeschrock void
3621e9dbad6fSeschrock zfs_free_proplist(zfs_proplist_t *pl)
3622e9dbad6fSeschrock {
3623e9dbad6fSeschrock 	zfs_proplist_t *next;
3624e9dbad6fSeschrock 
3625e9dbad6fSeschrock 	while (pl != NULL) {
3626e9dbad6fSeschrock 		next = pl->pl_next;
3627e9dbad6fSeschrock 		free(pl->pl_user_prop);
3628e9dbad6fSeschrock 		free(pl);
3629e9dbad6fSeschrock 		pl = next;
3630e9dbad6fSeschrock 	}
3631e9dbad6fSeschrock }
3632e9dbad6fSeschrock 
363366e2aaccSgw typedef struct expand_data {
363466e2aaccSgw 	zfs_proplist_t	**last;
363566e2aaccSgw 	libzfs_handle_t	*hdl;
363666e2aaccSgw } expand_data_t;
363766e2aaccSgw 
363866e2aaccSgw static zfs_prop_t
363966e2aaccSgw zfs_expand_proplist_cb(zfs_prop_t prop, void *cb)
364066e2aaccSgw {
364166e2aaccSgw 	zfs_proplist_t *entry;
364266e2aaccSgw 	expand_data_t *edp = cb;
364366e2aaccSgw 
364466e2aaccSgw 	if ((entry = zfs_alloc(edp->hdl, sizeof (zfs_proplist_t))) == NULL)
364566e2aaccSgw 		return (ZFS_PROP_INVAL);
364666e2aaccSgw 
364766e2aaccSgw 	entry->pl_prop = prop;
364866e2aaccSgw 	entry->pl_width = zfs_prop_width(prop, &entry->pl_fixed);
364966e2aaccSgw 	entry->pl_all = B_TRUE;
365066e2aaccSgw 
365166e2aaccSgw 	*(edp->last) = entry;
365266e2aaccSgw 	edp->last = &entry->pl_next;
365366e2aaccSgw 
365466e2aaccSgw 	return (ZFS_PROP_CONT);
365566e2aaccSgw }
365666e2aaccSgw 
3657e9dbad6fSeschrock int
3658b1b8ab34Slling zfs_expand_proplist_common(libzfs_handle_t *hdl, zfs_proplist_t **plp,
3659b1b8ab34Slling 	zfs_type_t type)
3660e9dbad6fSeschrock {
3661e9dbad6fSeschrock 	zfs_proplist_t *entry;
3662b1b8ab34Slling 	zfs_proplist_t **last;
366366e2aaccSgw 	expand_data_t exp;
3664e9dbad6fSeschrock 
3665e9dbad6fSeschrock 	if (*plp == NULL) {
3666e9dbad6fSeschrock 		/*
3667e9dbad6fSeschrock 		 * If this is the very first time we've been called for an 'all'
3668e9dbad6fSeschrock 		 * specification, expand the list to include all native
3669e9dbad6fSeschrock 		 * properties.
3670e9dbad6fSeschrock 		 */
3671e9dbad6fSeschrock 		last = plp;
3672e9dbad6fSeschrock 
367366e2aaccSgw 		exp.last = last;
367466e2aaccSgw 		exp.hdl = hdl;
3675e9dbad6fSeschrock 
3676b1b8ab34Slling 		if (zfs_prop_iter_common(zfs_expand_proplist_cb, &exp, type,
367766e2aaccSgw 		    B_FALSE) == ZFS_PROP_INVAL)
367866e2aaccSgw 			return (-1);
3679e9dbad6fSeschrock 
3680e9dbad6fSeschrock 		/*
3681e9dbad6fSeschrock 		 * Add 'name' to the beginning of the list, which is handled
3682e9dbad6fSeschrock 		 * specially.
3683e9dbad6fSeschrock 		 */
3684e9dbad6fSeschrock 		if ((entry = zfs_alloc(hdl,
3685e9dbad6fSeschrock 		    sizeof (zfs_proplist_t))) == NULL)
3686e9dbad6fSeschrock 			return (-1);
3687e9dbad6fSeschrock 
3688e9dbad6fSeschrock 		entry->pl_prop = ZFS_PROP_NAME;
3689e9dbad6fSeschrock 		entry->pl_width = zfs_prop_width(ZFS_PROP_NAME,
3690e9dbad6fSeschrock 		    &entry->pl_fixed);
3691e9dbad6fSeschrock 		entry->pl_all = B_TRUE;
3692e9dbad6fSeschrock 		entry->pl_next = *plp;
3693e9dbad6fSeschrock 		*plp = entry;
3694e9dbad6fSeschrock 	}
3695b1b8ab34Slling 	return (0);
3696b1b8ab34Slling }
3697b1b8ab34Slling 
3698b1b8ab34Slling /*
3699b1b8ab34Slling  * This function is used by 'zfs list' to determine the exact set of columns to
3700b1b8ab34Slling  * display, and their maximum widths.  This does two main things:
3701b1b8ab34Slling  *
3702b1b8ab34Slling  *      - If this is a list of all properties, then expand the list to include
3703b1b8ab34Slling  *        all native properties, and set a flag so that for each dataset we look
3704b1b8ab34Slling  *        for new unique user properties and add them to the list.
3705b1b8ab34Slling  *
3706b1b8ab34Slling  *      - For non fixed-width properties, keep track of the maximum width seen
3707b1b8ab34Slling  *        so that we can size the column appropriately.
3708b1b8ab34Slling  */
3709b1b8ab34Slling int
3710b1b8ab34Slling zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp)
3711b1b8ab34Slling {
3712b1b8ab34Slling 	libzfs_handle_t *hdl = zhp->zfs_hdl;
3713b1b8ab34Slling 	zfs_proplist_t *entry;
3714b1b8ab34Slling 	zfs_proplist_t **last, **start;
3715b1b8ab34Slling 	nvlist_t *userprops, *propval;
3716b1b8ab34Slling 	nvpair_t *elem;
3717b1b8ab34Slling 	char *strval;
3718b1b8ab34Slling 	char buf[ZFS_MAXPROPLEN];
3719b1b8ab34Slling 
3720b1b8ab34Slling 	if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_ANY) != 0)
3721b1b8ab34Slling 		return (-1);
3722e9dbad6fSeschrock 
3723e9dbad6fSeschrock 	userprops = zfs_get_user_props(zhp);
3724e9dbad6fSeschrock 
3725e9dbad6fSeschrock 	entry = *plp;
3726e9dbad6fSeschrock 	if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
3727e9dbad6fSeschrock 		/*
3728e9dbad6fSeschrock 		 * Go through and add any user properties as necessary.  We
3729e9dbad6fSeschrock 		 * start by incrementing our list pointer to the first
3730e9dbad6fSeschrock 		 * non-native property.
3731e9dbad6fSeschrock 		 */
3732e9dbad6fSeschrock 		start = plp;
3733e9dbad6fSeschrock 		while (*start != NULL) {
3734e9dbad6fSeschrock 			if ((*start)->pl_prop == ZFS_PROP_INVAL)
3735e9dbad6fSeschrock 				break;
3736e9dbad6fSeschrock 			start = &(*start)->pl_next;
3737e9dbad6fSeschrock 		}
3738e9dbad6fSeschrock 
3739e9dbad6fSeschrock 		elem = NULL;
3740e9dbad6fSeschrock 		while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
3741e9dbad6fSeschrock 			/*
3742e9dbad6fSeschrock 			 * See if we've already found this property in our list.
3743e9dbad6fSeschrock 			 */
3744e9dbad6fSeschrock 			for (last = start; *last != NULL;
3745e9dbad6fSeschrock 			    last = &(*last)->pl_next) {
3746e9dbad6fSeschrock 				if (strcmp((*last)->pl_user_prop,
3747e9dbad6fSeschrock 				    nvpair_name(elem)) == 0)
3748e9dbad6fSeschrock 					break;
3749e9dbad6fSeschrock 			}
3750e9dbad6fSeschrock 
3751e9dbad6fSeschrock 			if (*last == NULL) {
3752e9dbad6fSeschrock 				if ((entry = zfs_alloc(hdl,
3753e9dbad6fSeschrock 				    sizeof (zfs_proplist_t))) == NULL ||
3754e9dbad6fSeschrock 				    ((entry->pl_user_prop = zfs_strdup(hdl,
3755e9dbad6fSeschrock 				    nvpair_name(elem)))) == NULL) {
3756e9dbad6fSeschrock 					free(entry);
3757e9dbad6fSeschrock 					return (-1);
3758e9dbad6fSeschrock 				}
3759e9dbad6fSeschrock 
3760e9dbad6fSeschrock 				entry->pl_prop = ZFS_PROP_INVAL;
3761e9dbad6fSeschrock 				entry->pl_width = strlen(nvpair_name(elem));
3762e9dbad6fSeschrock 				entry->pl_all = B_TRUE;
3763e9dbad6fSeschrock 				*last = entry;
3764e9dbad6fSeschrock 			}
3765e9dbad6fSeschrock 		}
3766e9dbad6fSeschrock 	}
3767e9dbad6fSeschrock 
3768e9dbad6fSeschrock 	/*
3769e9dbad6fSeschrock 	 * Now go through and check the width of any non-fixed columns
3770e9dbad6fSeschrock 	 */
3771e9dbad6fSeschrock 	for (entry = *plp; entry != NULL; entry = entry->pl_next) {
3772e9dbad6fSeschrock 		if (entry->pl_fixed)
3773e9dbad6fSeschrock 			continue;
3774e9dbad6fSeschrock 
3775e9dbad6fSeschrock 		if (entry->pl_prop != ZFS_PROP_INVAL) {
3776e9dbad6fSeschrock 			if (zfs_prop_get(zhp, entry->pl_prop,
3777e9dbad6fSeschrock 			    buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) {
3778e9dbad6fSeschrock 				if (strlen(buf) > entry->pl_width)
3779e9dbad6fSeschrock 					entry->pl_width = strlen(buf);
3780e9dbad6fSeschrock 			}
3781e9dbad6fSeschrock 		} else if (nvlist_lookup_nvlist(userprops,
3782e9dbad6fSeschrock 		    entry->pl_user_prop, &propval)  == 0) {
3783e9dbad6fSeschrock 			verify(nvlist_lookup_string(propval,
3784e9dbad6fSeschrock 			    ZFS_PROP_VALUE, &strval) == 0);
3785e9dbad6fSeschrock 			if (strlen(strval) > entry->pl_width)
3786e9dbad6fSeschrock 				entry->pl_width = strlen(strval);
3787e9dbad6fSeschrock 		}
3788e9dbad6fSeschrock 	}
3789e9dbad6fSeschrock 
3790e9dbad6fSeschrock 	return (0);
3791e9dbad6fSeschrock }
3792