libzfs_dataset.c revision 168676
1168404Spjd/*
2168404Spjd * CDDL HEADER START
3168404Spjd *
4168404Spjd * The contents of this file are subject to the terms of the
5168404Spjd * Common Development and Distribution License (the "License").
6168404Spjd * You may not use this file except in compliance with the License.
7168404Spjd *
8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9168404Spjd * or http://www.opensolaris.org/os/licensing.
10168404Spjd * See the License for the specific language governing permissions
11168404Spjd * and limitations under the License.
12168404Spjd *
13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each
14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15168404Spjd * If applicable, add the following below this CDDL HEADER, with the
16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18168404Spjd *
19168404Spjd * CDDL HEADER END
20168404Spjd */
21168404Spjd
22168404Spjd/*
23168404Spjd * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24168404Spjd * Use is subject to license terms.
25168404Spjd */
26168404Spjd
27168404Spjd#pragma ident	"%Z%%M%	%I%	%E% SMI"
28168404Spjd
29168404Spjd#include <assert.h>
30168404Spjd#include <ctype.h>
31168404Spjd#include <errno.h>
32168404Spjd#include <libintl.h>
33168404Spjd#include <math.h>
34168404Spjd#include <stdio.h>
35168404Spjd#include <stdlib.h>
36168404Spjd#include <strings.h>
37168404Spjd#include <unistd.h>
38168404Spjd#include <zone.h>
39168404Spjd#include <fcntl.h>
40168404Spjd#include <sys/mntent.h>
41168404Spjd#include <sys/mnttab.h>
42168404Spjd#include <sys/mount.h>
43168404Spjd
44168404Spjd#include <sys/spa.h>
45168404Spjd#include <sys/zio.h>
46168404Spjd#include <sys/zap.h>
47168404Spjd#include <libzfs.h>
48168404Spjd
49168404Spjd#include "zfs_namecheck.h"
50168404Spjd#include "zfs_prop.h"
51168404Spjd#include "libzfs_impl.h"
52168404Spjd
53168676Spjdstatic int zvol_create_link_common(libzfs_handle_t *, const char *, int);
54168676Spjd
55168404Spjd/*
56168404Spjd * Given a single type (not a mask of types), return the type in a human
57168404Spjd * readable form.
58168404Spjd */
59168404Spjdconst char *
60168404Spjdzfs_type_to_name(zfs_type_t type)
61168404Spjd{
62168404Spjd	switch (type) {
63168404Spjd	case ZFS_TYPE_FILESYSTEM:
64168404Spjd		return (dgettext(TEXT_DOMAIN, "filesystem"));
65168404Spjd	case ZFS_TYPE_SNAPSHOT:
66168404Spjd		return (dgettext(TEXT_DOMAIN, "snapshot"));
67168404Spjd	case ZFS_TYPE_VOLUME:
68168404Spjd		return (dgettext(TEXT_DOMAIN, "volume"));
69168404Spjd	}
70168404Spjd
71168404Spjd	return (NULL);
72168404Spjd}
73168404Spjd
74168404Spjd/*
75168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset.
76168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type.
77168404Spjd * We guess what the type would have been based on the path and the mask of
78168404Spjd * acceptable types.
79168404Spjd */
80168404Spjdstatic const char *
81168404Spjdpath_to_str(const char *path, int types)
82168404Spjd{
83168404Spjd	/*
84168404Spjd	 * When given a single type, always report the exact type.
85168404Spjd	 */
86168404Spjd	if (types == ZFS_TYPE_SNAPSHOT)
87168404Spjd		return (dgettext(TEXT_DOMAIN, "snapshot"));
88168404Spjd	if (types == ZFS_TYPE_FILESYSTEM)
89168404Spjd		return (dgettext(TEXT_DOMAIN, "filesystem"));
90168404Spjd	if (types == ZFS_TYPE_VOLUME)
91168404Spjd		return (dgettext(TEXT_DOMAIN, "volume"));
92168404Spjd
93168404Spjd	/*
94168404Spjd	 * The user is requesting more than one type of dataset.  If this is the
95168404Spjd	 * case, consult the path itself.  If we're looking for a snapshot, and
96168404Spjd	 * a '@' is found, then report it as "snapshot".  Otherwise, remove the
97168404Spjd	 * snapshot attribute and try again.
98168404Spjd	 */
99168404Spjd	if (types & ZFS_TYPE_SNAPSHOT) {
100168404Spjd		if (strchr(path, '@') != NULL)
101168404Spjd			return (dgettext(TEXT_DOMAIN, "snapshot"));
102168404Spjd		return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT));
103168404Spjd	}
104168404Spjd
105168404Spjd
106168404Spjd	/*
107168404Spjd	 * The user has requested either filesystems or volumes.
108168404Spjd	 * We have no way of knowing a priori what type this would be, so always
109168404Spjd	 * report it as "filesystem" or "volume", our two primitive types.
110168404Spjd	 */
111168404Spjd	if (types & ZFS_TYPE_FILESYSTEM)
112168404Spjd		return (dgettext(TEXT_DOMAIN, "filesystem"));
113168404Spjd
114168404Spjd	assert(types & ZFS_TYPE_VOLUME);
115168404Spjd	return (dgettext(TEXT_DOMAIN, "volume"));
116168404Spjd}
117168404Spjd
118168404Spjd/*
119168404Spjd * Validate a ZFS path.  This is used even before trying to open the dataset, to
120168404Spjd * provide a more meaningful error message.  We place a more useful message in
121168404Spjd * 'buf' detailing exactly why the name was not valid.
122168404Spjd */
123168404Spjdstatic int
124168404Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type)
125168404Spjd{
126168404Spjd	namecheck_err_t why;
127168404Spjd	char what;
128168404Spjd
129168404Spjd	if (dataset_namecheck(path, &why, &what) != 0) {
130168404Spjd		if (hdl != NULL) {
131168404Spjd			switch (why) {
132168404Spjd			case NAME_ERR_TOOLONG:
133168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
134168404Spjd				    "name is too long"));
135168404Spjd				break;
136168404Spjd
137168404Spjd			case NAME_ERR_LEADING_SLASH:
138168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
139168404Spjd				    "leading slash in name"));
140168404Spjd				break;
141168404Spjd
142168404Spjd			case NAME_ERR_EMPTY_COMPONENT:
143168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
144168404Spjd				    "empty component in name"));
145168404Spjd				break;
146168404Spjd
147168404Spjd			case NAME_ERR_TRAILING_SLASH:
148168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
149168404Spjd				    "trailing slash in name"));
150168404Spjd				break;
151168404Spjd
152168404Spjd			case NAME_ERR_INVALCHAR:
153168404Spjd				zfs_error_aux(hdl,
154168404Spjd				    dgettext(TEXT_DOMAIN, "invalid character "
155168404Spjd				    "'%c' in name"), what);
156168404Spjd				break;
157168404Spjd
158168404Spjd			case NAME_ERR_MULTIPLE_AT:
159168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
160168404Spjd				    "multiple '@' delimiters in name"));
161168404Spjd				break;
162168404Spjd
163168404Spjd			case NAME_ERR_NOLETTER:
164168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
165168404Spjd				    "pool doesn't begin with a letter"));
166168404Spjd				break;
167168404Spjd
168168404Spjd			case NAME_ERR_RESERVED:
169168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
170168404Spjd				    "name is reserved"));
171168404Spjd				break;
172168404Spjd
173168404Spjd			case NAME_ERR_DISKLIKE:
174168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
175168404Spjd				    "reserved disk name"));
176168404Spjd				break;
177168404Spjd			}
178168404Spjd		}
179168404Spjd
180168404Spjd		return (0);
181168404Spjd	}
182168404Spjd
183168404Spjd	if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
184168404Spjd		if (hdl != NULL)
185168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
186168404Spjd			    "snapshot delimiter '@' in filesystem name"));
187168404Spjd		return (0);
188168404Spjd	}
189168404Spjd
190168404Spjd	if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
191168404Spjd		if (hdl != NULL)
192168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
193168404Spjd			    "missing '@' delimiter in snapshot name"));
194168404Spjd		return (0);
195168404Spjd	}
196168404Spjd
197168404Spjd	return (-1);
198168404Spjd}
199168404Spjd
200168404Spjdint
201168404Spjdzfs_name_valid(const char *name, zfs_type_t type)
202168404Spjd{
203168404Spjd	return (zfs_validate_name(NULL, name, type));
204168404Spjd}
205168404Spjd
206168404Spjd/*
207168404Spjd * This function takes the raw DSL properties, and filters out the user-defined
208168404Spjd * properties into a separate nvlist.
209168404Spjd */
210168404Spjdstatic int
211168404Spjdprocess_user_props(zfs_handle_t *zhp)
212168404Spjd{
213168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
214168404Spjd	nvpair_t *elem;
215168404Spjd	nvlist_t *propval;
216168404Spjd
217168404Spjd	nvlist_free(zhp->zfs_user_props);
218168404Spjd
219168404Spjd	if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0)
220168404Spjd		return (no_memory(hdl));
221168404Spjd
222168404Spjd	elem = NULL;
223168404Spjd	while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) {
224168404Spjd		if (!zfs_prop_user(nvpair_name(elem)))
225168404Spjd			continue;
226168404Spjd
227168404Spjd		verify(nvpair_value_nvlist(elem, &propval) == 0);
228168404Spjd		if (nvlist_add_nvlist(zhp->zfs_user_props,
229168404Spjd		    nvpair_name(elem), propval) != 0)
230168404Spjd			return (no_memory(hdl));
231168404Spjd	}
232168404Spjd
233168404Spjd	return (0);
234168404Spjd}
235168404Spjd
236168404Spjd/*
237168404Spjd * Utility function to gather stats (objset and zpl) for the given object.
238168404Spjd */
239168404Spjdstatic int
240168404Spjdget_stats(zfs_handle_t *zhp)
241168404Spjd{
242168404Spjd	zfs_cmd_t zc = { 0 };
243168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
244168404Spjd
245168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
246168404Spjd
247168404Spjd	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
248168404Spjd		return (-1);
249168404Spjd
250168404Spjd	while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
251168404Spjd		if (errno == ENOMEM) {
252168404Spjd			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
253168404Spjd				zcmd_free_nvlists(&zc);
254168404Spjd				return (-1);
255168404Spjd			}
256168404Spjd		} else {
257168404Spjd			zcmd_free_nvlists(&zc);
258168404Spjd			return (-1);
259168404Spjd		}
260168404Spjd	}
261168404Spjd
262168404Spjd	zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */
263168404Spjd
264168404Spjd	(void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root));
265168404Spjd
266168404Spjd	if (zhp->zfs_props) {
267168404Spjd		nvlist_free(zhp->zfs_props);
268168404Spjd		zhp->zfs_props = NULL;
269168404Spjd	}
270168404Spjd
271168404Spjd	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) {
272168404Spjd		zcmd_free_nvlists(&zc);
273168404Spjd		return (-1);
274168404Spjd	}
275168404Spjd
276168404Spjd	zcmd_free_nvlists(&zc);
277168404Spjd
278168404Spjd	if (process_user_props(zhp) != 0)
279168404Spjd		return (-1);
280168404Spjd
281168404Spjd	return (0);
282168404Spjd}
283168404Spjd
284168404Spjd/*
285168404Spjd * Refresh the properties currently stored in the handle.
286168404Spjd */
287168404Spjdvoid
288168404Spjdzfs_refresh_properties(zfs_handle_t *zhp)
289168404Spjd{
290168404Spjd	(void) get_stats(zhp);
291168404Spjd}
292168404Spjd
293168404Spjd/*
294168404Spjd * Makes a handle from the given dataset name.  Used by zfs_open() and
295168404Spjd * zfs_iter_* to create child handles on the fly.
296168404Spjd */
297168404Spjdzfs_handle_t *
298168404Spjdmake_dataset_handle(libzfs_handle_t *hdl, const char *path)
299168404Spjd{
300168404Spjd	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
301168404Spjd
302168404Spjd	if (zhp == NULL)
303168404Spjd		return (NULL);
304168404Spjd
305168404Spjd	zhp->zfs_hdl = hdl;
306168404Spjd
307168404Spjdtop:
308168404Spjd	(void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
309168404Spjd
310168404Spjd	if (get_stats(zhp) != 0) {
311168404Spjd		free(zhp);
312168404Spjd		return (NULL);
313168404Spjd	}
314168404Spjd
315168404Spjd	if (zhp->zfs_dmustats.dds_inconsistent) {
316168404Spjd		zfs_cmd_t zc = { 0 };
317168404Spjd
318168404Spjd		/*
319168404Spjd		 * If it is dds_inconsistent, then we've caught it in
320168404Spjd		 * the middle of a 'zfs receive' or 'zfs destroy', and
321168404Spjd		 * it is inconsistent from the ZPL's point of view, so
322168404Spjd		 * can't be mounted.  However, it could also be that we
323168404Spjd		 * have crashed in the middle of one of those
324168404Spjd		 * operations, in which case we need to get rid of the
325168404Spjd		 * inconsistent state.  We do that by either rolling
326168404Spjd		 * back to the previous snapshot (which will fail if
327168404Spjd		 * there is none), or destroying the filesystem.  Note
328168404Spjd		 * that if we are still in the middle of an active
329168404Spjd		 * 'receive' or 'destroy', then the rollback and destroy
330168404Spjd		 * will fail with EBUSY and we will drive on as usual.
331168404Spjd		 */
332168404Spjd
333168404Spjd		(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
334168404Spjd
335168404Spjd		if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) {
336168404Spjd			(void) zvol_remove_link(hdl, zhp->zfs_name);
337168404Spjd			zc.zc_objset_type = DMU_OST_ZVOL;
338168404Spjd		} else {
339168404Spjd			zc.zc_objset_type = DMU_OST_ZFS;
340168404Spjd		}
341168404Spjd
342168404Spjd		/* If we can successfully roll it back, reget the stats */
343168404Spjd		if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0)
344168404Spjd			goto top;
345168404Spjd		/*
346168404Spjd		 * If we can sucessfully destroy it, pretend that it
347168404Spjd		 * never existed.
348168404Spjd		 */
349168404Spjd		if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) {
350168404Spjd			free(zhp);
351168404Spjd			errno = ENOENT;
352168404Spjd			return (NULL);
353168404Spjd		}
354168404Spjd	}
355168404Spjd
356168404Spjd	/*
357168404Spjd	 * We've managed to open the dataset and gather statistics.  Determine
358168404Spjd	 * the high-level type.
359168404Spjd	 */
360168404Spjd	if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
361168404Spjd		zhp->zfs_head_type = ZFS_TYPE_VOLUME;
362168404Spjd	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
363168404Spjd		zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
364168404Spjd	else
365168404Spjd		abort();
366168404Spjd
367168404Spjd	if (zhp->zfs_dmustats.dds_is_snapshot)
368168404Spjd		zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
369168404Spjd	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
370168404Spjd		zhp->zfs_type = ZFS_TYPE_VOLUME;
371168404Spjd	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
372168404Spjd		zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
373168404Spjd	else
374168404Spjd		abort();	/* we should never see any other types */
375168404Spjd
376168404Spjd	return (zhp);
377168404Spjd}
378168404Spjd
379168404Spjd/*
380168404Spjd * Opens the given snapshot, filesystem, or volume.   The 'types'
381168404Spjd * argument is a mask of acceptable types.  The function will print an
382168404Spjd * appropriate error message and return NULL if it can't be opened.
383168404Spjd */
384168404Spjdzfs_handle_t *
385168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types)
386168404Spjd{
387168404Spjd	zfs_handle_t *zhp;
388168404Spjd	char errbuf[1024];
389168404Spjd
390168404Spjd	(void) snprintf(errbuf, sizeof (errbuf),
391168404Spjd	    dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
392168404Spjd
393168404Spjd	/*
394168404Spjd	 * Validate the name before we even try to open it.
395168404Spjd	 */
396168404Spjd	if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) {
397168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
398168404Spjd		    "invalid dataset name"));
399168404Spjd		(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
400168404Spjd		return (NULL);
401168404Spjd	}
402168404Spjd
403168404Spjd	/*
404168404Spjd	 * Try to get stats for the dataset, which will tell us if it exists.
405168404Spjd	 */
406168404Spjd	errno = 0;
407168404Spjd	if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
408168404Spjd		(void) zfs_standard_error(hdl, errno, errbuf);
409168404Spjd		return (NULL);
410168404Spjd	}
411168404Spjd
412168404Spjd	if (!(types & zhp->zfs_type)) {
413168404Spjd		(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
414168404Spjd		zfs_close(zhp);
415168404Spjd		return (NULL);
416168404Spjd	}
417168404Spjd
418168404Spjd	return (zhp);
419168404Spjd}
420168404Spjd
421168404Spjd/*
422168404Spjd * Release a ZFS handle.  Nothing to do but free the associated memory.
423168404Spjd */
424168404Spjdvoid
425168404Spjdzfs_close(zfs_handle_t *zhp)
426168404Spjd{
427168404Spjd	if (zhp->zfs_mntopts)
428168404Spjd		free(zhp->zfs_mntopts);
429168404Spjd	nvlist_free(zhp->zfs_props);
430168404Spjd	nvlist_free(zhp->zfs_user_props);
431168404Spjd	free(zhp);
432168404Spjd}
433168404Spjd
434168404Spjd/*
435168404Spjd * Given a numeric suffix, convert the value into a number of bits that the
436168404Spjd * resulting value must be shifted.
437168404Spjd */
438168404Spjdstatic int
439168404Spjdstr2shift(libzfs_handle_t *hdl, const char *buf)
440168404Spjd{
441168404Spjd	const char *ends = "BKMGTPEZ";
442168404Spjd	int i;
443168404Spjd
444168404Spjd	if (buf[0] == '\0')
445168404Spjd		return (0);
446168404Spjd	for (i = 0; i < strlen(ends); i++) {
447168404Spjd		if (toupper(buf[0]) == ends[i])
448168404Spjd			break;
449168404Spjd	}
450168404Spjd	if (i == strlen(ends)) {
451168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
452168404Spjd		    "invalid numeric suffix '%s'"), buf);
453168404Spjd		return (-1);
454168404Spjd	}
455168404Spjd
456168404Spjd	/*
457168404Spjd	 * We want to allow trailing 'b' characters for 'GB' or 'Mb'.  But don't
458168404Spjd	 * allow 'BB' - that's just weird.
459168404Spjd	 */
460168404Spjd	if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
461168404Spjd	    toupper(buf[0]) != 'B'))
462168404Spjd		return (10*i);
463168404Spjd
464168404Spjd	zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
465168404Spjd	    "invalid numeric suffix '%s'"), buf);
466168404Spjd	return (-1);
467168404Spjd}
468168404Spjd
469168404Spjd/*
470168404Spjd * Convert a string of the form '100G' into a real number.  Used when setting
471168404Spjd * properties or creating a volume.  'buf' is used to place an extended error
472168404Spjd * message for the caller to use.
473168404Spjd */
474168404Spjdstatic int
475168404Spjdnicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)
476168404Spjd{
477168404Spjd	char *end;
478168404Spjd	int shift;
479168404Spjd
480168404Spjd	*num = 0;
481168404Spjd
482168404Spjd	/* Check to see if this looks like a number.  */
483168404Spjd	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
484168404Spjd		if (hdl)
485168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
486168404Spjd			    "bad numeric value '%s'"), value);
487168404Spjd		return (-1);
488168404Spjd	}
489168404Spjd
490168404Spjd	/* Rely on stroll() to process the numeric portion.  */
491168404Spjd	errno = 0;
492168404Spjd	*num = strtoll(value, &end, 10);
493168404Spjd
494168404Spjd	/*
495168404Spjd	 * Check for ERANGE, which indicates that the value is too large to fit
496168404Spjd	 * in a 64-bit value.
497168404Spjd	 */
498168404Spjd	if (errno == ERANGE) {
499168404Spjd		if (hdl)
500168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
501168404Spjd			    "numeric value is too large"));
502168404Spjd		return (-1);
503168404Spjd	}
504168404Spjd
505168404Spjd	/*
506168404Spjd	 * If we have a decimal value, then do the computation with floating
507168404Spjd	 * point arithmetic.  Otherwise, use standard arithmetic.
508168404Spjd	 */
509168404Spjd	if (*end == '.') {
510168404Spjd		double fval = strtod(value, &end);
511168404Spjd
512168404Spjd		if ((shift = str2shift(hdl, end)) == -1)
513168404Spjd			return (-1);
514168404Spjd
515168404Spjd		fval *= pow(2, shift);
516168404Spjd
517168404Spjd		if (fval > UINT64_MAX) {
518168404Spjd			if (hdl)
519168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
520168404Spjd				    "numeric value is too large"));
521168404Spjd			return (-1);
522168404Spjd		}
523168404Spjd
524168404Spjd		*num = (uint64_t)fval;
525168404Spjd	} else {
526168404Spjd		if ((shift = str2shift(hdl, end)) == -1)
527168404Spjd			return (-1);
528168404Spjd
529168404Spjd		/* Check for overflow */
530168404Spjd		if (shift >= 64 || (*num << shift) >> shift != *num) {
531168404Spjd			if (hdl)
532168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
533168404Spjd				    "numeric value is too large"));
534168404Spjd			return (-1);
535168404Spjd		}
536168404Spjd
537168404Spjd		*num <<= shift;
538168404Spjd	}
539168404Spjd
540168404Spjd	return (0);
541168404Spjd}
542168404Spjd
543168404Spjdint
544168404Spjdzfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val)
545168404Spjd{
546168404Spjd	return (nicestrtonum(hdl, str, val));
547168404Spjd}
548168404Spjd
549168404Spjd/*
550168404Spjd * The prop_parse_*() functions are designed to allow flexibility in callers
551168404Spjd * when setting properties.  At the DSL layer, all properties are either 64-bit
552168404Spjd * numbers or strings.  We want the user to be able to ignore this fact and
553168404Spjd * specify properties as native values (boolean, for example) or as strings (to
554168404Spjd * simplify command line utilities).  This also handles converting index types
555168404Spjd * (compression, checksum, etc) from strings to their on-disk index.
556168404Spjd */
557168404Spjd
558168404Spjdstatic int
559168404Spjdprop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val)
560168404Spjd{
561168404Spjd	uint64_t ret;
562168404Spjd
563168404Spjd	switch (nvpair_type(elem)) {
564168404Spjd	case DATA_TYPE_STRING:
565168404Spjd		{
566168404Spjd			char *value;
567168404Spjd			verify(nvpair_value_string(elem, &value) == 0);
568168404Spjd
569168404Spjd			if (strcmp(value, "on") == 0) {
570168404Spjd				ret = 1;
571168404Spjd			} else if (strcmp(value, "off") == 0) {
572168404Spjd				ret = 0;
573168404Spjd			} else {
574168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
575168404Spjd				    "property '%s' must be 'on' or 'off'"),
576168404Spjd				    nvpair_name(elem));
577168404Spjd				return (-1);
578168404Spjd			}
579168404Spjd			break;
580168404Spjd		}
581168404Spjd
582168404Spjd	case DATA_TYPE_UINT64:
583168404Spjd		{
584168404Spjd			verify(nvpair_value_uint64(elem, &ret) == 0);
585168404Spjd			if (ret > 1) {
586168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
587168404Spjd				    "'%s' must be a boolean value"),
588168404Spjd				    nvpair_name(elem));
589168404Spjd				return (-1);
590168404Spjd			}
591168404Spjd			break;
592168404Spjd		}
593168404Spjd
594168404Spjd	case DATA_TYPE_BOOLEAN_VALUE:
595168404Spjd		{
596168404Spjd			boolean_t value;
597168404Spjd			verify(nvpair_value_boolean_value(elem, &value) == 0);
598168404Spjd			ret = value;
599168404Spjd			break;
600168404Spjd		}
601168404Spjd
602168404Spjd	default:
603168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
604168404Spjd		    "'%s' must be a boolean value"),
605168404Spjd		    nvpair_name(elem));
606168404Spjd		return (-1);
607168404Spjd	}
608168404Spjd
609168404Spjd	*val = ret;
610168404Spjd	return (0);
611168404Spjd}
612168404Spjd
613168404Spjdstatic int
614168404Spjdprop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop,
615168404Spjd    uint64_t *val)
616168404Spjd{
617168404Spjd	uint64_t ret;
618168404Spjd	boolean_t isnone = B_FALSE;
619168404Spjd
620168404Spjd	switch (nvpair_type(elem)) {
621168404Spjd	case DATA_TYPE_STRING:
622168404Spjd		{
623168404Spjd			char *value;
624168404Spjd			(void) nvpair_value_string(elem, &value);
625168404Spjd			if (strcmp(value, "none") == 0) {
626168404Spjd				isnone = B_TRUE;
627168404Spjd				ret = 0;
628168404Spjd			} else if (nicestrtonum(hdl, value, &ret) != 0) {
629168404Spjd				return (-1);
630168404Spjd			}
631168404Spjd			break;
632168404Spjd		}
633168404Spjd
634168404Spjd	case DATA_TYPE_UINT64:
635168404Spjd		(void) nvpair_value_uint64(elem, &ret);
636168404Spjd		break;
637168404Spjd
638168404Spjd	default:
639168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
640168404Spjd		    "'%s' must be a number"),
641168404Spjd		    nvpair_name(elem));
642168404Spjd		return (-1);
643168404Spjd	}
644168404Spjd
645168404Spjd	/*
646168404Spjd	 * Quota special: force 'none' and don't allow 0.
647168404Spjd	 */
648168404Spjd	if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) {
649168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
650168404Spjd		    "use 'none' to disable quota"));
651168404Spjd		return (-1);
652168404Spjd	}
653168404Spjd
654168404Spjd	*val = ret;
655168404Spjd	return (0);
656168404Spjd}
657168404Spjd
658168404Spjdstatic int
659168404Spjdprop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop,
660168404Spjd    uint64_t *val)
661168404Spjd{
662168404Spjd	char *propname = nvpair_name(elem);
663168404Spjd	char *value;
664168404Spjd
665168404Spjd	if (nvpair_type(elem) != DATA_TYPE_STRING) {
666168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
667168404Spjd		    "'%s' must be a string"), propname);
668168404Spjd		return (-1);
669168404Spjd	}
670168404Spjd
671168404Spjd	(void) nvpair_value_string(elem, &value);
672168404Spjd
673168404Spjd	if (zfs_prop_string_to_index(prop, value, val) != 0) {
674168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
675168404Spjd		    "'%s' must be one of '%s'"), propname,
676168404Spjd		    zfs_prop_values(prop));
677168404Spjd		return (-1);
678168404Spjd	}
679168404Spjd
680168404Spjd	return (0);
681168404Spjd}
682168404Spjd
683168404Spjd/*
684168404Spjd * Check if the bootfs name has the same pool name as it is set to.
685168404Spjd * Assuming bootfs is a valid dataset name.
686168404Spjd */
687168404Spjdstatic boolean_t
688168404Spjdbootfs_poolname_valid(char *pool, char *bootfs)
689168404Spjd{
690168404Spjd	char ch, *pname;
691168404Spjd
692168404Spjd	/* get the pool name from the bootfs name */
693168404Spjd	pname = bootfs;
694168404Spjd	while (*bootfs && !isspace(*bootfs) && *bootfs != '/')
695168404Spjd		bootfs++;
696168404Spjd
697168404Spjd	ch = *bootfs;
698168404Spjd	*bootfs = 0;
699168404Spjd
700168404Spjd	if (strcmp(pool, pname) == 0) {
701168404Spjd		*bootfs = ch;
702168404Spjd		return (B_TRUE);
703168404Spjd	}
704168404Spjd
705168404Spjd	*bootfs = ch;
706168404Spjd	return (B_FALSE);
707168404Spjd}
708168404Spjd
709168404Spjd/*
710168404Spjd * Given an nvlist of properties to set, validates that they are correct, and
711168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as
712168404Spjd * strings.
713168404Spjd */
714168404Spjdnvlist_t *
715168404Spjdzfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name,
716168404Spjd    nvlist_t *nvl, uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
717168404Spjd{
718168404Spjd	nvpair_t *elem;
719168404Spjd	const char *propname;
720168404Spjd	zfs_prop_t prop;
721168404Spjd	uint64_t intval;
722168404Spjd	char *strval;
723168404Spjd	nvlist_t *ret;
724168404Spjd	int isuser;
725168404Spjd
726168404Spjd	if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
727168404Spjd		(void) no_memory(hdl);
728168404Spjd		return (NULL);
729168404Spjd	}
730168404Spjd
731168404Spjd	if (type == ZFS_TYPE_SNAPSHOT) {
732168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
733168404Spjd		    "snapshot properties cannot be modified"));
734168404Spjd		(void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
735168404Spjd		goto error;
736168404Spjd	}
737168404Spjd
738168404Spjd	elem = NULL;
739168404Spjd	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
740168404Spjd		propname = nvpair_name(elem);
741168404Spjd
742168404Spjd		/*
743168404Spjd		 * Make sure this property is valid and applies to this type.
744168404Spjd		 */
745168404Spjd		if ((prop = zfs_name_to_prop_common(propname, type))
746168404Spjd		    == ZFS_PROP_INVAL) {
747168404Spjd			isuser = zfs_prop_user(propname);
748168404Spjd			if (!isuser || (isuser && (type & ZFS_TYPE_POOL))) {
749168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
750168404Spjd				    "invalid property '%s'"),
751168404Spjd				    propname);
752168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
753168404Spjd				goto error;
754168404Spjd			} else {
755168404Spjd				/*
756168404Spjd				 * If this is a user property, make sure it's a
757168404Spjd				 * string, and that it's less than
758168404Spjd				 * ZAP_MAXNAMELEN.
759168404Spjd				 */
760168404Spjd				if (nvpair_type(elem) != DATA_TYPE_STRING) {
761168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
762168404Spjd					    "'%s' must be a string"),
763168404Spjd					    propname);
764168404Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
765168404Spjd					    errbuf);
766168404Spjd					goto error;
767168404Spjd				}
768168404Spjd
769168404Spjd				if (strlen(nvpair_name(elem)) >=
770168404Spjd				    ZAP_MAXNAMELEN) {
771168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
772168404Spjd					    "property name '%s' is too long"),
773168404Spjd					    propname);
774168404Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
775168404Spjd					    errbuf);
776168404Spjd					goto error;
777168404Spjd				}
778168404Spjd			}
779168404Spjd
780168404Spjd			(void) nvpair_value_string(elem, &strval);
781168404Spjd			if (nvlist_add_string(ret, propname, strval) != 0) {
782168404Spjd				(void) no_memory(hdl);
783168404Spjd				goto error;
784168404Spjd			}
785168404Spjd			continue;
786168404Spjd		}
787168404Spjd
788168404Spjd		/*
789168404Spjd		 * Normalize the name, to get rid of shorthand abbrevations.
790168404Spjd		 */
791168404Spjd		propname = zfs_prop_to_name(prop);
792168404Spjd
793168404Spjd		if (!zfs_prop_valid_for_type(prop, type)) {
794168404Spjd			zfs_error_aux(hdl,
795168404Spjd			    dgettext(TEXT_DOMAIN, "'%s' does not "
796168404Spjd			    "apply to datasets of this type"), propname);
797168404Spjd			(void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
798168404Spjd			goto error;
799168404Spjd		}
800168404Spjd
801168404Spjd		if (zfs_prop_readonly(prop) &&
802168404Spjd		    (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) {
803168404Spjd			zfs_error_aux(hdl,
804168404Spjd			    dgettext(TEXT_DOMAIN, "'%s' is readonly"),
805168404Spjd			    propname);
806168404Spjd			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
807168404Spjd			goto error;
808168404Spjd		}
809168404Spjd
810168404Spjd		/*
811168404Spjd		 * Convert any properties to the internal DSL value types.
812168404Spjd		 */
813168404Spjd		strval = NULL;
814168404Spjd		switch (zfs_prop_get_type(prop)) {
815168404Spjd		case prop_type_boolean:
816168404Spjd			if (prop_parse_boolean(hdl, elem, &intval) != 0) {
817168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
818168404Spjd				goto error;
819168404Spjd			}
820168404Spjd			break;
821168404Spjd
822168404Spjd		case prop_type_string:
823168404Spjd			if (nvpair_type(elem) != DATA_TYPE_STRING) {
824168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
825168404Spjd				    "'%s' must be a string"),
826168404Spjd				    propname);
827168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
828168404Spjd				goto error;
829168404Spjd			}
830168404Spjd			(void) nvpair_value_string(elem, &strval);
831168404Spjd			if (strlen(strval) >= ZFS_MAXPROPLEN) {
832168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
833168404Spjd				    "'%s' is too long"), propname);
834168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
835168404Spjd				goto error;
836168404Spjd			}
837168404Spjd			break;
838168404Spjd
839168404Spjd		case prop_type_number:
840168404Spjd			if (prop_parse_number(hdl, elem, prop, &intval) != 0) {
841168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
842168404Spjd				goto error;
843168404Spjd			}
844168404Spjd			break;
845168404Spjd
846168404Spjd		case prop_type_index:
847168404Spjd			if (prop_parse_index(hdl, elem, prop, &intval) != 0) {
848168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
849168404Spjd				goto error;
850168404Spjd			}
851168404Spjd			break;
852168404Spjd
853168404Spjd		default:
854168404Spjd			abort();
855168404Spjd		}
856168404Spjd
857168404Spjd		/*
858168404Spjd		 * Add the result to our return set of properties.
859168404Spjd		 */
860168404Spjd		if (strval) {
861168404Spjd			if (nvlist_add_string(ret, propname, strval) != 0) {
862168404Spjd				(void) no_memory(hdl);
863168404Spjd				goto error;
864168404Spjd			}
865168404Spjd		} else if (nvlist_add_uint64(ret, propname, intval) != 0) {
866168404Spjd			(void) no_memory(hdl);
867168404Spjd			goto error;
868168404Spjd		}
869168404Spjd
870168404Spjd		/*
871168404Spjd		 * Perform some additional checks for specific properties.
872168404Spjd		 */
873168404Spjd		switch (prop) {
874168404Spjd		case ZFS_PROP_RECORDSIZE:
875168404Spjd		case ZFS_PROP_VOLBLOCKSIZE:
876168404Spjd			/* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */
877168404Spjd			if (intval < SPA_MINBLOCKSIZE ||
878168404Spjd			    intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) {
879168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
880168404Spjd				    "'%s' must be power of 2 from %u "
881168404Spjd				    "to %uk"), propname,
882168404Spjd				    (uint_t)SPA_MINBLOCKSIZE,
883168404Spjd				    (uint_t)SPA_MAXBLOCKSIZE >> 10);
884168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
885168404Spjd				goto error;
886168404Spjd			}
887168404Spjd			break;
888168404Spjd
889168404Spjd		case ZFS_PROP_SHAREISCSI:
890168404Spjd			if (strcmp(strval, "off") != 0 &&
891168404Spjd			    strcmp(strval, "on") != 0 &&
892168404Spjd			    strcmp(strval, "type=disk") != 0) {
893168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
894168404Spjd				    "'%s' must be 'on', 'off', or 'type=disk'"),
895168404Spjd				    propname);
896168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
897168404Spjd				goto error;
898168404Spjd			}
899168404Spjd
900168404Spjd			break;
901168404Spjd
902168404Spjd		case ZFS_PROP_MOUNTPOINT:
903168404Spjd			if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
904168404Spjd			    strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
905168404Spjd				break;
906168404Spjd
907168404Spjd			if (strval[0] != '/') {
908168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
909168404Spjd				    "'%s' must be an absolute path, "
910168404Spjd				    "'none', or 'legacy'"), propname);
911168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
912168404Spjd				goto error;
913168404Spjd			}
914168404Spjd			/*FALLTHRU*/
915168404Spjd
916168404Spjd		case ZFS_PROP_SHARENFS:
917168404Spjd			/*
918168404Spjd			 * For the mountpoint and sharenfs properties, check if
919168404Spjd			 * it can be set in a global/non-global zone based on
920168404Spjd			 * the zoned property value:
921168404Spjd			 *
922168404Spjd			 *		global zone	    non-global zone
923168404Spjd			 * --------------------------------------------------
924168404Spjd			 * zoned=on	mountpoint (no)	    mountpoint (yes)
925168404Spjd			 *		sharenfs (no)	    sharenfs (no)
926168404Spjd			 *
927168404Spjd			 * zoned=off	mountpoint (yes)	N/A
928168404Spjd			 *		sharenfs (yes)
929168404Spjd			 */
930168404Spjd			if (zoned) {
931168404Spjd				if (getzoneid() == GLOBAL_ZONEID) {
932168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
933168404Spjd					    "'%s' cannot be set on "
934168404Spjd					    "dataset in a non-global zone"),
935168404Spjd					    propname);
936168404Spjd					(void) zfs_error(hdl, EZFS_ZONED,
937168404Spjd					    errbuf);
938168404Spjd					goto error;
939168404Spjd				} else if (prop == ZFS_PROP_SHARENFS) {
940168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
941168404Spjd					    "'%s' cannot be set in "
942168404Spjd					    "a non-global zone"), propname);
943168404Spjd					(void) zfs_error(hdl, EZFS_ZONED,
944168404Spjd					    errbuf);
945168404Spjd					goto error;
946168404Spjd				}
947168404Spjd			} else if (getzoneid() != GLOBAL_ZONEID) {
948168404Spjd				/*
949168404Spjd				 * If zoned property is 'off', this must be in
950168404Spjd				 * a globle zone. If not, something is wrong.
951168404Spjd				 */
952168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
953168404Spjd				    "'%s' cannot be set while dataset "
954168404Spjd				    "'zoned' property is set"), propname);
955168404Spjd				(void) zfs_error(hdl, EZFS_ZONED, errbuf);
956168404Spjd				goto error;
957168404Spjd			}
958168404Spjd
959168404Spjd			break;
960168404Spjd
961168404Spjd		case ZFS_PROP_BOOTFS:
962168404Spjd			/*
963168404Spjd			 * bootfs property value has to be a dataset name and
964168404Spjd			 * the dataset has to be in the same pool as it sets to.
965168404Spjd			 */
966168404Spjd			if (strval[0] != '\0' && (!zfs_name_valid(strval,
967168404Spjd			    ZFS_TYPE_FILESYSTEM) || !bootfs_poolname_valid(
968168404Spjd			    pool_name, strval))) {
969168404Spjd
970168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
971168404Spjd				    "is an invalid name"), strval);
972168404Spjd				(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
973168404Spjd				goto error;
974168404Spjd			}
975168404Spjd			break;
976168404Spjd		}
977168404Spjd
978168404Spjd		/*
979168404Spjd		 * For changes to existing volumes, we have some additional
980168404Spjd		 * checks to enforce.
981168404Spjd		 */
982168404Spjd		if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
983168404Spjd			uint64_t volsize = zfs_prop_get_int(zhp,
984168404Spjd			    ZFS_PROP_VOLSIZE);
985168404Spjd			uint64_t blocksize = zfs_prop_get_int(zhp,
986168404Spjd			    ZFS_PROP_VOLBLOCKSIZE);
987168404Spjd			char buf[64];
988168404Spjd
989168404Spjd			switch (prop) {
990168404Spjd			case ZFS_PROP_RESERVATION:
991168404Spjd				if (intval > volsize) {
992168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
993168404Spjd					    "'%s' is greater than current "
994168404Spjd					    "volume size"), propname);
995168404Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
996168404Spjd					    errbuf);
997168404Spjd					goto error;
998168404Spjd				}
999168404Spjd				break;
1000168404Spjd
1001168404Spjd			case ZFS_PROP_VOLSIZE:
1002168404Spjd				if (intval % blocksize != 0) {
1003168404Spjd					zfs_nicenum(blocksize, buf,
1004168404Spjd					    sizeof (buf));
1005168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1006168404Spjd					    "'%s' must be a multiple of "
1007168404Spjd					    "volume block size (%s)"),
1008168404Spjd					    propname, buf);
1009168404Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
1010168404Spjd					    errbuf);
1011168404Spjd					goto error;
1012168404Spjd				}
1013168404Spjd
1014168404Spjd				if (intval == 0) {
1015168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1016168404Spjd					    "'%s' cannot be zero"),
1017168404Spjd					    propname);
1018168404Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
1019168404Spjd					    errbuf);
1020168404Spjd					goto error;
1021168404Spjd				}
1022168404Spjd				break;
1023168404Spjd			}
1024168404Spjd		}
1025168404Spjd	}
1026168404Spjd
1027168404Spjd	/*
1028168404Spjd	 * If this is an existing volume, and someone is setting the volsize,
1029168404Spjd	 * make sure that it matches the reservation, or add it if necessary.
1030168404Spjd	 */
1031168404Spjd	if (zhp != NULL && type == ZFS_TYPE_VOLUME &&
1032168404Spjd	    nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1033168404Spjd	    &intval) == 0) {
1034168404Spjd		uint64_t old_volsize = zfs_prop_get_int(zhp,
1035168404Spjd		    ZFS_PROP_VOLSIZE);
1036168404Spjd		uint64_t old_reservation = zfs_prop_get_int(zhp,
1037168404Spjd		    ZFS_PROP_RESERVATION);
1038168404Spjd		uint64_t new_reservation;
1039168404Spjd
1040168404Spjd		if (old_volsize == old_reservation &&
1041168404Spjd		    nvlist_lookup_uint64(ret,
1042168404Spjd		    zfs_prop_to_name(ZFS_PROP_RESERVATION),
1043168404Spjd		    &new_reservation) != 0) {
1044168404Spjd			if (nvlist_add_uint64(ret,
1045168404Spjd			    zfs_prop_to_name(ZFS_PROP_RESERVATION),
1046168404Spjd			    intval) != 0) {
1047168404Spjd				(void) no_memory(hdl);
1048168404Spjd				goto error;
1049168404Spjd			}
1050168404Spjd		}
1051168404Spjd	}
1052168404Spjd
1053168404Spjd	return (ret);
1054168404Spjd
1055168404Spjderror:
1056168404Spjd	nvlist_free(ret);
1057168404Spjd	return (NULL);
1058168404Spjd}
1059168404Spjd
1060168404Spjd/*
1061168404Spjd * Given a property name and value, set the property for the given dataset.
1062168404Spjd */
1063168404Spjdint
1064168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
1065168404Spjd{
1066168404Spjd	zfs_cmd_t zc = { 0 };
1067168404Spjd	int ret = -1;
1068168404Spjd	prop_changelist_t *cl = NULL;
1069168404Spjd	char errbuf[1024];
1070168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
1071168404Spjd	nvlist_t *nvl = NULL, *realprops;
1072168404Spjd	zfs_prop_t prop;
1073168404Spjd
1074168404Spjd	(void) snprintf(errbuf, sizeof (errbuf),
1075168404Spjd	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
1076168404Spjd	    zhp->zfs_name);
1077168404Spjd
1078168404Spjd	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
1079168404Spjd	    nvlist_add_string(nvl, propname, propval) != 0) {
1080168404Spjd		(void) no_memory(hdl);
1081168404Spjd		goto error;
1082168404Spjd	}
1083168404Spjd
1084168404Spjd	if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, NULL, nvl,
1085168404Spjd	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL)
1086168404Spjd		goto error;
1087168404Spjd	nvlist_free(nvl);
1088168404Spjd	nvl = realprops;
1089168404Spjd
1090168404Spjd	prop = zfs_name_to_prop(propname);
1091168404Spjd
1092168404Spjd	/* We don't support those properties on FreeBSD. */
1093168404Spjd	switch (prop) {
1094168404Spjd	case ZFS_PROP_SHAREISCSI:
1095168404Spjd	case ZFS_PROP_DEVICES:
1096168404Spjd	case ZFS_PROP_ACLMODE:
1097168404Spjd	case ZFS_PROP_ACLINHERIT:
1098168404Spjd	case ZFS_PROP_ISCSIOPTIONS:
1099168404Spjd		(void) snprintf(errbuf, sizeof (errbuf),
1100168404Spjd		    "property '%s' not supported on FreeBSD", propname);
1101168404Spjd		ret = zfs_error(hdl, EZFS_PERM, errbuf);
1102168404Spjd		goto error;
1103168404Spjd	}
1104168404Spjd
1105168404Spjd	if ((cl = changelist_gather(zhp, prop, 0)) == NULL)
1106168404Spjd		goto error;
1107168404Spjd
1108168404Spjd	if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
1109168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1110168404Spjd		    "child dataset with inherited mountpoint is used "
1111168404Spjd		    "in a non-global zone"));
1112168404Spjd		ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1113168404Spjd		goto error;
1114168404Spjd	}
1115168404Spjd
1116168404Spjd	if ((ret = changelist_prefix(cl)) != 0)
1117168404Spjd		goto error;
1118168404Spjd
1119168404Spjd	/*
1120168404Spjd	 * Execute the corresponding ioctl() to set this property.
1121168404Spjd	 */
1122168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1123168404Spjd
1124168404Spjd	if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0)
1125168404Spjd		goto error;
1126168404Spjd
1127168404Spjd	ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc);
1128168404Spjd
1129168404Spjd	if (ret != 0) {
1130168404Spjd		switch (errno) {
1131168404Spjd
1132168404Spjd		case ENOSPC:
1133168404Spjd			/*
1134168404Spjd			 * For quotas and reservations, ENOSPC indicates
1135168404Spjd			 * something different; setting a quota or reservation
1136168404Spjd			 * doesn't use any disk space.
1137168404Spjd			 */
1138168404Spjd			switch (prop) {
1139168404Spjd			case ZFS_PROP_QUOTA:
1140168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1141168404Spjd				    "size is less than current used or "
1142168404Spjd				    "reserved space"));
1143168404Spjd				(void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1144168404Spjd				break;
1145168404Spjd
1146168404Spjd			case ZFS_PROP_RESERVATION:
1147168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1148168404Spjd				    "size is greater than available space"));
1149168404Spjd				(void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1150168404Spjd				break;
1151168404Spjd
1152168404Spjd			default:
1153168404Spjd				(void) zfs_standard_error(hdl, errno, errbuf);
1154168404Spjd				break;
1155168404Spjd			}
1156168404Spjd			break;
1157168404Spjd
1158168404Spjd		case EBUSY:
1159168404Spjd			if (prop == ZFS_PROP_VOLBLOCKSIZE)
1160168404Spjd				(void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf);
1161168404Spjd			else
1162168404Spjd				(void) zfs_standard_error(hdl, EBUSY, errbuf);
1163168404Spjd			break;
1164168404Spjd
1165168404Spjd		case EROFS:
1166168404Spjd			(void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
1167168404Spjd			break;
1168168404Spjd
1169168404Spjd		case ENOTSUP:
1170168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1171168404Spjd			    "pool must be upgraded to allow gzip compression"));
1172168404Spjd			(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
1173168404Spjd			break;
1174168404Spjd
1175168404Spjd		case EOVERFLOW:
1176168404Spjd			/*
1177168404Spjd			 * This platform can't address a volume this big.
1178168404Spjd			 */
1179168404Spjd#ifdef _ILP32
1180168404Spjd			if (prop == ZFS_PROP_VOLSIZE) {
1181168404Spjd				(void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
1182168404Spjd				break;
1183168404Spjd			}
1184168404Spjd#endif
1185168404Spjd			/* FALLTHROUGH */
1186168404Spjd		default:
1187168404Spjd			(void) zfs_standard_error(hdl, errno, errbuf);
1188168404Spjd		}
1189168404Spjd	} else {
1190168404Spjd		/*
1191168404Spjd		 * Refresh the statistics so the new property value
1192168404Spjd		 * is reflected.
1193168404Spjd		 */
1194168404Spjd		if ((ret = changelist_postfix(cl)) == 0)
1195168404Spjd			(void) get_stats(zhp);
1196168404Spjd	}
1197168404Spjd
1198168404Spjderror:
1199168404Spjd	nvlist_free(nvl);
1200168404Spjd	zcmd_free_nvlists(&zc);
1201168404Spjd	if (cl)
1202168404Spjd		changelist_free(cl);
1203168404Spjd	return (ret);
1204168404Spjd}
1205168404Spjd
1206168404Spjd/*
1207168404Spjd * Given a property, inherit the value from the parent dataset.
1208168404Spjd */
1209168404Spjdint
1210168404Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname)
1211168404Spjd{
1212168404Spjd	zfs_cmd_t zc = { 0 };
1213168404Spjd	int ret;
1214168404Spjd	prop_changelist_t *cl;
1215168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
1216168404Spjd	char errbuf[1024];
1217168404Spjd	zfs_prop_t prop;
1218168404Spjd
1219168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1220168404Spjd	    "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
1221168404Spjd
1222168404Spjd	if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) {
1223168404Spjd		/*
1224168404Spjd		 * For user properties, the amount of work we have to do is very
1225168404Spjd		 * small, so just do it here.
1226168404Spjd		 */
1227168404Spjd		if (!zfs_prop_user(propname)) {
1228168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1229168404Spjd			    "invalid property"));
1230168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
1231168404Spjd		}
1232168404Spjd
1233168404Spjd		(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1234168404Spjd		(void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1235168404Spjd
1236168404Spjd		if (ioctl(zhp->zfs_hdl->libzfs_fd,
1237168404Spjd		    ZFS_IOC_SET_PROP, &zc) != 0)
1238168404Spjd			return (zfs_standard_error(hdl, errno, errbuf));
1239168404Spjd
1240168404Spjd		return (0);
1241168404Spjd	}
1242168404Spjd
1243168404Spjd	/*
1244168404Spjd	 * Verify that this property is inheritable.
1245168404Spjd	 */
1246168404Spjd	if (zfs_prop_readonly(prop))
1247168404Spjd		return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
1248168404Spjd
1249168404Spjd	if (!zfs_prop_inheritable(prop))
1250168404Spjd		return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
1251168404Spjd
1252168404Spjd	/*
1253168404Spjd	 * Check to see if the value applies to this type
1254168404Spjd	 */
1255168404Spjd	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
1256168404Spjd		return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
1257168404Spjd
1258168404Spjd	/*
1259168404Spjd	 * Normalize the name, to get rid of shorthand abbrevations.
1260168404Spjd	 */
1261168404Spjd	propname = zfs_prop_to_name(prop);
1262168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1263168404Spjd	(void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1264168404Spjd
1265168404Spjd	if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
1266168404Spjd	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
1267168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1268168404Spjd		    "dataset is used in a non-global zone"));
1269168404Spjd		return (zfs_error(hdl, EZFS_ZONED, errbuf));
1270168404Spjd	}
1271168404Spjd
1272168404Spjd	/*
1273168404Spjd	 * Determine datasets which will be affected by this change, if any.
1274168404Spjd	 */
1275168404Spjd	if ((cl = changelist_gather(zhp, prop, 0)) == NULL)
1276168404Spjd		return (-1);
1277168404Spjd
1278168404Spjd	if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
1279168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1280168404Spjd		    "child dataset with inherited mountpoint is used "
1281168404Spjd		    "in a non-global zone"));
1282168404Spjd		ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1283168404Spjd		goto error;
1284168404Spjd	}
1285168404Spjd
1286168404Spjd	if ((ret = changelist_prefix(cl)) != 0)
1287168404Spjd		goto error;
1288168404Spjd
1289168404Spjd	if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd,
1290168404Spjd	    ZFS_IOC_SET_PROP, &zc)) != 0) {
1291168404Spjd		return (zfs_standard_error(hdl, errno, errbuf));
1292168404Spjd	} else {
1293168404Spjd
1294168404Spjd		if ((ret = changelist_postfix(cl)) != 0)
1295168404Spjd			goto error;
1296168404Spjd
1297168404Spjd		/*
1298168404Spjd		 * Refresh the statistics so the new property is reflected.
1299168404Spjd		 */
1300168404Spjd		(void) get_stats(zhp);
1301168404Spjd	}
1302168404Spjd
1303168404Spjderror:
1304168404Spjd	changelist_free(cl);
1305168404Spjd	return (ret);
1306168404Spjd}
1307168404Spjd
1308168404Spjdvoid
1309168404Spjdnicebool(int value, char *buf, size_t buflen)
1310168404Spjd{
1311168404Spjd	if (value)
1312168404Spjd		(void) strlcpy(buf, "on", buflen);
1313168404Spjd	else
1314168404Spjd		(void) strlcpy(buf, "off", buflen);
1315168404Spjd}
1316168404Spjd
1317168404Spjd/*
1318168404Spjd * True DSL properties are stored in an nvlist.  The following two functions
1319168404Spjd * extract them appropriately.
1320168404Spjd */
1321168404Spjdstatic uint64_t
1322168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1323168404Spjd{
1324168404Spjd	nvlist_t *nv;
1325168404Spjd	uint64_t value;
1326168404Spjd
1327168404Spjd	*source = NULL;
1328168404Spjd	if (nvlist_lookup_nvlist(zhp->zfs_props,
1329168404Spjd	    zfs_prop_to_name(prop), &nv) == 0) {
1330168404Spjd		verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0);
1331168404Spjd		(void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source);
1332168404Spjd	} else {
1333168404Spjd		value = zfs_prop_default_numeric(prop);
1334168404Spjd		*source = "";
1335168404Spjd	}
1336168404Spjd
1337168404Spjd	return (value);
1338168404Spjd}
1339168404Spjd
1340168404Spjdstatic char *
1341168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1342168404Spjd{
1343168404Spjd	nvlist_t *nv;
1344168404Spjd	char *value;
1345168404Spjd
1346168404Spjd	*source = NULL;
1347168404Spjd	if (nvlist_lookup_nvlist(zhp->zfs_props,
1348168404Spjd	    zfs_prop_to_name(prop), &nv) == 0) {
1349168404Spjd		verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0);
1350168404Spjd		(void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source);
1351168404Spjd	} else {
1352168404Spjd		if ((value = (char *)zfs_prop_default_string(prop)) == NULL)
1353168404Spjd			value = "";
1354168404Spjd		*source = "";
1355168404Spjd	}
1356168404Spjd
1357168404Spjd	return (value);
1358168404Spjd}
1359168404Spjd
1360168404Spjd/*
1361168404Spjd * Internal function for getting a numeric property.  Both zfs_prop_get() and
1362168404Spjd * zfs_prop_get_int() are built using this interface.
1363168404Spjd *
1364168404Spjd * Certain properties can be overridden using 'mount -o'.  In this case, scan
1365168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options.
1366168404Spjd * If they differ from the on-disk values, report the current values and mark
1367168404Spjd * the source "temporary".
1368168404Spjd */
1369168404Spjdstatic int
1370168404Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
1371168404Spjd    char **source, uint64_t *val)
1372168404Spjd{
1373168404Spjd	struct mnttab mnt;
1374168404Spjd	char *mntopt_on = NULL;
1375168404Spjd	char *mntopt_off = NULL;
1376168404Spjd
1377168404Spjd	*source = NULL;
1378168404Spjd
1379168404Spjd	switch (prop) {
1380168404Spjd	case ZFS_PROP_ATIME:
1381168404Spjd		mntopt_on = MNTOPT_ATIME;
1382168404Spjd		mntopt_off = MNTOPT_NOATIME;
1383168404Spjd		break;
1384168404Spjd
1385168404Spjd	case ZFS_PROP_DEVICES:
1386168404Spjd		mntopt_on = MNTOPT_DEVICES;
1387168404Spjd		mntopt_off = MNTOPT_NODEVICES;
1388168404Spjd		break;
1389168404Spjd
1390168404Spjd	case ZFS_PROP_EXEC:
1391168404Spjd		mntopt_on = MNTOPT_EXEC;
1392168404Spjd		mntopt_off = MNTOPT_NOEXEC;
1393168404Spjd		break;
1394168404Spjd
1395168404Spjd	case ZFS_PROP_READONLY:
1396168404Spjd		mntopt_on = MNTOPT_RO;
1397168404Spjd		mntopt_off = MNTOPT_RW;
1398168404Spjd		break;
1399168404Spjd
1400168404Spjd	case ZFS_PROP_SETUID:
1401168404Spjd		mntopt_on = MNTOPT_SETUID;
1402168404Spjd		mntopt_off = MNTOPT_NOSETUID;
1403168404Spjd		break;
1404168404Spjd
1405168404Spjd	case ZFS_PROP_XATTR:
1406168404Spjd		mntopt_on = MNTOPT_XATTR;
1407168404Spjd		mntopt_off = MNTOPT_NOXATTR;
1408168404Spjd		break;
1409168404Spjd	}
1410168404Spjd
1411168404Spjd	/*
1412168404Spjd	 * Because looking up the mount options is potentially expensive
1413168404Spjd	 * (iterating over all of /etc/mnttab), we defer its calculation until
1414168404Spjd	 * we're looking up a property which requires its presence.
1415168404Spjd	 */
1416168404Spjd	if (!zhp->zfs_mntcheck &&
1417168404Spjd	    (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
1418168404Spjd		struct mnttab entry, search = { 0 };
1419168404Spjd		FILE *mnttab = zhp->zfs_hdl->libzfs_mnttab;
1420168404Spjd
1421168404Spjd		search.mnt_special = (char *)zhp->zfs_name;
1422168404Spjd		search.mnt_fstype = MNTTYPE_ZFS;
1423168404Spjd		rewind(mnttab);
1424168404Spjd
1425168404Spjd		if (getmntany(mnttab, &entry, &search) == 0) {
1426168404Spjd			zhp->zfs_mntopts = zfs_strdup(zhp->zfs_hdl,
1427168404Spjd			    entry.mnt_mntopts);
1428168404Spjd			if (zhp->zfs_mntopts == NULL)
1429168404Spjd				return (-1);
1430168404Spjd		}
1431168404Spjd
1432168404Spjd		zhp->zfs_mntcheck = B_TRUE;
1433168404Spjd	}
1434168404Spjd
1435168404Spjd	if (zhp->zfs_mntopts == NULL)
1436168404Spjd		mnt.mnt_mntopts = "";
1437168404Spjd	else
1438168404Spjd		mnt.mnt_mntopts = zhp->zfs_mntopts;
1439168404Spjd
1440168404Spjd	switch (prop) {
1441168404Spjd	case ZFS_PROP_ATIME:
1442168404Spjd	case ZFS_PROP_DEVICES:
1443168404Spjd	case ZFS_PROP_EXEC:
1444168404Spjd	case ZFS_PROP_READONLY:
1445168404Spjd	case ZFS_PROP_SETUID:
1446168404Spjd	case ZFS_PROP_XATTR:
1447168404Spjd		*val = getprop_uint64(zhp, prop, source);
1448168404Spjd
1449168404Spjd		if (hasmntopt(&mnt, mntopt_on) && !*val) {
1450168404Spjd			*val = B_TRUE;
1451168404Spjd			if (src)
1452168404Spjd				*src = ZFS_SRC_TEMPORARY;
1453168404Spjd		} else if (hasmntopt(&mnt, mntopt_off) && *val) {
1454168404Spjd			*val = B_FALSE;
1455168404Spjd			if (src)
1456168404Spjd				*src = ZFS_SRC_TEMPORARY;
1457168404Spjd		}
1458168404Spjd		break;
1459168404Spjd
1460168404Spjd	case ZFS_PROP_RECORDSIZE:
1461168404Spjd	case ZFS_PROP_COMPRESSION:
1462168404Spjd	case ZFS_PROP_ZONED:
1463168404Spjd	case ZFS_PROP_CREATION:
1464168404Spjd	case ZFS_PROP_COMPRESSRATIO:
1465168404Spjd	case ZFS_PROP_REFERENCED:
1466168404Spjd	case ZFS_PROP_USED:
1467168404Spjd	case ZFS_PROP_CREATETXG:
1468168404Spjd	case ZFS_PROP_AVAILABLE:
1469168404Spjd	case ZFS_PROP_VOLSIZE:
1470168404Spjd	case ZFS_PROP_VOLBLOCKSIZE:
1471168404Spjd		*val = getprop_uint64(zhp, prop, source);
1472168404Spjd		break;
1473168404Spjd
1474168404Spjd	case ZFS_PROP_CANMOUNT:
1475168404Spjd		*val = getprop_uint64(zhp, prop, source);
1476168404Spjd		if (*val == 0)
1477168404Spjd			*source = zhp->zfs_name;
1478168404Spjd		else
1479168404Spjd			*source = "";	/* default */
1480168404Spjd		break;
1481168404Spjd
1482168404Spjd	case ZFS_PROP_QUOTA:
1483168404Spjd	case ZFS_PROP_RESERVATION:
1484168404Spjd		*val = getprop_uint64(zhp, prop, source);
1485168404Spjd		if (*val == 0)
1486168404Spjd			*source = "";	/* default */
1487168404Spjd		else
1488168404Spjd			*source = zhp->zfs_name;
1489168404Spjd		break;
1490168404Spjd
1491168404Spjd	case ZFS_PROP_MOUNTED:
1492168404Spjd		*val = (zhp->zfs_mntopts != NULL);
1493168404Spjd		break;
1494168404Spjd
1495168404Spjd	case ZFS_PROP_NUMCLONES:
1496168404Spjd		*val = zhp->zfs_dmustats.dds_num_clones;
1497168404Spjd		break;
1498168404Spjd
1499168404Spjd	default:
1500168404Spjd		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
1501168404Spjd		    "cannot get non-numeric property"));
1502168404Spjd		return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
1503168404Spjd		    dgettext(TEXT_DOMAIN, "internal error")));
1504168404Spjd	}
1505168404Spjd
1506168404Spjd	return (0);
1507168404Spjd}
1508168404Spjd
1509168404Spjd/*
1510168404Spjd * Calculate the source type, given the raw source string.
1511168404Spjd */
1512168404Spjdstatic void
1513168404Spjdget_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source,
1514168404Spjd    char *statbuf, size_t statlen)
1515168404Spjd{
1516168404Spjd	if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY)
1517168404Spjd		return;
1518168404Spjd
1519168404Spjd	if (source == NULL) {
1520168404Spjd		*srctype = ZFS_SRC_NONE;
1521168404Spjd	} else if (source[0] == '\0') {
1522168404Spjd		*srctype = ZFS_SRC_DEFAULT;
1523168404Spjd	} else {
1524168404Spjd		if (strcmp(source, zhp->zfs_name) == 0) {
1525168404Spjd			*srctype = ZFS_SRC_LOCAL;
1526168404Spjd		} else {
1527168404Spjd			(void) strlcpy(statbuf, source, statlen);
1528168404Spjd			*srctype = ZFS_SRC_INHERITED;
1529168404Spjd		}
1530168404Spjd	}
1531168404Spjd
1532168404Spjd}
1533168404Spjd
1534168404Spjd/*
1535168404Spjd * Retrieve a property from the given object.  If 'literal' is specified, then
1536168404Spjd * numbers are left as exact values.  Otherwise, numbers are converted to a
1537168404Spjd * human-readable form.
1538168404Spjd *
1539168404Spjd * Returns 0 on success, or -1 on error.
1540168404Spjd */
1541168404Spjdint
1542168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
1543168404Spjd    zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
1544168404Spjd{
1545168404Spjd	char *source = NULL;
1546168404Spjd	uint64_t val;
1547168404Spjd	char *str;
1548168404Spjd	const char *root;
1549168404Spjd	const char *strval;
1550168404Spjd
1551168404Spjd	/*
1552168404Spjd	 * Check to see if this property applies to our object
1553168404Spjd	 */
1554168404Spjd	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
1555168404Spjd		return (-1);
1556168404Spjd
1557168404Spjd	if (src)
1558168404Spjd		*src = ZFS_SRC_NONE;
1559168404Spjd
1560168404Spjd	switch (prop) {
1561168404Spjd	case ZFS_PROP_ATIME:
1562168404Spjd	case ZFS_PROP_READONLY:
1563168404Spjd	case ZFS_PROP_SETUID:
1564168404Spjd	case ZFS_PROP_ZONED:
1565168404Spjd	case ZFS_PROP_DEVICES:
1566168404Spjd	case ZFS_PROP_EXEC:
1567168404Spjd	case ZFS_PROP_CANMOUNT:
1568168404Spjd	case ZFS_PROP_XATTR:
1569168404Spjd		/*
1570168404Spjd		 * Basic boolean values are built on top of
1571168404Spjd		 * get_numeric_property().
1572168404Spjd		 */
1573168404Spjd		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
1574168404Spjd			return (-1);
1575168404Spjd		nicebool(val, propbuf, proplen);
1576168404Spjd
1577168404Spjd		break;
1578168404Spjd
1579168404Spjd	case ZFS_PROP_AVAILABLE:
1580168404Spjd	case ZFS_PROP_RECORDSIZE:
1581168404Spjd	case ZFS_PROP_CREATETXG:
1582168404Spjd	case ZFS_PROP_REFERENCED:
1583168404Spjd	case ZFS_PROP_USED:
1584168404Spjd	case ZFS_PROP_VOLSIZE:
1585168404Spjd	case ZFS_PROP_VOLBLOCKSIZE:
1586168404Spjd	case ZFS_PROP_NUMCLONES:
1587168404Spjd		/*
1588168404Spjd		 * Basic numeric values are built on top of
1589168404Spjd		 * get_numeric_property().
1590168404Spjd		 */
1591168404Spjd		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
1592168404Spjd			return (-1);
1593168404Spjd		if (literal)
1594168404Spjd			(void) snprintf(propbuf, proplen, "%llu",
1595168404Spjd			    (u_longlong_t)val);
1596168404Spjd		else
1597168404Spjd			zfs_nicenum(val, propbuf, proplen);
1598168404Spjd		break;
1599168404Spjd
1600168404Spjd	case ZFS_PROP_COMPRESSION:
1601168404Spjd	case ZFS_PROP_CHECKSUM:
1602168404Spjd	case ZFS_PROP_SNAPDIR:
1603168404Spjd#ifdef	ZFS_NO_ACL
1604168404Spjd	case ZFS_PROP_ACLMODE:
1605168404Spjd	case ZFS_PROP_ACLINHERIT:
1606168404Spjd	case ZFS_PROP_COPIES:
1607168404Spjd		val = getprop_uint64(zhp, prop, &source);
1608168404Spjd		verify(zfs_prop_index_to_string(prop, val, &strval) == 0);
1609168404Spjd		(void) strlcpy(propbuf, strval, proplen);
1610168404Spjd		break;
1611168404Spjd#else	/* ZFS_NO_ACL */
1612168404Spjd	case ZFS_PROP_ACLMODE:
1613168404Spjd	case ZFS_PROP_ACLINHERIT:
1614168404Spjd		(void) strlcpy(propbuf, "<unsupported>", proplen);
1615168404Spjd		break;
1616168404Spjd#endif	/* ZFS_NO_ACL */
1617168404Spjd
1618168404Spjd	case ZFS_PROP_CREATION:
1619168404Spjd		/*
1620168404Spjd		 * 'creation' is a time_t stored in the statistics.  We convert
1621168404Spjd		 * this into a string unless 'literal' is specified.
1622168404Spjd		 */
1623168404Spjd		{
1624168404Spjd			val = getprop_uint64(zhp, prop, &source);
1625168404Spjd			time_t time = (time_t)val;
1626168404Spjd			struct tm t;
1627168404Spjd
1628168404Spjd			if (literal ||
1629168404Spjd			    localtime_r(&time, &t) == NULL ||
1630168404Spjd			    strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
1631168404Spjd			    &t) == 0)
1632168404Spjd				(void) snprintf(propbuf, proplen, "%llu", val);
1633168404Spjd		}
1634168404Spjd		break;
1635168404Spjd
1636168404Spjd	case ZFS_PROP_MOUNTPOINT:
1637168404Spjd		/*
1638168404Spjd		 * Getting the precise mountpoint can be tricky.
1639168404Spjd		 *
1640168404Spjd		 *  - for 'none' or 'legacy', return those values.
1641168404Spjd		 *  - for default mountpoints, construct it as /zfs/<dataset>
1642168404Spjd		 *  - for inherited mountpoints, we want to take everything
1643168404Spjd		 *    after our ancestor and append it to the inherited value.
1644168404Spjd		 *
1645168404Spjd		 * If the pool has an alternate root, we want to prepend that
1646168404Spjd		 * root to any values we return.
1647168404Spjd		 */
1648168404Spjd		root = zhp->zfs_root;
1649168404Spjd		str = getprop_string(zhp, prop, &source);
1650168404Spjd
1651168404Spjd		if (str[0] == '\0') {
1652168404Spjd			(void) snprintf(propbuf, proplen, "%s/zfs/%s",
1653168404Spjd			    root, zhp->zfs_name);
1654168404Spjd		} else if (str[0] == '/') {
1655168404Spjd			const char *relpath = zhp->zfs_name + strlen(source);
1656168404Spjd
1657168404Spjd			if (relpath[0] == '/')
1658168404Spjd				relpath++;
1659168404Spjd			if (str[1] == '\0')
1660168404Spjd				str++;
1661168404Spjd
1662168404Spjd			if (relpath[0] == '\0')
1663168404Spjd				(void) snprintf(propbuf, proplen, "%s%s",
1664168404Spjd				    root, str);
1665168404Spjd			else
1666168404Spjd				(void) snprintf(propbuf, proplen, "%s%s%s%s",
1667168404Spjd				    root, str, relpath[0] == '@' ? "" : "/",
1668168404Spjd				    relpath);
1669168404Spjd		} else {
1670168404Spjd			/* 'legacy' or 'none' */
1671168404Spjd			(void) strlcpy(propbuf, str, proplen);
1672168404Spjd		}
1673168404Spjd
1674168404Spjd		break;
1675168404Spjd
1676168404Spjd	case ZFS_PROP_SHARENFS:
1677168404Spjd	case ZFS_PROP_SHAREISCSI:
1678168404Spjd	case ZFS_PROP_ISCSIOPTIONS:
1679168404Spjd		(void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
1680168404Spjd		    proplen);
1681168404Spjd		break;
1682168404Spjd
1683168404Spjd	case ZFS_PROP_ORIGIN:
1684168404Spjd		(void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
1685168404Spjd		    proplen);
1686168404Spjd		/*
1687168404Spjd		 * If there is no parent at all, return failure to indicate that
1688168404Spjd		 * it doesn't apply to this dataset.
1689168404Spjd		 */
1690168404Spjd		if (propbuf[0] == '\0')
1691168404Spjd			return (-1);
1692168404Spjd		break;
1693168404Spjd
1694168404Spjd	case ZFS_PROP_QUOTA:
1695168404Spjd	case ZFS_PROP_RESERVATION:
1696168404Spjd		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
1697168404Spjd			return (-1);
1698168404Spjd
1699168404Spjd		/*
1700168404Spjd		 * If quota or reservation is 0, we translate this into 'none'
1701168404Spjd		 * (unless literal is set), and indicate that it's the default
1702168404Spjd		 * value.  Otherwise, we print the number nicely and indicate
1703168404Spjd		 * that its set locally.
1704168404Spjd		 */
1705168404Spjd		if (val == 0) {
1706168404Spjd			if (literal)
1707168404Spjd				(void) strlcpy(propbuf, "0", proplen);
1708168404Spjd			else
1709168404Spjd				(void) strlcpy(propbuf, "none", proplen);
1710168404Spjd		} else {
1711168404Spjd			if (literal)
1712168404Spjd				(void) snprintf(propbuf, proplen, "%llu",
1713168404Spjd				    (u_longlong_t)val);
1714168404Spjd			else
1715168404Spjd				zfs_nicenum(val, propbuf, proplen);
1716168404Spjd		}
1717168404Spjd		break;
1718168404Spjd
1719168404Spjd	case ZFS_PROP_COMPRESSRATIO:
1720168404Spjd		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
1721168404Spjd			return (-1);
1722168404Spjd		(void) snprintf(propbuf, proplen, "%lld.%02lldx", (longlong_t)
1723168404Spjd		    val / 100, (longlong_t)val % 100);
1724168404Spjd		break;
1725168404Spjd
1726168404Spjd	case ZFS_PROP_TYPE:
1727168404Spjd		switch (zhp->zfs_type) {
1728168404Spjd		case ZFS_TYPE_FILESYSTEM:
1729168404Spjd			str = "filesystem";
1730168404Spjd			break;
1731168404Spjd		case ZFS_TYPE_VOLUME:
1732168404Spjd			str = "volume";
1733168404Spjd			break;
1734168404Spjd		case ZFS_TYPE_SNAPSHOT:
1735168404Spjd			str = "snapshot";
1736168404Spjd			break;
1737168404Spjd		default:
1738168404Spjd			abort();
1739168404Spjd		}
1740168404Spjd		(void) snprintf(propbuf, proplen, "%s", str);
1741168404Spjd		break;
1742168404Spjd
1743168404Spjd	case ZFS_PROP_MOUNTED:
1744168404Spjd		/*
1745168404Spjd		 * The 'mounted' property is a pseudo-property that described
1746168404Spjd		 * whether the filesystem is currently mounted.  Even though
1747168404Spjd		 * it's a boolean value, the typical values of "on" and "off"
1748168404Spjd		 * don't make sense, so we translate to "yes" and "no".
1749168404Spjd		 */
1750168404Spjd		if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
1751168404Spjd		    src, &source, &val) != 0)
1752168404Spjd			return (-1);
1753168404Spjd		if (val)
1754168404Spjd			(void) strlcpy(propbuf, "yes", proplen);
1755168404Spjd		else
1756168404Spjd			(void) strlcpy(propbuf, "no", proplen);
1757168404Spjd		break;
1758168404Spjd
1759168404Spjd	case ZFS_PROP_NAME:
1760168404Spjd		/*
1761168404Spjd		 * The 'name' property is a pseudo-property derived from the
1762168404Spjd		 * dataset name.  It is presented as a real property to simplify
1763168404Spjd		 * consumers.
1764168404Spjd		 */
1765168404Spjd		(void) strlcpy(propbuf, zhp->zfs_name, proplen);
1766168404Spjd		break;
1767168404Spjd
1768168404Spjd	default:
1769168404Spjd		abort();
1770168404Spjd	}
1771168404Spjd
1772168404Spjd	get_source(zhp, src, source, statbuf, statlen);
1773168404Spjd
1774168404Spjd	return (0);
1775168404Spjd}
1776168404Spjd
1777168404Spjd/*
1778168404Spjd * Utility function to get the given numeric property.  Does no validation that
1779168404Spjd * the given property is the appropriate type; should only be used with
1780168404Spjd * hard-coded property types.
1781168404Spjd */
1782168404Spjduint64_t
1783168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
1784168404Spjd{
1785168404Spjd	char *source;
1786168404Spjd	zfs_source_t sourcetype = ZFS_SRC_NONE;
1787168404Spjd	uint64_t val;
1788168404Spjd
1789168404Spjd	(void) get_numeric_property(zhp, prop, &sourcetype, &source, &val);
1790168404Spjd
1791168404Spjd	return (val);
1792168404Spjd}
1793168404Spjd
1794168404Spjd/*
1795168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer.
1796168404Spjd */
1797168404Spjdint
1798168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
1799168404Spjd    zfs_source_t *src, char *statbuf, size_t statlen)
1800168404Spjd{
1801168404Spjd	char *source;
1802168404Spjd
1803168404Spjd	/*
1804168404Spjd	 * Check to see if this property applies to our object
1805168404Spjd	 */
1806168404Spjd	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
1807168404Spjd		return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
1808168404Spjd		    dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
1809168404Spjd		    zfs_prop_to_name(prop)));
1810168404Spjd
1811168404Spjd	if (src)
1812168404Spjd		*src = ZFS_SRC_NONE;
1813168404Spjd
1814168404Spjd	if (get_numeric_property(zhp, prop, src, &source, value) != 0)
1815168404Spjd		return (-1);
1816168404Spjd
1817168404Spjd	get_source(zhp, src, source, statbuf, statlen);
1818168404Spjd
1819168404Spjd	return (0);
1820168404Spjd}
1821168404Spjd
1822168404Spjd/*
1823168404Spjd * Returns the name of the given zfs handle.
1824168404Spjd */
1825168404Spjdconst char *
1826168404Spjdzfs_get_name(const zfs_handle_t *zhp)
1827168404Spjd{
1828168404Spjd	return (zhp->zfs_name);
1829168404Spjd}
1830168404Spjd
1831168404Spjd/*
1832168404Spjd * Returns the type of the given zfs handle.
1833168404Spjd */
1834168404Spjdzfs_type_t
1835168404Spjdzfs_get_type(const zfs_handle_t *zhp)
1836168404Spjd{
1837168404Spjd	return (zhp->zfs_type);
1838168404Spjd}
1839168404Spjd
1840168404Spjd/*
1841168404Spjd * Iterate over all child filesystems
1842168404Spjd */
1843168404Spjdint
1844168404Spjdzfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
1845168404Spjd{
1846168404Spjd	zfs_cmd_t zc = { 0 };
1847168404Spjd	zfs_handle_t *nzhp;
1848168404Spjd	int ret;
1849168404Spjd
1850168404Spjd	for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1851168404Spjd	    ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
1852168404Spjd	    (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
1853168404Spjd		/*
1854168404Spjd		 * Ignore private dataset names.
1855168404Spjd		 */
1856168404Spjd		if (dataset_name_hidden(zc.zc_name))
1857168404Spjd			continue;
1858168404Spjd
1859168404Spjd		/*
1860168404Spjd		 * Silently ignore errors, as the only plausible explanation is
1861168404Spjd		 * that the pool has since been removed.
1862168404Spjd		 */
1863168404Spjd		if ((nzhp = make_dataset_handle(zhp->zfs_hdl,
1864168404Spjd		    zc.zc_name)) == NULL)
1865168404Spjd			continue;
1866168404Spjd
1867168404Spjd		if ((ret = func(nzhp, data)) != 0)
1868168404Spjd			return (ret);
1869168404Spjd	}
1870168404Spjd
1871168404Spjd	/*
1872168404Spjd	 * An errno value of ESRCH indicates normal completion.  If ENOENT is
1873168404Spjd	 * returned, then the underlying dataset has been removed since we
1874168404Spjd	 * obtained the handle.
1875168404Spjd	 */
1876168404Spjd	if (errno != ESRCH && errno != ENOENT)
1877168404Spjd		return (zfs_standard_error(zhp->zfs_hdl, errno,
1878168404Spjd		    dgettext(TEXT_DOMAIN, "cannot iterate filesystems")));
1879168404Spjd
1880168404Spjd	return (0);
1881168404Spjd}
1882168404Spjd
1883168404Spjd/*
1884168404Spjd * Iterate over all snapshots
1885168404Spjd */
1886168404Spjdint
1887168404Spjdzfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
1888168404Spjd{
1889168404Spjd	zfs_cmd_t zc = { 0 };
1890168404Spjd	zfs_handle_t *nzhp;
1891168404Spjd	int ret;
1892168404Spjd
1893168404Spjd	for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1894168404Spjd	    ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT,
1895168404Spjd	    &zc) == 0;
1896168404Spjd	    (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) {
1897168404Spjd
1898168404Spjd		if ((nzhp = make_dataset_handle(zhp->zfs_hdl,
1899168404Spjd		    zc.zc_name)) == NULL)
1900168404Spjd			continue;
1901168404Spjd
1902168404Spjd		if ((ret = func(nzhp, data)) != 0)
1903168404Spjd			return (ret);
1904168404Spjd	}
1905168404Spjd
1906168404Spjd	/*
1907168404Spjd	 * An errno value of ESRCH indicates normal completion.  If ENOENT is
1908168404Spjd	 * returned, then the underlying dataset has been removed since we
1909168404Spjd	 * obtained the handle.  Silently ignore this case, and return success.
1910168404Spjd	 */
1911168404Spjd	if (errno != ESRCH && errno != ENOENT)
1912168404Spjd		return (zfs_standard_error(zhp->zfs_hdl, errno,
1913168404Spjd		    dgettext(TEXT_DOMAIN, "cannot iterate filesystems")));
1914168404Spjd
1915168404Spjd	return (0);
1916168404Spjd}
1917168404Spjd
1918168404Spjd/*
1919168404Spjd * Iterate over all children, snapshots and filesystems
1920168404Spjd */
1921168404Spjdint
1922168404Spjdzfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
1923168404Spjd{
1924168404Spjd	int ret;
1925168404Spjd
1926168404Spjd	if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0)
1927168404Spjd		return (ret);
1928168404Spjd
1929168404Spjd	return (zfs_iter_snapshots(zhp, func, data));
1930168404Spjd}
1931168404Spjd
1932168404Spjd/*
1933168404Spjd * Given a complete name, return just the portion that refers to the parent.
1934168404Spjd * Can return NULL if this is a pool.
1935168404Spjd */
1936168404Spjdstatic int
1937168404Spjdparent_name(const char *path, char *buf, size_t buflen)
1938168404Spjd{
1939168404Spjd	char *loc;
1940168404Spjd
1941168404Spjd	if ((loc = strrchr(path, '/')) == NULL)
1942168404Spjd		return (-1);
1943168404Spjd
1944168404Spjd	(void) strncpy(buf, path, MIN(buflen, loc - path));
1945168404Spjd	buf[loc - path] = '\0';
1946168404Spjd
1947168404Spjd	return (0);
1948168404Spjd}
1949168404Spjd
1950168404Spjd/*
1951168404Spjd * Checks to make sure that the given path has a parent, and that it exists.  We
1952168404Spjd * also fetch the 'zoned' property, which is used to validate property settings
1953168404Spjd * when creating new datasets.
1954168404Spjd */
1955168404Spjdstatic int
1956168404Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned)
1957168404Spjd{
1958168404Spjd	zfs_cmd_t zc = { 0 };
1959168404Spjd	char parent[ZFS_MAXNAMELEN];
1960168404Spjd	char *slash;
1961168404Spjd	zfs_handle_t *zhp;
1962168404Spjd	char errbuf[1024];
1963168404Spjd
1964168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'",
1965168404Spjd	    path);
1966168404Spjd
1967168404Spjd	/* get parent, and check to see if this is just a pool */
1968168404Spjd	if (parent_name(path, parent, sizeof (parent)) != 0) {
1969168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1970168404Spjd		    "missing dataset name"));
1971168404Spjd		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
1972168404Spjd	}
1973168404Spjd
1974168404Spjd	/* check to see if the pool exists */
1975168404Spjd	if ((slash = strchr(parent, '/')) == NULL)
1976168404Spjd		slash = parent + strlen(parent);
1977168404Spjd	(void) strncpy(zc.zc_name, parent, slash - parent);
1978168404Spjd	zc.zc_name[slash - parent] = '\0';
1979168404Spjd	if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
1980168404Spjd	    errno == ENOENT) {
1981168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1982168404Spjd		    "no such pool '%s'"), zc.zc_name);
1983168404Spjd		return (zfs_error(hdl, EZFS_NOENT, errbuf));
1984168404Spjd	}
1985168404Spjd
1986168404Spjd	/* check to see if the parent dataset exists */
1987168404Spjd	if ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
1988168404Spjd		switch (errno) {
1989168404Spjd		case ENOENT:
1990168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1991168404Spjd			    "parent does not exist"));
1992168404Spjd			return (zfs_error(hdl, EZFS_NOENT, errbuf));
1993168404Spjd
1994168404Spjd		default:
1995168404Spjd			return (zfs_standard_error(hdl, errno, errbuf));
1996168404Spjd		}
1997168404Spjd	}
1998168404Spjd
1999168404Spjd	*zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
2000168404Spjd	/* we are in a non-global zone, but parent is in the global zone */
2001168404Spjd	if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) {
2002168404Spjd		(void) zfs_standard_error(hdl, EPERM, errbuf);
2003168404Spjd		zfs_close(zhp);
2004168404Spjd		return (-1);
2005168404Spjd	}
2006168404Spjd
2007168404Spjd	/* make sure parent is a filesystem */
2008168404Spjd	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2009168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2010168404Spjd		    "parent is not a filesystem"));
2011168404Spjd		(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
2012168404Spjd		zfs_close(zhp);
2013168404Spjd		return (-1);
2014168404Spjd	}
2015168404Spjd
2016168404Spjd	zfs_close(zhp);
2017168404Spjd	return (0);
2018168404Spjd}
2019168404Spjd
2020168404Spjd/*
2021168404Spjd * Create a new filesystem or volume.
2022168404Spjd */
2023168404Spjdint
2024168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
2025168404Spjd    nvlist_t *props)
2026168404Spjd{
2027168404Spjd	zfs_cmd_t zc = { 0 };
2028168404Spjd	int ret;
2029168404Spjd	uint64_t size = 0;
2030168404Spjd	uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
2031168404Spjd	char errbuf[1024];
2032168404Spjd	uint64_t zoned;
2033168404Spjd
2034168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2035168404Spjd	    "cannot create '%s'"), path);
2036168404Spjd
2037168404Spjd	/* validate the path, taking care to note the extended error message */
2038168404Spjd	if (!zfs_validate_name(hdl, path, type))
2039168404Spjd		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2040168404Spjd
2041168404Spjd	/* validate parents exist */
2042168404Spjd	if (check_parents(hdl, path, &zoned) != 0)
2043168404Spjd		return (-1);
2044168404Spjd
2045168404Spjd	/*
2046168404Spjd	 * The failure modes when creating a dataset of a different type over
2047168404Spjd	 * one that already exists is a little strange.  In particular, if you
2048168404Spjd	 * try to create a dataset on top of an existing dataset, the ioctl()
2049168404Spjd	 * will return ENOENT, not EEXIST.  To prevent this from happening, we
2050168404Spjd	 * first try to see if the dataset exists.
2051168404Spjd	 */
2052168404Spjd	(void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name));
2053168404Spjd	if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) {
2054168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2055168404Spjd		    "dataset already exists"));
2056168404Spjd		return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2057168404Spjd	}
2058168404Spjd
2059168404Spjd	if (type == ZFS_TYPE_VOLUME)
2060168404Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
2061168404Spjd	else
2062168404Spjd		zc.zc_objset_type = DMU_OST_ZFS;
2063168404Spjd
2064168404Spjd	if (props && (props = zfs_validate_properties(hdl, type, NULL, props,
2065168404Spjd	    zoned, NULL, errbuf)) == 0)
2066168404Spjd		return (-1);
2067168404Spjd
2068168404Spjd	if (type == ZFS_TYPE_VOLUME) {
2069168404Spjd		/*
2070168404Spjd		 * If we are creating a volume, the size and block size must
2071168404Spjd		 * satisfy a few restraints.  First, the blocksize must be a
2072168404Spjd		 * valid block size between SPA_{MIN,MAX}BLOCKSIZE.  Second, the
2073168404Spjd		 * volsize must be a multiple of the block size, and cannot be
2074168404Spjd		 * zero.
2075168404Spjd		 */
2076168404Spjd		if (props == NULL || nvlist_lookup_uint64(props,
2077168404Spjd		    zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
2078168404Spjd			nvlist_free(props);
2079168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2080168404Spjd			    "missing volume size"));
2081168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2082168404Spjd		}
2083168404Spjd
2084168404Spjd		if ((ret = nvlist_lookup_uint64(props,
2085168404Spjd		    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
2086168404Spjd		    &blocksize)) != 0) {
2087168404Spjd			if (ret == ENOENT) {
2088168404Spjd				blocksize = zfs_prop_default_numeric(
2089168404Spjd				    ZFS_PROP_VOLBLOCKSIZE);
2090168404Spjd			} else {
2091168404Spjd				nvlist_free(props);
2092168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2093168404Spjd				    "missing volume block size"));
2094168404Spjd				return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2095168404Spjd			}
2096168404Spjd		}
2097168404Spjd
2098168404Spjd		if (size == 0) {
2099168404Spjd			nvlist_free(props);
2100168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2101168404Spjd			    "volume size cannot be zero"));
2102168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2103168404Spjd		}
2104168404Spjd
2105168404Spjd		if (size % blocksize != 0) {
2106168404Spjd			nvlist_free(props);
2107168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2108168404Spjd			    "volume size must be a multiple of volume block "
2109168404Spjd			    "size"));
2110168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2111168404Spjd		}
2112168404Spjd	}
2113168404Spjd
2114168404Spjd	if (props &&
2115168404Spjd	    zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0)
2116168404Spjd		return (-1);
2117168404Spjd	nvlist_free(props);
2118168404Spjd
2119168404Spjd	/* create the dataset */
2120168404Spjd	ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
2121168404Spjd
2122168404Spjd	if (ret == 0 && type == ZFS_TYPE_VOLUME) {
2123168404Spjd		ret = zvol_create_link(hdl, path);
2124168404Spjd		if (ret) {
2125168404Spjd			(void) zfs_standard_error(hdl, errno,
2126168404Spjd			    dgettext(TEXT_DOMAIN,
2127168404Spjd			    "Volume successfully created, but device links "
2128168404Spjd			    "were not created"));
2129168404Spjd			zcmd_free_nvlists(&zc);
2130168404Spjd			return (-1);
2131168404Spjd		}
2132168404Spjd	}
2133168404Spjd
2134168404Spjd	zcmd_free_nvlists(&zc);
2135168404Spjd
2136168404Spjd	/* check for failure */
2137168404Spjd	if (ret != 0) {
2138168404Spjd		char parent[ZFS_MAXNAMELEN];
2139168404Spjd		(void) parent_name(path, parent, sizeof (parent));
2140168404Spjd
2141168404Spjd		switch (errno) {
2142168404Spjd		case ENOENT:
2143168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2144168404Spjd			    "no such parent '%s'"), parent);
2145168404Spjd			return (zfs_error(hdl, EZFS_NOENT, errbuf));
2146168404Spjd
2147168404Spjd		case EINVAL:
2148168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2149168404Spjd			    "parent '%s' is not a filesystem"), parent);
2150168404Spjd			return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2151168404Spjd
2152168404Spjd		case EDOM:
2153168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2154168404Spjd			    "volume block size must be power of 2 from "
2155168404Spjd			    "%u to %uk"),
2156168404Spjd			    (uint_t)SPA_MINBLOCKSIZE,
2157168404Spjd			    (uint_t)SPA_MAXBLOCKSIZE >> 10);
2158168404Spjd
2159168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
2160168404Spjd
2161168404Spjd#ifdef _ILP32
2162168404Spjd		case EOVERFLOW:
2163168404Spjd			/*
2164168404Spjd			 * This platform can't address a volume this big.
2165168404Spjd			 */
2166168404Spjd			if (type == ZFS_TYPE_VOLUME)
2167168404Spjd				return (zfs_error(hdl, EZFS_VOLTOOBIG,
2168168404Spjd				    errbuf));
2169168404Spjd#endif
2170168404Spjd			/* FALLTHROUGH */
2171168404Spjd		default:
2172168404Spjd			return (zfs_standard_error(hdl, errno, errbuf));
2173168404Spjd		}
2174168404Spjd	}
2175168404Spjd
2176168404Spjd	return (0);
2177168404Spjd}
2178168404Spjd
2179168404Spjd/*
2180168404Spjd * Destroys the given dataset.  The caller must make sure that the filesystem
2181168404Spjd * isn't mounted, and that there are no active dependents.
2182168404Spjd */
2183168404Spjdint
2184168404Spjdzfs_destroy(zfs_handle_t *zhp)
2185168404Spjd{
2186168404Spjd	zfs_cmd_t zc = { 0 };
2187168404Spjd
2188168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2189168404Spjd
2190168404Spjd	if (ZFS_IS_VOLUME(zhp)) {
2191168404Spjd		/*
2192168404Spjd		 * Unconditionally unshare this zvol ignoring failure as it
2193168404Spjd		 * indicates only that the volume wasn't shared initially.
2194168404Spjd		 */
2195168404Spjd		(void) zfs_unshare_iscsi(zhp);
2196168404Spjd
2197168404Spjd		if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0)
2198168404Spjd			return (-1);
2199168404Spjd
2200168404Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
2201168404Spjd	} else {
2202168404Spjd		zc.zc_objset_type = DMU_OST_ZFS;
2203168404Spjd	}
2204168404Spjd
2205168404Spjd	if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) {
2206168404Spjd		return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
2207168404Spjd		    dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
2208168404Spjd		    zhp->zfs_name));
2209168404Spjd	}
2210168404Spjd
2211168404Spjd	remove_mountpoint(zhp);
2212168404Spjd
2213168404Spjd	return (0);
2214168404Spjd}
2215168404Spjd
2216168404Spjdstruct destroydata {
2217168404Spjd	char *snapname;
2218168404Spjd	boolean_t gotone;
2219168404Spjd	boolean_t closezhp;
2220168404Spjd};
2221168404Spjd
2222168404Spjdstatic int
2223168404Spjdzfs_remove_link_cb(zfs_handle_t *zhp, void *arg)
2224168404Spjd{
2225168404Spjd	struct destroydata *dd = arg;
2226168404Spjd	zfs_handle_t *szhp;
2227168404Spjd	char name[ZFS_MAXNAMELEN];
2228168404Spjd	boolean_t closezhp = dd->closezhp;
2229168404Spjd	int rv;
2230168404Spjd
2231168404Spjd	(void) strlcpy(name, zhp->zfs_name, sizeof (name));
2232168404Spjd	(void) strlcat(name, "@", sizeof (name));
2233168404Spjd	(void) strlcat(name, dd->snapname, sizeof (name));
2234168404Spjd
2235168404Spjd	szhp = make_dataset_handle(zhp->zfs_hdl, name);
2236168404Spjd	if (szhp) {
2237168404Spjd		dd->gotone = B_TRUE;
2238168404Spjd		zfs_close(szhp);
2239168404Spjd	}
2240168404Spjd
2241168404Spjd	if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
2242168404Spjd		(void) zvol_remove_link(zhp->zfs_hdl, name);
2243168404Spjd		/*
2244168404Spjd		 * NB: this is simply a best-effort.  We don't want to
2245168404Spjd		 * return an error, because then we wouldn't visit all
2246168404Spjd		 * the volumes.
2247168404Spjd		 */
2248168404Spjd	}
2249168404Spjd
2250168404Spjd	dd->closezhp = B_TRUE;
2251168404Spjd	rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg);
2252168404Spjd	if (closezhp)
2253168404Spjd		zfs_close(zhp);
2254168404Spjd	return (rv);
2255168404Spjd}
2256168404Spjd
2257168404Spjd/*
2258168404Spjd * Destroys all snapshots with the given name in zhp & descendants.
2259168404Spjd */
2260168404Spjdint
2261168404Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname)
2262168404Spjd{
2263168404Spjd	zfs_cmd_t zc = { 0 };
2264168404Spjd	int ret;
2265168404Spjd	struct destroydata dd = { 0 };
2266168404Spjd
2267168404Spjd	dd.snapname = snapname;
2268168404Spjd	(void) zfs_remove_link_cb(zhp, &dd);
2269168404Spjd
2270168404Spjd	if (!dd.gotone) {
2271168404Spjd		return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
2272168404Spjd		    dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
2273168404Spjd		    zhp->zfs_name, snapname));
2274168404Spjd	}
2275168404Spjd
2276168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2277168404Spjd	(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
2278168404Spjd
2279168404Spjd	ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc);
2280168404Spjd	if (ret != 0) {
2281168404Spjd		char errbuf[1024];
2282168404Spjd
2283168404Spjd		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2284168404Spjd		    "cannot destroy '%s@%s'"), zc.zc_name, snapname);
2285168404Spjd
2286168404Spjd		switch (errno) {
2287168404Spjd		case EEXIST:
2288168404Spjd			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
2289168404Spjd			    "snapshot is cloned"));
2290168404Spjd			return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf));
2291168404Spjd
2292168404Spjd		default:
2293168404Spjd			return (zfs_standard_error(zhp->zfs_hdl, errno,
2294168404Spjd			    errbuf));
2295168404Spjd		}
2296168404Spjd	}
2297168404Spjd
2298168404Spjd	return (0);
2299168404Spjd}
2300168404Spjd
2301168404Spjd/*
2302168404Spjd * Clones the given dataset.  The target must be of the same type as the source.
2303168404Spjd */
2304168404Spjdint
2305168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
2306168404Spjd{
2307168404Spjd	zfs_cmd_t zc = { 0 };
2308168404Spjd	char parent[ZFS_MAXNAMELEN];
2309168404Spjd	int ret;
2310168404Spjd	char errbuf[1024];
2311168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
2312168404Spjd	zfs_type_t type;
2313168404Spjd	uint64_t zoned;
2314168404Spjd
2315168404Spjd	assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
2316168404Spjd
2317168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2318168404Spjd	    "cannot create '%s'"), target);
2319168404Spjd
2320168404Spjd	/* validate the target name */
2321168404Spjd	if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM))
2322168404Spjd		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2323168404Spjd
2324168404Spjd	/* validate parents exist */
2325168404Spjd	if (check_parents(hdl, target, &zoned) != 0)
2326168404Spjd		return (-1);
2327168404Spjd
2328168404Spjd	(void) parent_name(target, parent, sizeof (parent));
2329168404Spjd
2330168404Spjd	/* do the clone */
2331168404Spjd	if (ZFS_IS_VOLUME(zhp)) {
2332168404Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
2333168404Spjd		type = ZFS_TYPE_VOLUME;
2334168404Spjd	} else {
2335168404Spjd		zc.zc_objset_type = DMU_OST_ZFS;
2336168404Spjd		type = ZFS_TYPE_FILESYSTEM;
2337168404Spjd	}
2338168404Spjd
2339168404Spjd	if (props) {
2340168404Spjd		if ((props = zfs_validate_properties(hdl, type, NULL, props,
2341168404Spjd		    zoned, zhp, errbuf)) == NULL)
2342168404Spjd			return (-1);
2343168404Spjd
2344168404Spjd		if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) {
2345168404Spjd			nvlist_free(props);
2346168404Spjd			return (-1);
2347168404Spjd		}
2348168404Spjd
2349168404Spjd		nvlist_free(props);
2350168404Spjd	}
2351168404Spjd
2352168404Spjd	(void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
2353168404Spjd	(void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value));
2354168404Spjd	ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
2355168404Spjd
2356168404Spjd	zcmd_free_nvlists(&zc);
2357168404Spjd
2358168404Spjd	if (ret != 0) {
2359168404Spjd		switch (errno) {
2360168404Spjd
2361168404Spjd		case ENOENT:
2362168404Spjd			/*
2363168404Spjd			 * The parent doesn't exist.  We should have caught this
2364168404Spjd			 * above, but there may a race condition that has since
2365168404Spjd			 * destroyed the parent.
2366168404Spjd			 *
2367168404Spjd			 * At this point, we don't know whether it's the source
2368168404Spjd			 * that doesn't exist anymore, or whether the target
2369168404Spjd			 * dataset doesn't exist.
2370168404Spjd			 */
2371168404Spjd			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
2372168404Spjd			    "no such parent '%s'"), parent);
2373168404Spjd			return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
2374168404Spjd
2375168404Spjd		case EXDEV:
2376168404Spjd			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
2377168404Spjd			    "source and target pools differ"));
2378168404Spjd			return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
2379168404Spjd			    errbuf));
2380168404Spjd
2381168404Spjd		default:
2382168404Spjd			return (zfs_standard_error(zhp->zfs_hdl, errno,
2383168404Spjd			    errbuf));
2384168404Spjd		}
2385168404Spjd	} else if (ZFS_IS_VOLUME(zhp)) {
2386168404Spjd		ret = zvol_create_link(zhp->zfs_hdl, target);
2387168404Spjd	}
2388168404Spjd
2389168404Spjd	return (ret);
2390168404Spjd}
2391168404Spjd
2392168404Spjdtypedef struct promote_data {
2393168404Spjd	char cb_mountpoint[MAXPATHLEN];
2394168404Spjd	const char *cb_target;
2395168404Spjd	const char *cb_errbuf;
2396168404Spjd	uint64_t cb_pivot_txg;
2397168404Spjd} promote_data_t;
2398168404Spjd
2399168404Spjdstatic int
2400168404Spjdpromote_snap_cb(zfs_handle_t *zhp, void *data)
2401168404Spjd{
2402168404Spjd	promote_data_t *pd = data;
2403168404Spjd	zfs_handle_t *szhp;
2404168404Spjd	char snapname[MAXPATHLEN];
2405168404Spjd	int rv = 0;
2406168404Spjd
2407168404Spjd	/* We don't care about snapshots after the pivot point */
2408168404Spjd	if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) {
2409168404Spjd		zfs_close(zhp);
2410168404Spjd		return (0);
2411168404Spjd	}
2412168404Spjd
2413168404Spjd	/* Remove the device link if it's a zvol. */
2414168404Spjd	if (ZFS_IS_VOLUME(zhp))
2415168404Spjd		(void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name);
2416168404Spjd
2417168404Spjd	/* Check for conflicting names */
2418168404Spjd	(void) strlcpy(snapname, pd->cb_target, sizeof (snapname));
2419168404Spjd	(void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname));
2420168404Spjd	szhp = make_dataset_handle(zhp->zfs_hdl, snapname);
2421168404Spjd	if (szhp != NULL) {
2422168404Spjd		zfs_close(szhp);
2423168404Spjd		zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
2424168404Spjd		    "snapshot name '%s' from origin \n"
2425168404Spjd		    "conflicts with '%s' from target"),
2426168404Spjd		    zhp->zfs_name, snapname);
2427168404Spjd		rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf);
2428168404Spjd	}
2429168404Spjd	zfs_close(zhp);
2430168404Spjd	return (rv);
2431168404Spjd}
2432168404Spjd
2433168404Spjdstatic int
2434168404Spjdpromote_snap_done_cb(zfs_handle_t *zhp, void *data)
2435168404Spjd{
2436168404Spjd	promote_data_t *pd = data;
2437168404Spjd
2438168404Spjd	/* We don't care about snapshots after the pivot point */
2439168404Spjd	if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) {
2440168404Spjd		/* Create the device link if it's a zvol. */
2441168404Spjd		if (ZFS_IS_VOLUME(zhp))
2442168404Spjd			(void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
2443168404Spjd	}
2444168404Spjd
2445168404Spjd	zfs_close(zhp);
2446168404Spjd	return (0);
2447168404Spjd}
2448168404Spjd
2449168404Spjd/*
2450168404Spjd * Promotes the given clone fs to be the clone parent.
2451168404Spjd */
2452168404Spjdint
2453168404Spjdzfs_promote(zfs_handle_t *zhp)
2454168404Spjd{
2455168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
2456168404Spjd	zfs_cmd_t zc = { 0 };
2457168404Spjd	char parent[MAXPATHLEN];
2458168404Spjd	char *cp;
2459168404Spjd	int ret;
2460168404Spjd	zfs_handle_t *pzhp;
2461168404Spjd	promote_data_t pd;
2462168404Spjd	char errbuf[1024];
2463168404Spjd
2464168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2465168404Spjd	    "cannot promote '%s'"), zhp->zfs_name);
2466168404Spjd
2467168404Spjd	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
2468168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2469168404Spjd		    "snapshots can not be promoted"));
2470168404Spjd		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2471168404Spjd	}
2472168404Spjd
2473168404Spjd	(void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent));
2474168404Spjd	if (parent[0] == '\0') {
2475168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2476168404Spjd		    "not a cloned filesystem"));
2477168404Spjd		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
2478168404Spjd	}
2479168404Spjd	cp = strchr(parent, '@');
2480168404Spjd	*cp = '\0';
2481168404Spjd
2482168404Spjd	/* Walk the snapshots we will be moving */
2483168404Spjd	pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT);
2484168404Spjd	if (pzhp == NULL)
2485168404Spjd		return (-1);
2486168404Spjd	pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG);
2487168404Spjd	zfs_close(pzhp);
2488168404Spjd	pd.cb_target = zhp->zfs_name;
2489168404Spjd	pd.cb_errbuf = errbuf;
2490168404Spjd	pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY);
2491168404Spjd	if (pzhp == NULL)
2492168404Spjd		return (-1);
2493168404Spjd	(void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint,
2494168404Spjd	    sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE);
2495168404Spjd	ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd);
2496168404Spjd	if (ret != 0) {
2497168404Spjd		zfs_close(pzhp);
2498168404Spjd		return (-1);
2499168404Spjd	}
2500168404Spjd
2501168404Spjd	/* issue the ioctl */
2502168404Spjd	(void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of,
2503168404Spjd	    sizeof (zc.zc_value));
2504168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2505168404Spjd	ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc);
2506168404Spjd
2507168404Spjd	if (ret != 0) {
2508168404Spjd		int save_errno = errno;
2509168404Spjd
2510168404Spjd		(void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd);
2511168404Spjd		zfs_close(pzhp);
2512168404Spjd
2513168404Spjd		switch (save_errno) {
2514168404Spjd		case EEXIST:
2515168404Spjd			/*
2516168404Spjd			 * There is a conflicting snapshot name.  We
2517168404Spjd			 * should have caught this above, but they could
2518168404Spjd			 * have renamed something in the mean time.
2519168404Spjd			 */
2520168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2521168404Spjd			    "conflicting snapshot name from parent '%s'"),
2522168404Spjd			    parent);
2523168404Spjd			return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2524168404Spjd
2525168404Spjd		default:
2526168404Spjd			return (zfs_standard_error(hdl, save_errno, errbuf));
2527168404Spjd		}
2528168404Spjd	} else {
2529168404Spjd		(void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd);
2530168404Spjd	}
2531168404Spjd
2532168404Spjd	zfs_close(pzhp);
2533168404Spjd	return (ret);
2534168404Spjd}
2535168404Spjd
2536168676Spjdstruct createdata {
2537168676Spjd	const char *cd_snapname;
2538168676Spjd	int cd_ifexists;
2539168676Spjd};
2540168676Spjd
2541168404Spjdstatic int
2542168404Spjdzfs_create_link_cb(zfs_handle_t *zhp, void *arg)
2543168404Spjd{
2544168676Spjd	struct createdata *cd = arg;
2545168404Spjd	int ret;
2546168404Spjd
2547168404Spjd	if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
2548168404Spjd		char name[MAXPATHLEN];
2549168404Spjd
2550168404Spjd		(void) strlcpy(name, zhp->zfs_name, sizeof (name));
2551168404Spjd		(void) strlcat(name, "@", sizeof (name));
2552168676Spjd		(void) strlcat(name, cd->cd_snapname, sizeof (name));
2553168676Spjd		(void) zvol_create_link_common(zhp->zfs_hdl, name,
2554168676Spjd		    cd->cd_ifexists);
2555168404Spjd		/*
2556168404Spjd		 * NB: this is simply a best-effort.  We don't want to
2557168404Spjd		 * return an error, because then we wouldn't visit all
2558168404Spjd		 * the volumes.
2559168404Spjd		 */
2560168404Spjd	}
2561168404Spjd
2562168676Spjd	ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, cd);
2563168404Spjd
2564168404Spjd	zfs_close(zhp);
2565168404Spjd
2566168404Spjd	return (ret);
2567168404Spjd}
2568168404Spjd
2569168404Spjd/*
2570168404Spjd * Takes a snapshot of the given dataset.
2571168404Spjd */
2572168404Spjdint
2573168404Spjdzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
2574168404Spjd{
2575168404Spjd	const char *delim;
2576168404Spjd	char *parent;
2577168404Spjd	zfs_handle_t *zhp;
2578168404Spjd	zfs_cmd_t zc = { 0 };
2579168404Spjd	int ret;
2580168404Spjd	char errbuf[1024];
2581168404Spjd
2582168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2583168404Spjd	    "cannot snapshot '%s'"), path);
2584168404Spjd
2585168404Spjd	/* validate the target name */
2586168404Spjd	if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT))
2587168404Spjd		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2588168404Spjd
2589168404Spjd	/* make sure the parent exists and is of the appropriate type */
2590168404Spjd	delim = strchr(path, '@');
2591168404Spjd	if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL)
2592168404Spjd		return (-1);
2593168404Spjd	(void) strncpy(parent, path, delim - path);
2594168404Spjd	parent[delim - path] = '\0';
2595168404Spjd
2596168404Spjd	if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM |
2597168404Spjd	    ZFS_TYPE_VOLUME)) == NULL) {
2598168404Spjd		free(parent);
2599168404Spjd		return (-1);
2600168404Spjd	}
2601168404Spjd
2602168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2603168404Spjd	(void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value));
2604168404Spjd	zc.zc_cookie = recursive;
2605168404Spjd	ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc);
2606168404Spjd
2607168404Spjd	/*
2608168404Spjd	 * if it was recursive, the one that actually failed will be in
2609168404Spjd	 * zc.zc_name.
2610168404Spjd	 */
2611168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2612168404Spjd	    "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value);
2613168404Spjd	if (ret == 0 && recursive) {
2614168676Spjd		struct createdata cd;
2615168676Spjd
2616168676Spjd		cd.cd_snapname = delim + 1;
2617168676Spjd		cd.cd_ifexists = B_FALSE;
2618168676Spjd		(void) zfs_iter_filesystems(zhp, zfs_create_link_cb, &cd);
2619168404Spjd	}
2620168404Spjd	if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) {
2621168404Spjd		ret = zvol_create_link(zhp->zfs_hdl, path);
2622168404Spjd		if (ret != 0) {
2623168404Spjd			(void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY,
2624168404Spjd			    &zc);
2625168404Spjd		}
2626168404Spjd	}
2627168404Spjd
2628168404Spjd	if (ret != 0)
2629168404Spjd		(void) zfs_standard_error(hdl, errno, errbuf);
2630168404Spjd
2631168404Spjd	free(parent);
2632168404Spjd	zfs_close(zhp);
2633168404Spjd
2634168404Spjd	return (ret);
2635168404Spjd}
2636168404Spjd
2637168404Spjd/*
2638168404Spjd * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
2639168404Spjd * NULL) to the file descriptor specified by outfd.
2640168404Spjd */
2641168404Spjdint
2642168404Spjdzfs_send(zfs_handle_t *zhp, const char *fromsnap, int outfd)
2643168404Spjd{
2644168404Spjd	zfs_cmd_t zc = { 0 };
2645168404Spjd	char errbuf[1024];
2646168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
2647168404Spjd
2648168404Spjd	assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
2649168404Spjd
2650168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2651168404Spjd	if (fromsnap)
2652168404Spjd		(void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name));
2653168404Spjd	zc.zc_cookie = outfd;
2654168404Spjd
2655168404Spjd	if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc) != 0) {
2656168404Spjd		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2657168404Spjd		    "cannot send '%s'"), zhp->zfs_name);
2658168404Spjd
2659168404Spjd		switch (errno) {
2660168404Spjd
2661168404Spjd		case EXDEV:
2662168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2663168404Spjd			    "not an earlier snapshot from the same fs"));
2664168404Spjd			return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
2665168404Spjd
2666168404Spjd		case EDQUOT:
2667168404Spjd		case EFBIG:
2668168404Spjd		case EIO:
2669168404Spjd		case ENOLINK:
2670168404Spjd		case ENOSPC:
2671168404Spjd		case ENXIO:
2672168404Spjd		case EPIPE:
2673168404Spjd		case ERANGE:
2674168404Spjd		case EFAULT:
2675168404Spjd		case EROFS:
2676168404Spjd			zfs_error_aux(hdl, strerror(errno));
2677168404Spjd			return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
2678168404Spjd
2679168404Spjd		default:
2680168404Spjd			return (zfs_standard_error(hdl, errno, errbuf));
2681168404Spjd		}
2682168404Spjd	}
2683168404Spjd
2684168404Spjd	return (0);
2685168404Spjd}
2686168404Spjd
2687168404Spjd/*
2688168404Spjd * Create ancestors of 'target', but not target itself, and not
2689168404Spjd * ancestors whose names are shorter than prefixlen.  Die if
2690168404Spjd * prefixlen-ancestor does not exist.
2691168404Spjd */
2692168404Spjdstatic int
2693168404Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
2694168404Spjd{
2695168404Spjd	zfs_handle_t *h;
2696168404Spjd	char *cp;
2697168404Spjd
2698168404Spjd	/* make sure prefix exists */
2699168404Spjd	cp = strchr(target + prefixlen, '/');
2700168404Spjd	*cp = '\0';
2701168404Spjd	h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2702168404Spjd	*cp = '/';
2703168404Spjd	if (h == NULL)
2704168404Spjd		return (-1);
2705168404Spjd	zfs_close(h);
2706168404Spjd
2707168404Spjd	/*
2708168404Spjd	 * Attempt to create, mount, and share any ancestor filesystems,
2709168404Spjd	 * up to the prefixlen-long one.
2710168404Spjd	 */
2711168404Spjd	for (cp = target + prefixlen + 1;
2712168404Spjd	    cp = strchr(cp, '/'); *cp = '/', cp++) {
2713168404Spjd		const char *opname;
2714168404Spjd
2715168404Spjd		*cp = '\0';
2716168404Spjd
2717168404Spjd		h = make_dataset_handle(hdl, target);
2718168404Spjd		if (h) {
2719168404Spjd			/* it already exists, nothing to do here */
2720168404Spjd			zfs_close(h);
2721168404Spjd			continue;
2722168404Spjd		}
2723168404Spjd
2724168404Spjd		opname = dgettext(TEXT_DOMAIN, "create");
2725168404Spjd		if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
2726168404Spjd		    NULL) != 0)
2727168404Spjd			goto ancestorerr;
2728168404Spjd
2729168404Spjd		opname = dgettext(TEXT_DOMAIN, "open");
2730168404Spjd		h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2731168404Spjd		if (h == NULL)
2732168404Spjd			goto ancestorerr;
2733168404Spjd
2734168404Spjd		opname = dgettext(TEXT_DOMAIN, "mount");
2735168404Spjd		if (zfs_mount(h, NULL, 0) != 0)
2736168404Spjd			goto ancestorerr;
2737168404Spjd
2738168404Spjd		opname = dgettext(TEXT_DOMAIN, "share");
2739168404Spjd		if (zfs_share(h) != 0)
2740168404Spjd			goto ancestorerr;
2741168404Spjd
2742168404Spjd		zfs_close(h);
2743168404Spjd
2744168404Spjd		continue;
2745168404Spjdancestorerr:
2746168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2747168404Spjd		    "failed to %s ancestor '%s'"), opname, target);
2748168404Spjd		return (-1);
2749168404Spjd	}
2750168404Spjd
2751168404Spjd	return (0);
2752168404Spjd}
2753168404Spjd
2754168404Spjd/*
2755168404Spjd * Restores a backup of tosnap from the file descriptor specified by infd.
2756168404Spjd */
2757168404Spjdint
2758168404Spjdzfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
2759168404Spjd    int verbose, int dryrun, boolean_t force, int infd)
2760168404Spjd{
2761168404Spjd	zfs_cmd_t zc = { 0 };
2762168404Spjd	time_t begin_time;
2763168404Spjd	int ioctl_err, err, bytes, size, choplen;
2764168404Spjd	char *cp;
2765168404Spjd	dmu_replay_record_t drr;
2766168404Spjd	struct drr_begin *drrb = &zc.zc_begin_record;
2767168404Spjd	char errbuf[1024];
2768168404Spjd	prop_changelist_t *clp;
2769168404Spjd	char chopprefix[ZFS_MAXNAMELEN];
2770168404Spjd
2771168404Spjd	begin_time = time(NULL);
2772168404Spjd
2773168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2774168404Spjd	    "cannot receive"));
2775168404Spjd
2776168404Spjd	/* read in the BEGIN record */
2777168404Spjd	cp = (char *)&drr;
2778168404Spjd	bytes = 0;
2779168404Spjd	do {
2780168404Spjd		size = read(infd, cp, sizeof (drr) - bytes);
2781168404Spjd		cp += size;
2782168404Spjd		bytes += size;
2783168404Spjd	} while (size > 0);
2784168404Spjd
2785168404Spjd	if (size < 0 || bytes != sizeof (drr)) {
2786168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
2787168404Spjd		    "stream (failed to read first record)"));
2788168404Spjd		return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2789168404Spjd	}
2790168404Spjd
2791168404Spjd	zc.zc_begin_record = drr.drr_u.drr_begin;
2792168404Spjd
2793168404Spjd	if (drrb->drr_magic != DMU_BACKUP_MAGIC &&
2794168404Spjd	    drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) {
2795168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
2796168404Spjd		    "stream (bad magic number)"));
2797168404Spjd		return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2798168404Spjd	}
2799168404Spjd
2800168404Spjd	if (drrb->drr_version != DMU_BACKUP_VERSION &&
2801168404Spjd	    drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) {
2802168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version "
2803168404Spjd		    "0x%llx is supported (stream is version 0x%llx)"),
2804168404Spjd		    DMU_BACKUP_VERSION, drrb->drr_version);
2805168404Spjd		return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2806168404Spjd	}
2807168404Spjd
2808168404Spjd	if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) {
2809168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
2810168404Spjd		    "stream (bad snapshot name)"));
2811168404Spjd		return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2812168404Spjd	}
2813168404Spjd	/*
2814168404Spjd	 * Determine how much of the snapshot name stored in the stream
2815168404Spjd	 * we are going to tack on to the name they specified on the
2816168404Spjd	 * command line, and how much we are going to chop off.
2817168404Spjd	 *
2818168404Spjd	 * If they specified a snapshot, chop the entire name stored in
2819168404Spjd	 * the stream.
2820168404Spjd	 */
2821168404Spjd	(void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname);
2822168404Spjd	if (isprefix) {
2823168404Spjd		/*
2824168404Spjd		 * They specified a fs with -d, we want to tack on
2825168404Spjd		 * everything but the pool name stored in the stream
2826168404Spjd		 */
2827168404Spjd		if (strchr(tosnap, '@')) {
2828168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
2829168404Spjd			    "argument - snapshot not allowed with -d"));
2830168404Spjd			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2831168404Spjd		}
2832168404Spjd		cp = strchr(chopprefix, '/');
2833168404Spjd		if (cp == NULL)
2834168404Spjd			cp = strchr(chopprefix, '@');
2835168404Spjd		*cp = '\0';
2836168404Spjd	} else if (strchr(tosnap, '@') == NULL) {
2837168404Spjd		/*
2838168404Spjd		 * If they specified a filesystem without -d, we want to
2839168404Spjd		 * tack on everything after the fs specified in the
2840168404Spjd		 * first name from the stream.
2841168404Spjd		 */
2842168404Spjd		cp = strchr(chopprefix, '@');
2843168404Spjd		*cp = '\0';
2844168404Spjd	}
2845168404Spjd	choplen = strlen(chopprefix);
2846168404Spjd
2847168404Spjd	/*
2848168404Spjd	 * Determine name of destination snapshot, store in zc_value.
2849168404Spjd	 */
2850168404Spjd	(void) strcpy(zc.zc_value, tosnap);
2851168404Spjd	(void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen,
2852168404Spjd	    sizeof (zc.zc_value));
2853168404Spjd	if (!zfs_validate_name(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT))
2854168404Spjd		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2855168404Spjd
2856168404Spjd	(void) strcpy(zc.zc_name, zc.zc_value);
2857168404Spjd	if (drrb->drr_fromguid) {
2858168404Spjd		/* incremental backup stream */
2859168404Spjd		zfs_handle_t *h;
2860168404Spjd
2861168404Spjd		/* do the recvbackup ioctl to the containing fs */
2862168404Spjd		*strchr(zc.zc_name, '@') = '\0';
2863168404Spjd
2864168404Spjd		/* make sure destination fs exists */
2865168404Spjd		h = zfs_open(hdl, zc.zc_name,
2866168404Spjd		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
2867168404Spjd		if (h == NULL)
2868168404Spjd			return (-1);
2869168404Spjd		if (!dryrun) {
2870168404Spjd			/*
2871168404Spjd			 * We need to unmount all the dependents of the dataset
2872168404Spjd			 * and the dataset itself. If it's a volume
2873168404Spjd			 * then remove device link.
2874168404Spjd			 */
2875168404Spjd			if (h->zfs_type == ZFS_TYPE_FILESYSTEM) {
2876168404Spjd				clp = changelist_gather(h, ZFS_PROP_NAME, 0);
2877168404Spjd				if (clp == NULL)
2878168404Spjd					return (-1);
2879168404Spjd				if (changelist_prefix(clp) != 0) {
2880168404Spjd					changelist_free(clp);
2881168404Spjd					return (-1);
2882168404Spjd				}
2883168404Spjd			} else {
2884168404Spjd				(void) zvol_remove_link(hdl, h->zfs_name);
2885168404Spjd			}
2886168404Spjd		}
2887168404Spjd		zfs_close(h);
2888168404Spjd	} else {
2889168404Spjd		/* full backup stream */
2890168404Spjd
2891168404Spjd		/* Make sure destination fs does not exist */
2892168404Spjd		*strchr(zc.zc_name, '@') = '\0';
2893168404Spjd		if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) {
2894168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2895168404Spjd			    "destination '%s' exists"), zc.zc_name);
2896168404Spjd			return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2897168404Spjd		}
2898168404Spjd
2899168404Spjd		if (strchr(zc.zc_name, '/') == NULL) {
2900168404Spjd			/*
2901168404Spjd			 * they're trying to do a recv into a
2902168404Spjd			 * nonexistant topmost filesystem.
2903168404Spjd			 */
2904168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2905168404Spjd			    "destination does not exist"), zc.zc_name);
2906168404Spjd			return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2907168404Spjd		}
2908168404Spjd
2909168404Spjd		/* Do the recvbackup ioctl to the fs's parent. */
2910168404Spjd		*strrchr(zc.zc_name, '/') = '\0';
2911168404Spjd
2912168404Spjd		if (isprefix && (err = create_parents(hdl,
2913168404Spjd		    zc.zc_value, strlen(tosnap))) != 0) {
2914168404Spjd			return (zfs_error(hdl, EZFS_BADRESTORE, errbuf));
2915168404Spjd		}
2916168404Spjd
2917168404Spjd	}
2918168404Spjd
2919168404Spjd	zc.zc_cookie = infd;
2920168404Spjd	zc.zc_guid = force;
2921168404Spjd	if (verbose) {
2922168404Spjd		(void) printf("%s %s stream of %s into %s\n",
2923168404Spjd		    dryrun ? "would receive" : "receiving",
2924168404Spjd		    drrb->drr_fromguid ? "incremental" : "full",
2925168404Spjd		    drr.drr_u.drr_begin.drr_toname,
2926168404Spjd		    zc.zc_value);
2927168404Spjd		(void) fflush(stdout);
2928168404Spjd	}
2929168404Spjd	if (dryrun)
2930168404Spjd		return (0);
2931168404Spjd	err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc);
2932168404Spjd	if (ioctl_err != 0) {
2933168404Spjd		switch (errno) {
2934168404Spjd		case ENODEV:
2935168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2936168404Spjd			    "most recent snapshot does not match incremental "
2937168404Spjd			    "source"));
2938168404Spjd			(void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
2939168404Spjd			break;
2940168404Spjd		case ETXTBSY:
2941168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2942168404Spjd			    "destination has been modified since most recent "
2943168404Spjd			    "snapshot"));
2944168404Spjd			(void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
2945168404Spjd			break;
2946168404Spjd		case EEXIST:
2947168404Spjd			if (drrb->drr_fromguid == 0) {
2948168404Spjd				/* it's the containing fs that exists */
2949168404Spjd				cp = strchr(zc.zc_value, '@');
2950168404Spjd				*cp = '\0';
2951168404Spjd			}
2952168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2953168404Spjd			    "destination already exists"));
2954168404Spjd			(void) zfs_error_fmt(hdl, EZFS_EXISTS,
2955168404Spjd			    dgettext(TEXT_DOMAIN, "cannot restore to %s"),
2956168404Spjd			    zc.zc_value);
2957168404Spjd			break;
2958168404Spjd		case EINVAL:
2959168404Spjd			(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
2960168404Spjd			break;
2961168404Spjd		case ECKSUM:
2962168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2963168404Spjd			    "invalid stream (checksum mismatch)"));
2964168404Spjd			(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
2965168404Spjd			break;
2966168404Spjd		default:
2967168404Spjd			(void) zfs_standard_error(hdl, errno, errbuf);
2968168404Spjd		}
2969168404Spjd	}
2970168404Spjd
2971168404Spjd	/*
2972168404Spjd	 * Mount or recreate the /dev links for the target filesystem
2973168404Spjd	 * (if created, or if we tore them down to do an incremental
2974168404Spjd	 * restore), and the /dev links for the new snapshot (if
2975168404Spjd	 * created). Also mount any children of the target filesystem
2976168404Spjd	 * if we did an incremental receive.
2977168404Spjd	 */
2978168404Spjd	cp = strchr(zc.zc_value, '@');
2979168404Spjd	if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) {
2980168404Spjd		zfs_handle_t *h;
2981168404Spjd
2982168404Spjd		*cp = '\0';
2983168404Spjd		h = zfs_open(hdl, zc.zc_value,
2984168404Spjd		    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
2985168404Spjd		*cp = '@';
2986168404Spjd		if (h) {
2987168404Spjd			if (h->zfs_type == ZFS_TYPE_VOLUME) {
2988168404Spjd				err = zvol_create_link(hdl, h->zfs_name);
2989168404Spjd				if (err == 0 && ioctl_err == 0)
2990168404Spjd					err = zvol_create_link(hdl,
2991168404Spjd					    zc.zc_value);
2992168404Spjd			} else {
2993168404Spjd				if (drrb->drr_fromguid) {
2994168404Spjd					err = changelist_postfix(clp);
2995168404Spjd					changelist_free(clp);
2996168404Spjd				} else {
2997168404Spjd					err = zfs_mount(h, NULL, 0);
2998168404Spjd				}
2999168404Spjd			}
3000168404Spjd		zfs_close(h);
3001168404Spjd		}
3002168404Spjd	}
3003168404Spjd
3004168404Spjd	if (err || ioctl_err)
3005168404Spjd		return (-1);
3006168404Spjd
3007168404Spjd	if (verbose) {
3008168404Spjd		char buf1[64];
3009168404Spjd		char buf2[64];
3010168404Spjd		uint64_t bytes = zc.zc_cookie;
3011168404Spjd		time_t delta = time(NULL) - begin_time;
3012168404Spjd		if (delta == 0)
3013168404Spjd			delta = 1;
3014168404Spjd		zfs_nicenum(bytes, buf1, sizeof (buf1));
3015168404Spjd		zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
3016168404Spjd
3017168404Spjd		(void) printf("received %sb stream in %lu seconds (%sb/sec)\n",
3018168404Spjd		    buf1, delta, buf2);
3019168404Spjd	}
3020168404Spjd
3021168404Spjd	return (0);
3022168404Spjd}
3023168404Spjd
3024168404Spjd/*
3025168404Spjd * Destroy any more recent snapshots.  We invoke this callback on any dependents
3026168404Spjd * of the snapshot first.  If the 'cb_dependent' member is non-zero, then this
3027168404Spjd * is a dependent and we should just destroy it without checking the transaction
3028168404Spjd * group.
3029168404Spjd */
3030168404Spjdtypedef struct rollback_data {
3031168404Spjd	const char	*cb_target;		/* the snapshot */
3032168404Spjd	uint64_t	cb_create;		/* creation time reference */
3033168404Spjd	prop_changelist_t *cb_clp;		/* changelist pointer */
3034168404Spjd	int		cb_error;
3035168404Spjd	boolean_t	cb_dependent;
3036168404Spjd} rollback_data_t;
3037168404Spjd
3038168404Spjdstatic int
3039168404Spjdrollback_destroy(zfs_handle_t *zhp, void *data)
3040168404Spjd{
3041168404Spjd	rollback_data_t *cbp = data;
3042168404Spjd
3043168404Spjd	if (!cbp->cb_dependent) {
3044168404Spjd		if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 &&
3045168404Spjd		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
3046168404Spjd		    zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
3047168404Spjd		    cbp->cb_create) {
3048168404Spjd
3049168404Spjd			cbp->cb_dependent = B_TRUE;
3050168404Spjd			if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy,
3051168404Spjd			    cbp) != 0)
3052168404Spjd				cbp->cb_error = 1;
3053168404Spjd			cbp->cb_dependent = B_FALSE;
3054168404Spjd
3055168404Spjd			if (zfs_destroy(zhp) != 0)
3056168404Spjd				cbp->cb_error = 1;
3057168404Spjd			else
3058168404Spjd				changelist_remove(zhp, cbp->cb_clp);
3059168404Spjd		}
3060168404Spjd	} else {
3061168404Spjd		if (zfs_destroy(zhp) != 0)
3062168404Spjd			cbp->cb_error = 1;
3063168404Spjd		else
3064168404Spjd			changelist_remove(zhp, cbp->cb_clp);
3065168404Spjd	}
3066168404Spjd
3067168404Spjd	zfs_close(zhp);
3068168404Spjd	return (0);
3069168404Spjd}
3070168404Spjd
3071168404Spjd/*
3072168404Spjd * Rollback the dataset to its latest snapshot.
3073168404Spjd */
3074168404Spjdstatic int
3075168404Spjddo_rollback(zfs_handle_t *zhp)
3076168404Spjd{
3077168404Spjd	int ret;
3078168404Spjd	zfs_cmd_t zc = { 0 };
3079168404Spjd
3080168404Spjd	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
3081168404Spjd	    zhp->zfs_type == ZFS_TYPE_VOLUME);
3082168404Spjd
3083168404Spjd	if (zhp->zfs_type == ZFS_TYPE_VOLUME &&
3084168404Spjd	    zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0)
3085168404Spjd		return (-1);
3086168404Spjd
3087168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3088168404Spjd
3089168404Spjd	if (ZFS_IS_VOLUME(zhp))
3090168404Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
3091168404Spjd	else
3092168404Spjd		zc.zc_objset_type = DMU_OST_ZFS;
3093168404Spjd
3094168404Spjd	/*
3095168404Spjd	 * We rely on the consumer to verify that there are no newer snapshots
3096168404Spjd	 * for the given dataset.  Given these constraints, we can simply pass
3097168404Spjd	 * the name on to the ioctl() call.  There is still an unlikely race
3098168404Spjd	 * condition where the user has taken a snapshot since we verified that
3099168404Spjd	 * this was the most recent.
3100168404Spjd	 */
3101168404Spjd	if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK,
3102168404Spjd	    &zc)) != 0) {
3103168404Spjd		(void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3104168404Spjd		    dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
3105168404Spjd		    zhp->zfs_name);
3106168404Spjd	} else if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
3107168404Spjd		ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
3108168404Spjd	}
3109168404Spjd
3110168404Spjd	return (ret);
3111168404Spjd}
3112168404Spjd
3113168404Spjd/*
3114168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any
3115168404Spjd * data changes since then and making it the active dataset.
3116168404Spjd *
3117168404Spjd * Any snapshots more recent than the target are destroyed, along with
3118168404Spjd * their dependents.
3119168404Spjd */
3120168404Spjdint
3121168404Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag)
3122168404Spjd{
3123168404Spjd	int ret;
3124168404Spjd	rollback_data_t cb = { 0 };
3125168404Spjd	prop_changelist_t *clp;
3126168404Spjd
3127168404Spjd	/*
3128168404Spjd	 * Unmount all dependendents of the dataset and the dataset itself.
3129168404Spjd	 * The list we need to gather is the same as for doing rename
3130168404Spjd	 */
3131168404Spjd	clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0);
3132168404Spjd	if (clp == NULL)
3133168404Spjd		return (-1);
3134168404Spjd
3135168404Spjd	if ((ret = changelist_prefix(clp)) != 0)
3136168404Spjd		goto out;
3137168404Spjd
3138168404Spjd	/*
3139168404Spjd	 * Destroy all recent snapshots and its dependends.
3140168404Spjd	 */
3141168404Spjd	cb.cb_target = snap->zfs_name;
3142168404Spjd	cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
3143168404Spjd	cb.cb_clp = clp;
3144168404Spjd	(void) zfs_iter_children(zhp, rollback_destroy, &cb);
3145168404Spjd
3146168404Spjd	if ((ret = cb.cb_error) != 0) {
3147168404Spjd		(void) changelist_postfix(clp);
3148168404Spjd		goto out;
3149168404Spjd	}
3150168404Spjd
3151168404Spjd	/*
3152168404Spjd	 * Now that we have verified that the snapshot is the latest,
3153168404Spjd	 * rollback to the given snapshot.
3154168404Spjd	 */
3155168404Spjd	ret = do_rollback(zhp);
3156168404Spjd
3157168404Spjd	if (ret != 0) {
3158168404Spjd		(void) changelist_postfix(clp);
3159168404Spjd		goto out;
3160168404Spjd	}
3161168404Spjd
3162168404Spjd	/*
3163168404Spjd	 * We only want to re-mount the filesystem if it was mounted in the
3164168404Spjd	 * first place.
3165168404Spjd	 */
3166168404Spjd	ret = changelist_postfix(clp);
3167168404Spjd
3168168404Spjdout:
3169168404Spjd	changelist_free(clp);
3170168404Spjd	return (ret);
3171168404Spjd}
3172168404Spjd
3173168404Spjd/*
3174168404Spjd * Iterate over all dependents for a given dataset.  This includes both
3175168404Spjd * hierarchical dependents (children) and data dependents (snapshots and
3176168404Spjd * clones).  The bulk of the processing occurs in get_dependents() in
3177168404Spjd * libzfs_graph.c.
3178168404Spjd */
3179168404Spjdint
3180168404Spjdzfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
3181168404Spjd    zfs_iter_f func, void *data)
3182168404Spjd{
3183168404Spjd	char **dependents;
3184168404Spjd	size_t count;
3185168404Spjd	int i;
3186168404Spjd	zfs_handle_t *child;
3187168404Spjd	int ret = 0;
3188168404Spjd
3189168404Spjd	if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name,
3190168404Spjd	    &dependents, &count) != 0)
3191168404Spjd		return (-1);
3192168404Spjd
3193168404Spjd	for (i = 0; i < count; i++) {
3194168404Spjd		if ((child = make_dataset_handle(zhp->zfs_hdl,
3195168404Spjd		    dependents[i])) == NULL)
3196168404Spjd			continue;
3197168404Spjd
3198168404Spjd		if ((ret = func(child, data)) != 0)
3199168404Spjd			break;
3200168404Spjd	}
3201168404Spjd
3202168404Spjd	for (i = 0; i < count; i++)
3203168404Spjd		free(dependents[i]);
3204168404Spjd	free(dependents);
3205168404Spjd
3206168404Spjd	return (ret);
3207168404Spjd}
3208168404Spjd
3209168404Spjd/*
3210168404Spjd * Renames the given dataset.
3211168404Spjd */
3212168404Spjdint
3213168676Spjdzfs_rename(zfs_handle_t *zhp, const char *target, int recursive)
3214168404Spjd{
3215168404Spjd	int ret;
3216168404Spjd	zfs_cmd_t zc = { 0 };
3217168404Spjd	char *delim;
3218168676Spjd	prop_changelist_t *cl = NULL;
3219168676Spjd	zfs_handle_t *zhrp = NULL;
3220168676Spjd	char *parentname = NULL;
3221168404Spjd	char parent[ZFS_MAXNAMELEN];
3222168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
3223168404Spjd	char errbuf[1024];
3224168404Spjd
3225168404Spjd	/* if we have the same exact name, just return success */
3226168404Spjd	if (strcmp(zhp->zfs_name, target) == 0)
3227168404Spjd		return (0);
3228168404Spjd
3229168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3230168404Spjd	    "cannot rename to '%s'"), target);
3231168404Spjd
3232168404Spjd	/*
3233168404Spjd	 * Make sure the target name is valid
3234168404Spjd	 */
3235168404Spjd	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3236168404Spjd		if ((strchr(target, '@') == NULL) ||
3237168404Spjd		    *target == '@') {
3238168404Spjd			/*
3239168404Spjd			 * Snapshot target name is abbreviated,
3240168404Spjd			 * reconstruct full dataset name
3241168404Spjd			 */
3242168404Spjd			(void) strlcpy(parent, zhp->zfs_name,
3243168404Spjd			    sizeof (parent));
3244168404Spjd			delim = strchr(parent, '@');
3245168404Spjd			if (strchr(target, '@') == NULL)
3246168404Spjd				*(++delim) = '\0';
3247168404Spjd			else
3248168404Spjd				*delim = '\0';
3249168404Spjd			(void) strlcat(parent, target, sizeof (parent));
3250168404Spjd			target = parent;
3251168404Spjd		} else {
3252168404Spjd			/*
3253168404Spjd			 * Make sure we're renaming within the same dataset.
3254168404Spjd			 */
3255168404Spjd			delim = strchr(target, '@');
3256168404Spjd			if (strncmp(zhp->zfs_name, target, delim - target)
3257168404Spjd			    != 0 || zhp->zfs_name[delim - target] != '@') {
3258168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3259168404Spjd				    "snapshots must be part of same "
3260168404Spjd				    "dataset"));
3261168404Spjd				return (zfs_error(hdl, EZFS_CROSSTARGET,
3262168404Spjd				    errbuf));
3263168404Spjd			}
3264168404Spjd		}
3265168404Spjd		if (!zfs_validate_name(hdl, target, zhp->zfs_type))
3266168404Spjd			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3267168404Spjd	} else {
3268168676Spjd		if (recursive) {
3269168676Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3270168676Spjd			    "recursive rename must be a snapshot"));
3271168676Spjd			return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3272168676Spjd		}
3273168676Spjd
3274168404Spjd		if (!zfs_validate_name(hdl, target, zhp->zfs_type))
3275168404Spjd			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3276168404Spjd		uint64_t unused;
3277168404Spjd
3278168404Spjd		/* validate parents */
3279168404Spjd		if (check_parents(hdl, target, &unused) != 0)
3280168404Spjd			return (-1);
3281168404Spjd
3282168404Spjd		(void) parent_name(target, parent, sizeof (parent));
3283168404Spjd
3284168404Spjd		/* make sure we're in the same pool */
3285168404Spjd		verify((delim = strchr(target, '/')) != NULL);
3286168404Spjd		if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
3287168404Spjd		    zhp->zfs_name[delim - target] != '/') {
3288168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3289168404Spjd			    "datasets must be within same pool"));
3290168404Spjd			return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
3291168404Spjd		}
3292168404Spjd
3293168404Spjd		/* new name cannot be a child of the current dataset name */
3294168404Spjd		if (strncmp(parent, zhp->zfs_name,
3295168404Spjd		    strlen(zhp->zfs_name)) == 0) {
3296168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3297168404Spjd			    "New dataset name cannot be a descendent of "
3298168404Spjd			    "current dataset name"));
3299168404Spjd			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3300168404Spjd		}
3301168404Spjd	}
3302168404Spjd
3303168404Spjd	(void) snprintf(errbuf, sizeof (errbuf),
3304168404Spjd	    dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
3305168404Spjd
3306168404Spjd	if (getzoneid() == GLOBAL_ZONEID &&
3307168404Spjd	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
3308168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3309168404Spjd		    "dataset is used in a non-global zone"));
3310168404Spjd		return (zfs_error(hdl, EZFS_ZONED, errbuf));
3311168404Spjd	}
3312168404Spjd
3313168676Spjd	if (recursive) {
3314168676Spjd		struct destroydata dd;
3315168404Spjd
3316168676Spjd		parentname = strdup(zhp->zfs_name);
3317168676Spjd		delim = strchr(parentname, '@');
3318168676Spjd		*delim = '\0';
3319168676Spjd		zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_ANY);
3320168676Spjd		if (zhrp == NULL) {
3321168676Spjd			return (-1);
3322168676Spjd		}
3323168676Spjd
3324168676Spjd		dd.snapname = delim + 1;
3325168676Spjd		dd.gotone = B_FALSE;
3326168676Spjd		dd.closezhp = B_FALSE;
3327168676Spjd
3328168676Spjd		/* We remove any zvol links prior to renaming them */
3329168676Spjd		ret = zfs_iter_filesystems(zhrp, zfs_remove_link_cb, &dd);
3330168676Spjd		if (ret) {
3331168676Spjd			goto error;
3332168676Spjd		}
3333168676Spjd	} else {
3334168676Spjd		if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL)
3335168676Spjd			return (-1);
3336168676Spjd
3337168676Spjd		if (changelist_haszonedchild(cl)) {
3338168676Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3339168676Spjd			    "child dataset with inherited mountpoint is used "
3340168676Spjd			    "in a non-global zone"));
3341168676Spjd			(void) zfs_error(hdl, EZFS_ZONED, errbuf);
3342168676Spjd			goto error;
3343168676Spjd		}
3344168676Spjd
3345168676Spjd		if ((ret = changelist_prefix(cl)) != 0)
3346168676Spjd			goto error;
3347168404Spjd	}
3348168404Spjd
3349168404Spjd	if (ZFS_IS_VOLUME(zhp))
3350168404Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
3351168404Spjd	else
3352168404Spjd		zc.zc_objset_type = DMU_OST_ZFS;
3353168404Spjd
3354168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3355168404Spjd	(void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
3356168404Spjd
3357168676Spjd	zc.zc_cookie = recursive;
3358168676Spjd
3359168404Spjd	if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) {
3360168676Spjd		/*
3361168676Spjd		 * if it was recursive, the one that actually failed will
3362168676Spjd		 * be in zc.zc_name
3363168676Spjd		 */
3364168676Spjd		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3365168676Spjd		    "cannot rename to '%s'"), zc.zc_name);
3366168404Spjd
3367168676Spjd		if (recursive && errno == EEXIST) {
3368168676Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3369168676Spjd			    "a child dataset already has a snapshot "
3370168676Spjd			    "with the new name"));
3371168676Spjd			(void) zfs_error(hdl, EZFS_CROSSTARGET, errbuf);
3372168676Spjd		} else {
3373168676Spjd			(void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
3374168676Spjd		}
3375168676Spjd
3376168404Spjd		/*
3377168404Spjd		 * On failure, we still want to remount any filesystems that
3378168404Spjd		 * were previously mounted, so we don't alter the system state.
3379168404Spjd		 */
3380168676Spjd		if (recursive) {
3381168676Spjd			struct createdata cd;
3382168676Spjd
3383168676Spjd			/* only create links for datasets that had existed */
3384168676Spjd			cd.cd_snapname = delim + 1;
3385168676Spjd			cd.cd_ifexists = B_TRUE;
3386168676Spjd			(void) zfs_iter_filesystems(zhrp, zfs_create_link_cb,
3387168676Spjd			    &cd);
3388168676Spjd		} else {
3389168676Spjd			(void) changelist_postfix(cl);
3390168676Spjd		}
3391168404Spjd	} else {
3392168676Spjd		if (recursive) {
3393168676Spjd			struct createdata cd;
3394168404Spjd
3395168676Spjd			/* only create links for datasets that had existed */
3396168676Spjd			cd.cd_snapname = strchr(target, '@') + 1;
3397168676Spjd			cd.cd_ifexists = B_TRUE;
3398168676Spjd			ret = zfs_iter_filesystems(zhrp, zfs_create_link_cb,
3399168676Spjd			    &cd);
3400168676Spjd		} else {
3401168676Spjd			changelist_rename(cl, zfs_get_name(zhp), target);
3402168676Spjd			ret = changelist_postfix(cl);
3403168676Spjd		}
3404168404Spjd	}
3405168404Spjd
3406168404Spjderror:
3407168676Spjd	if (parentname) {
3408168676Spjd		free(parentname);
3409168676Spjd	}
3410168676Spjd	if (zhrp) {
3411168676Spjd		zfs_close(zhrp);
3412168676Spjd	}
3413168676Spjd	if (cl) {
3414168676Spjd		changelist_free(cl);
3415168676Spjd	}
3416168404Spjd	return (ret);
3417168404Spjd}
3418168404Spjd
3419168404Spjd/*
3420168404Spjd * Given a zvol dataset, issue the ioctl to create the appropriate minor node,
3421168404Spjd * poke devfsadm to create the /dev link, and then wait for the link to appear.
3422168404Spjd */
3423168404Spjdint
3424168404Spjdzvol_create_link(libzfs_handle_t *hdl, const char *dataset)
3425168404Spjd{
3426168676Spjd	return (zvol_create_link_common(hdl, dataset, B_FALSE));
3427168676Spjd}
3428168676Spjd
3429168676Spjdstatic int
3430168676Spjdzvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists)
3431168676Spjd{
3432168404Spjd	zfs_cmd_t zc = { 0 };
3433168404Spjd#if 0
3434168404Spjd	di_devlink_handle_t dhdl;
3435168404Spjd#endif
3436168404Spjd
3437168404Spjd	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
3438168404Spjd
3439168404Spjd	/*
3440168404Spjd	 * Issue the appropriate ioctl.
3441168404Spjd	 */
3442168404Spjd	if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) {
3443168404Spjd		switch (errno) {
3444168404Spjd		case EEXIST:
3445168404Spjd			/*
3446168404Spjd			 * Silently ignore the case where the link already
3447168404Spjd			 * exists.  This allows 'zfs volinit' to be run multiple
3448168404Spjd			 * times without errors.
3449168404Spjd			 */
3450168404Spjd			return (0);
3451168404Spjd
3452168676Spjd		case ENOENT:
3453168676Spjd			/*
3454168676Spjd			 * Dataset does not exist in the kernel.  If we
3455168676Spjd			 * don't care (see zfs_rename), then ignore the
3456168676Spjd			 * error quietly.
3457168676Spjd			 */
3458168676Spjd			if (ifexists) {
3459168676Spjd				return (0);
3460168676Spjd			}
3461168676Spjd
3462168676Spjd			/* FALLTHROUGH */
3463168676Spjd
3464168404Spjd		default:
3465168404Spjd			return (zfs_standard_error_fmt(hdl, errno,
3466168404Spjd			    dgettext(TEXT_DOMAIN, "cannot create device links "
3467168404Spjd			    "for '%s'"), dataset));
3468168404Spjd		}
3469168404Spjd	}
3470168404Spjd
3471168404Spjd#if 0
3472168404Spjd	/*
3473168404Spjd	 * Call devfsadm and wait for the links to magically appear.
3474168404Spjd	 */
3475168404Spjd	if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) {
3476168404Spjd		zfs_error_aux(hdl, strerror(errno));
3477168404Spjd		(void) zfs_error_fmt(hdl, EZFS_DEVLINKS,
3478168404Spjd		    dgettext(TEXT_DOMAIN, "cannot create device links "
3479168404Spjd		    "for '%s'"), dataset);
3480168404Spjd		(void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc);
3481168404Spjd		return (-1);
3482168404Spjd	} else {
3483168404Spjd		(void) di_devlink_fini(&dhdl);
3484168404Spjd	}
3485168404Spjd#endif
3486168404Spjd
3487168404Spjd	return (0);
3488168404Spjd}
3489168404Spjd
3490168404Spjd/*
3491168404Spjd * Remove a minor node for the given zvol and the associated /dev links.
3492168404Spjd */
3493168404Spjdint
3494168404Spjdzvol_remove_link(libzfs_handle_t *hdl, const char *dataset)
3495168404Spjd{
3496168404Spjd	zfs_cmd_t zc = { 0 };
3497168404Spjd
3498168404Spjd	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
3499168404Spjd
3500168404Spjd	if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) {
3501168404Spjd		switch (errno) {
3502168404Spjd		case ENXIO:
3503168404Spjd			/*
3504168404Spjd			 * Silently ignore the case where the link no longer
3505168404Spjd			 * exists, so that 'zfs volfini' can be run multiple
3506168404Spjd			 * times without errors.
3507168404Spjd			 */
3508168404Spjd			return (0);
3509168404Spjd
3510168404Spjd		default:
3511168404Spjd			return (zfs_standard_error_fmt(hdl, errno,
3512168404Spjd			    dgettext(TEXT_DOMAIN, "cannot remove device "
3513168404Spjd			    "links for '%s'"), dataset));
3514168404Spjd		}
3515168404Spjd	}
3516168404Spjd
3517168404Spjd	return (0);
3518168404Spjd}
3519168404Spjd
3520168404Spjdnvlist_t *
3521168404Spjdzfs_get_user_props(zfs_handle_t *zhp)
3522168404Spjd{
3523168404Spjd	return (zhp->zfs_user_props);
3524168404Spjd}
3525168404Spjd
3526168404Spjd/*
3527168404Spjd * Given a comma-separated list of properties, contruct a property list
3528168404Spjd * containing both user-defined and native properties.  This function will
3529168404Spjd * return a NULL list if 'all' is specified, which can later be expanded on a
3530168404Spjd * per-dataset basis by zfs_expand_proplist().
3531168404Spjd */
3532168404Spjdint
3533168404Spjdzfs_get_proplist_common(libzfs_handle_t *hdl, char *fields,
3534168404Spjd    zfs_proplist_t **listp, zfs_type_t type)
3535168404Spjd{
3536168404Spjd	size_t len;
3537168404Spjd	char *s, *p;
3538168404Spjd	char c;
3539168404Spjd	zfs_prop_t prop;
3540168404Spjd	zfs_proplist_t *entry;
3541168404Spjd	zfs_proplist_t **last;
3542168404Spjd
3543168404Spjd	*listp = NULL;
3544168404Spjd	last = listp;
3545168404Spjd
3546168404Spjd	/*
3547168404Spjd	 * If 'all' is specified, return a NULL list.
3548168404Spjd	 */
3549168404Spjd	if (strcmp(fields, "all") == 0)
3550168404Spjd		return (0);
3551168404Spjd
3552168404Spjd	/*
3553168404Spjd	 * If no fields were specified, return an error.
3554168404Spjd	 */
3555168404Spjd	if (fields[0] == '\0') {
3556168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3557168404Spjd		    "no properties specified"));
3558168404Spjd		return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
3559168404Spjd		    "bad property list")));
3560168404Spjd	}
3561168404Spjd
3562168404Spjd	/*
3563168404Spjd	 * It would be nice to use getsubopt() here, but the inclusion of column
3564168404Spjd	 * aliases makes this more effort than it's worth.
3565168404Spjd	 */
3566168404Spjd	s = fields;
3567168404Spjd	while (*s != '\0') {
3568168404Spjd		if ((p = strchr(s, ',')) == NULL) {
3569168404Spjd			len = strlen(s);
3570168404Spjd			p = s + len;
3571168404Spjd		} else {
3572168404Spjd			len = p - s;
3573168404Spjd		}
3574168404Spjd
3575168404Spjd		/*
3576168404Spjd		 * Check for empty options.
3577168404Spjd		 */
3578168404Spjd		if (len == 0) {
3579168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3580168404Spjd			    "empty property name"));
3581168404Spjd			return (zfs_error(hdl, EZFS_BADPROP,
3582168404Spjd			    dgettext(TEXT_DOMAIN, "bad property list")));
3583168404Spjd		}
3584168404Spjd
3585168404Spjd		/*
3586168404Spjd		 * Check all regular property names.
3587168404Spjd		 */
3588168404Spjd		c = s[len];
3589168404Spjd		s[len] = '\0';
3590168404Spjd		prop = zfs_name_to_prop_common(s, type);
3591168404Spjd
3592168404Spjd		if (prop != ZFS_PROP_INVAL &&
3593168404Spjd		    !zfs_prop_valid_for_type(prop, type))
3594168404Spjd			prop = ZFS_PROP_INVAL;
3595168404Spjd
3596168404Spjd		/*
3597168404Spjd		 * When no property table entry can be found, return failure if
3598168404Spjd		 * this is a pool property or if this isn't a user-defined
3599168404Spjd		 * dataset property,
3600168404Spjd		 */
3601168404Spjd		if (prop == ZFS_PROP_INVAL &&
3602168404Spjd		    (type & ZFS_TYPE_POOL || !zfs_prop_user(s))) {
3603168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3604168404Spjd			    "invalid property '%s'"), s);
3605168404Spjd			return (zfs_error(hdl, EZFS_BADPROP,
3606168404Spjd			    dgettext(TEXT_DOMAIN, "bad property list")));
3607168404Spjd		}
3608168404Spjd
3609168404Spjd		if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL)
3610168404Spjd			return (-1);
3611168404Spjd
3612168404Spjd		entry->pl_prop = prop;
3613168404Spjd		if (prop == ZFS_PROP_INVAL) {
3614168404Spjd			if ((entry->pl_user_prop =
3615168404Spjd			    zfs_strdup(hdl, s)) == NULL) {
3616168404Spjd				free(entry);
3617168404Spjd				return (-1);
3618168404Spjd			}
3619168404Spjd			entry->pl_width = strlen(s);
3620168404Spjd		} else {
3621168404Spjd			entry->pl_width = zfs_prop_width(prop,
3622168404Spjd			    &entry->pl_fixed);
3623168404Spjd		}
3624168404Spjd
3625168404Spjd		*last = entry;
3626168404Spjd		last = &entry->pl_next;
3627168404Spjd
3628168404Spjd		s = p;
3629168404Spjd		if (c == ',')
3630168404Spjd			s++;
3631168404Spjd	}
3632168404Spjd
3633168404Spjd	return (0);
3634168404Spjd}
3635168404Spjd
3636168404Spjdint
3637168404Spjdzfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp)
3638168404Spjd{
3639168404Spjd	return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_ANY));
3640168404Spjd}
3641168404Spjd
3642168404Spjdvoid
3643168404Spjdzfs_free_proplist(zfs_proplist_t *pl)
3644168404Spjd{
3645168404Spjd	zfs_proplist_t *next;
3646168404Spjd
3647168404Spjd	while (pl != NULL) {
3648168404Spjd		next = pl->pl_next;
3649168404Spjd		free(pl->pl_user_prop);
3650168404Spjd		free(pl);
3651168404Spjd		pl = next;
3652168404Spjd	}
3653168404Spjd}
3654168404Spjd
3655168404Spjdtypedef struct expand_data {
3656168404Spjd	zfs_proplist_t	**last;
3657168404Spjd	libzfs_handle_t	*hdl;
3658168404Spjd} expand_data_t;
3659168404Spjd
3660168404Spjdstatic zfs_prop_t
3661168404Spjdzfs_expand_proplist_cb(zfs_prop_t prop, void *cb)
3662168404Spjd{
3663168404Spjd	zfs_proplist_t *entry;
3664168404Spjd	expand_data_t *edp = cb;
3665168404Spjd
3666168404Spjd	if ((entry = zfs_alloc(edp->hdl, sizeof (zfs_proplist_t))) == NULL)
3667168404Spjd		return (ZFS_PROP_INVAL);
3668168404Spjd
3669168404Spjd	entry->pl_prop = prop;
3670168404Spjd	entry->pl_width = zfs_prop_width(prop, &entry->pl_fixed);
3671168404Spjd	entry->pl_all = B_TRUE;
3672168404Spjd
3673168404Spjd	*(edp->last) = entry;
3674168404Spjd	edp->last = &entry->pl_next;
3675168404Spjd
3676168404Spjd	return (ZFS_PROP_CONT);
3677168404Spjd}
3678168404Spjd
3679168404Spjdint
3680168404Spjdzfs_expand_proplist_common(libzfs_handle_t *hdl, zfs_proplist_t **plp,
3681168404Spjd	zfs_type_t type)
3682168404Spjd{
3683168404Spjd	zfs_proplist_t *entry;
3684168404Spjd	zfs_proplist_t **last;
3685168404Spjd	expand_data_t exp;
3686168404Spjd
3687168404Spjd	if (*plp == NULL) {
3688168404Spjd		/*
3689168404Spjd		 * If this is the very first time we've been called for an 'all'
3690168404Spjd		 * specification, expand the list to include all native
3691168404Spjd		 * properties.
3692168404Spjd		 */
3693168404Spjd		last = plp;
3694168404Spjd
3695168404Spjd		exp.last = last;
3696168404Spjd		exp.hdl = hdl;
3697168404Spjd
3698168404Spjd		if (zfs_prop_iter_common(zfs_expand_proplist_cb, &exp, type,
3699168404Spjd		    B_FALSE) == ZFS_PROP_INVAL)
3700168404Spjd			return (-1);
3701168404Spjd
3702168404Spjd		/*
3703168404Spjd		 * Add 'name' to the beginning of the list, which is handled
3704168404Spjd		 * specially.
3705168404Spjd		 */
3706168404Spjd		if ((entry = zfs_alloc(hdl,
3707168404Spjd		    sizeof (zfs_proplist_t))) == NULL)
3708168404Spjd			return (-1);
3709168404Spjd
3710168404Spjd		entry->pl_prop = ZFS_PROP_NAME;
3711168404Spjd		entry->pl_width = zfs_prop_width(ZFS_PROP_NAME,
3712168404Spjd		    &entry->pl_fixed);
3713168404Spjd		entry->pl_all = B_TRUE;
3714168404Spjd		entry->pl_next = *plp;
3715168404Spjd		*plp = entry;
3716168404Spjd	}
3717168404Spjd	return (0);
3718168404Spjd}
3719168404Spjd
3720168404Spjd/*
3721168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to
3722168404Spjd * display, and their maximum widths.  This does two main things:
3723168404Spjd *
3724168404Spjd *      - If this is a list of all properties, then expand the list to include
3725168404Spjd *        all native properties, and set a flag so that for each dataset we look
3726168404Spjd *        for new unique user properties and add them to the list.
3727168404Spjd *
3728168404Spjd *      - For non fixed-width properties, keep track of the maximum width seen
3729168404Spjd *        so that we can size the column appropriately.
3730168404Spjd */
3731168404Spjdint
3732168404Spjdzfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp)
3733168404Spjd{
3734168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
3735168404Spjd	zfs_proplist_t *entry;
3736168404Spjd	zfs_proplist_t **last, **start;
3737168404Spjd	nvlist_t *userprops, *propval;
3738168404Spjd	nvpair_t *elem;
3739168404Spjd	char *strval;
3740168404Spjd	char buf[ZFS_MAXPROPLEN];
3741168404Spjd
3742168404Spjd	if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_ANY) != 0)
3743168404Spjd		return (-1);
3744168404Spjd
3745168404Spjd	userprops = zfs_get_user_props(zhp);
3746168404Spjd
3747168404Spjd	entry = *plp;
3748168404Spjd	if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
3749168404Spjd		/*
3750168404Spjd		 * Go through and add any user properties as necessary.  We
3751168404Spjd		 * start by incrementing our list pointer to the first
3752168404Spjd		 * non-native property.
3753168404Spjd		 */
3754168404Spjd		start = plp;
3755168404Spjd		while (*start != NULL) {
3756168404Spjd			if ((*start)->pl_prop == ZFS_PROP_INVAL)
3757168404Spjd				break;
3758168404Spjd			start = &(*start)->pl_next;
3759168404Spjd		}
3760168404Spjd
3761168404Spjd		elem = NULL;
3762168404Spjd		while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
3763168404Spjd			/*
3764168404Spjd			 * See if we've already found this property in our list.
3765168404Spjd			 */
3766168404Spjd			for (last = start; *last != NULL;
3767168404Spjd			    last = &(*last)->pl_next) {
3768168404Spjd				if (strcmp((*last)->pl_user_prop,
3769168404Spjd				    nvpair_name(elem)) == 0)
3770168404Spjd					break;
3771168404Spjd			}
3772168404Spjd
3773168404Spjd			if (*last == NULL) {
3774168404Spjd				if ((entry = zfs_alloc(hdl,
3775168404Spjd				    sizeof (zfs_proplist_t))) == NULL ||
3776168404Spjd				    ((entry->pl_user_prop = zfs_strdup(hdl,
3777168404Spjd				    nvpair_name(elem)))) == NULL) {
3778168404Spjd					free(entry);
3779168404Spjd					return (-1);
3780168404Spjd				}
3781168404Spjd
3782168404Spjd				entry->pl_prop = ZFS_PROP_INVAL;
3783168404Spjd				entry->pl_width = strlen(nvpair_name(elem));
3784168404Spjd				entry->pl_all = B_TRUE;
3785168404Spjd				*last = entry;
3786168404Spjd			}
3787168404Spjd		}
3788168404Spjd	}
3789168404Spjd
3790168404Spjd	/*
3791168404Spjd	 * Now go through and check the width of any non-fixed columns
3792168404Spjd	 */
3793168404Spjd	for (entry = *plp; entry != NULL; entry = entry->pl_next) {
3794168404Spjd		if (entry->pl_fixed)
3795168404Spjd			continue;
3796168404Spjd
3797168404Spjd		if (entry->pl_prop != ZFS_PROP_INVAL) {
3798168404Spjd			if (zfs_prop_get(zhp, entry->pl_prop,
3799168404Spjd			    buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) {
3800168404Spjd				if (strlen(buf) > entry->pl_width)
3801168404Spjd					entry->pl_width = strlen(buf);
3802168404Spjd			}
3803168404Spjd		} else if (nvlist_lookup_nvlist(userprops,
3804168404Spjd		    entry->pl_user_prop, &propval)  == 0) {
3805168404Spjd			verify(nvlist_lookup_string(propval,
3806168404Spjd			    ZFS_PROP_VALUE, &strval) == 0);
3807168404Spjd			if (strlen(strval) > entry->pl_width)
3808168404Spjd				entry->pl_width = strlen(strval);
3809168404Spjd		}
3810168404Spjd	}
3811168404Spjd
3812168404Spjd	return (0);
3813168404Spjd}
3814168404Spjd
3815168404Spjd/*
3816168404Spjd * Attach/detach the given filesystem to/from the given jail.
3817168404Spjd */
3818168404Spjdint
3819168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach)
3820168404Spjd{
3821168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
3822168404Spjd	zfs_cmd_t zc = { 0 };
3823168404Spjd	char errbuf[1024];
3824168404Spjd	int cmd, ret;
3825168404Spjd
3826168404Spjd	if (attach) {
3827168404Spjd		(void) snprintf(errbuf, sizeof (errbuf),
3828168404Spjd		    dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
3829168404Spjd	} else {
3830168404Spjd		(void) snprintf(errbuf, sizeof (errbuf),
3831168404Spjd		    dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
3832168404Spjd	}
3833168404Spjd
3834168404Spjd	switch (zhp->zfs_type) {
3835168404Spjd	case ZFS_TYPE_VOLUME:
3836168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3837168404Spjd		    "volumes can not be jailed"));
3838168404Spjd		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3839168404Spjd	case ZFS_TYPE_SNAPSHOT:
3840168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3841168404Spjd		    "snapshots can not be jailed"));
3842168404Spjd		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3843168404Spjd	}
3844168404Spjd	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
3845168404Spjd
3846168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3847168404Spjd	zc.zc_objset_type = DMU_OST_ZFS;
3848168404Spjd	zc.zc_jailid = jailid;
3849168404Spjd
3850168404Spjd	cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL;
3851168404Spjd	if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0)
3852168404Spjd		zfs_standard_error(hdl, errno, errbuf);
3853168404Spjd
3854168404Spjd	return (ret);
3855168404Spjd}
3856