libzfs_dataset.c revision 230514
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/*
23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24219089Spjd * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
25223623Smm * Copyright (c) 2011 by Delphix. All rights reserved.
26230438Spjd * Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
27226706Spjd * All rights reserved.
28168404Spjd */
29168404Spjd
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>
38185029Spjd#include <stddef.h>
39168404Spjd#include <zone.h>
40168404Spjd#include <fcntl.h>
41168404Spjd#include <sys/mntent.h>
42168404Spjd#include <sys/mount.h>
43185029Spjd#include <priv.h>
44185029Spjd#include <pwd.h>
45185029Spjd#include <grp.h>
46185029Spjd#include <stddef.h>
47209962Smm#include <idmap.h>
48168404Spjd
49219089Spjd#include <sys/dnode.h>
50168404Spjd#include <sys/spa.h>
51168404Spjd#include <sys/zap.h>
52209962Smm#include <sys/misc.h>
53168404Spjd#include <libzfs.h>
54168404Spjd
55168404Spjd#include "zfs_namecheck.h"
56168404Spjd#include "zfs_prop.h"
57168404Spjd#include "libzfs_impl.h"
58185029Spjd#include "zfs_deleg.h"
59168404Spjd
60209962Smmstatic int userquota_propname_decode(const char *propname, boolean_t zoned,
61209962Smm    zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
62168676Spjd
63168404Spjd/*
64168404Spjd * Given a single type (not a mask of types), return the type in a human
65168404Spjd * readable form.
66168404Spjd */
67168404Spjdconst char *
68168404Spjdzfs_type_to_name(zfs_type_t type)
69168404Spjd{
70168404Spjd	switch (type) {
71168404Spjd	case ZFS_TYPE_FILESYSTEM:
72168404Spjd		return (dgettext(TEXT_DOMAIN, "filesystem"));
73168404Spjd	case ZFS_TYPE_SNAPSHOT:
74168404Spjd		return (dgettext(TEXT_DOMAIN, "snapshot"));
75168404Spjd	case ZFS_TYPE_VOLUME:
76168404Spjd		return (dgettext(TEXT_DOMAIN, "volume"));
77168404Spjd	}
78168404Spjd
79168404Spjd	return (NULL);
80168404Spjd}
81168404Spjd
82168404Spjd/*
83168404Spjd * Given a path and mask of ZFS types, return a string describing this dataset.
84168404Spjd * This is used when we fail to open a dataset and we cannot get an exact type.
85168404Spjd * We guess what the type would have been based on the path and the mask of
86168404Spjd * acceptable types.
87168404Spjd */
88168404Spjdstatic const char *
89168404Spjdpath_to_str(const char *path, int types)
90168404Spjd{
91168404Spjd	/*
92168404Spjd	 * When given a single type, always report the exact type.
93168404Spjd	 */
94168404Spjd	if (types == ZFS_TYPE_SNAPSHOT)
95168404Spjd		return (dgettext(TEXT_DOMAIN, "snapshot"));
96168404Spjd	if (types == ZFS_TYPE_FILESYSTEM)
97168404Spjd		return (dgettext(TEXT_DOMAIN, "filesystem"));
98168404Spjd	if (types == ZFS_TYPE_VOLUME)
99168404Spjd		return (dgettext(TEXT_DOMAIN, "volume"));
100168404Spjd
101168404Spjd	/*
102168404Spjd	 * The user is requesting more than one type of dataset.  If this is the
103168404Spjd	 * case, consult the path itself.  If we're looking for a snapshot, and
104168404Spjd	 * a '@' is found, then report it as "snapshot".  Otherwise, remove the
105168404Spjd	 * snapshot attribute and try again.
106168404Spjd	 */
107168404Spjd	if (types & ZFS_TYPE_SNAPSHOT) {
108168404Spjd		if (strchr(path, '@') != NULL)
109168404Spjd			return (dgettext(TEXT_DOMAIN, "snapshot"));
110168404Spjd		return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT));
111168404Spjd	}
112168404Spjd
113168404Spjd	/*
114168404Spjd	 * The user has requested either filesystems or volumes.
115168404Spjd	 * We have no way of knowing a priori what type this would be, so always
116168404Spjd	 * report it as "filesystem" or "volume", our two primitive types.
117168404Spjd	 */
118168404Spjd	if (types & ZFS_TYPE_FILESYSTEM)
119168404Spjd		return (dgettext(TEXT_DOMAIN, "filesystem"));
120168404Spjd
121168404Spjd	assert(types & ZFS_TYPE_VOLUME);
122168404Spjd	return (dgettext(TEXT_DOMAIN, "volume"));
123168404Spjd}
124168404Spjd
125168404Spjd/*
126168404Spjd * Validate a ZFS path.  This is used even before trying to open the dataset, to
127209962Smm * provide a more meaningful error message.  We call zfs_error_aux() to
128209962Smm * explain exactly why the name was not valid.
129168404Spjd */
130219089Spjdint
131185029Spjdzfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
132185029Spjd    boolean_t modifying)
133168404Spjd{
134168404Spjd	namecheck_err_t why;
135168404Spjd	char what;
136168404Spjd
137219089Spjd	(void) zfs_prop_get_table();
138168404Spjd	if (dataset_namecheck(path, &why, &what) != 0) {
139168404Spjd		if (hdl != NULL) {
140168404Spjd			switch (why) {
141168404Spjd			case NAME_ERR_TOOLONG:
142168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
143168404Spjd				    "name is too long"));
144168404Spjd				break;
145168404Spjd
146168404Spjd			case NAME_ERR_LEADING_SLASH:
147168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
148168404Spjd				    "leading slash in name"));
149168404Spjd				break;
150168404Spjd
151168404Spjd			case NAME_ERR_EMPTY_COMPONENT:
152168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
153168404Spjd				    "empty component in name"));
154168404Spjd				break;
155168404Spjd
156168404Spjd			case NAME_ERR_TRAILING_SLASH:
157168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
158168404Spjd				    "trailing slash in name"));
159168404Spjd				break;
160168404Spjd
161168404Spjd			case NAME_ERR_INVALCHAR:
162168404Spjd				zfs_error_aux(hdl,
163168404Spjd				    dgettext(TEXT_DOMAIN, "invalid character "
164168404Spjd				    "'%c' in name"), what);
165168404Spjd				break;
166168404Spjd
167168404Spjd			case NAME_ERR_MULTIPLE_AT:
168168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
169168404Spjd				    "multiple '@' delimiters in name"));
170168404Spjd				break;
171168404Spjd
172168404Spjd			case NAME_ERR_NOLETTER:
173168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
174168404Spjd				    "pool doesn't begin with a letter"));
175168404Spjd				break;
176168404Spjd
177168404Spjd			case NAME_ERR_RESERVED:
178168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
179168404Spjd				    "name is reserved"));
180168404Spjd				break;
181168404Spjd
182168404Spjd			case NAME_ERR_DISKLIKE:
183168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
184168404Spjd				    "reserved disk name"));
185168404Spjd				break;
186168404Spjd			}
187168404Spjd		}
188168404Spjd
189168404Spjd		return (0);
190168404Spjd	}
191168404Spjd
192168404Spjd	if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
193168404Spjd		if (hdl != NULL)
194168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
195168404Spjd			    "snapshot delimiter '@' in filesystem name"));
196168404Spjd		return (0);
197168404Spjd	}
198168404Spjd
199168404Spjd	if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
200168404Spjd		if (hdl != NULL)
201168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
202168404Spjd			    "missing '@' delimiter in snapshot name"));
203168404Spjd		return (0);
204168404Spjd	}
205168404Spjd
206185029Spjd	if (modifying && strchr(path, '%') != NULL) {
207185029Spjd		if (hdl != NULL)
208185029Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
209185029Spjd			    "invalid character %c in name"), '%');
210185029Spjd		return (0);
211185029Spjd	}
212185029Spjd
213168404Spjd	return (-1);
214168404Spjd}
215168404Spjd
216168404Spjdint
217168404Spjdzfs_name_valid(const char *name, zfs_type_t type)
218168404Spjd{
219185029Spjd	if (type == ZFS_TYPE_POOL)
220185029Spjd		return (zpool_name_valid(NULL, B_FALSE, name));
221185029Spjd	return (zfs_validate_name(NULL, name, type, B_FALSE));
222168404Spjd}
223168404Spjd
224168404Spjd/*
225168404Spjd * This function takes the raw DSL properties, and filters out the user-defined
226168404Spjd * properties into a separate nvlist.
227168404Spjd */
228185029Spjdstatic nvlist_t *
229185029Spjdprocess_user_props(zfs_handle_t *zhp, nvlist_t *props)
230168404Spjd{
231168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
232168404Spjd	nvpair_t *elem;
233168404Spjd	nvlist_t *propval;
234185029Spjd	nvlist_t *nvl;
235168404Spjd
236185029Spjd	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
237185029Spjd		(void) no_memory(hdl);
238185029Spjd		return (NULL);
239185029Spjd	}
240168404Spjd
241168404Spjd	elem = NULL;
242185029Spjd	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
243168404Spjd		if (!zfs_prop_user(nvpair_name(elem)))
244168404Spjd			continue;
245168404Spjd
246168404Spjd		verify(nvpair_value_nvlist(elem, &propval) == 0);
247185029Spjd		if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) {
248185029Spjd			nvlist_free(nvl);
249185029Spjd			(void) no_memory(hdl);
250185029Spjd			return (NULL);
251185029Spjd		}
252168404Spjd	}
253168404Spjd
254185029Spjd	return (nvl);
255168404Spjd}
256168404Spjd
257185029Spjdstatic zpool_handle_t *
258185029Spjdzpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
259185029Spjd{
260185029Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
261185029Spjd	zpool_handle_t *zph;
262185029Spjd
263185029Spjd	if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
264185029Spjd		if (hdl->libzfs_pool_handles != NULL)
265185029Spjd			zph->zpool_next = hdl->libzfs_pool_handles;
266185029Spjd		hdl->libzfs_pool_handles = zph;
267185029Spjd	}
268185029Spjd	return (zph);
269185029Spjd}
270185029Spjd
271185029Spjdstatic zpool_handle_t *
272185029Spjdzpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
273185029Spjd{
274185029Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
275185029Spjd	zpool_handle_t *zph = hdl->libzfs_pool_handles;
276185029Spjd
277185029Spjd	while ((zph != NULL) &&
278185029Spjd	    (strncmp(pool_name, zpool_get_name(zph), len) != 0))
279185029Spjd		zph = zph->zpool_next;
280185029Spjd	return (zph);
281185029Spjd}
282185029Spjd
283168404Spjd/*
284185029Spjd * Returns a handle to the pool that contains the provided dataset.
285185029Spjd * If a handle to that pool already exists then that handle is returned.
286185029Spjd * Otherwise, a new handle is created and added to the list of handles.
287185029Spjd */
288185029Spjdstatic zpool_handle_t *
289185029Spjdzpool_handle(zfs_handle_t *zhp)
290185029Spjd{
291185029Spjd	char *pool_name;
292185029Spjd	int len;
293185029Spjd	zpool_handle_t *zph;
294185029Spjd
295185029Spjd	len = strcspn(zhp->zfs_name, "/@") + 1;
296185029Spjd	pool_name = zfs_alloc(zhp->zfs_hdl, len);
297185029Spjd	(void) strlcpy(pool_name, zhp->zfs_name, len);
298185029Spjd
299185029Spjd	zph = zpool_find_handle(zhp, pool_name, len);
300185029Spjd	if (zph == NULL)
301185029Spjd		zph = zpool_add_handle(zhp, pool_name);
302185029Spjd
303185029Spjd	free(pool_name);
304185029Spjd	return (zph);
305185029Spjd}
306185029Spjd
307185029Spjdvoid
308185029Spjdzpool_free_handles(libzfs_handle_t *hdl)
309185029Spjd{
310185029Spjd	zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
311185029Spjd
312185029Spjd	while (zph != NULL) {
313185029Spjd		next = zph->zpool_next;
314185029Spjd		zpool_close(zph);
315185029Spjd		zph = next;
316185029Spjd	}
317185029Spjd	hdl->libzfs_pool_handles = NULL;
318185029Spjd}
319185029Spjd
320185029Spjd/*
321168404Spjd * Utility function to gather stats (objset and zpl) for the given object.
322168404Spjd */
323219089Spjdstatic int
324209962Smmget_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
325168404Spjd{
326168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
327168404Spjd
328209962Smm	(void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
329168404Spjd
330209962Smm	while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
331168404Spjd		if (errno == ENOMEM) {
332209962Smm			if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
333168404Spjd				return (-1);
334168404Spjd			}
335168404Spjd		} else {
336168404Spjd			return (-1);
337168404Spjd		}
338168404Spjd	}
339209962Smm	return (0);
340209962Smm}
341168404Spjd
342219089Spjd/*
343219089Spjd * Utility function to get the received properties of the given object.
344219089Spjd */
345209962Smmstatic int
346219089Spjdget_recvd_props_ioctl(zfs_handle_t *zhp)
347219089Spjd{
348219089Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
349219089Spjd	nvlist_t *recvdprops;
350219089Spjd	zfs_cmd_t zc = { 0 };
351219089Spjd	int err;
352219089Spjd
353219089Spjd	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
354219089Spjd		return (-1);
355219089Spjd
356219089Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
357219089Spjd
358219089Spjd	while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) {
359219089Spjd		if (errno == ENOMEM) {
360219089Spjd			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
361219089Spjd				return (-1);
362219089Spjd			}
363219089Spjd		} else {
364219089Spjd			zcmd_free_nvlists(&zc);
365219089Spjd			return (-1);
366219089Spjd		}
367219089Spjd	}
368219089Spjd
369219089Spjd	err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops);
370219089Spjd	zcmd_free_nvlists(&zc);
371219089Spjd	if (err != 0)
372219089Spjd		return (-1);
373219089Spjd
374219089Spjd	nvlist_free(zhp->zfs_recvd_props);
375219089Spjd	zhp->zfs_recvd_props = recvdprops;
376219089Spjd
377219089Spjd	return (0);
378219089Spjd}
379219089Spjd
380219089Spjdstatic int
381209962Smmput_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
382209962Smm{
383209962Smm	nvlist_t *allprops, *userprops;
384168404Spjd
385209962Smm	zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
386209962Smm
387209962Smm	if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
388168404Spjd		return (-1);
389168404Spjd	}
390168404Spjd
391209962Smm	/*
392209962Smm	 * XXX Why do we store the user props separately, in addition to
393209962Smm	 * storing them in zfs_props?
394209962Smm	 */
395185029Spjd	if ((userprops = process_user_props(zhp, allprops)) == NULL) {
396185029Spjd		nvlist_free(allprops);
397168404Spjd		return (-1);
398185029Spjd	}
399168404Spjd
400185029Spjd	nvlist_free(zhp->zfs_props);
401185029Spjd	nvlist_free(zhp->zfs_user_props);
402185029Spjd
403185029Spjd	zhp->zfs_props = allprops;
404185029Spjd	zhp->zfs_user_props = userprops;
405185029Spjd
406168404Spjd	return (0);
407168404Spjd}
408168404Spjd
409209962Smmstatic int
410209962Smmget_stats(zfs_handle_t *zhp)
411209962Smm{
412209962Smm	int rc = 0;
413209962Smm	zfs_cmd_t zc = { 0 };
414209962Smm
415209962Smm	if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
416209962Smm		return (-1);
417209962Smm	if (get_stats_ioctl(zhp, &zc) != 0)
418209962Smm		rc = -1;
419209962Smm	else if (put_stats_zhdl(zhp, &zc) != 0)
420209962Smm		rc = -1;
421209962Smm	zcmd_free_nvlists(&zc);
422209962Smm	return (rc);
423209962Smm}
424209962Smm
425168404Spjd/*
426168404Spjd * Refresh the properties currently stored in the handle.
427168404Spjd */
428168404Spjdvoid
429168404Spjdzfs_refresh_properties(zfs_handle_t *zhp)
430168404Spjd{
431168404Spjd	(void) get_stats(zhp);
432168404Spjd}
433168404Spjd
434168404Spjd/*
435168404Spjd * Makes a handle from the given dataset name.  Used by zfs_open() and
436168404Spjd * zfs_iter_* to create child handles on the fly.
437168404Spjd */
438209962Smmstatic int
439209962Smmmake_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
440168404Spjd{
441219089Spjd	if (put_stats_zhdl(zhp, zc) != 0)
442209962Smm		return (-1);
443168404Spjd
444168404Spjd	/*
445168404Spjd	 * We've managed to open the dataset and gather statistics.  Determine
446168404Spjd	 * the high-level type.
447168404Spjd	 */
448168404Spjd	if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
449168404Spjd		zhp->zfs_head_type = ZFS_TYPE_VOLUME;
450168404Spjd	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
451168404Spjd		zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
452168404Spjd	else
453168404Spjd		abort();
454168404Spjd
455168404Spjd	if (zhp->zfs_dmustats.dds_is_snapshot)
456168404Spjd		zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
457168404Spjd	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
458168404Spjd		zhp->zfs_type = ZFS_TYPE_VOLUME;
459168404Spjd	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
460168404Spjd		zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
461168404Spjd	else
462168404Spjd		abort();	/* we should never see any other types */
463168404Spjd
464219089Spjd	if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL)
465219089Spjd		return (-1);
466219089Spjd
467209962Smm	return (0);
468209962Smm}
469209962Smm
470209962Smmzfs_handle_t *
471209962Smmmake_dataset_handle(libzfs_handle_t *hdl, const char *path)
472209962Smm{
473209962Smm	zfs_cmd_t zc = { 0 };
474209962Smm
475209962Smm	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
476209962Smm
477209962Smm	if (zhp == NULL)
478209962Smm		return (NULL);
479209962Smm
480209962Smm	zhp->zfs_hdl = hdl;
481209962Smm	(void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
482209962Smm	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
483209962Smm		free(zhp);
484209962Smm		return (NULL);
485209962Smm	}
486209962Smm	if (get_stats_ioctl(zhp, &zc) == -1) {
487209962Smm		zcmd_free_nvlists(&zc);
488209962Smm		free(zhp);
489209962Smm		return (NULL);
490209962Smm	}
491209962Smm	if (make_dataset_handle_common(zhp, &zc) == -1) {
492209962Smm		free(zhp);
493209962Smm		zhp = NULL;
494209962Smm	}
495209962Smm	zcmd_free_nvlists(&zc);
496168404Spjd	return (zhp);
497168404Spjd}
498168404Spjd
499228103Smmzfs_handle_t *
500209962Smmmake_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
501209962Smm{
502209962Smm	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
503209962Smm
504209962Smm	if (zhp == NULL)
505209962Smm		return (NULL);
506209962Smm
507209962Smm	zhp->zfs_hdl = hdl;
508209962Smm	(void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
509209962Smm	if (make_dataset_handle_common(zhp, zc) == -1) {
510209962Smm		free(zhp);
511209962Smm		return (NULL);
512209962Smm	}
513209962Smm	return (zhp);
514209962Smm}
515209962Smm
516228103Smmzfs_handle_t *
517230438Spjdmake_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc)
518230438Spjd{
519230438Spjd	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
520230438Spjd
521230438Spjd	if (zhp == NULL)
522230438Spjd		return (NULL);
523230438Spjd
524230438Spjd	zhp->zfs_hdl = pzhp->zfs_hdl;
525230438Spjd	(void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
526230438Spjd	zhp->zfs_head_type = pzhp->zfs_type;
527230438Spjd	zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
528230438Spjd	zhp->zpool_hdl = zpool_handle(zhp);
529230438Spjd	return (zhp);
530230438Spjd}
531230438Spjd
532230438Spjdzfs_handle_t *
533228103Smmzfs_handle_dup(zfs_handle_t *zhp_orig)
534228103Smm{
535228103Smm	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
536228103Smm
537228103Smm	if (zhp == NULL)
538228103Smm		return (NULL);
539228103Smm
540228103Smm	zhp->zfs_hdl = zhp_orig->zfs_hdl;
541228103Smm	zhp->zpool_hdl = zhp_orig->zpool_hdl;
542228103Smm	(void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
543228103Smm	    sizeof (zhp->zfs_name));
544228103Smm	zhp->zfs_type = zhp_orig->zfs_type;
545228103Smm	zhp->zfs_head_type = zhp_orig->zfs_head_type;
546228103Smm	zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
547228103Smm	if (zhp_orig->zfs_props != NULL) {
548228103Smm		if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
549228103Smm			(void) no_memory(zhp->zfs_hdl);
550228103Smm			zfs_close(zhp);
551228103Smm			return (NULL);
552228103Smm		}
553228103Smm	}
554228103Smm	if (zhp_orig->zfs_user_props != NULL) {
555228103Smm		if (nvlist_dup(zhp_orig->zfs_user_props,
556228103Smm		    &zhp->zfs_user_props, 0) != 0) {
557228103Smm			(void) no_memory(zhp->zfs_hdl);
558228103Smm			zfs_close(zhp);
559228103Smm			return (NULL);
560228103Smm		}
561228103Smm	}
562228103Smm	if (zhp_orig->zfs_recvd_props != NULL) {
563228103Smm		if (nvlist_dup(zhp_orig->zfs_recvd_props,
564228103Smm		    &zhp->zfs_recvd_props, 0)) {
565228103Smm			(void) no_memory(zhp->zfs_hdl);
566228103Smm			zfs_close(zhp);
567228103Smm			return (NULL);
568228103Smm		}
569228103Smm	}
570228103Smm	zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
571228103Smm	if (zhp_orig->zfs_mntopts != NULL) {
572228103Smm		zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
573228103Smm		    zhp_orig->zfs_mntopts);
574228103Smm	}
575228103Smm	zhp->zfs_props_table = zhp_orig->zfs_props_table;
576228103Smm	return (zhp);
577228103Smm}
578228103Smm
579168404Spjd/*
580168404Spjd * Opens the given snapshot, filesystem, or volume.   The 'types'
581168404Spjd * argument is a mask of acceptable types.  The function will print an
582168404Spjd * appropriate error message and return NULL if it can't be opened.
583168404Spjd */
584168404Spjdzfs_handle_t *
585168404Spjdzfs_open(libzfs_handle_t *hdl, const char *path, int types)
586168404Spjd{
587168404Spjd	zfs_handle_t *zhp;
588168404Spjd	char errbuf[1024];
589168404Spjd
590168404Spjd	(void) snprintf(errbuf, sizeof (errbuf),
591168404Spjd	    dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
592168404Spjd
593168404Spjd	/*
594168404Spjd	 * Validate the name before we even try to open it.
595168404Spjd	 */
596185029Spjd	if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) {
597168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
598168404Spjd		    "invalid dataset name"));
599168404Spjd		(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
600168404Spjd		return (NULL);
601168404Spjd	}
602168404Spjd
603168404Spjd	/*
604168404Spjd	 * Try to get stats for the dataset, which will tell us if it exists.
605168404Spjd	 */
606168404Spjd	errno = 0;
607168404Spjd	if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
608168404Spjd		(void) zfs_standard_error(hdl, errno, errbuf);
609168404Spjd		return (NULL);
610168404Spjd	}
611168404Spjd
612168404Spjd	if (!(types & zhp->zfs_type)) {
613168404Spjd		(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
614168404Spjd		zfs_close(zhp);
615168404Spjd		return (NULL);
616168404Spjd	}
617168404Spjd
618168404Spjd	return (zhp);
619168404Spjd}
620168404Spjd
621168404Spjd/*
622168404Spjd * Release a ZFS handle.  Nothing to do but free the associated memory.
623168404Spjd */
624168404Spjdvoid
625168404Spjdzfs_close(zfs_handle_t *zhp)
626168404Spjd{
627168404Spjd	if (zhp->zfs_mntopts)
628168404Spjd		free(zhp->zfs_mntopts);
629168404Spjd	nvlist_free(zhp->zfs_props);
630168404Spjd	nvlist_free(zhp->zfs_user_props);
631219089Spjd	nvlist_free(zhp->zfs_recvd_props);
632168404Spjd	free(zhp);
633168404Spjd}
634168404Spjd
635209962Smmtypedef struct mnttab_node {
636209962Smm	struct mnttab mtn_mt;
637209962Smm	avl_node_t mtn_node;
638209962Smm} mnttab_node_t;
639209962Smm
640209962Smmstatic int
641209962Smmlibzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
642209962Smm{
643209962Smm	const mnttab_node_t *mtn1 = arg1;
644209962Smm	const mnttab_node_t *mtn2 = arg2;
645209962Smm	int rv;
646209962Smm
647209962Smm	rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
648209962Smm
649209962Smm	if (rv == 0)
650209962Smm		return (0);
651209962Smm	return (rv > 0 ? 1 : -1);
652209962Smm}
653209962Smm
654209962Smmvoid
655209962Smmlibzfs_mnttab_init(libzfs_handle_t *hdl)
656209962Smm{
657209962Smm	assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
658209962Smm	avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
659209962Smm	    sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
660209962Smm}
661209962Smm
662209962Smmvoid
663209962Smmlibzfs_mnttab_update(libzfs_handle_t *hdl)
664209962Smm{
665209962Smm	struct mnttab entry;
666209962Smm
667209962Smm	rewind(hdl->libzfs_mnttab);
668209962Smm	while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
669209962Smm		mnttab_node_t *mtn;
670209962Smm
671209962Smm		if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
672209962Smm			continue;
673209962Smm		mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
674209962Smm		mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special);
675209962Smm		mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp);
676209962Smm		mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype);
677209962Smm		mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts);
678209962Smm		avl_add(&hdl->libzfs_mnttab_cache, mtn);
679209962Smm	}
680209962Smm}
681209962Smm
682209962Smmvoid
683209962Smmlibzfs_mnttab_fini(libzfs_handle_t *hdl)
684209962Smm{
685209962Smm	void *cookie = NULL;
686209962Smm	mnttab_node_t *mtn;
687209962Smm
688209962Smm	while (mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) {
689209962Smm		free(mtn->mtn_mt.mnt_special);
690209962Smm		free(mtn->mtn_mt.mnt_mountp);
691209962Smm		free(mtn->mtn_mt.mnt_fstype);
692209962Smm		free(mtn->mtn_mt.mnt_mntopts);
693209962Smm		free(mtn);
694209962Smm	}
695209962Smm	avl_destroy(&hdl->libzfs_mnttab_cache);
696209962Smm}
697209962Smm
698209962Smmvoid
699209962Smmlibzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
700209962Smm{
701209962Smm	hdl->libzfs_mnttab_enable = enable;
702209962Smm}
703209962Smm
704185029Spjdint
705209962Smmlibzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
706209962Smm    struct mnttab *entry)
707209962Smm{
708209962Smm	mnttab_node_t find;
709209962Smm	mnttab_node_t *mtn;
710209962Smm
711209962Smm	if (!hdl->libzfs_mnttab_enable) {
712209962Smm		struct mnttab srch = { 0 };
713209962Smm
714209962Smm		if (avl_numnodes(&hdl->libzfs_mnttab_cache))
715209962Smm			libzfs_mnttab_fini(hdl);
716209962Smm		rewind(hdl->libzfs_mnttab);
717209962Smm		srch.mnt_special = (char *)fsname;
718209962Smm		srch.mnt_fstype = MNTTYPE_ZFS;
719209962Smm		if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0)
720209962Smm			return (0);
721209962Smm		else
722209962Smm			return (ENOENT);
723209962Smm	}
724209962Smm
725209962Smm	if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
726209962Smm		libzfs_mnttab_update(hdl);
727209962Smm
728209962Smm	find.mtn_mt.mnt_special = (char *)fsname;
729209962Smm	mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
730209962Smm	if (mtn) {
731209962Smm		*entry = mtn->mtn_mt;
732209962Smm		return (0);
733209962Smm	}
734209962Smm	return (ENOENT);
735209962Smm}
736209962Smm
737209962Smmvoid
738209962Smmlibzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
739209962Smm    const char *mountp, const char *mntopts)
740209962Smm{
741209962Smm	mnttab_node_t *mtn;
742209962Smm
743209962Smm	if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
744209962Smm		return;
745209962Smm	mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
746209962Smm	mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
747209962Smm	mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
748209962Smm	mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
749209962Smm	mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
750209962Smm	avl_add(&hdl->libzfs_mnttab_cache, mtn);
751209962Smm}
752209962Smm
753209962Smmvoid
754209962Smmlibzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
755209962Smm{
756209962Smm	mnttab_node_t find;
757209962Smm	mnttab_node_t *ret;
758209962Smm
759209962Smm	find.mtn_mt.mnt_special = (char *)fsname;
760209962Smm	if (ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) {
761209962Smm		avl_remove(&hdl->libzfs_mnttab_cache, ret);
762209962Smm		free(ret->mtn_mt.mnt_special);
763209962Smm		free(ret->mtn_mt.mnt_mountp);
764209962Smm		free(ret->mtn_mt.mnt_fstype);
765209962Smm		free(ret->mtn_mt.mnt_mntopts);
766209962Smm		free(ret);
767209962Smm	}
768209962Smm}
769209962Smm
770209962Smmint
771185029Spjdzfs_spa_version(zfs_handle_t *zhp, int *spa_version)
772168404Spjd{
773185029Spjd	zpool_handle_t *zpool_handle = zhp->zpool_hdl;
774168404Spjd
775185029Spjd	if (zpool_handle == NULL)
776168404Spjd		return (-1);
777168404Spjd
778185029Spjd	*spa_version = zpool_get_prop_int(zpool_handle,
779185029Spjd	    ZPOOL_PROP_VERSION, NULL);
780168404Spjd	return (0);
781168404Spjd}
782168404Spjd
783168404Spjd/*
784185029Spjd * The choice of reservation property depends on the SPA version.
785168404Spjd */
786168404Spjdstatic int
787185029Spjdzfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
788168404Spjd{
789185029Spjd	int spa_version;
790168404Spjd
791185029Spjd	if (zfs_spa_version(zhp, &spa_version) < 0)
792168404Spjd		return (-1);
793168404Spjd
794185029Spjd	if (spa_version >= SPA_VERSION_REFRESERVATION)
795185029Spjd		*resv_prop = ZFS_PROP_REFRESERVATION;
796185029Spjd	else
797185029Spjd		*resv_prop = ZFS_PROP_RESERVATION;
798168404Spjd
799168404Spjd	return (0);
800168404Spjd}
801168404Spjd
802168404Spjd/*
803168404Spjd * Given an nvlist of properties to set, validates that they are correct, and
804168404Spjd * parses any numeric properties (index, boolean, etc) if they are specified as
805168404Spjd * strings.
806168404Spjd */
807168404Spjdnvlist_t *
808185029Spjdzfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
809185029Spjd    uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
810168404Spjd{
811168404Spjd	nvpair_t *elem;
812168404Spjd	uint64_t intval;
813168404Spjd	char *strval;
814185029Spjd	zfs_prop_t prop;
815168404Spjd	nvlist_t *ret;
816185029Spjd	int chosen_normal = -1;
817185029Spjd	int chosen_utf = -1;
818168404Spjd
819168404Spjd	if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
820168404Spjd		(void) no_memory(hdl);
821168404Spjd		return (NULL);
822168404Spjd	}
823168404Spjd
824209962Smm	/*
825209962Smm	 * Make sure this property is valid and applies to this type.
826209962Smm	 */
827209962Smm
828168404Spjd	elem = NULL;
829168404Spjd	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
830185029Spjd		const char *propname = nvpair_name(elem);
831168404Spjd
832209962Smm		prop = zfs_name_to_prop(propname);
833209962Smm		if (prop == ZPROP_INVAL && zfs_prop_user(propname)) {
834185029Spjd			/*
835209962Smm			 * This is a user property: make sure it's a
836185029Spjd			 * string, and that it's less than ZAP_MAXNAMELEN.
837185029Spjd			 */
838185029Spjd			if (nvpair_type(elem) != DATA_TYPE_STRING) {
839185029Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
840185029Spjd				    "'%s' must be a string"), propname);
841185029Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
842185029Spjd				goto error;
843168404Spjd			}
844168404Spjd
845185029Spjd			if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
846185029Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
847185029Spjd				    "property name '%s' is too long"),
848185029Spjd				    propname);
849185029Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
850185029Spjd				goto error;
851185029Spjd			}
852185029Spjd
853168404Spjd			(void) nvpair_value_string(elem, &strval);
854168404Spjd			if (nvlist_add_string(ret, propname, strval) != 0) {
855168404Spjd				(void) no_memory(hdl);
856168404Spjd				goto error;
857168404Spjd			}
858168404Spjd			continue;
859168404Spjd		}
860168404Spjd
861209962Smm		/*
862209962Smm		 * Currently, only user properties can be modified on
863209962Smm		 * snapshots.
864209962Smm		 */
865185029Spjd		if (type == ZFS_TYPE_SNAPSHOT) {
866185029Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
867185029Spjd			    "this property can not be modified for snapshots"));
868185029Spjd			(void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
869185029Spjd			goto error;
870185029Spjd		}
871168404Spjd
872209962Smm		if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) {
873209962Smm			zfs_userquota_prop_t uqtype;
874209962Smm			char newpropname[128];
875209962Smm			char domain[128];
876209962Smm			uint64_t rid;
877209962Smm			uint64_t valary[3];
878209962Smm
879209962Smm			if (userquota_propname_decode(propname, zoned,
880209962Smm			    &uqtype, domain, sizeof (domain), &rid) != 0) {
881209962Smm				zfs_error_aux(hdl,
882209962Smm				    dgettext(TEXT_DOMAIN,
883209962Smm				    "'%s' has an invalid user/group name"),
884209962Smm				    propname);
885209962Smm				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
886209962Smm				goto error;
887209962Smm			}
888209962Smm
889209962Smm			if (uqtype != ZFS_PROP_USERQUOTA &&
890209962Smm			    uqtype != ZFS_PROP_GROUPQUOTA) {
891209962Smm				zfs_error_aux(hdl,
892209962Smm				    dgettext(TEXT_DOMAIN, "'%s' is readonly"),
893209962Smm				    propname);
894209962Smm				(void) zfs_error(hdl, EZFS_PROPREADONLY,
895209962Smm				    errbuf);
896209962Smm				goto error;
897209962Smm			}
898209962Smm
899209962Smm			if (nvpair_type(elem) == DATA_TYPE_STRING) {
900209962Smm				(void) nvpair_value_string(elem, &strval);
901209962Smm				if (strcmp(strval, "none") == 0) {
902209962Smm					intval = 0;
903209962Smm				} else if (zfs_nicestrtonum(hdl,
904209962Smm				    strval, &intval) != 0) {
905209962Smm					(void) zfs_error(hdl,
906209962Smm					    EZFS_BADPROP, errbuf);
907209962Smm					goto error;
908209962Smm				}
909209962Smm			} else if (nvpair_type(elem) ==
910209962Smm			    DATA_TYPE_UINT64) {
911209962Smm				(void) nvpair_value_uint64(elem, &intval);
912209962Smm				if (intval == 0) {
913209962Smm					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
914209962Smm					    "use 'none' to disable "
915209962Smm					    "userquota/groupquota"));
916209962Smm					goto error;
917209962Smm				}
918209962Smm			} else {
919209962Smm				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
920209962Smm				    "'%s' must be a number"), propname);
921209962Smm				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
922209962Smm				goto error;
923209962Smm			}
924209962Smm
925219089Spjd			/*
926219089Spjd			 * Encode the prop name as
927219089Spjd			 * userquota@<hex-rid>-domain, to make it easy
928219089Spjd			 * for the kernel to decode.
929219089Spjd			 */
930209962Smm			(void) snprintf(newpropname, sizeof (newpropname),
931219089Spjd			    "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype],
932219089Spjd			    (longlong_t)rid, domain);
933209962Smm			valary[0] = uqtype;
934209962Smm			valary[1] = rid;
935209962Smm			valary[2] = intval;
936209962Smm			if (nvlist_add_uint64_array(ret, newpropname,
937209962Smm			    valary, 3) != 0) {
938209962Smm				(void) no_memory(hdl);
939209962Smm				goto error;
940209962Smm			}
941209962Smm			continue;
942228103Smm		} else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
943228103Smm			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
944228103Smm			    "'%s' is readonly"),
945228103Smm			    propname);
946228103Smm			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
947228103Smm			goto error;
948209962Smm		}
949209962Smm
950209962Smm		if (prop == ZPROP_INVAL) {
951209962Smm			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
952209962Smm			    "invalid property '%s'"), propname);
953209962Smm			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
954209962Smm			goto error;
955209962Smm		}
956209962Smm
957168404Spjd		if (!zfs_prop_valid_for_type(prop, type)) {
958168404Spjd			zfs_error_aux(hdl,
959168404Spjd			    dgettext(TEXT_DOMAIN, "'%s' does not "
960168404Spjd			    "apply to datasets of this type"), propname);
961168404Spjd			(void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
962168404Spjd			goto error;
963168404Spjd		}
964168404Spjd
965168404Spjd		if (zfs_prop_readonly(prop) &&
966185029Spjd		    (!zfs_prop_setonce(prop) || zhp != NULL)) {
967168404Spjd			zfs_error_aux(hdl,
968168404Spjd			    dgettext(TEXT_DOMAIN, "'%s' is readonly"),
969168404Spjd			    propname);
970168404Spjd			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
971168404Spjd			goto error;
972168404Spjd		}
973168404Spjd
974185029Spjd		if (zprop_parse_value(hdl, elem, prop, type, ret,
975185029Spjd		    &strval, &intval, errbuf) != 0)
976185029Spjd			goto error;
977185029Spjd
978168404Spjd		/*
979185029Spjd		 * Perform some additional checks for specific properties.
980168404Spjd		 */
981185029Spjd		switch (prop) {
982185029Spjd		case ZFS_PROP_VERSION:
983185029Spjd		{
984185029Spjd			int version;
985168404Spjd
986185029Spjd			if (zhp == NULL)
987185029Spjd				break;
988185029Spjd			version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
989185029Spjd			if (intval < version) {
990168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
991185029Spjd				    "Can not downgrade; already at version %u"),
992185029Spjd				    version);
993168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
994168404Spjd				goto error;
995168404Spjd			}
996168404Spjd			break;
997168404Spjd		}
998168404Spjd
999168404Spjd		case ZFS_PROP_RECORDSIZE:
1000168404Spjd		case ZFS_PROP_VOLBLOCKSIZE:
1001168404Spjd			/* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */
1002168404Spjd			if (intval < SPA_MINBLOCKSIZE ||
1003168404Spjd			    intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) {
1004168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1005168404Spjd				    "'%s' must be power of 2 from %u "
1006168404Spjd				    "to %uk"), propname,
1007168404Spjd				    (uint_t)SPA_MINBLOCKSIZE,
1008168404Spjd				    (uint_t)SPA_MAXBLOCKSIZE >> 10);
1009168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1010168404Spjd				goto error;
1011168404Spjd			}
1012168404Spjd			break;
1013168404Spjd
1014219089Spjd		case ZFS_PROP_MLSLABEL:
1015219089Spjd		{
1016219089Spjd#ifdef sun
1017219089Spjd			/*
1018219089Spjd			 * Verify the mlslabel string and convert to
1019219089Spjd			 * internal hex label string.
1020219089Spjd			 */
1021219089Spjd
1022219089Spjd			m_label_t *new_sl;
1023219089Spjd			char *hex = NULL;	/* internal label string */
1024219089Spjd
1025219089Spjd			/* Default value is already OK. */
1026219089Spjd			if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
1027219089Spjd				break;
1028219089Spjd
1029219089Spjd			/* Verify the label can be converted to binary form */
1030219089Spjd			if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) ||
1031219089Spjd			    (str_to_label(strval, &new_sl, MAC_LABEL,
1032219089Spjd			    L_NO_CORRECTION, NULL) == -1)) {
1033219089Spjd				goto badlabel;
1034168404Spjd			}
1035168404Spjd
1036219089Spjd			/* Now translate to hex internal label string */
1037219089Spjd			if (label_to_str(new_sl, &hex, M_INTERNAL,
1038219089Spjd			    DEF_NAMES) != 0) {
1039219089Spjd				if (hex)
1040219089Spjd					free(hex);
1041219089Spjd				goto badlabel;
1042219089Spjd			}
1043219089Spjd			m_label_free(new_sl);
1044219089Spjd
1045219089Spjd			/* If string is already in internal form, we're done. */
1046219089Spjd			if (strcmp(strval, hex) == 0) {
1047219089Spjd				free(hex);
1048219089Spjd				break;
1049219089Spjd			}
1050219089Spjd
1051219089Spjd			/* Replace the label string with the internal form. */
1052219089Spjd			(void) nvlist_remove(ret, zfs_prop_to_name(prop),
1053219089Spjd			    DATA_TYPE_STRING);
1054219089Spjd			verify(nvlist_add_string(ret, zfs_prop_to_name(prop),
1055219089Spjd			    hex) == 0);
1056219089Spjd			free(hex);
1057219089Spjd
1058168404Spjd			break;
1059168404Spjd
1060219089Spjdbadlabel:
1061219089Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1062219089Spjd			    "invalid mlslabel '%s'"), strval);
1063219089Spjd			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1064219089Spjd			m_label_free(new_sl);	/* OK if null */
1065219089Spjd#else	/* !sun */
1066219089Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1067219089Spjd			    "mlslabel is not supported on FreeBSD"));
1068219089Spjd			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1069219089Spjd#endif	/* !sun */
1070219089Spjd			goto error;
1071219089Spjd
1072219089Spjd		}
1073219089Spjd
1074168404Spjd		case ZFS_PROP_MOUNTPOINT:
1075185029Spjd		{
1076185029Spjd			namecheck_err_t why;
1077185029Spjd
1078168404Spjd			if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
1079168404Spjd			    strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
1080168404Spjd				break;
1081168404Spjd
1082185029Spjd			if (mountpoint_namecheck(strval, &why)) {
1083185029Spjd				switch (why) {
1084185029Spjd				case NAME_ERR_LEADING_SLASH:
1085185029Spjd					zfs_error_aux(hdl,
1086185029Spjd					    dgettext(TEXT_DOMAIN,
1087185029Spjd					    "'%s' must be an absolute path, "
1088185029Spjd					    "'none', or 'legacy'"), propname);
1089185029Spjd					break;
1090185029Spjd				case NAME_ERR_TOOLONG:
1091185029Spjd					zfs_error_aux(hdl,
1092185029Spjd					    dgettext(TEXT_DOMAIN,
1093185029Spjd					    "component of '%s' is too long"),
1094185029Spjd					    propname);
1095185029Spjd					break;
1096185029Spjd				}
1097168404Spjd				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1098168404Spjd				goto error;
1099168404Spjd			}
1100185029Spjd		}
1101185029Spjd
1102168404Spjd			/*FALLTHRU*/
1103168404Spjd
1104185029Spjd		case ZFS_PROP_SHARESMB:
1105168404Spjd		case ZFS_PROP_SHARENFS:
1106168404Spjd			/*
1107185029Spjd			 * For the mountpoint and sharenfs or sharesmb
1108185029Spjd			 * properties, check if it can be set in a
1109185029Spjd			 * global/non-global zone based on
1110168404Spjd			 * the zoned property value:
1111168404Spjd			 *
1112168404Spjd			 *		global zone	    non-global zone
1113168404Spjd			 * --------------------------------------------------
1114168404Spjd			 * zoned=on	mountpoint (no)	    mountpoint (yes)
1115168404Spjd			 *		sharenfs (no)	    sharenfs (no)
1116185029Spjd			 *		sharesmb (no)	    sharesmb (no)
1117168404Spjd			 *
1118168404Spjd			 * zoned=off	mountpoint (yes)	N/A
1119168404Spjd			 *		sharenfs (yes)
1120185029Spjd			 *		sharesmb (yes)
1121168404Spjd			 */
1122168404Spjd			if (zoned) {
1123168404Spjd				if (getzoneid() == GLOBAL_ZONEID) {
1124168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1125168404Spjd					    "'%s' cannot be set on "
1126168404Spjd					    "dataset in a non-global zone"),
1127168404Spjd					    propname);
1128168404Spjd					(void) zfs_error(hdl, EZFS_ZONED,
1129168404Spjd					    errbuf);
1130168404Spjd					goto error;
1131185029Spjd				} else if (prop == ZFS_PROP_SHARENFS ||
1132185029Spjd				    prop == ZFS_PROP_SHARESMB) {
1133168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1134168404Spjd					    "'%s' cannot be set in "
1135168404Spjd					    "a non-global zone"), propname);
1136168404Spjd					(void) zfs_error(hdl, EZFS_ZONED,
1137168404Spjd					    errbuf);
1138168404Spjd					goto error;
1139168404Spjd				}
1140168404Spjd			} else if (getzoneid() != GLOBAL_ZONEID) {
1141168404Spjd				/*
1142168404Spjd				 * If zoned property is 'off', this must be in
1143209962Smm				 * a global zone. If not, something is wrong.
1144168404Spjd				 */
1145168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1146168404Spjd				    "'%s' cannot be set while dataset "
1147168404Spjd				    "'zoned' property is set"), propname);
1148168404Spjd				(void) zfs_error(hdl, EZFS_ZONED, errbuf);
1149168404Spjd				goto error;
1150168404Spjd			}
1151168404Spjd
1152168404Spjd			/*
1153185029Spjd			 * At this point, it is legitimate to set the
1154185029Spjd			 * property. Now we want to make sure that the
1155185029Spjd			 * property value is valid if it is sharenfs.
1156168404Spjd			 */
1157185029Spjd			if ((prop == ZFS_PROP_SHARENFS ||
1158185029Spjd			    prop == ZFS_PROP_SHARESMB) &&
1159185029Spjd			    strcmp(strval, "on") != 0 &&
1160185029Spjd			    strcmp(strval, "off") != 0) {
1161185029Spjd				zfs_share_proto_t proto;
1162168404Spjd
1163185029Spjd				if (prop == ZFS_PROP_SHARESMB)
1164185029Spjd					proto = PROTO_SMB;
1165185029Spjd				else
1166185029Spjd					proto = PROTO_NFS;
1167185029Spjd
1168185029Spjd				/*
1169185029Spjd				 * Must be an valid sharing protocol
1170185029Spjd				 * option string so init the libshare
1171185029Spjd				 * in order to enable the parser and
1172185029Spjd				 * then parse the options. We use the
1173185029Spjd				 * control API since we don't care about
1174185029Spjd				 * the current configuration and don't
1175185029Spjd				 * want the overhead of loading it
1176185029Spjd				 * until we actually do something.
1177185029Spjd				 */
1178185029Spjd
1179185029Spjd				if (zfs_init_libshare(hdl,
1180185029Spjd				    SA_INIT_CONTROL_API) != SA_OK) {
1181185029Spjd					/*
1182185029Spjd					 * An error occurred so we can't do
1183185029Spjd					 * anything
1184185029Spjd					 */
1185185029Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1186185029Spjd					    "'%s' cannot be set: problem "
1187185029Spjd					    "in share initialization"),
1188185029Spjd					    propname);
1189185029Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
1190185029Spjd					    errbuf);
1191185029Spjd					goto error;
1192185029Spjd				}
1193185029Spjd
1194185029Spjd				if (zfs_parse_options(strval, proto) != SA_OK) {
1195185029Spjd					/*
1196185029Spjd					 * There was an error in parsing so
1197185029Spjd					 * deal with it by issuing an error
1198185029Spjd					 * message and leaving after
1199185029Spjd					 * uninitializing the the libshare
1200185029Spjd					 * interface.
1201185029Spjd					 */
1202185029Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1203185029Spjd					    "'%s' cannot be set to invalid "
1204185029Spjd					    "options"), propname);
1205185029Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
1206185029Spjd					    errbuf);
1207185029Spjd					zfs_uninit_libshare(hdl);
1208185029Spjd					goto error;
1209185029Spjd				}
1210185029Spjd				zfs_uninit_libshare(hdl);
1211168404Spjd			}
1212185029Spjd
1213168404Spjd			break;
1214185029Spjd		case ZFS_PROP_UTF8ONLY:
1215185029Spjd			chosen_utf = (int)intval;
1216185029Spjd			break;
1217185029Spjd		case ZFS_PROP_NORMALIZE:
1218185029Spjd			chosen_normal = (int)intval;
1219185029Spjd			break;
1220168404Spjd		}
1221168404Spjd
1222168404Spjd		/*
1223168404Spjd		 * For changes to existing volumes, we have some additional
1224168404Spjd		 * checks to enforce.
1225168404Spjd		 */
1226168404Spjd		if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
1227168404Spjd			uint64_t volsize = zfs_prop_get_int(zhp,
1228168404Spjd			    ZFS_PROP_VOLSIZE);
1229168404Spjd			uint64_t blocksize = zfs_prop_get_int(zhp,
1230168404Spjd			    ZFS_PROP_VOLBLOCKSIZE);
1231168404Spjd			char buf[64];
1232168404Spjd
1233168404Spjd			switch (prop) {
1234168404Spjd			case ZFS_PROP_RESERVATION:
1235185029Spjd			case ZFS_PROP_REFRESERVATION:
1236168404Spjd				if (intval > volsize) {
1237168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1238168404Spjd					    "'%s' is greater than current "
1239168404Spjd					    "volume size"), propname);
1240168404Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
1241168404Spjd					    errbuf);
1242168404Spjd					goto error;
1243168404Spjd				}
1244168404Spjd				break;
1245168404Spjd
1246168404Spjd			case ZFS_PROP_VOLSIZE:
1247168404Spjd				if (intval % blocksize != 0) {
1248168404Spjd					zfs_nicenum(blocksize, buf,
1249168404Spjd					    sizeof (buf));
1250168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1251168404Spjd					    "'%s' must be a multiple of "
1252168404Spjd					    "volume block size (%s)"),
1253168404Spjd					    propname, buf);
1254168404Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
1255168404Spjd					    errbuf);
1256168404Spjd					goto error;
1257168404Spjd				}
1258168404Spjd
1259168404Spjd				if (intval == 0) {
1260168404Spjd					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1261168404Spjd					    "'%s' cannot be zero"),
1262168404Spjd					    propname);
1263168404Spjd					(void) zfs_error(hdl, EZFS_BADPROP,
1264168404Spjd					    errbuf);
1265168404Spjd					goto error;
1266168404Spjd				}
1267168404Spjd				break;
1268168404Spjd			}
1269168404Spjd		}
1270168404Spjd	}
1271168404Spjd
1272168404Spjd	/*
1273185029Spjd	 * If normalization was chosen, but no UTF8 choice was made,
1274185029Spjd	 * enforce rejection of non-UTF8 names.
1275185029Spjd	 *
1276185029Spjd	 * If normalization was chosen, but rejecting non-UTF8 names
1277185029Spjd	 * was explicitly not chosen, it is an error.
1278185029Spjd	 */
1279185029Spjd	if (chosen_normal > 0 && chosen_utf < 0) {
1280185029Spjd		if (nvlist_add_uint64(ret,
1281185029Spjd		    zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
1282185029Spjd			(void) no_memory(hdl);
1283185029Spjd			goto error;
1284185029Spjd		}
1285185029Spjd	} else if (chosen_normal > 0 && chosen_utf == 0) {
1286185029Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1287185029Spjd		    "'%s' must be set 'on' if normalization chosen"),
1288185029Spjd		    zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
1289185029Spjd		(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1290185029Spjd		goto error;
1291185029Spjd	}
1292219089Spjd	return (ret);
1293185029Spjd
1294219089Spjderror:
1295219089Spjd	nvlist_free(ret);
1296219089Spjd	return (NULL);
1297219089Spjd}
1298219089Spjd
1299219089Spjdint
1300219089Spjdzfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
1301219089Spjd{
1302219089Spjd	uint64_t old_volsize;
1303219089Spjd	uint64_t new_volsize;
1304219089Spjd	uint64_t old_reservation;
1305219089Spjd	uint64_t new_reservation;
1306219089Spjd	zfs_prop_t resv_prop;
1307219089Spjd
1308185029Spjd	/*
1309168404Spjd	 * If this is an existing volume, and someone is setting the volsize,
1310168404Spjd	 * make sure that it matches the reservation, or add it if necessary.
1311168404Spjd	 */
1312219089Spjd	old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
1313219089Spjd	if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
1314219089Spjd		return (-1);
1315219089Spjd	old_reservation = zfs_prop_get_int(zhp, resv_prop);
1316219089Spjd	if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) !=
1317219089Spjd	    old_reservation) || nvlist_lookup_uint64(nvl,
1318219089Spjd	    zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) {
1319219089Spjd		return (0);
1320219089Spjd	}
1321219089Spjd	if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1322219089Spjd	    &new_volsize) != 0)
1323219089Spjd		return (-1);
1324219089Spjd	new_reservation = zvol_volsize_to_reservation(new_volsize,
1325219089Spjd	    zhp->zfs_props);
1326219089Spjd	if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
1327219089Spjd	    new_reservation) != 0) {
1328219089Spjd		(void) no_memory(zhp->zfs_hdl);
1329219089Spjd		return (-1);
1330219089Spjd	}
1331219089Spjd	return (1);
1332219089Spjd}
1333168404Spjd
1334219089Spjdvoid
1335219089Spjdzfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
1336219089Spjd    char *errbuf)
1337219089Spjd{
1338219089Spjd	switch (err) {
1339185029Spjd
1340219089Spjd	case ENOSPC:
1341219089Spjd		/*
1342219089Spjd		 * For quotas and reservations, ENOSPC indicates
1343219089Spjd		 * something different; setting a quota or reservation
1344219089Spjd		 * doesn't use any disk space.
1345219089Spjd		 */
1346219089Spjd		switch (prop) {
1347219089Spjd		case ZFS_PROP_QUOTA:
1348219089Spjd		case ZFS_PROP_REFQUOTA:
1349219089Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1350219089Spjd			    "size is less than current used or "
1351219089Spjd			    "reserved space"));
1352219089Spjd			(void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1353219089Spjd			break;
1354219089Spjd
1355219089Spjd		case ZFS_PROP_RESERVATION:
1356219089Spjd		case ZFS_PROP_REFRESERVATION:
1357219089Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1358219089Spjd			    "size is greater than available space"));
1359219089Spjd			(void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
1360219089Spjd			break;
1361219089Spjd
1362219089Spjd		default:
1363219089Spjd			(void) zfs_standard_error(hdl, err, errbuf);
1364219089Spjd			break;
1365168404Spjd		}
1366219089Spjd		break;
1367219089Spjd
1368219089Spjd	case EBUSY:
1369219089Spjd		(void) zfs_standard_error(hdl, EBUSY, errbuf);
1370219089Spjd		break;
1371219089Spjd
1372219089Spjd	case EROFS:
1373219089Spjd		(void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
1374219089Spjd		break;
1375219089Spjd
1376219089Spjd	case ENOTSUP:
1377219089Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1378219089Spjd		    "pool and or dataset must be upgraded to set this "
1379219089Spjd		    "property or value"));
1380219089Spjd		(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
1381219089Spjd		break;
1382219089Spjd
1383219089Spjd	case ERANGE:
1384219089Spjd		if (prop == ZFS_PROP_COMPRESSION) {
1385219089Spjd			(void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1386219089Spjd			    "property setting is not allowed on "
1387219089Spjd			    "bootable datasets"));
1388219089Spjd			(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
1389219089Spjd		} else {
1390219089Spjd			(void) zfs_standard_error(hdl, err, errbuf);
1391219089Spjd		}
1392219089Spjd		break;
1393219089Spjd
1394219089Spjd	case EINVAL:
1395219089Spjd		if (prop == ZPROP_INVAL) {
1396219089Spjd			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
1397219089Spjd		} else {
1398219089Spjd			(void) zfs_standard_error(hdl, err, errbuf);
1399219089Spjd		}
1400219089Spjd		break;
1401219089Spjd
1402219089Spjd	case EOVERFLOW:
1403219089Spjd		/*
1404219089Spjd		 * This platform can't address a volume this big.
1405219089Spjd		 */
1406219089Spjd#ifdef _ILP32
1407219089Spjd		if (prop == ZFS_PROP_VOLSIZE) {
1408219089Spjd			(void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
1409219089Spjd			break;
1410219089Spjd		}
1411219089Spjd#endif
1412219089Spjd		/* FALLTHROUGH */
1413219089Spjd	default:
1414219089Spjd		(void) zfs_standard_error(hdl, err, errbuf);
1415168404Spjd	}
1416168404Spjd}
1417168404Spjd
1418168404Spjd/*
1419168404Spjd * Given a property name and value, set the property for the given dataset.
1420168404Spjd */
1421168404Spjdint
1422168404Spjdzfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
1423168404Spjd{
1424168404Spjd	zfs_cmd_t zc = { 0 };
1425168404Spjd	int ret = -1;
1426168404Spjd	prop_changelist_t *cl = NULL;
1427168404Spjd	char errbuf[1024];
1428168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
1429168404Spjd	nvlist_t *nvl = NULL, *realprops;
1430168404Spjd	zfs_prop_t prop;
1431185029Spjd	boolean_t do_prefix;
1432185029Spjd	uint64_t idx;
1433219089Spjd	int added_resv;
1434168404Spjd
1435168404Spjd	(void) snprintf(errbuf, sizeof (errbuf),
1436168404Spjd	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
1437168404Spjd	    zhp->zfs_name);
1438168404Spjd
1439168404Spjd	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
1440168404Spjd	    nvlist_add_string(nvl, propname, propval) != 0) {
1441168404Spjd		(void) no_memory(hdl);
1442168404Spjd		goto error;
1443168404Spjd	}
1444168404Spjd
1445185029Spjd	if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl,
1446168404Spjd	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL)
1447168404Spjd		goto error;
1448185029Spjd
1449168404Spjd	nvlist_free(nvl);
1450168404Spjd	nvl = realprops;
1451168404Spjd
1452168404Spjd	prop = zfs_name_to_prop(propname);
1453168404Spjd
1454168404Spjd	/* We don't support those properties on FreeBSD. */
1455168404Spjd	switch (prop) {
1456197867Strasz	case ZFS_PROP_DEVICES:
1457168404Spjd	case ZFS_PROP_ISCSIOPTIONS:
1458197867Strasz	case ZFS_PROP_XATTR:
1459197867Strasz	case ZFS_PROP_VSCAN:
1460197867Strasz	case ZFS_PROP_NBMAND:
1461219089Spjd	case ZFS_PROP_MLSLABEL:
1462168404Spjd		(void) snprintf(errbuf, sizeof (errbuf),
1463168404Spjd		    "property '%s' not supported on FreeBSD", propname);
1464168404Spjd		ret = zfs_error(hdl, EZFS_PERM, errbuf);
1465168404Spjd		goto error;
1466168404Spjd	}
1467168404Spjd
1468219089Spjd	if (prop == ZFS_PROP_VOLSIZE) {
1469219089Spjd		if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1)
1470219089Spjd			goto error;
1471219089Spjd	}
1472219089Spjd
1473185029Spjd	if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
1474168404Spjd		goto error;
1475168404Spjd
1476168404Spjd	if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
1477168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1478168404Spjd		    "child dataset with inherited mountpoint is used "
1479168404Spjd		    "in a non-global zone"));
1480168404Spjd		ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1481168404Spjd		goto error;
1482168404Spjd	}
1483168404Spjd
1484185029Spjd	/*
1485185029Spjd	 * If the dataset's canmount property is being set to noauto,
1486185029Spjd	 * then we want to prevent unmounting & remounting it.
1487185029Spjd	 */
1488185029Spjd	do_prefix = !((prop == ZFS_PROP_CANMOUNT) &&
1489185029Spjd	    (zprop_string_to_index(prop, propval, &idx,
1490185029Spjd	    ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO));
1491185029Spjd
1492185029Spjd	if (do_prefix && (ret = changelist_prefix(cl)) != 0)
1493168404Spjd		goto error;
1494168404Spjd
1495168404Spjd	/*
1496168404Spjd	 * Execute the corresponding ioctl() to set this property.
1497168404Spjd	 */
1498168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1499168404Spjd
1500185029Spjd	if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
1501168404Spjd		goto error;
1502168404Spjd
1503185029Spjd	ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1504209962Smm
1505168404Spjd	if (ret != 0) {
1506219089Spjd		zfs_setprop_error(hdl, prop, errno, errbuf);
1507219089Spjd		if (added_resv && errno == ENOSPC) {
1508219089Spjd			/* clean up the volsize property we tried to set */
1509219089Spjd			uint64_t old_volsize = zfs_prop_get_int(zhp,
1510219089Spjd			    ZFS_PROP_VOLSIZE);
1511219089Spjd			nvlist_free(nvl);
1512219089Spjd			zcmd_free_nvlists(&zc);
1513219089Spjd			if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1514219089Spjd				goto error;
1515219089Spjd			if (nvlist_add_uint64(nvl,
1516219089Spjd			    zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1517219089Spjd			    old_volsize) != 0)
1518219089Spjd				goto error;
1519219089Spjd			if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
1520219089Spjd				goto error;
1521219089Spjd			(void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
1522168404Spjd		}
1523168404Spjd	} else {
1524185029Spjd		if (do_prefix)
1525185029Spjd			ret = changelist_postfix(cl);
1526185029Spjd
1527168404Spjd		/*
1528168404Spjd		 * Refresh the statistics so the new property value
1529168404Spjd		 * is reflected.
1530168404Spjd		 */
1531185029Spjd		if (ret == 0)
1532168404Spjd			(void) get_stats(zhp);
1533168404Spjd	}
1534168404Spjd
1535168404Spjderror:
1536168404Spjd	nvlist_free(nvl);
1537168404Spjd	zcmd_free_nvlists(&zc);
1538168404Spjd	if (cl)
1539168404Spjd		changelist_free(cl);
1540168404Spjd	return (ret);
1541168404Spjd}
1542168404Spjd
1543168404Spjd/*
1544219089Spjd * Given a property, inherit the value from the parent dataset, or if received
1545219089Spjd * is TRUE, revert to the received value, if any.
1546168404Spjd */
1547168404Spjdint
1548219089Spjdzfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received)
1549168404Spjd{
1550168404Spjd	zfs_cmd_t zc = { 0 };
1551168404Spjd	int ret;
1552168404Spjd	prop_changelist_t *cl;
1553168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
1554168404Spjd	char errbuf[1024];
1555168404Spjd	zfs_prop_t prop;
1556168404Spjd
1557168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1558168404Spjd	    "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
1559168404Spjd
1560219089Spjd	zc.zc_cookie = received;
1561185029Spjd	if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
1562168404Spjd		/*
1563168404Spjd		 * For user properties, the amount of work we have to do is very
1564168404Spjd		 * small, so just do it here.
1565168404Spjd		 */
1566168404Spjd		if (!zfs_prop_user(propname)) {
1567168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1568168404Spjd			    "invalid property"));
1569168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
1570168404Spjd		}
1571168404Spjd
1572168404Spjd		(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1573168404Spjd		(void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1574168404Spjd
1575185029Spjd		if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0)
1576168404Spjd			return (zfs_standard_error(hdl, errno, errbuf));
1577168404Spjd
1578168404Spjd		return (0);
1579168404Spjd	}
1580168404Spjd
1581168404Spjd	/*
1582168404Spjd	 * Verify that this property is inheritable.
1583168404Spjd	 */
1584168404Spjd	if (zfs_prop_readonly(prop))
1585168404Spjd		return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
1586168404Spjd
1587219089Spjd	if (!zfs_prop_inheritable(prop) && !received)
1588168404Spjd		return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
1589168404Spjd
1590168404Spjd	/*
1591168404Spjd	 * Check to see if the value applies to this type
1592168404Spjd	 */
1593168404Spjd	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
1594168404Spjd		return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
1595168404Spjd
1596168404Spjd	/*
1597219089Spjd	 * Normalize the name, to get rid of shorthand abbreviations.
1598168404Spjd	 */
1599168404Spjd	propname = zfs_prop_to_name(prop);
1600168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1601168404Spjd	(void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
1602168404Spjd
1603168404Spjd	if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
1604168404Spjd	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
1605168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1606168404Spjd		    "dataset is used in a non-global zone"));
1607168404Spjd		return (zfs_error(hdl, EZFS_ZONED, errbuf));
1608168404Spjd	}
1609168404Spjd
1610168404Spjd	/*
1611168404Spjd	 * Determine datasets which will be affected by this change, if any.
1612168404Spjd	 */
1613185029Spjd	if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
1614168404Spjd		return (-1);
1615168404Spjd
1616168404Spjd	if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
1617168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1618168404Spjd		    "child dataset with inherited mountpoint is used "
1619168404Spjd		    "in a non-global zone"));
1620168404Spjd		ret = zfs_error(hdl, EZFS_ZONED, errbuf);
1621168404Spjd		goto error;
1622168404Spjd	}
1623168404Spjd
1624168404Spjd	if ((ret = changelist_prefix(cl)) != 0)
1625168404Spjd		goto error;
1626168404Spjd
1627185029Spjd	if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) {
1628168404Spjd		return (zfs_standard_error(hdl, errno, errbuf));
1629168404Spjd	} else {
1630168404Spjd
1631168404Spjd		if ((ret = changelist_postfix(cl)) != 0)
1632168404Spjd			goto error;
1633168404Spjd
1634168404Spjd		/*
1635168404Spjd		 * Refresh the statistics so the new property is reflected.
1636168404Spjd		 */
1637168404Spjd		(void) get_stats(zhp);
1638168404Spjd	}
1639168404Spjd
1640168404Spjderror:
1641168404Spjd	changelist_free(cl);
1642168404Spjd	return (ret);
1643168404Spjd}
1644168404Spjd
1645168404Spjd/*
1646168404Spjd * True DSL properties are stored in an nvlist.  The following two functions
1647168404Spjd * extract them appropriately.
1648168404Spjd */
1649168404Spjdstatic uint64_t
1650168404Spjdgetprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1651168404Spjd{
1652168404Spjd	nvlist_t *nv;
1653168404Spjd	uint64_t value;
1654168404Spjd
1655168404Spjd	*source = NULL;
1656168404Spjd	if (nvlist_lookup_nvlist(zhp->zfs_props,
1657168404Spjd	    zfs_prop_to_name(prop), &nv) == 0) {
1658185029Spjd		verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
1659185029Spjd		(void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
1660168404Spjd	} else {
1661205198Sdelphij		verify(!zhp->zfs_props_table ||
1662205198Sdelphij		    zhp->zfs_props_table[prop] == B_TRUE);
1663168404Spjd		value = zfs_prop_default_numeric(prop);
1664168404Spjd		*source = "";
1665168404Spjd	}
1666168404Spjd
1667168404Spjd	return (value);
1668168404Spjd}
1669168404Spjd
1670168404Spjdstatic char *
1671168404Spjdgetprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
1672168404Spjd{
1673168404Spjd	nvlist_t *nv;
1674168404Spjd	char *value;
1675168404Spjd
1676168404Spjd	*source = NULL;
1677168404Spjd	if (nvlist_lookup_nvlist(zhp->zfs_props,
1678168404Spjd	    zfs_prop_to_name(prop), &nv) == 0) {
1679185029Spjd		verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
1680185029Spjd		(void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
1681168404Spjd	} else {
1682205198Sdelphij		verify(!zhp->zfs_props_table ||
1683205198Sdelphij		    zhp->zfs_props_table[prop] == B_TRUE);
1684168404Spjd		if ((value = (char *)zfs_prop_default_string(prop)) == NULL)
1685168404Spjd			value = "";
1686168404Spjd		*source = "";
1687168404Spjd	}
1688168404Spjd
1689168404Spjd	return (value);
1690168404Spjd}
1691168404Spjd
1692219089Spjdstatic boolean_t
1693219089Spjdzfs_is_recvd_props_mode(zfs_handle_t *zhp)
1694219089Spjd{
1695219089Spjd	return (zhp->zfs_props == zhp->zfs_recvd_props);
1696219089Spjd}
1697219089Spjd
1698219089Spjdstatic void
1699219089Spjdzfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
1700219089Spjd{
1701219089Spjd	*cookie = (uint64_t)(uintptr_t)zhp->zfs_props;
1702219089Spjd	zhp->zfs_props = zhp->zfs_recvd_props;
1703219089Spjd}
1704219089Spjd
1705219089Spjdstatic void
1706219089Spjdzfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
1707219089Spjd{
1708219089Spjd	zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie;
1709219089Spjd	*cookie = 0;
1710219089Spjd}
1711219089Spjd
1712168404Spjd/*
1713168404Spjd * Internal function for getting a numeric property.  Both zfs_prop_get() and
1714168404Spjd * zfs_prop_get_int() are built using this interface.
1715168404Spjd *
1716168404Spjd * Certain properties can be overridden using 'mount -o'.  In this case, scan
1717168404Spjd * the contents of the /etc/mnttab entry, searching for the appropriate options.
1718168404Spjd * If they differ from the on-disk values, report the current values and mark
1719168404Spjd * the source "temporary".
1720168404Spjd */
1721168404Spjdstatic int
1722185029Spjdget_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
1723168404Spjd    char **source, uint64_t *val)
1724168404Spjd{
1725185029Spjd	zfs_cmd_t zc = { 0 };
1726185029Spjd	nvlist_t *zplprops = NULL;
1727168404Spjd	struct mnttab mnt;
1728168404Spjd	char *mntopt_on = NULL;
1729168404Spjd	char *mntopt_off = NULL;
1730219089Spjd	boolean_t received = zfs_is_recvd_props_mode(zhp);
1731168404Spjd
1732168404Spjd	*source = NULL;
1733168404Spjd
1734168404Spjd	switch (prop) {
1735168404Spjd	case ZFS_PROP_ATIME:
1736168404Spjd		mntopt_on = MNTOPT_ATIME;
1737168404Spjd		mntopt_off = MNTOPT_NOATIME;
1738168404Spjd		break;
1739168404Spjd
1740168404Spjd	case ZFS_PROP_DEVICES:
1741168404Spjd		mntopt_on = MNTOPT_DEVICES;
1742168404Spjd		mntopt_off = MNTOPT_NODEVICES;
1743168404Spjd		break;
1744168404Spjd
1745168404Spjd	case ZFS_PROP_EXEC:
1746168404Spjd		mntopt_on = MNTOPT_EXEC;
1747168404Spjd		mntopt_off = MNTOPT_NOEXEC;
1748168404Spjd		break;
1749168404Spjd
1750168404Spjd	case ZFS_PROP_READONLY:
1751168404Spjd		mntopt_on = MNTOPT_RO;
1752168404Spjd		mntopt_off = MNTOPT_RW;
1753168404Spjd		break;
1754168404Spjd
1755168404Spjd	case ZFS_PROP_SETUID:
1756168404Spjd		mntopt_on = MNTOPT_SETUID;
1757168404Spjd		mntopt_off = MNTOPT_NOSETUID;
1758168404Spjd		break;
1759168404Spjd
1760168404Spjd	case ZFS_PROP_XATTR:
1761168404Spjd		mntopt_on = MNTOPT_XATTR;
1762168404Spjd		mntopt_off = MNTOPT_NOXATTR;
1763168404Spjd		break;
1764185029Spjd
1765185029Spjd	case ZFS_PROP_NBMAND:
1766185029Spjd		mntopt_on = MNTOPT_NBMAND;
1767185029Spjd		mntopt_off = MNTOPT_NONBMAND;
1768185029Spjd		break;
1769168404Spjd	}
1770168404Spjd
1771168404Spjd	/*
1772168404Spjd	 * Because looking up the mount options is potentially expensive
1773168404Spjd	 * (iterating over all of /etc/mnttab), we defer its calculation until
1774168404Spjd	 * we're looking up a property which requires its presence.
1775168404Spjd	 */
1776168404Spjd	if (!zhp->zfs_mntcheck &&
1777168404Spjd	    (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
1778209962Smm		libzfs_handle_t *hdl = zhp->zfs_hdl;
1779209962Smm		struct mnttab entry;
1780168404Spjd
1781209962Smm		if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) {
1782209962Smm			zhp->zfs_mntopts = zfs_strdup(hdl,
1783168404Spjd			    entry.mnt_mntopts);
1784168404Spjd			if (zhp->zfs_mntopts == NULL)
1785168404Spjd				return (-1);
1786168404Spjd		}
1787168404Spjd
1788168404Spjd		zhp->zfs_mntcheck = B_TRUE;
1789168404Spjd	}
1790168404Spjd
1791168404Spjd	if (zhp->zfs_mntopts == NULL)
1792168404Spjd		mnt.mnt_mntopts = "";
1793168404Spjd	else
1794168404Spjd		mnt.mnt_mntopts = zhp->zfs_mntopts;
1795168404Spjd
1796168404Spjd	switch (prop) {
1797168404Spjd	case ZFS_PROP_ATIME:
1798168404Spjd	case ZFS_PROP_DEVICES:
1799168404Spjd	case ZFS_PROP_EXEC:
1800168404Spjd	case ZFS_PROP_READONLY:
1801168404Spjd	case ZFS_PROP_SETUID:
1802168404Spjd	case ZFS_PROP_XATTR:
1803185029Spjd	case ZFS_PROP_NBMAND:
1804168404Spjd		*val = getprop_uint64(zhp, prop, source);
1805168404Spjd
1806219089Spjd		if (received)
1807219089Spjd			break;
1808219089Spjd
1809168404Spjd		if (hasmntopt(&mnt, mntopt_on) && !*val) {
1810168404Spjd			*val = B_TRUE;
1811168404Spjd			if (src)
1812185029Spjd				*src = ZPROP_SRC_TEMPORARY;
1813168404Spjd		} else if (hasmntopt(&mnt, mntopt_off) && *val) {
1814168404Spjd			*val = B_FALSE;
1815168404Spjd			if (src)
1816185029Spjd				*src = ZPROP_SRC_TEMPORARY;
1817168404Spjd		}
1818168404Spjd		break;
1819168404Spjd
1820168404Spjd	case ZFS_PROP_CANMOUNT:
1821219089Spjd	case ZFS_PROP_VOLSIZE:
1822168404Spjd	case ZFS_PROP_QUOTA:
1823185029Spjd	case ZFS_PROP_REFQUOTA:
1824168404Spjd	case ZFS_PROP_RESERVATION:
1825185029Spjd	case ZFS_PROP_REFRESERVATION:
1826168404Spjd		*val = getprop_uint64(zhp, prop, source);
1827219089Spjd
1828219089Spjd		if (*source == NULL) {
1829219089Spjd			/* not default, must be local */
1830168404Spjd			*source = zhp->zfs_name;
1831219089Spjd		}
1832168404Spjd		break;
1833168404Spjd
1834168404Spjd	case ZFS_PROP_MOUNTED:
1835168404Spjd		*val = (zhp->zfs_mntopts != NULL);
1836168404Spjd		break;
1837168404Spjd
1838168404Spjd	case ZFS_PROP_NUMCLONES:
1839168404Spjd		*val = zhp->zfs_dmustats.dds_num_clones;
1840168404Spjd		break;
1841168404Spjd
1842185029Spjd	case ZFS_PROP_VERSION:
1843185029Spjd	case ZFS_PROP_NORMALIZE:
1844185029Spjd	case ZFS_PROP_UTF8ONLY:
1845185029Spjd	case ZFS_PROP_CASE:
1846185029Spjd		if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) ||
1847185029Spjd		    zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
1848185029Spjd			return (-1);
1849185029Spjd		(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1850185029Spjd		if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) {
1851185029Spjd			zcmd_free_nvlists(&zc);
1852219089Spjd			return (-1);
1853185029Spjd		}
1854185029Spjd		if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 ||
1855185029Spjd		    nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop),
1856185029Spjd		    val) != 0) {
1857185029Spjd			zcmd_free_nvlists(&zc);
1858219089Spjd			return (-1);
1859185029Spjd		}
1860185029Spjd		if (zplprops)
1861185029Spjd			nvlist_free(zplprops);
1862185029Spjd		zcmd_free_nvlists(&zc);
1863185029Spjd		break;
1864185029Spjd
1865168404Spjd	default:
1866185029Spjd		switch (zfs_prop_get_type(prop)) {
1867185029Spjd		case PROP_TYPE_NUMBER:
1868185029Spjd		case PROP_TYPE_INDEX:
1869185029Spjd			*val = getprop_uint64(zhp, prop, source);
1870185029Spjd			/*
1871209962Smm			 * If we tried to use a default value for a
1872185029Spjd			 * readonly property, it means that it was not
1873219089Spjd			 * present.
1874185029Spjd			 */
1875185029Spjd			if (zfs_prop_readonly(prop) &&
1876219089Spjd			    *source != NULL && (*source)[0] == '\0') {
1877219089Spjd				*source = NULL;
1878185029Spjd			}
1879185029Spjd			break;
1880185029Spjd
1881185029Spjd		case PROP_TYPE_STRING:
1882185029Spjd		default:
1883185029Spjd			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
1884185029Spjd			    "cannot get non-numeric property"));
1885185029Spjd			return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
1886185029Spjd			    dgettext(TEXT_DOMAIN, "internal error")));
1887185029Spjd		}
1888168404Spjd	}
1889168404Spjd
1890168404Spjd	return (0);
1891168404Spjd}
1892168404Spjd
1893168404Spjd/*
1894168404Spjd * Calculate the source type, given the raw source string.
1895168404Spjd */
1896168404Spjdstatic void
1897185029Spjdget_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source,
1898168404Spjd    char *statbuf, size_t statlen)
1899168404Spjd{
1900185029Spjd	if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY)
1901168404Spjd		return;
1902168404Spjd
1903168404Spjd	if (source == NULL) {
1904185029Spjd		*srctype = ZPROP_SRC_NONE;
1905168404Spjd	} else if (source[0] == '\0') {
1906185029Spjd		*srctype = ZPROP_SRC_DEFAULT;
1907219089Spjd	} else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) {
1908219089Spjd		*srctype = ZPROP_SRC_RECEIVED;
1909168404Spjd	} else {
1910168404Spjd		if (strcmp(source, zhp->zfs_name) == 0) {
1911185029Spjd			*srctype = ZPROP_SRC_LOCAL;
1912168404Spjd		} else {
1913168404Spjd			(void) strlcpy(statbuf, source, statlen);
1914185029Spjd			*srctype = ZPROP_SRC_INHERITED;
1915168404Spjd		}
1916168404Spjd	}
1917168404Spjd
1918168404Spjd}
1919168404Spjd
1920219089Spjdint
1921219089Spjdzfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
1922219089Spjd    size_t proplen, boolean_t literal)
1923219089Spjd{
1924219089Spjd	zfs_prop_t prop;
1925219089Spjd	int err = 0;
1926219089Spjd
1927219089Spjd	if (zhp->zfs_recvd_props == NULL)
1928219089Spjd		if (get_recvd_props_ioctl(zhp) != 0)
1929219089Spjd			return (-1);
1930219089Spjd
1931219089Spjd	prop = zfs_name_to_prop(propname);
1932219089Spjd
1933219089Spjd	if (prop != ZPROP_INVAL) {
1934219089Spjd		uint64_t cookie;
1935219089Spjd		if (!nvlist_exists(zhp->zfs_recvd_props, propname))
1936219089Spjd			return (-1);
1937219089Spjd		zfs_set_recvd_props_mode(zhp, &cookie);
1938219089Spjd		err = zfs_prop_get(zhp, prop, propbuf, proplen,
1939219089Spjd		    NULL, NULL, 0, literal);
1940219089Spjd		zfs_unset_recvd_props_mode(zhp, &cookie);
1941219089Spjd	} else {
1942219089Spjd		nvlist_t *propval;
1943219089Spjd		char *recvdval;
1944219089Spjd		if (nvlist_lookup_nvlist(zhp->zfs_recvd_props,
1945219089Spjd		    propname, &propval) != 0)
1946219089Spjd			return (-1);
1947219089Spjd		verify(nvlist_lookup_string(propval, ZPROP_VALUE,
1948219089Spjd		    &recvdval) == 0);
1949219089Spjd		(void) strlcpy(propbuf, recvdval, proplen);
1950219089Spjd	}
1951219089Spjd
1952219089Spjd	return (err == 0 ? 0 : -1);
1953219089Spjd}
1954219089Spjd
1955228103Smmstatic int
1956228103Smmget_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
1957228103Smm{
1958228103Smm	nvlist_t *value;
1959228103Smm	nvpair_t *pair;
1960228103Smm
1961228103Smm	value = zfs_get_clones_nvl(zhp);
1962228103Smm	if (value == NULL)
1963228103Smm		return (-1);
1964228103Smm
1965228103Smm	propbuf[0] = '\0';
1966228103Smm	for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
1967228103Smm	    pair = nvlist_next_nvpair(value, pair)) {
1968228103Smm		if (propbuf[0] != '\0')
1969228103Smm			(void) strlcat(propbuf, ",", proplen);
1970228103Smm		(void) strlcat(propbuf, nvpair_name(pair), proplen);
1971228103Smm	}
1972228103Smm
1973228103Smm	return (0);
1974228103Smm}
1975228103Smm
1976228103Smmstruct get_clones_arg {
1977228103Smm	uint64_t numclones;
1978228103Smm	nvlist_t *value;
1979228103Smm	const char *origin;
1980228103Smm	char buf[ZFS_MAXNAMELEN];
1981228103Smm};
1982228103Smm
1983228103Smmint
1984228103Smmget_clones_cb(zfs_handle_t *zhp, void *arg)
1985228103Smm{
1986228103Smm	struct get_clones_arg *gca = arg;
1987228103Smm
1988228103Smm	if (gca->numclones == 0) {
1989228103Smm		zfs_close(zhp);
1990228103Smm		return (0);
1991228103Smm	}
1992228103Smm
1993228103Smm	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
1994228103Smm	    NULL, NULL, 0, B_TRUE) != 0)
1995228103Smm		goto out;
1996228103Smm	if (strcmp(gca->buf, gca->origin) == 0) {
1997228103Smm		if (nvlist_add_boolean(gca->value, zfs_get_name(zhp)) != 0) {
1998228103Smm			zfs_close(zhp);
1999228103Smm			return (no_memory(zhp->zfs_hdl));
2000228103Smm		}
2001228103Smm		gca->numclones--;
2002228103Smm	}
2003228103Smm
2004228103Smmout:
2005228103Smm	(void) zfs_iter_children(zhp, get_clones_cb, gca);
2006228103Smm	zfs_close(zhp);
2007228103Smm	return (0);
2008228103Smm}
2009228103Smm
2010228103Smmnvlist_t *
2011228103Smmzfs_get_clones_nvl(zfs_handle_t *zhp)
2012228103Smm{
2013228103Smm	nvlist_t *nv, *value;
2014228103Smm
2015228103Smm	if (nvlist_lookup_nvlist(zhp->zfs_props,
2016228103Smm	    zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
2017228103Smm		struct get_clones_arg gca;
2018228103Smm
2019228103Smm		/*
2020228103Smm		 * if this is a snapshot, then the kernel wasn't able
2021228103Smm		 * to get the clones.  Do it by slowly iterating.
2022228103Smm		 */
2023228103Smm		if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
2024228103Smm			return (NULL);
2025228103Smm		if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
2026228103Smm			return (NULL);
2027228103Smm		if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
2028228103Smm			nvlist_free(nv);
2029228103Smm			return (NULL);
2030228103Smm		}
2031228103Smm
2032228103Smm		gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
2033228103Smm		gca.value = value;
2034228103Smm		gca.origin = zhp->zfs_name;
2035228103Smm
2036228103Smm		if (gca.numclones != 0) {
2037228103Smm			zfs_handle_t *root;
2038228103Smm			char pool[ZFS_MAXNAMELEN];
2039228103Smm			char *cp = pool;
2040228103Smm
2041228103Smm			/* get the pool name */
2042228103Smm			(void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
2043228103Smm			(void) strsep(&cp, "/@");
2044228103Smm			root = zfs_open(zhp->zfs_hdl, pool,
2045228103Smm			    ZFS_TYPE_FILESYSTEM);
2046228103Smm
2047228103Smm			(void) get_clones_cb(root, &gca);
2048228103Smm		}
2049228103Smm
2050228103Smm		if (gca.numclones != 0 ||
2051228103Smm		    nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
2052228103Smm		    nvlist_add_nvlist(zhp->zfs_props,
2053228103Smm		    zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
2054228103Smm			nvlist_free(nv);
2055228103Smm			nvlist_free(value);
2056228103Smm			return (NULL);
2057228103Smm		}
2058228103Smm		nvlist_free(nv);
2059228103Smm		nvlist_free(value);
2060228103Smm		verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
2061228103Smm		    zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
2062228103Smm	}
2063228103Smm
2064228103Smm	verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
2065228103Smm
2066228103Smm	return (value);
2067228103Smm}
2068228103Smm
2069168404Spjd/*
2070168404Spjd * Retrieve a property from the given object.  If 'literal' is specified, then
2071168404Spjd * numbers are left as exact values.  Otherwise, numbers are converted to a
2072168404Spjd * human-readable form.
2073168404Spjd *
2074168404Spjd * Returns 0 on success, or -1 on error.
2075168404Spjd */
2076168404Spjdint
2077168404Spjdzfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
2078185029Spjd    zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
2079168404Spjd{
2080168404Spjd	char *source = NULL;
2081168404Spjd	uint64_t val;
2082168404Spjd	char *str;
2083168404Spjd	const char *strval;
2084219089Spjd	boolean_t received = zfs_is_recvd_props_mode(zhp);
2085168404Spjd
2086168404Spjd	/*
2087168404Spjd	 * Check to see if this property applies to our object
2088168404Spjd	 */
2089168404Spjd	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
2090168404Spjd		return (-1);
2091168404Spjd
2092219089Spjd	if (received && zfs_prop_readonly(prop))
2093219089Spjd		return (-1);
2094219089Spjd
2095168404Spjd	if (src)
2096185029Spjd		*src = ZPROP_SRC_NONE;
2097168404Spjd
2098168404Spjd	switch (prop) {
2099168404Spjd	case ZFS_PROP_CREATION:
2100168404Spjd		/*
2101168404Spjd		 * 'creation' is a time_t stored in the statistics.  We convert
2102168404Spjd		 * this into a string unless 'literal' is specified.
2103168404Spjd		 */
2104168404Spjd		{
2105168404Spjd			val = getprop_uint64(zhp, prop, &source);
2106168404Spjd			time_t time = (time_t)val;
2107168404Spjd			struct tm t;
2108168404Spjd
2109168404Spjd			if (literal ||
2110168404Spjd			    localtime_r(&time, &t) == NULL ||
2111168404Spjd			    strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
2112168404Spjd			    &t) == 0)
2113168404Spjd				(void) snprintf(propbuf, proplen, "%llu", val);
2114168404Spjd		}
2115168404Spjd		break;
2116168404Spjd
2117168404Spjd	case ZFS_PROP_MOUNTPOINT:
2118168404Spjd		/*
2119168404Spjd		 * Getting the precise mountpoint can be tricky.
2120168404Spjd		 *
2121168404Spjd		 *  - for 'none' or 'legacy', return those values.
2122168404Spjd		 *  - for inherited mountpoints, we want to take everything
2123168404Spjd		 *    after our ancestor and append it to the inherited value.
2124168404Spjd		 *
2125168404Spjd		 * If the pool has an alternate root, we want to prepend that
2126168404Spjd		 * root to any values we return.
2127168404Spjd		 */
2128185029Spjd
2129168404Spjd		str = getprop_string(zhp, prop, &source);
2130168404Spjd
2131185029Spjd		if (str[0] == '/') {
2132185029Spjd			char buf[MAXPATHLEN];
2133185029Spjd			char *root = buf;
2134219089Spjd			const char *relpath;
2135168404Spjd
2136219089Spjd			/*
2137219089Spjd			 * If we inherit the mountpoint, even from a dataset
2138219089Spjd			 * with a received value, the source will be the path of
2139219089Spjd			 * the dataset we inherit from. If source is
2140219089Spjd			 * ZPROP_SOURCE_VAL_RECVD, the received value is not
2141219089Spjd			 * inherited.
2142219089Spjd			 */
2143219089Spjd			if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
2144219089Spjd				relpath = "";
2145219089Spjd			} else {
2146219089Spjd				relpath = zhp->zfs_name + strlen(source);
2147219089Spjd				if (relpath[0] == '/')
2148219089Spjd					relpath++;
2149219089Spjd			}
2150185029Spjd
2151185029Spjd			if ((zpool_get_prop(zhp->zpool_hdl,
2152185029Spjd			    ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) ||
2153185029Spjd			    (strcmp(root, "-") == 0))
2154185029Spjd				root[0] = '\0';
2155185029Spjd			/*
2156185029Spjd			 * Special case an alternate root of '/'. This will
2157185029Spjd			 * avoid having multiple leading slashes in the
2158185029Spjd			 * mountpoint path.
2159185029Spjd			 */
2160185029Spjd			if (strcmp(root, "/") == 0)
2161185029Spjd				root++;
2162185029Spjd
2163185029Spjd			/*
2164185029Spjd			 * If the mountpoint is '/' then skip over this
2165185029Spjd			 * if we are obtaining either an alternate root or
2166185029Spjd			 * an inherited mountpoint.
2167185029Spjd			 */
2168185029Spjd			if (str[1] == '\0' && (root[0] != '\0' ||
2169185029Spjd			    relpath[0] != '\0'))
2170168404Spjd				str++;
2171168404Spjd
2172168404Spjd			if (relpath[0] == '\0')
2173168404Spjd				(void) snprintf(propbuf, proplen, "%s%s",
2174168404Spjd				    root, str);
2175168404Spjd			else
2176168404Spjd				(void) snprintf(propbuf, proplen, "%s%s%s%s",
2177168404Spjd				    root, str, relpath[0] == '@' ? "" : "/",
2178168404Spjd				    relpath);
2179168404Spjd		} else {
2180168404Spjd			/* 'legacy' or 'none' */
2181168404Spjd			(void) strlcpy(propbuf, str, proplen);
2182168404Spjd		}
2183168404Spjd
2184168404Spjd		break;
2185168404Spjd
2186168404Spjd	case ZFS_PROP_ORIGIN:
2187168404Spjd		(void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
2188168404Spjd		    proplen);
2189168404Spjd		/*
2190168404Spjd		 * If there is no parent at all, return failure to indicate that
2191168404Spjd		 * it doesn't apply to this dataset.
2192168404Spjd		 */
2193168404Spjd		if (propbuf[0] == '\0')
2194168404Spjd			return (-1);
2195168404Spjd		break;
2196168404Spjd
2197228103Smm	case ZFS_PROP_CLONES:
2198228103Smm		if (get_clones_string(zhp, propbuf, proplen) != 0)
2199228103Smm			return (-1);
2200228103Smm		break;
2201228103Smm
2202168404Spjd	case ZFS_PROP_QUOTA:
2203185029Spjd	case ZFS_PROP_REFQUOTA:
2204168404Spjd	case ZFS_PROP_RESERVATION:
2205185029Spjd	case ZFS_PROP_REFRESERVATION:
2206185029Spjd
2207168404Spjd		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2208168404Spjd			return (-1);
2209168404Spjd
2210168404Spjd		/*
2211168404Spjd		 * If quota or reservation is 0, we translate this into 'none'
2212168404Spjd		 * (unless literal is set), and indicate that it's the default
2213168404Spjd		 * value.  Otherwise, we print the number nicely and indicate
2214168404Spjd		 * that its set locally.
2215168404Spjd		 */
2216168404Spjd		if (val == 0) {
2217168404Spjd			if (literal)
2218168404Spjd				(void) strlcpy(propbuf, "0", proplen);
2219168404Spjd			else
2220168404Spjd				(void) strlcpy(propbuf, "none", proplen);
2221168404Spjd		} else {
2222168404Spjd			if (literal)
2223168404Spjd				(void) snprintf(propbuf, proplen, "%llu",
2224168404Spjd				    (u_longlong_t)val);
2225168404Spjd			else
2226168404Spjd				zfs_nicenum(val, propbuf, proplen);
2227168404Spjd		}
2228168404Spjd		break;
2229168404Spjd
2230223623Smm	case ZFS_PROP_REFRATIO:
2231168404Spjd	case ZFS_PROP_COMPRESSRATIO:
2232168404Spjd		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
2233168404Spjd			return (-1);
2234219089Spjd		(void) snprintf(propbuf, proplen, "%llu.%02llux",
2235219089Spjd		    (u_longlong_t)(val / 100),
2236219089Spjd		    (u_longlong_t)(val % 100));
2237168404Spjd		break;
2238168404Spjd
2239168404Spjd	case ZFS_PROP_TYPE:
2240168404Spjd		switch (zhp->zfs_type) {
2241168404Spjd		case ZFS_TYPE_FILESYSTEM:
2242168404Spjd			str = "filesystem";
2243168404Spjd			break;
2244168404Spjd		case ZFS_TYPE_VOLUME:
2245168404Spjd			str = "volume";
2246168404Spjd			break;
2247168404Spjd		case ZFS_TYPE_SNAPSHOT:
2248168404Spjd			str = "snapshot";
2249168404Spjd			break;
2250168404Spjd		default:
2251168404Spjd			abort();
2252168404Spjd		}
2253168404Spjd		(void) snprintf(propbuf, proplen, "%s", str);
2254168404Spjd		break;
2255168404Spjd
2256168404Spjd	case ZFS_PROP_MOUNTED:
2257168404Spjd		/*
2258168404Spjd		 * The 'mounted' property is a pseudo-property that described
2259168404Spjd		 * whether the filesystem is currently mounted.  Even though
2260168404Spjd		 * it's a boolean value, the typical values of "on" and "off"
2261168404Spjd		 * don't make sense, so we translate to "yes" and "no".
2262168404Spjd		 */
2263168404Spjd		if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
2264168404Spjd		    src, &source, &val) != 0)
2265168404Spjd			return (-1);
2266168404Spjd		if (val)
2267168404Spjd			(void) strlcpy(propbuf, "yes", proplen);
2268168404Spjd		else
2269168404Spjd			(void) strlcpy(propbuf, "no", proplen);
2270168404Spjd		break;
2271168404Spjd
2272168404Spjd	case ZFS_PROP_NAME:
2273168404Spjd		/*
2274168404Spjd		 * The 'name' property is a pseudo-property derived from the
2275168404Spjd		 * dataset name.  It is presented as a real property to simplify
2276168404Spjd		 * consumers.
2277168404Spjd		 */
2278168404Spjd		(void) strlcpy(propbuf, zhp->zfs_name, proplen);
2279168404Spjd		break;
2280168404Spjd
2281219089Spjd	case ZFS_PROP_MLSLABEL:
2282219089Spjd		{
2283219089Spjd#ifdef sun
2284219089Spjd			m_label_t *new_sl = NULL;
2285219089Spjd			char *ascii = NULL;	/* human readable label */
2286219089Spjd
2287219089Spjd			(void) strlcpy(propbuf,
2288219089Spjd			    getprop_string(zhp, prop, &source), proplen);
2289219089Spjd
2290219089Spjd			if (literal || (strcasecmp(propbuf,
2291219089Spjd			    ZFS_MLSLABEL_DEFAULT) == 0))
2292219089Spjd				break;
2293219089Spjd
2294219089Spjd			/*
2295219089Spjd			 * Try to translate the internal hex string to
2296219089Spjd			 * human-readable output.  If there are any
2297219089Spjd			 * problems just use the hex string.
2298219089Spjd			 */
2299219089Spjd
2300219089Spjd			if (str_to_label(propbuf, &new_sl, MAC_LABEL,
2301219089Spjd			    L_NO_CORRECTION, NULL) == -1) {
2302219089Spjd				m_label_free(new_sl);
2303219089Spjd				break;
2304219089Spjd			}
2305219089Spjd
2306219089Spjd			if (label_to_str(new_sl, &ascii, M_LABEL,
2307219089Spjd			    DEF_NAMES) != 0) {
2308219089Spjd				if (ascii)
2309219089Spjd					free(ascii);
2310219089Spjd				m_label_free(new_sl);
2311219089Spjd				break;
2312219089Spjd			}
2313219089Spjd			m_label_free(new_sl);
2314219089Spjd
2315219089Spjd			(void) strlcpy(propbuf, ascii, proplen);
2316219089Spjd			free(ascii);
2317219089Spjd#else	/* !sun */
2318219089Spjd			propbuf[0] = '\0';
2319219089Spjd#endif	/* !sun */
2320219089Spjd		}
2321219089Spjd		break;
2322219089Spjd
2323168404Spjd	default:
2324185029Spjd		switch (zfs_prop_get_type(prop)) {
2325185029Spjd		case PROP_TYPE_NUMBER:
2326185029Spjd			if (get_numeric_property(zhp, prop, src,
2327185029Spjd			    &source, &val) != 0)
2328185029Spjd				return (-1);
2329185029Spjd			if (literal)
2330185029Spjd				(void) snprintf(propbuf, proplen, "%llu",
2331185029Spjd				    (u_longlong_t)val);
2332185029Spjd			else
2333185029Spjd				zfs_nicenum(val, propbuf, proplen);
2334185029Spjd			break;
2335185029Spjd
2336185029Spjd		case PROP_TYPE_STRING:
2337185029Spjd			(void) strlcpy(propbuf,
2338185029Spjd			    getprop_string(zhp, prop, &source), proplen);
2339185029Spjd			break;
2340185029Spjd
2341185029Spjd		case PROP_TYPE_INDEX:
2342185029Spjd			if (get_numeric_property(zhp, prop, src,
2343185029Spjd			    &source, &val) != 0)
2344185029Spjd				return (-1);
2345185029Spjd			if (zfs_prop_index_to_string(prop, val, &strval) != 0)
2346185029Spjd				return (-1);
2347185029Spjd			(void) strlcpy(propbuf, strval, proplen);
2348185029Spjd			break;
2349185029Spjd
2350185029Spjd		default:
2351185029Spjd			abort();
2352185029Spjd		}
2353168404Spjd	}
2354168404Spjd
2355168404Spjd	get_source(zhp, src, source, statbuf, statlen);
2356168404Spjd
2357168404Spjd	return (0);
2358168404Spjd}
2359168404Spjd
2360168404Spjd/*
2361168404Spjd * Utility function to get the given numeric property.  Does no validation that
2362168404Spjd * the given property is the appropriate type; should only be used with
2363168404Spjd * hard-coded property types.
2364168404Spjd */
2365168404Spjduint64_t
2366168404Spjdzfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
2367168404Spjd{
2368168404Spjd	char *source;
2369168404Spjd	uint64_t val;
2370168404Spjd
2371185029Spjd	(void) get_numeric_property(zhp, prop, NULL, &source, &val);
2372168404Spjd
2373168404Spjd	return (val);
2374168404Spjd}
2375168404Spjd
2376185029Spjdint
2377185029Spjdzfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
2378185029Spjd{
2379185029Spjd	char buf[64];
2380185029Spjd
2381209962Smm	(void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val);
2382185029Spjd	return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
2383185029Spjd}
2384185029Spjd
2385168404Spjd/*
2386168404Spjd * Similar to zfs_prop_get(), but returns the value as an integer.
2387168404Spjd */
2388168404Spjdint
2389168404Spjdzfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
2390185029Spjd    zprop_source_t *src, char *statbuf, size_t statlen)
2391168404Spjd{
2392168404Spjd	char *source;
2393168404Spjd
2394168404Spjd	/*
2395168404Spjd	 * Check to see if this property applies to our object
2396168404Spjd	 */
2397185029Spjd	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) {
2398168404Spjd		return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
2399168404Spjd		    dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
2400168404Spjd		    zfs_prop_to_name(prop)));
2401185029Spjd	}
2402168404Spjd
2403168404Spjd	if (src)
2404185029Spjd		*src = ZPROP_SRC_NONE;
2405168404Spjd
2406168404Spjd	if (get_numeric_property(zhp, prop, src, &source, value) != 0)
2407168404Spjd		return (-1);
2408168404Spjd
2409168404Spjd	get_source(zhp, src, source, statbuf, statlen);
2410168404Spjd
2411168404Spjd	return (0);
2412168404Spjd}
2413168404Spjd
2414209962Smmstatic int
2415209962Smmidmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
2416209962Smm    char **domainp, idmap_rid_t *ridp)
2417209962Smm{
2418209962Smm#ifdef sun
2419209962Smm	idmap_get_handle_t *get_hdl = NULL;
2420209962Smm	idmap_stat status;
2421209962Smm	int err = EINVAL;
2422209962Smm
2423219089Spjd	if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS)
2424209962Smm		goto out;
2425209962Smm
2426209962Smm	if (isuser) {
2427209962Smm		err = idmap_get_sidbyuid(get_hdl, id,
2428209962Smm		    IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2429209962Smm	} else {
2430209962Smm		err = idmap_get_sidbygid(get_hdl, id,
2431209962Smm		    IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
2432209962Smm	}
2433209962Smm	if (err == IDMAP_SUCCESS &&
2434209962Smm	    idmap_get_mappings(get_hdl) == IDMAP_SUCCESS &&
2435209962Smm	    status == IDMAP_SUCCESS)
2436209962Smm		err = 0;
2437209962Smm	else
2438209962Smm		err = EINVAL;
2439209962Smmout:
2440209962Smm	if (get_hdl)
2441209962Smm		idmap_get_destroy(get_hdl);
2442209962Smm	return (err);
2443209962Smm#else	/* !sun */
2444209962Smm	assert(!"invalid code path");
2445209962Smm#endif	/* !sun */
2446209962Smm}
2447209962Smm
2448168404Spjd/*
2449209962Smm * convert the propname into parameters needed by kernel
2450209962Smm * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829
2451209962Smm * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789
2452209962Smm */
2453209962Smmstatic int
2454209962Smmuserquota_propname_decode(const char *propname, boolean_t zoned,
2455209962Smm    zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
2456209962Smm{
2457209962Smm	zfs_userquota_prop_t type;
2458209962Smm	char *cp, *end;
2459209962Smm	char *numericsid = NULL;
2460209962Smm	boolean_t isuser;
2461209962Smm
2462209962Smm	domain[0] = '\0';
2463209962Smm
2464209962Smm	/* Figure out the property type ({user|group}{quota|space}) */
2465209962Smm	for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
2466209962Smm		if (strncmp(propname, zfs_userquota_prop_prefixes[type],
2467209962Smm		    strlen(zfs_userquota_prop_prefixes[type])) == 0)
2468209962Smm			break;
2469209962Smm	}
2470209962Smm	if (type == ZFS_NUM_USERQUOTA_PROPS)
2471209962Smm		return (EINVAL);
2472209962Smm	*typep = type;
2473209962Smm
2474209962Smm	isuser = (type == ZFS_PROP_USERQUOTA ||
2475209962Smm	    type == ZFS_PROP_USERUSED);
2476209962Smm
2477209962Smm	cp = strchr(propname, '@') + 1;
2478209962Smm
2479209962Smm	if (strchr(cp, '@')) {
2480209962Smm#ifdef sun
2481209962Smm		/*
2482209962Smm		 * It's a SID name (eg "user@domain") that needs to be
2483209962Smm		 * turned into S-1-domainID-RID.
2484209962Smm		 */
2485209962Smm		directory_error_t e;
2486209962Smm		if (zoned && getzoneid() == GLOBAL_ZONEID)
2487209962Smm			return (ENOENT);
2488209962Smm		if (isuser) {
2489209962Smm			e = directory_sid_from_user_name(NULL,
2490209962Smm			    cp, &numericsid);
2491209962Smm		} else {
2492209962Smm			e = directory_sid_from_group_name(NULL,
2493209962Smm			    cp, &numericsid);
2494209962Smm		}
2495209962Smm		if (e != NULL) {
2496209962Smm			directory_error_free(e);
2497209962Smm			return (ENOENT);
2498209962Smm		}
2499209962Smm		if (numericsid == NULL)
2500209962Smm			return (ENOENT);
2501209962Smm		cp = numericsid;
2502209962Smm		/* will be further decoded below */
2503209962Smm#else	/* !sun */
2504219089Spjd		return (ENOENT);
2505209962Smm#endif	/* !sun */
2506209962Smm	}
2507209962Smm
2508209962Smm	if (strncmp(cp, "S-1-", 4) == 0) {
2509209962Smm		/* It's a numeric SID (eg "S-1-234-567-89") */
2510209962Smm		(void) strlcpy(domain, cp, domainlen);
2511209962Smm		cp = strrchr(domain, '-');
2512209962Smm		*cp = '\0';
2513209962Smm		cp++;
2514209962Smm
2515209962Smm		errno = 0;
2516209962Smm		*ridp = strtoull(cp, &end, 10);
2517209962Smm		if (numericsid) {
2518209962Smm			free(numericsid);
2519209962Smm			numericsid = NULL;
2520209962Smm		}
2521209962Smm		if (errno != 0 || *end != '\0')
2522209962Smm			return (EINVAL);
2523209962Smm	} else if (!isdigit(*cp)) {
2524209962Smm		/*
2525209962Smm		 * It's a user/group name (eg "user") that needs to be
2526209962Smm		 * turned into a uid/gid
2527209962Smm		 */
2528209962Smm		if (zoned && getzoneid() == GLOBAL_ZONEID)
2529209962Smm			return (ENOENT);
2530209962Smm		if (isuser) {
2531209962Smm			struct passwd *pw;
2532209962Smm			pw = getpwnam(cp);
2533209962Smm			if (pw == NULL)
2534209962Smm				return (ENOENT);
2535209962Smm			*ridp = pw->pw_uid;
2536209962Smm		} else {
2537209962Smm			struct group *gr;
2538209962Smm			gr = getgrnam(cp);
2539209962Smm			if (gr == NULL)
2540209962Smm				return (ENOENT);
2541209962Smm			*ridp = gr->gr_gid;
2542209962Smm		}
2543209962Smm	} else {
2544209962Smm		/* It's a user/group ID (eg "12345"). */
2545209962Smm		uid_t id = strtoul(cp, &end, 10);
2546209962Smm		idmap_rid_t rid;
2547209962Smm		char *mapdomain;
2548209962Smm
2549209962Smm		if (*end != '\0')
2550209962Smm			return (EINVAL);
2551209962Smm		if (id > MAXUID) {
2552209962Smm			/* It's an ephemeral ID. */
2553209962Smm			if (idmap_id_to_numeric_domain_rid(id, isuser,
2554209962Smm			    &mapdomain, &rid) != 0)
2555209962Smm				return (ENOENT);
2556209962Smm			(void) strlcpy(domain, mapdomain, domainlen);
2557209962Smm			*ridp = rid;
2558209962Smm		} else {
2559209962Smm			*ridp = id;
2560209962Smm		}
2561209962Smm	}
2562209962Smm
2563209962Smm	ASSERT3P(numericsid, ==, NULL);
2564209962Smm	return (0);
2565209962Smm}
2566209962Smm
2567209962Smmstatic int
2568209962Smmzfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
2569209962Smm    uint64_t *propvalue, zfs_userquota_prop_t *typep)
2570209962Smm{
2571209962Smm	int err;
2572209962Smm	zfs_cmd_t zc = { 0 };
2573209962Smm
2574228103Smm	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2575209962Smm
2576209962Smm	err = userquota_propname_decode(propname,
2577209962Smm	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
2578209962Smm	    typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid);
2579209962Smm	zc.zc_objset_type = *typep;
2580209962Smm	if (err)
2581209962Smm		return (err);
2582209962Smm
2583209962Smm	err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc);
2584209962Smm	if (err)
2585209962Smm		return (err);
2586209962Smm
2587209962Smm	*propvalue = zc.zc_cookie;
2588209962Smm	return (0);
2589209962Smm}
2590209962Smm
2591209962Smmint
2592209962Smmzfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
2593209962Smm    uint64_t *propvalue)
2594209962Smm{
2595209962Smm	zfs_userquota_prop_t type;
2596209962Smm
2597209962Smm	return (zfs_prop_get_userquota_common(zhp, propname, propvalue,
2598209962Smm	    &type));
2599209962Smm}
2600209962Smm
2601209962Smmint
2602209962Smmzfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
2603209962Smm    char *propbuf, int proplen, boolean_t literal)
2604209962Smm{
2605209962Smm	int err;
2606209962Smm	uint64_t propvalue;
2607209962Smm	zfs_userquota_prop_t type;
2608209962Smm
2609209962Smm	err = zfs_prop_get_userquota_common(zhp, propname, &propvalue,
2610209962Smm	    &type);
2611209962Smm
2612209962Smm	if (err)
2613209962Smm		return (err);
2614209962Smm
2615209962Smm	if (literal) {
2616209962Smm		(void) snprintf(propbuf, proplen, "%llu", propvalue);
2617209962Smm	} else if (propvalue == 0 &&
2618209962Smm	    (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) {
2619209962Smm		(void) strlcpy(propbuf, "none", proplen);
2620209962Smm	} else {
2621209962Smm		zfs_nicenum(propvalue, propbuf, proplen);
2622209962Smm	}
2623209962Smm	return (0);
2624209962Smm}
2625209962Smm
2626228103Smmint
2627228103Smmzfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
2628228103Smm    uint64_t *propvalue)
2629168404Spjd{
2630228103Smm	int err;
2631228103Smm	zfs_cmd_t zc = { 0 };
2632228103Smm	const char *snapname;
2633168404Spjd
2634228103Smm	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
2635168404Spjd
2636228103Smm	snapname = strchr(propname, '@') + 1;
2637228103Smm	if (strchr(snapname, '@')) {
2638228103Smm		(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
2639228103Smm	} else {
2640228103Smm		/* snapname is the short name, append it to zhp's fsname */
2641228103Smm		char *cp;
2642209962Smm
2643228103Smm		(void) strlcpy(zc.zc_value, zhp->zfs_name,
2644228103Smm		    sizeof (zc.zc_value));
2645228103Smm		cp = strchr(zc.zc_value, '@');
2646228103Smm		if (cp != NULL)
2647228103Smm			*cp = '\0';
2648228103Smm		(void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
2649228103Smm		(void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
2650228103Smm	}
2651209962Smm
2652228103Smm	err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
2653228103Smm	if (err)
2654228103Smm		return (err);
2655228103Smm
2656228103Smm	*propvalue = zc.zc_cookie;
2657228103Smm	return (0);
2658209962Smm}
2659209962Smm
2660168404Spjdint
2661228103Smmzfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
2662228103Smm    char *propbuf, int proplen, boolean_t literal)
2663168404Spjd{
2664228103Smm	int err;
2665228103Smm	uint64_t propvalue;
2666168404Spjd
2667228103Smm	err = zfs_prop_get_written_int(zhp, propname, &propvalue);
2668185029Spjd
2669228103Smm	if (err)
2670228103Smm		return (err);
2671209962Smm
2672228103Smm	if (literal) {
2673228103Smm		(void) snprintf(propbuf, proplen, "%llu", propvalue);
2674228103Smm	} else {
2675228103Smm		zfs_nicenum(propvalue, propbuf, proplen);
2676168404Spjd	}
2677228103Smm	return (0);
2678168404Spjd}
2679168404Spjd
2680168404Spjdint
2681228103Smmzfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap,
2682228103Smm    uint64_t *usedp)
2683168404Spjd{
2684228103Smm	int err;
2685168404Spjd	zfs_cmd_t zc = { 0 };
2686168404Spjd
2687228103Smm	(void) strlcpy(zc.zc_name, lastsnap->zfs_name, sizeof (zc.zc_name));
2688228103Smm	(void) strlcpy(zc.zc_value, firstsnap->zfs_name, sizeof (zc.zc_value));
2689185029Spjd
2690228103Smm	err = ioctl(lastsnap->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_SNAPS, &zc);
2691228103Smm	if (err)
2692228103Smm		return (err);
2693168404Spjd
2694228103Smm	*usedp = zc.zc_cookie;
2695209962Smm
2696228103Smm	return (0);
2697168404Spjd}
2698168404Spjd
2699168404Spjd/*
2700228103Smm * Returns the name of the given zfs handle.
2701168404Spjd */
2702228103Smmconst char *
2703228103Smmzfs_get_name(const zfs_handle_t *zhp)
2704168404Spjd{
2705228103Smm	return (zhp->zfs_name);
2706228103Smm}
2707168404Spjd
2708228103Smm/*
2709228103Smm * Returns the type of the given zfs handle.
2710228103Smm */
2711228103Smmzfs_type_t
2712228103Smmzfs_get_type(const zfs_handle_t *zhp)
2713228103Smm{
2714228103Smm	return (zhp->zfs_type);
2715168404Spjd}
2716168404Spjd
2717168404Spjd/*
2718219089Spjd * Is one dataset name a child dataset of another?
2719219089Spjd *
2720219089Spjd * Needs to handle these cases:
2721219089Spjd * Dataset 1	"a/foo"		"a/foo"		"a/foo"		"a/foo"
2722219089Spjd * Dataset 2	"a/fo"		"a/foobar"	"a/bar/baz"	"a/foo/bar"
2723219089Spjd * Descendant?	No.		No.		No.		Yes.
2724219089Spjd */
2725219089Spjdstatic boolean_t
2726219089Spjdis_descendant(const char *ds1, const char *ds2)
2727219089Spjd{
2728219089Spjd	size_t d1len = strlen(ds1);
2729219089Spjd
2730219089Spjd	/* ds2 can't be a descendant if it's smaller */
2731219089Spjd	if (strlen(ds2) < d1len)
2732219089Spjd		return (B_FALSE);
2733219089Spjd
2734219089Spjd	/* otherwise, compare strings and verify that there's a '/' char */
2735219089Spjd	return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
2736219089Spjd}
2737219089Spjd
2738219089Spjd/*
2739168404Spjd * Given a complete name, return just the portion that refers to the parent.
2740228103Smm * Will return -1 if there is no parent (path is just the name of the
2741228103Smm * pool).
2742168404Spjd */
2743168404Spjdstatic int
2744168404Spjdparent_name(const char *path, char *buf, size_t buflen)
2745168404Spjd{
2746228103Smm	char *slashp;
2747168404Spjd
2748228103Smm	(void) strlcpy(buf, path, buflen);
2749228103Smm
2750228103Smm	if ((slashp = strrchr(buf, '/')) == NULL)
2751168404Spjd		return (-1);
2752228103Smm	*slashp = '\0';
2753168404Spjd
2754168404Spjd	return (0);
2755168404Spjd}
2756168404Spjd
2757168404Spjd/*
2758185029Spjd * If accept_ancestor is false, then check to make sure that the given path has
2759185029Spjd * a parent, and that it exists.  If accept_ancestor is true, then find the
2760185029Spjd * closest existing ancestor for the given path.  In prefixlen return the
2761185029Spjd * length of already existing prefix of the given path.  We also fetch the
2762185029Spjd * 'zoned' property, which is used to validate property settings when creating
2763185029Spjd * new datasets.
2764168404Spjd */
2765168404Spjdstatic int
2766185029Spjdcheck_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
2767185029Spjd    boolean_t accept_ancestor, int *prefixlen)
2768168404Spjd{
2769168404Spjd	zfs_cmd_t zc = { 0 };
2770168404Spjd	char parent[ZFS_MAXNAMELEN];
2771168404Spjd	char *slash;
2772168404Spjd	zfs_handle_t *zhp;
2773168404Spjd	char errbuf[1024];
2774219089Spjd	uint64_t is_zoned;
2775168404Spjd
2776209962Smm	(void) snprintf(errbuf, sizeof (errbuf),
2777209962Smm	    dgettext(TEXT_DOMAIN, "cannot create '%s'"), path);
2778168404Spjd
2779168404Spjd	/* get parent, and check to see if this is just a pool */
2780168404Spjd	if (parent_name(path, parent, sizeof (parent)) != 0) {
2781168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2782168404Spjd		    "missing dataset name"));
2783168404Spjd		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2784168404Spjd	}
2785168404Spjd
2786168404Spjd	/* check to see if the pool exists */
2787168404Spjd	if ((slash = strchr(parent, '/')) == NULL)
2788168404Spjd		slash = parent + strlen(parent);
2789168404Spjd	(void) strncpy(zc.zc_name, parent, slash - parent);
2790168404Spjd	zc.zc_name[slash - parent] = '\0';
2791168404Spjd	if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
2792168404Spjd	    errno == ENOENT) {
2793168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2794168404Spjd		    "no such pool '%s'"), zc.zc_name);
2795168404Spjd		return (zfs_error(hdl, EZFS_NOENT, errbuf));
2796168404Spjd	}
2797168404Spjd
2798168404Spjd	/* check to see if the parent dataset exists */
2799185029Spjd	while ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
2800185029Spjd		if (errno == ENOENT && accept_ancestor) {
2801185029Spjd			/*
2802185029Spjd			 * Go deeper to find an ancestor, give up on top level.
2803185029Spjd			 */
2804185029Spjd			if (parent_name(parent, parent, sizeof (parent)) != 0) {
2805185029Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2806185029Spjd				    "no such pool '%s'"), zc.zc_name);
2807185029Spjd				return (zfs_error(hdl, EZFS_NOENT, errbuf));
2808185029Spjd			}
2809185029Spjd		} else if (errno == ENOENT) {
2810168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2811168404Spjd			    "parent does not exist"));
2812168404Spjd			return (zfs_error(hdl, EZFS_NOENT, errbuf));
2813185029Spjd		} else
2814168404Spjd			return (zfs_standard_error(hdl, errno, errbuf));
2815168404Spjd	}
2816168404Spjd
2817219089Spjd	is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
2818219089Spjd	if (zoned != NULL)
2819219089Spjd		*zoned = is_zoned;
2820219089Spjd
2821168404Spjd	/* we are in a non-global zone, but parent is in the global zone */
2822219089Spjd	if (getzoneid() != GLOBAL_ZONEID && !is_zoned) {
2823168404Spjd		(void) zfs_standard_error(hdl, EPERM, errbuf);
2824168404Spjd		zfs_close(zhp);
2825168404Spjd		return (-1);
2826168404Spjd	}
2827168404Spjd
2828168404Spjd	/* make sure parent is a filesystem */
2829168404Spjd	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2830168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2831168404Spjd		    "parent is not a filesystem"));
2832168404Spjd		(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
2833168404Spjd		zfs_close(zhp);
2834168404Spjd		return (-1);
2835168404Spjd	}
2836168404Spjd
2837168404Spjd	zfs_close(zhp);
2838185029Spjd	if (prefixlen != NULL)
2839185029Spjd		*prefixlen = strlen(parent);
2840168404Spjd	return (0);
2841168404Spjd}
2842168404Spjd
2843168404Spjd/*
2844185029Spjd * Finds whether the dataset of the given type(s) exists.
2845185029Spjd */
2846185029Spjdboolean_t
2847185029Spjdzfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types)
2848185029Spjd{
2849185029Spjd	zfs_handle_t *zhp;
2850185029Spjd
2851185029Spjd	if (!zfs_validate_name(hdl, path, types, B_FALSE))
2852185029Spjd		return (B_FALSE);
2853185029Spjd
2854185029Spjd	/*
2855185029Spjd	 * Try to get stats for the dataset, which will tell us if it exists.
2856185029Spjd	 */
2857185029Spjd	if ((zhp = make_dataset_handle(hdl, path)) != NULL) {
2858185029Spjd		int ds_type = zhp->zfs_type;
2859185029Spjd
2860185029Spjd		zfs_close(zhp);
2861185029Spjd		if (types & ds_type)
2862185029Spjd			return (B_TRUE);
2863185029Spjd	}
2864185029Spjd	return (B_FALSE);
2865185029Spjd}
2866185029Spjd
2867185029Spjd/*
2868185029Spjd * Given a path to 'target', create all the ancestors between
2869185029Spjd * the prefixlen portion of the path, and the target itself.
2870185029Spjd * Fail if the initial prefixlen-ancestor does not already exist.
2871185029Spjd */
2872185029Spjdint
2873185029Spjdcreate_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
2874185029Spjd{
2875185029Spjd	zfs_handle_t *h;
2876185029Spjd	char *cp;
2877185029Spjd	const char *opname;
2878185029Spjd
2879185029Spjd	/* make sure prefix exists */
2880185029Spjd	cp = target + prefixlen;
2881185029Spjd	if (*cp != '/') {
2882185029Spjd		assert(strchr(cp, '/') == NULL);
2883185029Spjd		h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2884185029Spjd	} else {
2885185029Spjd		*cp = '\0';
2886185029Spjd		h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2887185029Spjd		*cp = '/';
2888185029Spjd	}
2889185029Spjd	if (h == NULL)
2890185029Spjd		return (-1);
2891185029Spjd	zfs_close(h);
2892185029Spjd
2893185029Spjd	/*
2894185029Spjd	 * Attempt to create, mount, and share any ancestor filesystems,
2895185029Spjd	 * up to the prefixlen-long one.
2896185029Spjd	 */
2897185029Spjd	for (cp = target + prefixlen + 1;
2898185029Spjd	    cp = strchr(cp, '/'); *cp = '/', cp++) {
2899185029Spjd		char *logstr;
2900185029Spjd
2901185029Spjd		*cp = '\0';
2902185029Spjd
2903185029Spjd		h = make_dataset_handle(hdl, target);
2904185029Spjd		if (h) {
2905185029Spjd			/* it already exists, nothing to do here */
2906185029Spjd			zfs_close(h);
2907185029Spjd			continue;
2908185029Spjd		}
2909185029Spjd
2910185029Spjd		logstr = hdl->libzfs_log_str;
2911185029Spjd		hdl->libzfs_log_str = NULL;
2912185029Spjd		if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
2913185029Spjd		    NULL) != 0) {
2914185029Spjd			hdl->libzfs_log_str = logstr;
2915185029Spjd			opname = dgettext(TEXT_DOMAIN, "create");
2916185029Spjd			goto ancestorerr;
2917185029Spjd		}
2918185029Spjd
2919185029Spjd		hdl->libzfs_log_str = logstr;
2920185029Spjd		h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
2921185029Spjd		if (h == NULL) {
2922185029Spjd			opname = dgettext(TEXT_DOMAIN, "open");
2923185029Spjd			goto ancestorerr;
2924185029Spjd		}
2925185029Spjd
2926185029Spjd		if (zfs_mount(h, NULL, 0) != 0) {
2927185029Spjd			opname = dgettext(TEXT_DOMAIN, "mount");
2928185029Spjd			goto ancestorerr;
2929185029Spjd		}
2930185029Spjd
2931185029Spjd		if (zfs_share(h) != 0) {
2932185029Spjd			opname = dgettext(TEXT_DOMAIN, "share");
2933185029Spjd			goto ancestorerr;
2934185029Spjd		}
2935185029Spjd
2936185029Spjd		zfs_close(h);
2937185029Spjd	}
2938185029Spjd
2939185029Spjd	return (0);
2940185029Spjd
2941185029Spjdancestorerr:
2942185029Spjd	zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2943185029Spjd	    "failed to %s ancestor '%s'"), opname, target);
2944185029Spjd	return (-1);
2945185029Spjd}
2946185029Spjd
2947185029Spjd/*
2948185029Spjd * Creates non-existing ancestors of the given path.
2949185029Spjd */
2950185029Spjdint
2951185029Spjdzfs_create_ancestors(libzfs_handle_t *hdl, const char *path)
2952185029Spjd{
2953185029Spjd	int prefix;
2954185029Spjd	char *path_copy;
2955185029Spjd	int rc;
2956185029Spjd
2957219089Spjd	if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0)
2958185029Spjd		return (-1);
2959185029Spjd
2960185029Spjd	if ((path_copy = strdup(path)) != NULL) {
2961185029Spjd		rc = create_parents(hdl, path_copy, prefix);
2962185029Spjd		free(path_copy);
2963185029Spjd	}
2964185029Spjd	if (path_copy == NULL || rc != 0)
2965185029Spjd		return (-1);
2966185029Spjd
2967185029Spjd	return (0);
2968185029Spjd}
2969185029Spjd
2970185029Spjd/*
2971168404Spjd * Create a new filesystem or volume.
2972168404Spjd */
2973168404Spjdint
2974168404Spjdzfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
2975168404Spjd    nvlist_t *props)
2976168404Spjd{
2977168404Spjd	zfs_cmd_t zc = { 0 };
2978168404Spjd	int ret;
2979168404Spjd	uint64_t size = 0;
2980168404Spjd	uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
2981168404Spjd	char errbuf[1024];
2982168404Spjd	uint64_t zoned;
2983168404Spjd
2984168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2985168404Spjd	    "cannot create '%s'"), path);
2986168404Spjd
2987168404Spjd	/* validate the path, taking care to note the extended error message */
2988185029Spjd	if (!zfs_validate_name(hdl, path, type, B_TRUE))
2989168404Spjd		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2990168404Spjd
2991168404Spjd	/* validate parents exist */
2992185029Spjd	if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0)
2993168404Spjd		return (-1);
2994168404Spjd
2995168404Spjd	/*
2996168404Spjd	 * The failure modes when creating a dataset of a different type over
2997168404Spjd	 * one that already exists is a little strange.  In particular, if you
2998168404Spjd	 * try to create a dataset on top of an existing dataset, the ioctl()
2999168404Spjd	 * will return ENOENT, not EEXIST.  To prevent this from happening, we
3000168404Spjd	 * first try to see if the dataset exists.
3001168404Spjd	 */
3002168404Spjd	(void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name));
3003185029Spjd	if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
3004168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3005168404Spjd		    "dataset already exists"));
3006168404Spjd		return (zfs_error(hdl, EZFS_EXISTS, errbuf));
3007168404Spjd	}
3008168404Spjd
3009168404Spjd	if (type == ZFS_TYPE_VOLUME)
3010168404Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
3011168404Spjd	else
3012168404Spjd		zc.zc_objset_type = DMU_OST_ZFS;
3013168404Spjd
3014185029Spjd	if (props && (props = zfs_valid_proplist(hdl, type, props,
3015168404Spjd	    zoned, NULL, errbuf)) == 0)
3016168404Spjd		return (-1);
3017168404Spjd
3018168404Spjd	if (type == ZFS_TYPE_VOLUME) {
3019168404Spjd		/*
3020168404Spjd		 * If we are creating a volume, the size and block size must
3021168404Spjd		 * satisfy a few restraints.  First, the blocksize must be a
3022168404Spjd		 * valid block size between SPA_{MIN,MAX}BLOCKSIZE.  Second, the
3023168404Spjd		 * volsize must be a multiple of the block size, and cannot be
3024168404Spjd		 * zero.
3025168404Spjd		 */
3026168404Spjd		if (props == NULL || nvlist_lookup_uint64(props,
3027168404Spjd		    zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
3028168404Spjd			nvlist_free(props);
3029168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3030168404Spjd			    "missing volume size"));
3031168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3032168404Spjd		}
3033168404Spjd
3034168404Spjd		if ((ret = nvlist_lookup_uint64(props,
3035168404Spjd		    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
3036168404Spjd		    &blocksize)) != 0) {
3037168404Spjd			if (ret == ENOENT) {
3038168404Spjd				blocksize = zfs_prop_default_numeric(
3039168404Spjd				    ZFS_PROP_VOLBLOCKSIZE);
3040168404Spjd			} else {
3041168404Spjd				nvlist_free(props);
3042168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3043168404Spjd				    "missing volume block size"));
3044168404Spjd				return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3045168404Spjd			}
3046168404Spjd		}
3047168404Spjd
3048168404Spjd		if (size == 0) {
3049168404Spjd			nvlist_free(props);
3050168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3051168404Spjd			    "volume size cannot be zero"));
3052168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3053168404Spjd		}
3054168404Spjd
3055168404Spjd		if (size % blocksize != 0) {
3056168404Spjd			nvlist_free(props);
3057168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3058168404Spjd			    "volume size must be a multiple of volume block "
3059168404Spjd			    "size"));
3060168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3061168404Spjd		}
3062168404Spjd	}
3063168404Spjd
3064185029Spjd	if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0)
3065168404Spjd		return (-1);
3066168404Spjd	nvlist_free(props);
3067168404Spjd
3068168404Spjd	/* create the dataset */
3069185029Spjd	ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc);
3070168404Spjd
3071168404Spjd	zcmd_free_nvlists(&zc);
3072168404Spjd
3073168404Spjd	/* check for failure */
3074168404Spjd	if (ret != 0) {
3075168404Spjd		char parent[ZFS_MAXNAMELEN];
3076168404Spjd		(void) parent_name(path, parent, sizeof (parent));
3077168404Spjd
3078168404Spjd		switch (errno) {
3079168404Spjd		case ENOENT:
3080168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3081168404Spjd			    "no such parent '%s'"), parent);
3082168404Spjd			return (zfs_error(hdl, EZFS_NOENT, errbuf));
3083168404Spjd
3084168404Spjd		case EINVAL:
3085168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3086168404Spjd			    "parent '%s' is not a filesystem"), parent);
3087168404Spjd			return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3088168404Spjd
3089168404Spjd		case EDOM:
3090168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3091168404Spjd			    "volume block size must be power of 2 from "
3092168404Spjd			    "%u to %uk"),
3093168404Spjd			    (uint_t)SPA_MINBLOCKSIZE,
3094168404Spjd			    (uint_t)SPA_MAXBLOCKSIZE >> 10);
3095168404Spjd
3096168404Spjd			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
3097168404Spjd
3098185029Spjd		case ENOTSUP:
3099185029Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3100185029Spjd			    "pool must be upgraded to set this "
3101185029Spjd			    "property or value"));
3102185029Spjd			return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
3103168404Spjd#ifdef _ILP32
3104168404Spjd		case EOVERFLOW:
3105168404Spjd			/*
3106168404Spjd			 * This platform can't address a volume this big.
3107168404Spjd			 */
3108168404Spjd			if (type == ZFS_TYPE_VOLUME)
3109168404Spjd				return (zfs_error(hdl, EZFS_VOLTOOBIG,
3110168404Spjd				    errbuf));
3111168404Spjd#endif
3112168404Spjd			/* FALLTHROUGH */
3113168404Spjd		default:
3114168404Spjd			return (zfs_standard_error(hdl, errno, errbuf));
3115168404Spjd		}
3116168404Spjd	}
3117168404Spjd
3118168404Spjd	return (0);
3119168404Spjd}
3120168404Spjd
3121168404Spjd/*
3122168404Spjd * Destroys the given dataset.  The caller must make sure that the filesystem
3123168404Spjd * isn't mounted, and that there are no active dependents.
3124168404Spjd */
3125168404Spjdint
3126219089Spjdzfs_destroy(zfs_handle_t *zhp, boolean_t defer)
3127168404Spjd{
3128168404Spjd	zfs_cmd_t zc = { 0 };
3129168404Spjd
3130168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3131168404Spjd
3132168404Spjd	if (ZFS_IS_VOLUME(zhp)) {
3133168404Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
3134168404Spjd	} else {
3135168404Spjd		zc.zc_objset_type = DMU_OST_ZFS;
3136168404Spjd	}
3137168404Spjd
3138219089Spjd	zc.zc_defer_destroy = defer;
3139185029Spjd	if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0) {
3140168404Spjd		return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3141168404Spjd		    dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
3142168404Spjd		    zhp->zfs_name));
3143168404Spjd	}
3144168404Spjd
3145168404Spjd	remove_mountpoint(zhp);
3146168404Spjd
3147168404Spjd	return (0);
3148168404Spjd}
3149168404Spjd
3150168404Spjdstruct destroydata {
3151228103Smm	nvlist_t *nvl;
3152228103Smm	const char *snapname;
3153168404Spjd};
3154168404Spjd
3155168404Spjdstatic int
3156219089Spjdzfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
3157168404Spjd{
3158168404Spjd	struct destroydata *dd = arg;
3159168404Spjd	zfs_handle_t *szhp;
3160168404Spjd	char name[ZFS_MAXNAMELEN];
3161219089Spjd	int rv = 0;
3162168404Spjd
3163228103Smm	(void) snprintf(name, sizeof (name),
3164228103Smm	    "%s@%s", zhp->zfs_name, dd->snapname);
3165168404Spjd
3166168404Spjd	szhp = make_dataset_handle(zhp->zfs_hdl, name);
3167168404Spjd	if (szhp) {
3168228103Smm		verify(nvlist_add_boolean(dd->nvl, name) == 0);
3169168404Spjd		zfs_close(szhp);
3170168404Spjd	}
3171168404Spjd
3172228103Smm	rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
3173228103Smm	zfs_close(zhp);
3174168404Spjd	return (rv);
3175168404Spjd}
3176168404Spjd
3177168404Spjd/*
3178168404Spjd * Destroys all snapshots with the given name in zhp & descendants.
3179168404Spjd */
3180168404Spjdint
3181219089Spjdzfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
3182168404Spjd{
3183168404Spjd	int ret;
3184168404Spjd	struct destroydata dd = { 0 };
3185168404Spjd
3186168404Spjd	dd.snapname = snapname;
3187228103Smm	verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
3188228103Smm	(void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
3189168404Spjd
3190228103Smm	if (nvlist_next_nvpair(dd.nvl, NULL) == NULL) {
3191228103Smm		ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
3192168404Spjd		    dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
3193228103Smm		    zhp->zfs_name, snapname);
3194228103Smm	} else {
3195228103Smm		ret = zfs_destroy_snaps_nvl(zhp, dd.nvl, defer);
3196168404Spjd	}
3197228103Smm	nvlist_free(dd.nvl);
3198228103Smm	return (ret);
3199228103Smm}
3200168404Spjd
3201228103Smm/*
3202228103Smm * Destroys all the snapshots named in the nvlist.  They must be underneath
3203228103Smm * the zhp (either snapshots of it, or snapshots of its descendants).
3204228103Smm */
3205228103Smmint
3206228103Smmzfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
3207228103Smm{
3208228103Smm	int ret;
3209228103Smm	zfs_cmd_t zc = { 0 };
3210228103Smm
3211168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3212228103Smm	if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, snaps) != 0)
3213228103Smm		return (-1);
3214219089Spjd	zc.zc_defer_destroy = defer;
3215168404Spjd
3216228103Smm	ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS_NVL, &zc);
3217168404Spjd	if (ret != 0) {
3218168404Spjd		char errbuf[1024];
3219168404Spjd
3220168404Spjd		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3221228103Smm		    "cannot destroy snapshots in %s"), zc.zc_name);
3222168404Spjd
3223168404Spjd		switch (errno) {
3224168404Spjd		case EEXIST:
3225168404Spjd			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3226168404Spjd			    "snapshot is cloned"));
3227168404Spjd			return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf));
3228168404Spjd
3229168404Spjd		default:
3230168404Spjd			return (zfs_standard_error(zhp->zfs_hdl, errno,
3231168404Spjd			    errbuf));
3232168404Spjd		}
3233168404Spjd	}
3234168404Spjd
3235168404Spjd	return (0);
3236168404Spjd}
3237168404Spjd
3238168404Spjd/*
3239168404Spjd * Clones the given dataset.  The target must be of the same type as the source.
3240168404Spjd */
3241168404Spjdint
3242168404Spjdzfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
3243168404Spjd{
3244168404Spjd	zfs_cmd_t zc = { 0 };
3245168404Spjd	char parent[ZFS_MAXNAMELEN];
3246168404Spjd	int ret;
3247168404Spjd	char errbuf[1024];
3248168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
3249168404Spjd	zfs_type_t type;
3250168404Spjd	uint64_t zoned;
3251168404Spjd
3252168404Spjd	assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
3253168404Spjd
3254168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3255168404Spjd	    "cannot create '%s'"), target);
3256168404Spjd
3257228103Smm	/* validate the target/clone name */
3258185029Spjd	if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
3259168404Spjd		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3260168404Spjd
3261168404Spjd	/* validate parents exist */
3262185029Spjd	if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0)
3263168404Spjd		return (-1);
3264168404Spjd
3265168404Spjd	(void) parent_name(target, parent, sizeof (parent));
3266168404Spjd
3267168404Spjd	/* do the clone */
3268168404Spjd	if (ZFS_IS_VOLUME(zhp)) {
3269168404Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
3270168404Spjd		type = ZFS_TYPE_VOLUME;
3271168404Spjd	} else {
3272168404Spjd		zc.zc_objset_type = DMU_OST_ZFS;
3273168404Spjd		type = ZFS_TYPE_FILESYSTEM;
3274168404Spjd	}
3275168404Spjd
3276168404Spjd	if (props) {
3277185029Spjd		if ((props = zfs_valid_proplist(hdl, type, props, zoned,
3278185029Spjd		    zhp, errbuf)) == NULL)
3279168404Spjd			return (-1);
3280168404Spjd
3281185029Spjd		if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
3282168404Spjd			nvlist_free(props);
3283168404Spjd			return (-1);
3284168404Spjd		}
3285168404Spjd
3286168404Spjd		nvlist_free(props);
3287168404Spjd	}
3288168404Spjd
3289168404Spjd	(void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
3290168404Spjd	(void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value));
3291185029Spjd	ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc);
3292168404Spjd
3293168404Spjd	zcmd_free_nvlists(&zc);
3294168404Spjd
3295168404Spjd	if (ret != 0) {
3296168404Spjd		switch (errno) {
3297168404Spjd
3298168404Spjd		case ENOENT:
3299168404Spjd			/*
3300168404Spjd			 * The parent doesn't exist.  We should have caught this
3301168404Spjd			 * above, but there may a race condition that has since
3302168404Spjd			 * destroyed the parent.
3303168404Spjd			 *
3304168404Spjd			 * At this point, we don't know whether it's the source
3305168404Spjd			 * that doesn't exist anymore, or whether the target
3306168404Spjd			 * dataset doesn't exist.
3307168404Spjd			 */
3308168404Spjd			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3309168404Spjd			    "no such parent '%s'"), parent);
3310168404Spjd			return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
3311168404Spjd
3312168404Spjd		case EXDEV:
3313168404Spjd			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
3314168404Spjd			    "source and target pools differ"));
3315168404Spjd			return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
3316168404Spjd			    errbuf));
3317168404Spjd
3318168404Spjd		default:
3319168404Spjd			return (zfs_standard_error(zhp->zfs_hdl, errno,
3320168404Spjd			    errbuf));
3321168404Spjd		}
3322168404Spjd	}
3323168404Spjd
3324168404Spjd	return (ret);
3325168404Spjd}
3326168404Spjd
3327168404Spjd/*
3328168404Spjd * Promotes the given clone fs to be the clone parent.
3329168404Spjd */
3330168404Spjdint
3331168404Spjdzfs_promote(zfs_handle_t *zhp)
3332168404Spjd{
3333168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
3334168404Spjd	zfs_cmd_t zc = { 0 };
3335168404Spjd	char parent[MAXPATHLEN];
3336168404Spjd	int ret;
3337168404Spjd	char errbuf[1024];
3338168404Spjd
3339168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3340168404Spjd	    "cannot promote '%s'"), zhp->zfs_name);
3341168404Spjd
3342168404Spjd	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3343168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3344168404Spjd		    "snapshots can not be promoted"));
3345168404Spjd		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3346168404Spjd	}
3347168404Spjd
3348185029Spjd	(void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent));
3349168404Spjd	if (parent[0] == '\0') {
3350168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3351168404Spjd		    "not a cloned filesystem"));
3352168404Spjd		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3353168404Spjd	}
3354168404Spjd
3355185029Spjd	(void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin,
3356168404Spjd	    sizeof (zc.zc_value));
3357168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3358185029Spjd	ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);
3359168404Spjd
3360168404Spjd	if (ret != 0) {
3361168404Spjd		int save_errno = errno;
3362168404Spjd
3363168404Spjd		switch (save_errno) {
3364168404Spjd		case EEXIST:
3365219089Spjd			/* There is a conflicting snapshot name. */
3366168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3367219089Spjd			    "conflicting snapshot '%s' from parent '%s'"),
3368219089Spjd			    zc.zc_string, parent);
3369168404Spjd			return (zfs_error(hdl, EZFS_EXISTS, errbuf));
3370168404Spjd
3371168404Spjd		default:
3372168404Spjd			return (zfs_standard_error(hdl, save_errno, errbuf));
3373168404Spjd		}
3374168404Spjd	}
3375168404Spjd	return (ret);
3376168404Spjd}
3377168404Spjd
3378168404Spjd/*
3379168404Spjd * Takes a snapshot of the given dataset.
3380168404Spjd */
3381168404Spjdint
3382185029Spjdzfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
3383185029Spjd    nvlist_t *props)
3384168404Spjd{
3385168404Spjd	const char *delim;
3386185029Spjd	char parent[ZFS_MAXNAMELEN];
3387168404Spjd	zfs_handle_t *zhp;
3388168404Spjd	zfs_cmd_t zc = { 0 };
3389168404Spjd	int ret;
3390168404Spjd	char errbuf[1024];
3391168404Spjd
3392168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3393168404Spjd	    "cannot snapshot '%s'"), path);
3394168404Spjd
3395168404Spjd	/* validate the target name */
3396185029Spjd	if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
3397168404Spjd		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3398168404Spjd
3399185029Spjd	if (props) {
3400185029Spjd		if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
3401185029Spjd		    props, B_FALSE, NULL, errbuf)) == NULL)
3402185029Spjd			return (-1);
3403185029Spjd
3404185029Spjd		if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
3405185029Spjd			nvlist_free(props);
3406185029Spjd			return (-1);
3407185029Spjd		}
3408185029Spjd
3409185029Spjd		nvlist_free(props);
3410185029Spjd	}
3411185029Spjd
3412168404Spjd	/* make sure the parent exists and is of the appropriate type */
3413168404Spjd	delim = strchr(path, '@');
3414168404Spjd	(void) strncpy(parent, path, delim - path);
3415168404Spjd	parent[delim - path] = '\0';
3416168404Spjd
3417168404Spjd	if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM |
3418168404Spjd	    ZFS_TYPE_VOLUME)) == NULL) {
3419185029Spjd		zcmd_free_nvlists(&zc);
3420168404Spjd		return (-1);
3421168404Spjd	}
3422168404Spjd
3423168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3424168404Spjd	(void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value));
3425185029Spjd	if (ZFS_IS_VOLUME(zhp))
3426185029Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
3427185029Spjd	else
3428185029Spjd		zc.zc_objset_type = DMU_OST_ZFS;
3429168404Spjd	zc.zc_cookie = recursive;
3430185029Spjd	ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc);
3431168404Spjd
3432185029Spjd	zcmd_free_nvlists(&zc);
3433185029Spjd
3434168404Spjd	/*
3435168404Spjd	 * if it was recursive, the one that actually failed will be in
3436168404Spjd	 * zc.zc_name.
3437168404Spjd	 */
3438219089Spjd	if (ret != 0) {
3439185029Spjd		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3440185029Spjd		    "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value);
3441219089Spjd		(void) zfs_standard_error(hdl, errno, errbuf);
3442168404Spjd	}
3443168404Spjd
3444168404Spjd	zfs_close(zhp);
3445168404Spjd
3446168404Spjd	return (ret);
3447168404Spjd}
3448168404Spjd
3449168404Spjd/*
3450168404Spjd * Destroy any more recent snapshots.  We invoke this callback on any dependents
3451168404Spjd * of the snapshot first.  If the 'cb_dependent' member is non-zero, then this
3452168404Spjd * is a dependent and we should just destroy it without checking the transaction
3453168404Spjd * group.
3454168404Spjd */
3455168404Spjdtypedef struct rollback_data {
3456168404Spjd	const char	*cb_target;		/* the snapshot */
3457168404Spjd	uint64_t	cb_create;		/* creation time reference */
3458185029Spjd	boolean_t	cb_error;
3459168404Spjd	boolean_t	cb_dependent;
3460185029Spjd	boolean_t	cb_force;
3461168404Spjd} rollback_data_t;
3462168404Spjd
3463168404Spjdstatic int
3464168404Spjdrollback_destroy(zfs_handle_t *zhp, void *data)
3465168404Spjd{
3466168404Spjd	rollback_data_t *cbp = data;
3467168404Spjd
3468168404Spjd	if (!cbp->cb_dependent) {
3469168404Spjd		if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 &&
3470168404Spjd		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
3471168404Spjd		    zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
3472168404Spjd		    cbp->cb_create) {
3473185029Spjd			char *logstr;
3474168404Spjd
3475168404Spjd			cbp->cb_dependent = B_TRUE;
3476185029Spjd			cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
3477185029Spjd			    rollback_destroy, cbp);
3478168404Spjd			cbp->cb_dependent = B_FALSE;
3479168404Spjd
3480185029Spjd			logstr = zhp->zfs_hdl->libzfs_log_str;
3481185029Spjd			zhp->zfs_hdl->libzfs_log_str = NULL;
3482219089Spjd			cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
3483185029Spjd			zhp->zfs_hdl->libzfs_log_str = logstr;
3484168404Spjd		}
3485168404Spjd	} else {
3486185029Spjd		/* We must destroy this clone; first unmount it */
3487185029Spjd		prop_changelist_t *clp;
3488185029Spjd
3489185029Spjd		clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
3490185029Spjd		    cbp->cb_force ? MS_FORCE: 0);
3491185029Spjd		if (clp == NULL || changelist_prefix(clp) != 0) {
3492185029Spjd			cbp->cb_error = B_TRUE;
3493185029Spjd			zfs_close(zhp);
3494185029Spjd			return (0);
3495185029Spjd		}
3496219089Spjd		if (zfs_destroy(zhp, B_FALSE) != 0)
3497185029Spjd			cbp->cb_error = B_TRUE;
3498168404Spjd		else
3499185029Spjd			changelist_remove(clp, zhp->zfs_name);
3500185029Spjd		(void) changelist_postfix(clp);
3501185029Spjd		changelist_free(clp);
3502168404Spjd	}
3503168404Spjd
3504168404Spjd	zfs_close(zhp);
3505168404Spjd	return (0);
3506168404Spjd}
3507168404Spjd
3508168404Spjd/*
3509168404Spjd * Given a dataset, rollback to a specific snapshot, discarding any
3510168404Spjd * data changes since then and making it the active dataset.
3511168404Spjd *
3512168404Spjd * Any snapshots more recent than the target are destroyed, along with
3513168404Spjd * their dependents.
3514168404Spjd */
3515168404Spjdint
3516185029Spjdzfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
3517168404Spjd{
3518168404Spjd	rollback_data_t cb = { 0 };
3519185029Spjd	int err;
3520185029Spjd	zfs_cmd_t zc = { 0 };
3521185029Spjd	boolean_t restore_resv = 0;
3522185029Spjd	uint64_t old_volsize, new_volsize;
3523185029Spjd	zfs_prop_t resv_prop;
3524168404Spjd
3525185029Spjd	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
3526185029Spjd	    zhp->zfs_type == ZFS_TYPE_VOLUME);
3527168404Spjd
3528168404Spjd	/*
3529168404Spjd	 * Destroy all recent snapshots and its dependends.
3530168404Spjd	 */
3531185029Spjd	cb.cb_force = force;
3532168404Spjd	cb.cb_target = snap->zfs_name;
3533168404Spjd	cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
3534168404Spjd	(void) zfs_iter_children(zhp, rollback_destroy, &cb);
3535168404Spjd
3536185029Spjd	if (cb.cb_error)
3537185029Spjd		return (-1);
3538168404Spjd
3539168404Spjd	/*
3540168404Spjd	 * Now that we have verified that the snapshot is the latest,
3541168404Spjd	 * rollback to the given snapshot.
3542168404Spjd	 */
3543168404Spjd
3544185029Spjd	if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
3545185029Spjd		if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
3546185029Spjd			return (-1);
3547185029Spjd		old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3548185029Spjd		restore_resv =
3549185029Spjd		    (old_volsize == zfs_prop_get_int(zhp, resv_prop));
3550168404Spjd	}
3551168404Spjd
3552185029Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3553185029Spjd
3554185029Spjd	if (ZFS_IS_VOLUME(zhp))
3555185029Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
3556185029Spjd	else
3557185029Spjd		zc.zc_objset_type = DMU_OST_ZFS;
3558185029Spjd
3559168404Spjd	/*
3560185029Spjd	 * We rely on zfs_iter_children() to verify that there are no
3561185029Spjd	 * newer snapshots for the given dataset.  Therefore, we can
3562185029Spjd	 * simply pass the name on to the ioctl() call.  There is still
3563185029Spjd	 * an unlikely race condition where the user has taken a
3564185029Spjd	 * snapshot since we verified that this was the most recent.
3565185029Spjd	 *
3566168404Spjd	 */
3567185029Spjd	if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) {
3568185029Spjd		(void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
3569185029Spjd		    dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
3570185029Spjd		    zhp->zfs_name);
3571185029Spjd		return (err);
3572185029Spjd	}
3573168404Spjd
3574185029Spjd	/*
3575185029Spjd	 * For volumes, if the pre-rollback volsize matched the pre-
3576185029Spjd	 * rollback reservation and the volsize has changed then set
3577185029Spjd	 * the reservation property to the post-rollback volsize.
3578185029Spjd	 * Make a new handle since the rollback closed the dataset.
3579185029Spjd	 */
3580185029Spjd	if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
3581185029Spjd	    (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
3582185029Spjd		if (restore_resv) {
3583185029Spjd			new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
3584185029Spjd			if (old_volsize != new_volsize)
3585185029Spjd				err = zfs_prop_set_int(zhp, resv_prop,
3586185029Spjd				    new_volsize);
3587185029Spjd		}
3588185029Spjd		zfs_close(zhp);
3589185029Spjd	}
3590185029Spjd	return (err);
3591168404Spjd}
3592168404Spjd
3593168404Spjd/*
3594168404Spjd * Renames the given dataset.
3595168404Spjd */
3596168404Spjdint
3597226705Spjdzfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags)
3598168404Spjd{
3599168404Spjd	int ret;
3600168404Spjd	zfs_cmd_t zc = { 0 };
3601168404Spjd	char *delim;
3602168676Spjd	prop_changelist_t *cl = NULL;
3603168676Spjd	zfs_handle_t *zhrp = NULL;
3604168676Spjd	char *parentname = NULL;
3605168404Spjd	char parent[ZFS_MAXNAMELEN];
3606226676Spjd	char property[ZFS_MAXPROPLEN];
3607168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
3608168404Spjd	char errbuf[1024];
3609168404Spjd
3610168404Spjd	/* if we have the same exact name, just return success */
3611168404Spjd	if (strcmp(zhp->zfs_name, target) == 0)
3612168404Spjd		return (0);
3613168404Spjd
3614168404Spjd	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3615168404Spjd	    "cannot rename to '%s'"), target);
3616168404Spjd
3617168404Spjd	/*
3618168404Spjd	 * Make sure the target name is valid
3619168404Spjd	 */
3620168404Spjd	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
3621168404Spjd		if ((strchr(target, '@') == NULL) ||
3622168404Spjd		    *target == '@') {
3623168404Spjd			/*
3624168404Spjd			 * Snapshot target name is abbreviated,
3625168404Spjd			 * reconstruct full dataset name
3626168404Spjd			 */
3627168404Spjd			(void) strlcpy(parent, zhp->zfs_name,
3628168404Spjd			    sizeof (parent));
3629168404Spjd			delim = strchr(parent, '@');
3630168404Spjd			if (strchr(target, '@') == NULL)
3631168404Spjd				*(++delim) = '\0';
3632168404Spjd			else
3633168404Spjd				*delim = '\0';
3634168404Spjd			(void) strlcat(parent, target, sizeof (parent));
3635168404Spjd			target = parent;
3636168404Spjd		} else {
3637168404Spjd			/*
3638168404Spjd			 * Make sure we're renaming within the same dataset.
3639168404Spjd			 */
3640168404Spjd			delim = strchr(target, '@');
3641168404Spjd			if (strncmp(zhp->zfs_name, target, delim - target)
3642168404Spjd			    != 0 || zhp->zfs_name[delim - target] != '@') {
3643168404Spjd				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3644168404Spjd				    "snapshots must be part of same "
3645168404Spjd				    "dataset"));
3646168404Spjd				return (zfs_error(hdl, EZFS_CROSSTARGET,
3647168404Spjd				    errbuf));
3648168404Spjd			}
3649168404Spjd		}
3650185029Spjd		if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
3651168404Spjd			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3652168404Spjd	} else {
3653226705Spjd		if (flags.recurse) {
3654168676Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3655168676Spjd			    "recursive rename must be a snapshot"));
3656168676Spjd			return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
3657168676Spjd		}
3658168676Spjd
3659185029Spjd		if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
3660168404Spjd			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3661168404Spjd
3662168404Spjd		/* validate parents */
3663219089Spjd		if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0)
3664168404Spjd			return (-1);
3665168404Spjd
3666168404Spjd		/* make sure we're in the same pool */
3667168404Spjd		verify((delim = strchr(target, '/')) != NULL);
3668168404Spjd		if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
3669168404Spjd		    zhp->zfs_name[delim - target] != '/') {
3670168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3671168404Spjd			    "datasets must be within same pool"));
3672168404Spjd			return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
3673168404Spjd		}
3674168404Spjd
3675168404Spjd		/* new name cannot be a child of the current dataset name */
3676219089Spjd		if (is_descendant(zhp->zfs_name, target)) {
3677168404Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3678219089Spjd			    "New dataset name cannot be a descendant of "
3679168404Spjd			    "current dataset name"));
3680168404Spjd			return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3681168404Spjd		}
3682168404Spjd	}
3683168404Spjd
3684168404Spjd	(void) snprintf(errbuf, sizeof (errbuf),
3685168404Spjd	    dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
3686168404Spjd
3687168404Spjd	if (getzoneid() == GLOBAL_ZONEID &&
3688168404Spjd	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
3689168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3690168404Spjd		    "dataset is used in a non-global zone"));
3691168404Spjd		return (zfs_error(hdl, EZFS_ZONED, errbuf));
3692168404Spjd	}
3693168404Spjd
3694226705Spjd	/*
3695226705Spjd	 * Avoid unmounting file systems with mountpoint property set to
3696226705Spjd	 * 'legacy' or 'none' even if -u option is not given.
3697226705Spjd	 */
3698226705Spjd	if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
3699226705Spjd	    !flags.recurse && !flags.nounmount &&
3700226705Spjd	    zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property,
3701226705Spjd	    sizeof (property), NULL, NULL, 0, B_FALSE) == 0 &&
3702226705Spjd	    (strcmp(property, "legacy") == 0 ||
3703226705Spjd	     strcmp(property, "none") == 0)) {
3704226705Spjd		flags.nounmount = B_TRUE;
3705226705Spjd	}
3706168404Spjd
3707226705Spjd	if (flags.recurse) {
3708226705Spjd
3709185029Spjd		parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
3710185029Spjd		if (parentname == NULL) {
3711185029Spjd			ret = -1;
3712185029Spjd			goto error;
3713185029Spjd		}
3714168676Spjd		delim = strchr(parentname, '@');
3715168676Spjd		*delim = '\0';
3716185029Spjd		zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET);
3717168676Spjd		if (zhrp == NULL) {
3718185029Spjd			ret = -1;
3719185029Spjd			goto error;
3720168676Spjd		}
3721168676Spjd
3722168676Spjd	} else {
3723226676Spjd		if ((cl = changelist_gather(zhp, ZFS_PROP_NAME,
3724226705Spjd		    flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, 0)) == NULL) {
3725168676Spjd			return (-1);
3726226676Spjd		}
3727168676Spjd
3728168676Spjd		if (changelist_haszonedchild(cl)) {
3729168676Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3730168676Spjd			    "child dataset with inherited mountpoint is used "
3731168676Spjd			    "in a non-global zone"));
3732168676Spjd			(void) zfs_error(hdl, EZFS_ZONED, errbuf);
3733168676Spjd			goto error;
3734168676Spjd		}
3735168676Spjd
3736168676Spjd		if ((ret = changelist_prefix(cl)) != 0)
3737168676Spjd			goto error;
3738168404Spjd	}
3739168404Spjd
3740168404Spjd	if (ZFS_IS_VOLUME(zhp))
3741168404Spjd		zc.zc_objset_type = DMU_OST_ZVOL;
3742168404Spjd	else
3743168404Spjd		zc.zc_objset_type = DMU_OST_ZFS;
3744168404Spjd
3745168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
3746168404Spjd	(void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
3747168404Spjd
3748226705Spjd	zc.zc_cookie = flags.recurse ? 1 : 0;
3749226705Spjd	if (flags.nounmount)
3750226676Spjd		zc.zc_cookie |= 2;
3751168676Spjd
3752185029Spjd	if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
3753168676Spjd		/*
3754168676Spjd		 * if it was recursive, the one that actually failed will
3755168676Spjd		 * be in zc.zc_name
3756168676Spjd		 */
3757168676Spjd		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3758185029Spjd		    "cannot rename '%s'"), zc.zc_name);
3759168404Spjd
3760226705Spjd		if (flags.recurse && errno == EEXIST) {
3761168676Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3762168676Spjd			    "a child dataset already has a snapshot "
3763168676Spjd			    "with the new name"));
3764185029Spjd			(void) zfs_error(hdl, EZFS_EXISTS, errbuf);
3765168676Spjd		} else {
3766168676Spjd			(void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
3767168676Spjd		}
3768168676Spjd
3769168404Spjd		/*
3770168404Spjd		 * On failure, we still want to remount any filesystems that
3771168404Spjd		 * were previously mounted, so we don't alter the system state.
3772168404Spjd		 */
3773226705Spjd		if (!flags.recurse)
3774168676Spjd			(void) changelist_postfix(cl);
3775168404Spjd	} else {
3776226705Spjd		if (!flags.recurse) {
3777168676Spjd			changelist_rename(cl, zfs_get_name(zhp), target);
3778168676Spjd			ret = changelist_postfix(cl);
3779168676Spjd		}
3780168404Spjd	}
3781168404Spjd
3782168404Spjderror:
3783168676Spjd	if (parentname) {
3784168676Spjd		free(parentname);
3785168676Spjd	}
3786168676Spjd	if (zhrp) {
3787168676Spjd		zfs_close(zhrp);
3788168676Spjd	}
3789168676Spjd	if (cl) {
3790168676Spjd		changelist_free(cl);
3791168676Spjd	}
3792168404Spjd	return (ret);
3793168404Spjd}
3794168404Spjd
3795219089Spjdnvlist_t *
3796219089Spjdzfs_get_user_props(zfs_handle_t *zhp)
3797168404Spjd{
3798219089Spjd	return (zhp->zfs_user_props);
3799168676Spjd}
3800168676Spjd
3801168404Spjdnvlist_t *
3802219089Spjdzfs_get_recvd_props(zfs_handle_t *zhp)
3803168404Spjd{
3804219089Spjd	if (zhp->zfs_recvd_props == NULL)
3805219089Spjd		if (get_recvd_props_ioctl(zhp) != 0)
3806219089Spjd			return (NULL);
3807219089Spjd	return (zhp->zfs_recvd_props);
3808168404Spjd}
3809168404Spjd
3810168404Spjd/*
3811168404Spjd * This function is used by 'zfs list' to determine the exact set of columns to
3812168404Spjd * display, and their maximum widths.  This does two main things:
3813168404Spjd *
3814168404Spjd *      - If this is a list of all properties, then expand the list to include
3815168404Spjd *        all native properties, and set a flag so that for each dataset we look
3816168404Spjd *        for new unique user properties and add them to the list.
3817168404Spjd *
3818168404Spjd *      - For non fixed-width properties, keep track of the maximum width seen
3819219089Spjd *        so that we can size the column appropriately. If the user has
3820219089Spjd *        requested received property values, we also need to compute the width
3821219089Spjd *        of the RECEIVED column.
3822168404Spjd */
3823168404Spjdint
3824219089Spjdzfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received)
3825168404Spjd{
3826168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
3827185029Spjd	zprop_list_t *entry;
3828185029Spjd	zprop_list_t **last, **start;
3829168404Spjd	nvlist_t *userprops, *propval;
3830168404Spjd	nvpair_t *elem;
3831168404Spjd	char *strval;
3832168404Spjd	char buf[ZFS_MAXPROPLEN];
3833168404Spjd
3834185029Spjd	if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0)
3835168404Spjd		return (-1);
3836168404Spjd
3837168404Spjd	userprops = zfs_get_user_props(zhp);
3838168404Spjd
3839168404Spjd	entry = *plp;
3840168404Spjd	if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
3841168404Spjd		/*
3842168404Spjd		 * Go through and add any user properties as necessary.  We
3843168404Spjd		 * start by incrementing our list pointer to the first
3844168404Spjd		 * non-native property.
3845168404Spjd		 */
3846168404Spjd		start = plp;
3847168404Spjd		while (*start != NULL) {
3848185029Spjd			if ((*start)->pl_prop == ZPROP_INVAL)
3849168404Spjd				break;
3850168404Spjd			start = &(*start)->pl_next;
3851168404Spjd		}
3852168404Spjd
3853168404Spjd		elem = NULL;
3854168404Spjd		while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
3855168404Spjd			/*
3856168404Spjd			 * See if we've already found this property in our list.
3857168404Spjd			 */
3858168404Spjd			for (last = start; *last != NULL;
3859168404Spjd			    last = &(*last)->pl_next) {
3860168404Spjd				if (strcmp((*last)->pl_user_prop,
3861168404Spjd				    nvpair_name(elem)) == 0)
3862168404Spjd					break;
3863168404Spjd			}
3864168404Spjd
3865168404Spjd			if (*last == NULL) {
3866168404Spjd				if ((entry = zfs_alloc(hdl,
3867185029Spjd				    sizeof (zprop_list_t))) == NULL ||
3868168404Spjd				    ((entry->pl_user_prop = zfs_strdup(hdl,
3869168404Spjd				    nvpair_name(elem)))) == NULL) {
3870168404Spjd					free(entry);
3871168404Spjd					return (-1);
3872168404Spjd				}
3873168404Spjd
3874185029Spjd				entry->pl_prop = ZPROP_INVAL;
3875168404Spjd				entry->pl_width = strlen(nvpair_name(elem));
3876168404Spjd				entry->pl_all = B_TRUE;
3877168404Spjd				*last = entry;
3878168404Spjd			}
3879168404Spjd		}
3880168404Spjd	}
3881168404Spjd
3882168404Spjd	/*
3883168404Spjd	 * Now go through and check the width of any non-fixed columns
3884168404Spjd	 */
3885168404Spjd	for (entry = *plp; entry != NULL; entry = entry->pl_next) {
3886168404Spjd		if (entry->pl_fixed)
3887168404Spjd			continue;
3888168404Spjd
3889185029Spjd		if (entry->pl_prop != ZPROP_INVAL) {
3890168404Spjd			if (zfs_prop_get(zhp, entry->pl_prop,
3891168404Spjd			    buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) {
3892168404Spjd				if (strlen(buf) > entry->pl_width)
3893168404Spjd					entry->pl_width = strlen(buf);
3894168404Spjd			}
3895219089Spjd			if (received && zfs_prop_get_recvd(zhp,
3896219089Spjd			    zfs_prop_to_name(entry->pl_prop),
3897219089Spjd			    buf, sizeof (buf), B_FALSE) == 0)
3898219089Spjd				if (strlen(buf) > entry->pl_recvd_width)
3899219089Spjd					entry->pl_recvd_width = strlen(buf);
3900219089Spjd		} else {
3901219089Spjd			if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop,
3902219089Spjd			    &propval) == 0) {
3903219089Spjd				verify(nvlist_lookup_string(propval,
3904219089Spjd				    ZPROP_VALUE, &strval) == 0);
3905219089Spjd				if (strlen(strval) > entry->pl_width)
3906219089Spjd					entry->pl_width = strlen(strval);
3907219089Spjd			}
3908219089Spjd			if (received && zfs_prop_get_recvd(zhp,
3909219089Spjd			    entry->pl_user_prop,
3910219089Spjd			    buf, sizeof (buf), B_FALSE) == 0)
3911219089Spjd				if (strlen(buf) > entry->pl_recvd_width)
3912219089Spjd					entry->pl_recvd_width = strlen(buf);
3913168404Spjd		}
3914168404Spjd	}
3915168404Spjd
3916168404Spjd	return (0);
3917168404Spjd}
3918168404Spjd
3919185029Spjdint
3920185029Spjdzfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path,
3921209962Smm    char *resource, void *export, void *sharetab,
3922209962Smm    int sharemax, zfs_share_op_t operation)
3923185029Spjd{
3924185029Spjd	zfs_cmd_t zc = { 0 };
3925185029Spjd	int error;
3926185029Spjd
3927185029Spjd	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
3928185029Spjd	(void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
3929209962Smm	if (resource)
3930209962Smm		(void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string));
3931185029Spjd	zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab;
3932185029Spjd	zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export;
3933185029Spjd	zc.zc_share.z_sharetype = operation;
3934185029Spjd	zc.zc_share.z_sharemax = sharemax;
3935185029Spjd	error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc);
3936185029Spjd	return (error);
3937185029Spjd}
3938185029Spjd
3939205198Sdelphijvoid
3940205198Sdelphijzfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
3941205198Sdelphij{
3942205198Sdelphij	nvpair_t *curr;
3943205198Sdelphij
3944205198Sdelphij	/*
3945205198Sdelphij	 * Keep a reference to the props-table against which we prune the
3946205198Sdelphij	 * properties.
3947205198Sdelphij	 */
3948205198Sdelphij	zhp->zfs_props_table = props;
3949205198Sdelphij
3950205198Sdelphij	curr = nvlist_next_nvpair(zhp->zfs_props, NULL);
3951205198Sdelphij
3952205198Sdelphij	while (curr) {
3953205198Sdelphij		zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr));
3954205198Sdelphij		nvpair_t *next = nvlist_next_nvpair(zhp->zfs_props, curr);
3955205198Sdelphij
3956206199Sdelphij		/*
3957219089Spjd		 * User properties will result in ZPROP_INVAL, and since we
3958219089Spjd		 * only know how to prune standard ZFS properties, we always
3959219089Spjd		 * leave these in the list.  This can also happen if we
3960219089Spjd		 * encounter an unknown DSL property (when running older
3961219089Spjd		 * software, for example).
3962206199Sdelphij		 */
3963206199Sdelphij		if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
3964205198Sdelphij			(void) nvlist_remove(zhp->zfs_props,
3965205198Sdelphij			    nvpair_name(curr), nvpair_type(curr));
3966205198Sdelphij		curr = next;
3967205198Sdelphij	}
3968205198Sdelphij}
3969205198Sdelphij
3970209962Smm#ifdef sun
3971209962Smmstatic int
3972209962Smmzfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
3973209962Smm    zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
3974209962Smm{
3975209962Smm	zfs_cmd_t zc = { 0 };
3976209962Smm	nvlist_t *nvlist = NULL;
3977209962Smm	int error;
3978209962Smm
3979209962Smm	(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
3980209962Smm	(void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
3981209962Smm	zc.zc_cookie = (uint64_t)cmd;
3982209962Smm
3983209962Smm	if (cmd == ZFS_SMB_ACL_RENAME) {
3984209962Smm		if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
3985209962Smm			(void) no_memory(hdl);
3986209962Smm			return (NULL);
3987209962Smm		}
3988209962Smm	}
3989209962Smm
3990209962Smm	switch (cmd) {
3991209962Smm	case ZFS_SMB_ACL_ADD:
3992209962Smm	case ZFS_SMB_ACL_REMOVE:
3993209962Smm		(void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string));
3994209962Smm		break;
3995209962Smm	case ZFS_SMB_ACL_RENAME:
3996209962Smm		if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC,
3997209962Smm		    resource1) != 0) {
3998209962Smm				(void) no_memory(hdl);
3999209962Smm				return (-1);
4000209962Smm		}
4001209962Smm		if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET,
4002209962Smm		    resource2) != 0) {
4003209962Smm				(void) no_memory(hdl);
4004209962Smm				return (-1);
4005209962Smm		}
4006209962Smm		if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) {
4007209962Smm			nvlist_free(nvlist);
4008209962Smm			return (-1);
4009209962Smm		}
4010209962Smm		break;
4011209962Smm	case ZFS_SMB_ACL_PURGE:
4012209962Smm		break;
4013209962Smm	default:
4014209962Smm		return (-1);
4015209962Smm	}
4016209962Smm	error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
4017209962Smm	if (nvlist)
4018209962Smm		nvlist_free(nvlist);
4019209962Smm	return (error);
4020209962Smm}
4021209962Smm
4022209962Smmint
4023209962Smmzfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset,
4024209962Smm    char *path, char *resource)
4025209962Smm{
4026209962Smm	return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD,
4027209962Smm	    resource, NULL));
4028209962Smm}
4029209962Smm
4030209962Smmint
4031209962Smmzfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset,
4032209962Smm    char *path, char *resource)
4033209962Smm{
4034209962Smm	return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE,
4035209962Smm	    resource, NULL));
4036209962Smm}
4037209962Smm
4038209962Smmint
4039209962Smmzfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path)
4040209962Smm{
4041209962Smm	return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE,
4042209962Smm	    NULL, NULL));
4043209962Smm}
4044209962Smm
4045209962Smmint
4046209962Smmzfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path,
4047209962Smm    char *oldname, char *newname)
4048209962Smm{
4049209962Smm	return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
4050209962Smm	    oldname, newname));
4051209962Smm}
4052209962Smm#endif	/* sun */
4053209962Smm
4054209962Smmint
4055209962Smmzfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
4056209962Smm    zfs_userspace_cb_t func, void *arg)
4057209962Smm{
4058209962Smm	zfs_cmd_t zc = { 0 };
4059209962Smm	int error;
4060209962Smm	zfs_useracct_t buf[100];
4061209962Smm
4062228103Smm	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4063209962Smm
4064209962Smm	zc.zc_objset_type = type;
4065209962Smm	zc.zc_nvlist_dst = (uintptr_t)buf;
4066209962Smm
4067209962Smm	/* CONSTCOND */
4068209962Smm	while (1) {
4069209962Smm		zfs_useracct_t *zua = buf;
4070209962Smm
4071209962Smm		zc.zc_nvlist_dst_size = sizeof (buf);
4072209962Smm		error = ioctl(zhp->zfs_hdl->libzfs_fd,
4073209962Smm		    ZFS_IOC_USERSPACE_MANY, &zc);
4074209962Smm		if (error || zc.zc_nvlist_dst_size == 0)
4075209962Smm			break;
4076209962Smm
4077209962Smm		while (zc.zc_nvlist_dst_size > 0) {
4078209962Smm			error = func(arg, zua->zu_domain, zua->zu_rid,
4079209962Smm			    zua->zu_space);
4080209962Smm			if (error != 0)
4081209962Smm				return (error);
4082209962Smm			zua++;
4083209962Smm			zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4084209962Smm		}
4085209962Smm	}
4086209962Smm
4087209962Smm	return (error);
4088209962Smm}
4089209962Smm
4090219089Spjdint
4091219089Spjdzfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4092219089Spjd    boolean_t recursive, boolean_t temphold, boolean_t enoent_ok,
4093219089Spjd    int cleanup_fd, uint64_t dsobj, uint64_t createtxg)
4094219089Spjd{
4095219089Spjd	zfs_cmd_t zc = { 0 };
4096219089Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
4097219089Spjd
4098219089Spjd	ASSERT(!recursive || dsobj == 0);
4099219089Spjd
4100219089Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4101219089Spjd	(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
4102219089Spjd	if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string))
4103219089Spjd	    >= sizeof (zc.zc_string))
4104219089Spjd		return (zfs_error(hdl, EZFS_TAGTOOLONG, tag));
4105219089Spjd	zc.zc_cookie = recursive;
4106219089Spjd	zc.zc_temphold = temphold;
4107219089Spjd	zc.zc_cleanup_fd = cleanup_fd;
4108219089Spjd	zc.zc_sendobj = dsobj;
4109219089Spjd	zc.zc_createtxg = createtxg;
4110219089Spjd
4111219089Spjd	if (zfs_ioctl(hdl, ZFS_IOC_HOLD, &zc) != 0) {
4112219089Spjd		char errbuf[ZFS_MAXNAMELEN+32];
4113219089Spjd
4114219089Spjd		/*
4115219089Spjd		 * if it was recursive, the one that actually failed will be in
4116219089Spjd		 * zc.zc_name.
4117219089Spjd		 */
4118219089Spjd		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4119219089Spjd		    "cannot hold '%s@%s'"), zc.zc_name, snapname);
4120219089Spjd		switch (errno) {
4121219089Spjd		case E2BIG:
4122219089Spjd			/*
4123219089Spjd			 * Temporary tags wind up having the ds object id
4124219089Spjd			 * prepended. So even if we passed the length check
4125219089Spjd			 * above, it's still possible for the tag to wind
4126219089Spjd			 * up being slightly too long.
4127219089Spjd			 */
4128219089Spjd			return (zfs_error(hdl, EZFS_TAGTOOLONG, errbuf));
4129219089Spjd		case ENOTSUP:
4130219089Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4131219089Spjd			    "pool must be upgraded"));
4132219089Spjd			return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
4133219089Spjd		case EINVAL:
4134219089Spjd			return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
4135219089Spjd		case EEXIST:
4136219089Spjd			return (zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf));
4137219089Spjd		case ENOENT:
4138219089Spjd			if (enoent_ok)
4139219089Spjd				return (ENOENT);
4140219089Spjd			/* FALLTHROUGH */
4141219089Spjd		default:
4142219089Spjd			return (zfs_standard_error_fmt(hdl, errno, errbuf));
4143219089Spjd		}
4144219089Spjd	}
4145219089Spjd
4146219089Spjd	return (0);
4147219089Spjd}
4148219089Spjd
4149219089Spjdint
4150219089Spjdzfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4151219089Spjd    boolean_t recursive)
4152219089Spjd{
4153219089Spjd	zfs_cmd_t zc = { 0 };
4154219089Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
4155219089Spjd
4156219089Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4157219089Spjd	(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
4158219089Spjd	if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string))
4159219089Spjd	    >= sizeof (zc.zc_string))
4160219089Spjd		return (zfs_error(hdl, EZFS_TAGTOOLONG, tag));
4161219089Spjd	zc.zc_cookie = recursive;
4162219089Spjd
4163219089Spjd	if (zfs_ioctl(hdl, ZFS_IOC_RELEASE, &zc) != 0) {
4164219089Spjd		char errbuf[ZFS_MAXNAMELEN+32];
4165219089Spjd
4166219089Spjd		/*
4167219089Spjd		 * if it was recursive, the one that actually failed will be in
4168219089Spjd		 * zc.zc_name.
4169219089Spjd		 */
4170219089Spjd		(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4171219089Spjd		    "cannot release '%s' from '%s@%s'"), tag, zc.zc_name,
4172219089Spjd		    snapname);
4173219089Spjd		switch (errno) {
4174219089Spjd		case ESRCH:
4175219089Spjd			return (zfs_error(hdl, EZFS_REFTAG_RELE, errbuf));
4176219089Spjd		case ENOTSUP:
4177219089Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4178219089Spjd			    "pool must be upgraded"));
4179219089Spjd			return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
4180219089Spjd		case EINVAL:
4181219089Spjd			return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
4182219089Spjd		default:
4183219089Spjd			return (zfs_standard_error_fmt(hdl, errno, errbuf));
4184219089Spjd		}
4185219089Spjd	}
4186219089Spjd
4187219089Spjd	return (0);
4188219089Spjd}
4189219089Spjd
4190219089Spjdint
4191219089Spjdzfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
4192219089Spjd{
4193219089Spjd	zfs_cmd_t zc = { 0 };
4194219089Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
4195219089Spjd	int nvsz = 2048;
4196219089Spjd	void *nvbuf;
4197219089Spjd	int err = 0;
4198219089Spjd	char errbuf[ZFS_MAXNAMELEN+32];
4199219089Spjd
4200219089Spjd	assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
4201219089Spjd	    zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
4202219089Spjd
4203219089Spjdtryagain:
4204219089Spjd
4205219089Spjd	nvbuf = malloc(nvsz);
4206219089Spjd	if (nvbuf == NULL) {
4207219089Spjd		err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
4208219089Spjd		goto out;
4209219089Spjd	}
4210219089Spjd
4211219089Spjd	zc.zc_nvlist_dst_size = nvsz;
4212219089Spjd	zc.zc_nvlist_dst = (uintptr_t)nvbuf;
4213219089Spjd
4214219089Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN);
4215219089Spjd
4216230514Smm	if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
4217219089Spjd		(void) snprintf(errbuf, sizeof (errbuf),
4218219089Spjd		    dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"),
4219219089Spjd		    zc.zc_name);
4220219089Spjd		switch (errno) {
4221219089Spjd		case ENOMEM:
4222219089Spjd			free(nvbuf);
4223219089Spjd			nvsz = zc.zc_nvlist_dst_size;
4224219089Spjd			goto tryagain;
4225219089Spjd
4226219089Spjd		case ENOTSUP:
4227219089Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4228219089Spjd			    "pool must be upgraded"));
4229219089Spjd			err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4230219089Spjd			break;
4231219089Spjd		case EINVAL:
4232219089Spjd			err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4233219089Spjd			break;
4234219089Spjd		case ENOENT:
4235219089Spjd			err = zfs_error(hdl, EZFS_NOENT, errbuf);
4236219089Spjd			break;
4237219089Spjd		default:
4238219089Spjd			err = zfs_standard_error_fmt(hdl, errno, errbuf);
4239219089Spjd			break;
4240219089Spjd		}
4241219089Spjd	} else {
4242219089Spjd		/* success */
4243219089Spjd		int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
4244219089Spjd		if (rc) {
4245219089Spjd			(void) snprintf(errbuf, sizeof (errbuf), dgettext(
4246219089Spjd			    TEXT_DOMAIN, "cannot get permissions on '%s'"),
4247219089Spjd			    zc.zc_name);
4248219089Spjd			err = zfs_standard_error_fmt(hdl, rc, errbuf);
4249219089Spjd		}
4250219089Spjd	}
4251219089Spjd
4252219089Spjd	free(nvbuf);
4253219089Spjdout:
4254219089Spjd	return (err);
4255219089Spjd}
4256219089Spjd
4257219089Spjdint
4258219089Spjdzfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
4259219089Spjd{
4260219089Spjd	zfs_cmd_t zc = { 0 };
4261219089Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
4262219089Spjd	char *nvbuf;
4263219089Spjd	char errbuf[ZFS_MAXNAMELEN+32];
4264219089Spjd	size_t nvsz;
4265219089Spjd	int err;
4266219089Spjd
4267219089Spjd	assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
4268219089Spjd	    zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
4269219089Spjd
4270219089Spjd	err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
4271219089Spjd	assert(err == 0);
4272219089Spjd
4273219089Spjd	nvbuf = malloc(nvsz);
4274219089Spjd
4275219089Spjd	err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
4276219089Spjd	assert(err == 0);
4277219089Spjd
4278219089Spjd	zc.zc_nvlist_src_size = nvsz;
4279219089Spjd	zc.zc_nvlist_src = (uintptr_t)nvbuf;
4280219089Spjd	zc.zc_perm_action = un;
4281219089Spjd
4282219089Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4283219089Spjd
4284219089Spjd	if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) {
4285219089Spjd		(void) snprintf(errbuf, sizeof (errbuf),
4286219089Spjd		    dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"),
4287219089Spjd		    zc.zc_name);
4288219089Spjd		switch (errno) {
4289219089Spjd		case ENOTSUP:
4290219089Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4291219089Spjd			    "pool must be upgraded"));
4292219089Spjd			err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4293219089Spjd			break;
4294219089Spjd		case EINVAL:
4295219089Spjd			err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4296219089Spjd			break;
4297219089Spjd		case ENOENT:
4298219089Spjd			err = zfs_error(hdl, EZFS_NOENT, errbuf);
4299219089Spjd			break;
4300219089Spjd		default:
4301219089Spjd			err = zfs_standard_error_fmt(hdl, errno, errbuf);
4302219089Spjd			break;
4303219089Spjd		}
4304219089Spjd	}
4305219089Spjd
4306219089Spjd	free(nvbuf);
4307219089Spjd
4308219089Spjd	return (err);
4309219089Spjd}
4310219089Spjd
4311219089Spjdint
4312219089Spjdzfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
4313219089Spjd{
4314219089Spjd	zfs_cmd_t zc = { 0 };
4315219089Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
4316219089Spjd	int nvsz = 2048;
4317219089Spjd	void *nvbuf;
4318219089Spjd	int err = 0;
4319219089Spjd	char errbuf[ZFS_MAXNAMELEN+32];
4320219089Spjd
4321219089Spjd	assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
4322219089Spjd
4323219089Spjdtryagain:
4324219089Spjd
4325219089Spjd	nvbuf = malloc(nvsz);
4326219089Spjd	if (nvbuf == NULL) {
4327219089Spjd		err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
4328219089Spjd		goto out;
4329219089Spjd	}
4330219089Spjd
4331219089Spjd	zc.zc_nvlist_dst_size = nvsz;
4332219089Spjd	zc.zc_nvlist_dst = (uintptr_t)nvbuf;
4333219089Spjd
4334219089Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN);
4335219089Spjd
4336219089Spjd	if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) != 0) {
4337219089Spjd		(void) snprintf(errbuf, sizeof (errbuf),
4338219089Spjd		    dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
4339219089Spjd		    zc.zc_name);
4340219089Spjd		switch (errno) {
4341219089Spjd		case ENOMEM:
4342219089Spjd			free(nvbuf);
4343219089Spjd			nvsz = zc.zc_nvlist_dst_size;
4344219089Spjd			goto tryagain;
4345219089Spjd
4346219089Spjd		case ENOTSUP:
4347219089Spjd			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4348219089Spjd			    "pool must be upgraded"));
4349219089Spjd			err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
4350219089Spjd			break;
4351219089Spjd		case EINVAL:
4352219089Spjd			err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
4353219089Spjd			break;
4354219089Spjd		case ENOENT:
4355219089Spjd			err = zfs_error(hdl, EZFS_NOENT, errbuf);
4356219089Spjd			break;
4357219089Spjd		default:
4358219089Spjd			err = zfs_standard_error_fmt(hdl, errno, errbuf);
4359219089Spjd			break;
4360219089Spjd		}
4361219089Spjd	} else {
4362219089Spjd		/* success */
4363219089Spjd		int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
4364219089Spjd		if (rc) {
4365219089Spjd			(void) snprintf(errbuf, sizeof (errbuf),
4366219089Spjd			    dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
4367219089Spjd			    zc.zc_name);
4368219089Spjd			err = zfs_standard_error_fmt(hdl, rc, errbuf);
4369219089Spjd		}
4370219089Spjd	}
4371219089Spjd
4372219089Spjd	free(nvbuf);
4373219089Spjdout:
4374219089Spjd	return (err);
4375219089Spjd}
4376219089Spjd
4377219089Spjduint64_t
4378219089Spjdzvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props)
4379219089Spjd{
4380219089Spjd	uint64_t numdb;
4381219089Spjd	uint64_t nblocks, volblocksize;
4382219089Spjd	int ncopies;
4383219089Spjd	char *strval;
4384219089Spjd
4385219089Spjd	if (nvlist_lookup_string(props,
4386219089Spjd	    zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
4387219089Spjd		ncopies = atoi(strval);
4388219089Spjd	else
4389219089Spjd		ncopies = 1;
4390219089Spjd	if (nvlist_lookup_uint64(props,
4391219089Spjd	    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
4392219089Spjd	    &volblocksize) != 0)
4393219089Spjd		volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
4394219089Spjd	nblocks = volsize/volblocksize;
4395219089Spjd	/* start with metadnode L0-L6 */
4396219089Spjd	numdb = 7;
4397219089Spjd	/* calculate number of indirects */
4398219089Spjd	while (nblocks > 1) {
4399219089Spjd		nblocks += DNODES_PER_LEVEL - 1;
4400219089Spjd		nblocks /= DNODES_PER_LEVEL;
4401219089Spjd		numdb += nblocks;
4402219089Spjd	}
4403219089Spjd	numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
4404219089Spjd	volsize *= ncopies;
4405219089Spjd	/*
4406219089Spjd	 * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
4407219089Spjd	 * compressed, but in practice they compress down to about
4408219089Spjd	 * 1100 bytes
4409219089Spjd	 */
4410219089Spjd	numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
4411219089Spjd	volsize += numdb;
4412219089Spjd	return (volsize);
4413219089Spjd}
4414219089Spjd
4415168404Spjd/*
4416168404Spjd * Attach/detach the given filesystem to/from the given jail.
4417168404Spjd */
4418168404Spjdint
4419168404Spjdzfs_jail(zfs_handle_t *zhp, int jailid, int attach)
4420168404Spjd{
4421168404Spjd	libzfs_handle_t *hdl = zhp->zfs_hdl;
4422168404Spjd	zfs_cmd_t zc = { 0 };
4423168404Spjd	char errbuf[1024];
4424224525Smm	unsigned long cmd;
4425224525Smm	int ret;
4426168404Spjd
4427168404Spjd	if (attach) {
4428168404Spjd		(void) snprintf(errbuf, sizeof (errbuf),
4429168404Spjd		    dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
4430168404Spjd	} else {
4431168404Spjd		(void) snprintf(errbuf, sizeof (errbuf),
4432168404Spjd		    dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name);
4433168404Spjd	}
4434168404Spjd
4435168404Spjd	switch (zhp->zfs_type) {
4436168404Spjd	case ZFS_TYPE_VOLUME:
4437168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4438168404Spjd		    "volumes can not be jailed"));
4439168404Spjd		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
4440168404Spjd	case ZFS_TYPE_SNAPSHOT:
4441168404Spjd		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4442168404Spjd		    "snapshots can not be jailed"));
4443168404Spjd		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
4444168404Spjd	}
4445168404Spjd	assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
4446168404Spjd
4447168404Spjd	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
4448168404Spjd	zc.zc_objset_type = DMU_OST_ZFS;
4449168404Spjd	zc.zc_jailid = jailid;
4450168404Spjd
4451168404Spjd	cmd = attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL;
4452168404Spjd	if ((ret = ioctl(hdl->libzfs_fd, cmd, &zc)) != 0)
4453168404Spjd		zfs_standard_error(hdl, errno, errbuf);
4454168404Spjd
4455168404Spjd	return (ret);
4456168404Spjd}
4457