1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
22fa9e4066Sahrens /*
2336db6475SEric Taylor  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24*0dfe541eSEvan Layton  */
25*0dfe541eSEvan Layton 
26*0dfe541eSEvan Layton /*
27*0dfe541eSEvan Layton  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
28ad2760acSMatthew Ahrens  * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
29f0f3ef5aSGarrett D'Amore  * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
300d8fa8f8SMartin Matuska  * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
31013023d4SMartin Matuska  * Copyright (c) 2013 Martin Matuska. All rights reserved.
32a7a845e4SSteven Hartland  * Copyright (c) 2013 Steven Hartland. All rights reserved.
33c3d26abcSMatthew Ahrens  * Copyright (c) 2014 Integros [integros.com]
34*0dfe541eSEvan Layton  * Copyright 2018 Nexenta Systems, Inc.
3588f61deeSIgor Kozhukhov  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
36f62db44dSAndrew Stormont  * Copyright 2017-2018 RackTop Systems.
37fa9e4066Sahrens  */
39fa9e4066Sahrens #include <ctype.h>
40fa9e4066Sahrens #include <errno.h>
41fa9e4066Sahrens #include <libintl.h>
42fa9e4066Sahrens #include <stdio.h>
43fa9e4066Sahrens #include <stdlib.h>
44fa9e4066Sahrens #include <strings.h>
45fa9e4066Sahrens #include <unistd.h>
463cb34c60Sahrens #include <stddef.h>
47fa9e4066Sahrens #include <zone.h>
4899653d4eSeschrock #include <fcntl.h>
49fa9e4066Sahrens #include <sys/mntent.h>
50b12a1c38Slling #include <sys/mount.h>
51ecd6cf80Smarks #include <priv.h>
52ecd6cf80Smarks #include <pwd.h>
53ecd6cf80Smarks #include <grp.h>
54ecd6cf80Smarks #include <stddef.h>
55ecd6cf80Smarks #include <ucred.h>
5614843421SMatthew Ahrens #include <idmap.h>
5714843421SMatthew Ahrens #include <aclutils.h>
583b12c289SMatthew Ahrens #include <directory.h>
59591e0e13SSebastien Roy #include <time.h>
61c1449561SEric Taylor #include <sys/dnode.h>
62fa9e4066Sahrens #include <sys/spa.h>
63e9dbad6fSeschrock #include <sys/zap.h>
64eb633035STom Caputi #include <sys/dsl_crypt.h>
65fa9e4066Sahrens #include <libzfs.h>
66d8ab6e12SDon Brady #include <libzutil.h>
68fa9e4066Sahrens #include "zfs_namecheck.h"
69fa9e4066Sahrens #include "zfs_prop.h"
70fa9e4066Sahrens #include "libzfs_impl.h"
71ecd6cf80Smarks #include "zfs_deleg.h"
7314843421SMatthew Ahrens static int userquota_propname_decode(const char *propname, boolean_t zoned,
7414843421SMatthew Ahrens     zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
76fa9e4066Sahrens /*
77fa9e4066Sahrens  * Given a single type (not a mask of types), return the type in a human
78fa9e4066Sahrens  * readable form.
79fa9e4066Sahrens  */
80fa9e4066Sahrens const char *
zfs_type_to_name(zfs_type_t type)81fa9e4066Sahrens zfs_type_to_name(zfs_type_t type)
82fa9e4066Sahrens {
83fa9e4066Sahrens 	switch (type) {
84fa9e4066Sahrens 	case ZFS_TYPE_FILESYSTEM:
85fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "filesystem"));
86fa9e4066Sahrens 	case ZFS_TYPE_SNAPSHOT:
87fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "snapshot"));
88fa9e4066Sahrens 	case ZFS_TYPE_VOLUME:
89fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "volume"));
9088f61deeSIgor Kozhukhov 	case ZFS_TYPE_POOL:
9188f61deeSIgor Kozhukhov 		return (dgettext(TEXT_DOMAIN, "pool"));
9288f61deeSIgor Kozhukhov 	case ZFS_TYPE_BOOKMARK:
9388f61deeSIgor Kozhukhov 		return (dgettext(TEXT_DOMAIN, "bookmark"));
9488f61deeSIgor Kozhukhov 	default:
9588f61deeSIgor Kozhukhov 		assert(!"unhandled zfs_type_t");
96fa9e4066Sahrens 	}
98fa9e4066Sahrens 	return (NULL);
99fa9e4066Sahrens }
101fa9e4066Sahrens /*
102fa9e4066Sahrens  * Validate a ZFS path.  This is used even before trying to open the dataset, to
10314843421SMatthew Ahrens  * provide a more meaningful error message.  We call zfs_error_aux() to
10414843421SMatthew Ahrens  * explain exactly why the name was not valid.
105fa9e4066Sahrens  */
10699d5e173STim Haley int
zfs_validate_name(libzfs_handle_t * hdl,const char * path,int type,boolean_t modifying)107f18faf3fSek zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
108f18faf3fSek     boolean_t modifying)
109fa9e4066Sahrens {
110fa9e4066Sahrens 	namecheck_err_t why;
111fa9e4066Sahrens 	char what;
113edb901aaSMarcel Telka 	if (entity_namecheck(path, &why, &what) != 0) {
11499653d4eSeschrock 		if (hdl != NULL) {
115fa9e4066Sahrens 			switch (why) {
116b81d61a6Slling 			case NAME_ERR_TOOLONG:
11799653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
11899653d4eSeschrock 				    "name is too long"));
119b81d61a6Slling 				break;
121fa9e4066Sahrens 			case NAME_ERR_LEADING_SLASH:
12299653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
12399653d4eSeschrock 				    "leading slash in name"));
124fa9e4066Sahrens 				break;
126fa9e4066Sahrens 			case NAME_ERR_EMPTY_COMPONENT:
12799653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
12899653d4eSeschrock 				    "empty component in name"));
129fa9e4066Sahrens 				break;
131fa9e4066Sahrens 			case NAME_ERR_TRAILING_SLASH:
13299653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
13399653d4eSeschrock 				    "trailing slash in name"));
134fa9e4066Sahrens 				break;
136fa9e4066Sahrens 			case NAME_ERR_INVALCHAR:
13799653d4eSeschrock 				zfs_error_aux(hdl,
138fa9e4066Sahrens 				    dgettext(TEXT_DOMAIN, "invalid character "
13999653d4eSeschrock 				    "'%c' in name"), what);
140fa9e4066Sahrens 				break;
142edb901aaSMarcel Telka 			case NAME_ERR_MULTIPLE_DELIMITERS:
14399653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
144edb901aaSMarcel Telka 				    "multiple '@' and/or '#' delimiters in "
145edb901aaSMarcel Telka 				    "name"));
146fa9e4066Sahrens 				break;
1485ad82045Snd 			case NAME_ERR_NOLETTER:
1495ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1505ad82045Snd 				    "pool doesn't begin with a letter"));
1515ad82045Snd 				break;
1535ad82045Snd 			case NAME_ERR_RESERVED:
1545ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1555ad82045Snd 				    "name is reserved"));
1565ad82045Snd 				break;
1585ad82045Snd 			case NAME_ERR_DISKLIKE:
1595ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1605ad82045Snd 				    "reserved disk name"));
1615ad82045Snd 				break;
16288f61deeSIgor Kozhukhov 
16388f61deeSIgor Kozhukhov 			default:
16488f61deeSIgor Kozhukhov 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
16588f61deeSIgor Kozhukhov 				    "(%d) not defined"), why);
16688f61deeSIgor Kozhukhov 				break;
167fa9e4066Sahrens 			}
168fa9e4066Sahrens 		}
170fa9e4066Sahrens 		return (0);
171fa9e4066Sahrens 	}
173fa9e4066Sahrens 	if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
17499653d4eSeschrock 		if (hdl != NULL)
17599653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
176edb901aaSMarcel Telka 			    "snapshot delimiter '@' is not expected here"));
177fa9e4066Sahrens 		return (0);
178fa9e4066Sahrens 	}
1801d452cf5Sahrens 	if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
1811d452cf5Sahrens 		if (hdl != NULL)
1821d452cf5Sahrens 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
183d7d4af51Smmusante 			    "missing '@' delimiter in snapshot name"));
1841d452cf5Sahrens 		return (0);
1851d452cf5Sahrens 	}
187edb901aaSMarcel Telka 	if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) {
188edb901aaSMarcel Telka 		if (hdl != NULL)
189edb901aaSMarcel Telka 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
190edb901aaSMarcel Telka 			    "bookmark delimiter '#' is not expected here"));
191edb901aaSMarcel Telka 		return (0);
192edb901aaSMarcel Telka 	}
193edb901aaSMarcel Telka 
194edb901aaSMarcel Telka 	if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) {
195edb901aaSMarcel Telka 		if (hdl != NULL)
196edb901aaSMarcel Telka 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
197edb901aaSMarcel Telka 			    "missing '#' delimiter in bookmark name"));
198edb901aaSMarcel Telka 		return (0);
199edb901aaSMarcel Telka 	}
200edb901aaSMarcel Telka 
201f18faf3fSek 	if (modifying && strchr(path, '%') != NULL) {
202f18faf3fSek 		if (hdl != NULL)
203f18faf3fSek 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
204f18faf3fSek 			    "invalid character %c in name"), '%');
205f18faf3fSek 		return (0);
206f18faf3fSek 	}
20899653d4eSeschrock 	return (-1);
209fa9e4066Sahrens }
211fa9e4066Sahrens int
zfs_name_valid(const char * name,zfs_type_t type)212fa9e4066Sahrens zfs_name_valid(const char *name, zfs_type_t type)
213fa9e4066Sahrens {
214e7cbe64fSgw 	if (type == ZFS_TYPE_POOL)
215e7cbe64fSgw 		return (zpool_name_valid(NULL, B_FALSE, name));
216f18faf3fSek 	return (zfs_validate_name(NULL, name, type, B_FALSE));
217fa9e4066Sahrens }
219e9dbad6fSeschrock /*
220e9dbad6fSeschrock  * This function takes the raw DSL properties, and filters out the user-defined
221e9dbad6fSeschrock  * properties into a separate nvlist.
222e9dbad6fSeschrock  */
223fac3008cSeschrock static nvlist_t *
process_user_props(zfs_handle_t * zhp,nvlist_t * props)224fac3008cSeschrock process_user_props(zfs_handle_t *zhp, nvlist_t *props)
225e9dbad6fSeschrock {
226e9dbad6fSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
227e9dbad6fSeschrock 	nvpair_t *elem;
228e9dbad6fSeschrock 	nvlist_t *propval;
229fac3008cSeschrock 	nvlist_t *nvl;
231fac3008cSeschrock 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
232fac3008cSeschrock 		(void) no_memory(hdl);
233fac3008cSeschrock 		return (NULL);
234fac3008cSeschrock 	}
236e9dbad6fSeschrock 	elem = NULL;
237fac3008cSeschrock 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
238e9dbad6fSeschrock 		if (!zfs_prop_user(nvpair_name(elem)))
239e9dbad6fSeschrock 			continue;
241e9dbad6fSeschrock 		verify(nvpair_value_nvlist(elem, &propval) == 0);
242fac3008cSeschrock 		if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) {
243fac3008cSeschrock 			nvlist_free(nvl);
244fac3008cSeschrock 			(void) no_memory(hdl);
245fac3008cSeschrock 			return (NULL);
246fac3008cSeschrock 		}
247e9dbad6fSeschrock 	}
249fac3008cSeschrock 	return (nvl);
250e9dbad6fSeschrock }
25229ab75c9Srm static zpool_handle_t *
zpool_add_handle(zfs_handle_t * zhp,const char * pool_name)25329ab75c9Srm zpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
25429ab75c9Srm {
25529ab75c9Srm 	libzfs_handle_t *hdl = zhp->zfs_hdl;
25629ab75c9Srm 	zpool_handle_t *zph;
25829ab75c9Srm 	if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
25929ab75c9Srm 		if (hdl->libzfs_pool_handles != NULL)
26029ab75c9Srm 			zph->zpool_next = hdl->libzfs_pool_handles;
26129ab75c9Srm 		hdl->libzfs_pool_handles = zph;
26229ab75c9Srm 	}
26329ab75c9Srm 	return (zph);
26429ab75c9Srm }
26629ab75c9Srm static zpool_handle_t *
zpool_find_handle(zfs_handle_t * zhp,const char * pool_name,int len)26729ab75c9Srm zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
26829ab75c9Srm {
26929ab75c9Srm 	libzfs_handle_t *hdl = zhp->zfs_hdl;
27029ab75c9Srm 	zpool_handle_t *zph = hdl->libzfs_pool_handles;
27229ab75c9Srm 	while ((zph != NULL) &&
27329ab75c9Srm 	    (strncmp(pool_name, zpool_get_name(zph), len) != 0))
27429ab75c9Srm 		zph = zph->zpool_next;
27529ab75c9Srm 	return (zph);
27629ab75c9Srm }
27829ab75c9Srm /*
27929ab75c9Srm  * Returns a handle to the pool that contains the provided dataset.
28029ab75c9Srm  * If a handle to that pool already exists then that handle is returned.
28129ab75c9Srm  * Otherwise, a new handle is created and added to the list of handles.
28229ab75c9Srm  */
28329ab75c9Srm static zpool_handle_t *
zpool_handle(zfs_handle_t * zhp)28429ab75c9Srm zpool_handle(zfs_handle_t *zhp)
28529ab75c9Srm {
28629ab75c9Srm 	char *pool_name;
28729ab75c9Srm 	int len;
28829ab75c9Srm 	zpool_handle_t *zph;
29078f17100SMatthew Ahrens 	len = strcspn(zhp->zfs_name, "/@#") + 1;
29129ab75c9Srm 	pool_name = zfs_alloc(zhp->zfs_hdl, len);
29229ab75c9Srm 	(void) strlcpy(pool_name, zhp->zfs_name, len);
29429ab75c9Srm 	zph = zpool_find_handle(zhp, pool_name, len);
29529ab75c9Srm 	if (zph == NULL)
29629ab75c9Srm 		zph = zpool_add_handle(zhp, pool_name);
29829ab75c9Srm 	free(pool_name);
29929ab75c9Srm 	return (zph);
30029ab75c9Srm }
30229ab75c9Srm void
zpool_free_handles(libzfs_handle_t * hdl)30329ab75c9Srm zpool_free_handles(libzfs_handle_t *hdl)
30429ab75c9Srm {
30529ab75c9Srm 	zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
30729ab75c9Srm 	while (zph != NULL) {
30829ab75c9Srm 		next = zph->zpool_next;
30929ab75c9Srm 		zpool_close(zph);
31029ab75c9Srm 		zph = next;
31129ab75c9Srm 	}
31229ab75c9Srm 	hdl->libzfs_pool_handles = NULL;
31329ab75c9Srm }
315fa9e4066Sahrens /*
316fa9e4066Sahrens  * Utility function to gather stats (objset and zpl) for the given object.
317fa9e4066Sahrens  */
318fa9e4066Sahrens static int
get_stats_ioctl(zfs_handle_t * zhp,zfs_cmd_t * zc)319ebedde84SEric Taylor get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
320fa9e4066Sahrens {
321e9dbad6fSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
323ebedde84SEric Taylor 	(void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
325ebedde84SEric Taylor 	while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
3267f7322feSeschrock 		if (errno == ENOMEM) {
327ebedde84SEric Taylor 			if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
32899653d4eSeschrock 				return (-1);
329e9dbad6fSeschrock 			}
3307f7322feSeschrock 		} else {
3317f7322feSeschrock 			return (-1);
3327f7322feSeschrock 		}
3337f7322feSeschrock 	}
334ebedde84SEric Taylor 	return (0);
335ebedde84SEric Taylor }
33792241e0bSTom Erickson /*
33892241e0bSTom Erickson  * Utility function to get the received properties of the given object.
33992241e0bSTom Erickson  */
34092241e0bSTom Erickson static int
get_recvd_props_ioctl(zfs_handle_t * zhp)34192241e0bSTom Erickson get_recvd_props_ioctl(zfs_handle_t *zhp)
34292241e0bSTom Erickson {
34392241e0bSTom Erickson 	libzfs_handle_t *hdl = zhp->zfs_hdl;
34492241e0bSTom Erickson 	nvlist_t *recvdprops;
34592241e0bSTom Erickson 	zfs_cmd_t zc = { 0 };
34692241e0bSTom Erickson 	int err;
34792241e0bSTom Erickson 
34892241e0bSTom Erickson 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
34992241e0bSTom Erickson 		return (-1);
35092241e0bSTom Erickson 
35192241e0bSTom Erickson 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
35292241e0bSTom Erickson 
35392241e0bSTom Erickson 	while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) {
35492241e0bSTom Erickson 		if (errno == ENOMEM) {
35592241e0bSTom Erickson 			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
35692241e0bSTom Erickson 				return (-1);
35792241e0bSTom Erickson 			}
35892241e0bSTom Erickson 		} else {
35992241e0bSTom Erickson 			zcmd_free_nvlists(&zc);
36092241e0bSTom Erickson 			return (-1);
36192241e0bSTom Erickson 		}
36292241e0bSTom Erickson 	}
36392241e0bSTom Erickson 
36492241e0bSTom Erickson 	err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops);
36592241e0bSTom Erickson 	zcmd_free_nvlists(&zc);
36692241e0bSTom Erickson 	if (err != 0)
36792241e0bSTom Erickson 		return (-1);
36892241e0bSTom Erickson 
36992241e0bSTom Erickson 	nvlist_free(zhp->zfs_recvd_props);
37092241e0bSTom Erickson 	zhp->zfs_recvd_props = recvdprops;
37192241e0bSTom Erickson 
37292241e0bSTom Erickson 	return (0);
37392241e0bSTom Erickson }
37492241e0bSTom Erickson 
375ebedde84SEric Taylor static int
put_stats_zhdl(zfs_handle_t * zhp,zfs_cmd_t * zc)376ebedde84SEric Taylor put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
377ebedde84SEric Taylor {
378ebedde84SEric Taylor 	nvlist_t *allprops, *userprops;
380ebedde84SEric Taylor 	zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
381ebedde84SEric Taylor 
382ebedde84SEric Taylor 	if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
38399653d4eSeschrock 		return (-1);
38499653d4eSeschrock 	}
38614843421SMatthew Ahrens 	/*
38714843421SMatthew Ahrens 	 * XXX Why do we store the user props separately, in addition to
38814843421SMatthew Ahrens 	 * storing them in zfs_props?
38914843421SMatthew Ahrens 	 */
390fac3008cSeschrock 	if ((userprops = process_user_props(zhp, allprops)) == NULL) {
391fac3008cSeschrock 		nvlist_free(allprops);
392e9dbad6fSeschrock 		return (-1);
393fac3008cSeschrock 	}
395fac3008cSeschrock 	nvlist_free(zhp->zfs_props);
396fac3008cSeschrock 	nvlist_free(zhp->zfs_user_props);
398fac3008cSeschrock 	zhp->zfs_props = allprops;
399fac3008cSeschrock 	zhp->zfs_user_props = userprops;
401fa9e4066Sahrens 	return (0);
402fa9e4066Sahrens }
404ebedde84SEric Taylor static int
get_stats(zfs_handle_t * zhp)405ebedde84SEric Taylor get_stats(zfs_handle_t *zhp)
406ebedde84SEric Taylor {
407ebedde84SEric Taylor 	int rc = 0;
408ebedde84SEric Taylor 	zfs_cmd_t zc = { 0 };
409ebedde84SEric Taylor 
410ebedde84SEric Taylor 	if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
411ebedde84SEric Taylor 		return (-1);
412ebedde84SEric Taylor 	if (get_stats_ioctl(zhp, &zc) != 0)
413ebedde84SEric Taylor 		rc = -1;
414ebedde84SEric Taylor 	else if (put_stats_zhdl(zhp, &zc) != 0)
415ebedde84SEric Taylor 		rc = -1;
416ebedde84SEric Taylor 	zcmd_free_nvlists(&zc);
417ebedde84SEric Taylor 	return (rc);
418ebedde84SEric Taylor }
419ebedde84SEric Taylor 
420fa9e4066Sahrens /*
421fa9e4066Sahrens  * Refresh the properties currently stored in the handle.
422fa9e4066Sahrens  */
423fa9e4066Sahrens void
zfs_refresh_properties(zfs_handle_t * zhp)424fa9e4066Sahrens zfs_refresh_properties(zfs_handle_t *zhp)
425fa9e4066Sahrens {
426fa9e4066Sahrens 	(void) get_stats(zhp);
427fa9e4066Sahrens }
429fa9e4066Sahrens /*
430fa9e4066Sahrens  * Makes a handle from the given dataset name.  Used by zfs_open() and
431fa9e4066Sahrens  * zfs_iter_* to create child handles on the fly.
432fa9e4066Sahrens  */
433ebedde84SEric Taylor static int
make_dataset_handle_common(zfs_handle_t * zhp,zfs_cmd_t * zc)434ebedde84SEric Taylor make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
435fa9e4066Sahrens {
436503ad85cSMatthew Ahrens 	if (put_stats_zhdl(zhp, zc) != 0)
437ebedde84SEric Taylor 		return (-1);
439fa9e4066Sahrens 	/*
440fa9e4066Sahrens 	 * We've managed to open the dataset and gather statistics.  Determine
441fa9e4066Sahrens 	 * the high-level type.
442fa9e4066Sahrens 	 */
443a2eea2e1Sahrens 	if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
444a2eea2e1Sahrens 		zhp->zfs_head_type = ZFS_TYPE_VOLUME;
445a2eea2e1Sahrens 	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
446a2eea2e1Sahrens 		zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
447e0f1c0afSOlaf Faaland 	else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER)
448e0f1c0afSOlaf Faaland 		return (-1);
449a2eea2e1Sahrens 	else
450a2eea2e1Sahrens 		abort();
452fa9e4066Sahrens 	if (zhp->zfs_dmustats.dds_is_snapshot)
453fa9e4066Sahrens 		zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
454fa9e4066Sahrens 	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
455fa9e4066Sahrens 		zhp->zfs_type = ZFS_TYPE_VOLUME;
456fa9e4066Sahrens 	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
457fa9e4066Sahrens 		zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
458fa9e4066Sahrens 	else
45999653d4eSeschrock 		abort();	/* we should never see any other types */
4619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL)
4629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
4639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
464ebedde84SEric Taylor 	return (0);
465ebedde84SEric Taylor }
466ebedde84SEric Taylor 
467ebedde84SEric Taylor zfs_handle_t *
make_dataset_handle(libzfs_handle_t * hdl,const char * path)468ebedde84SEric Taylor make_dataset_handle(libzfs_handle_t *hdl, const char *path)
469ebedde84SEric Taylor {
470ebedde84SEric Taylor 	zfs_cmd_t zc = { 0 };
471ebedde84SEric Taylor 
472ebedde84SEric Taylor 	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
473ebedde84SEric Taylor 
474ebedde84SEric Taylor 	if (zhp == NULL)
475ebedde84SEric Taylor 		return (NULL);
476ebedde84SEric Taylor 
477ebedde84SEric Taylor 	zhp->zfs_hdl = hdl;
478ebedde84SEric Taylor 	(void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
479ebedde84SEric Taylor 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
480ebedde84SEric Taylor 		free(zhp);
481ebedde84SEric Taylor 		return (NULL);
482ebedde84SEric Taylor 	}
483ebedde84SEric Taylor 	if (get_stats_ioctl(zhp, &zc) == -1) {
484ebedde84SEric Taylor 		zcmd_free_nvlists(&zc);
485ebedde84SEric Taylor 		free(zhp);
486ebedde84SEric Taylor 		return (NULL);
487ebedde84SEric Taylor 	}
488ebedde84SEric Taylor 	if (make_dataset_handle_common(zhp, &zc) == -1) {
489ebedde84SEric Taylor 		free(zhp);
490ebedde84SEric Taylor 		zhp = NULL;
491ebedde84SEric Taylor 	}
492ebedde84SEric Taylor 	zcmd_free_nvlists(&zc);
493ebedde84SEric Taylor 	return (zhp);
494ebedde84SEric Taylor }
495ebedde84SEric Taylor 
49619b94df9SMatthew Ahrens zfs_handle_t *
make_dataset_handle_zc(libzfs_handle_t * hdl,zfs_cmd_t * zc)497ebedde84SEric Taylor make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
498ebedde84SEric Taylor {
499ebedde84SEric Taylor 	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
500ebedde84SEric Taylor 
501ebedde84SEric Taylor 	if (zhp == NULL)
502ebedde84SEric Taylor 		return (NULL);
503ebedde84SEric Taylor 
504ebedde84SEric Taylor 	zhp->zfs_hdl = hdl;
505ebedde84SEric Taylor 	(void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
506ebedde84SEric Taylor 	if (make_dataset_handle_common(zhp, zc) == -1) {
507ebedde84SEric Taylor 		free(zhp);
508ebedde84SEric Taylor 		return (NULL);
509ebedde84SEric Taylor 	}
510fa9e4066Sahrens 	return (zhp);
511fa9e4066Sahrens }
5130d8fa8f8SMartin Matuska zfs_handle_t *
make_dataset_simple_handle_zc(zfs_handle_t * pzhp,zfs_cmd_t * zc)5140d8fa8f8SMartin Matuska make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc)
5150d8fa8f8SMartin Matuska {
5160d8fa8f8SMartin Matuska 	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
5170d8fa8f8SMartin Matuska 
5180d8fa8f8SMartin Matuska 	if (zhp == NULL)
5190d8fa8f8SMartin Matuska 		return (NULL);
5200d8fa8f8SMartin Matuska 
5210d8fa8f8SMartin Matuska 	zhp->zfs_hdl = pzhp->zfs_hdl;
5220d8fa8f8SMartin Matuska 	(void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
5230d8fa8f8SMartin Matuska 	zhp->zfs_head_type = pzhp->zfs_type;
5240d8fa8f8SMartin Matuska 	zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
5250d8fa8f8SMartin Matuska 	zhp->zpool_hdl = zpool_handle(zhp);
5260d8fa8f8SMartin Matuska 	return (zhp);
5270d8fa8f8SMartin Matuska }
5280d8fa8f8SMartin Matuska 
52919b94df9SMatthew Ahrens zfs_handle_t *
zfs_handle_dup(zfs_handle_t * zhp_orig)53019b94df9SMatthew Ahrens zfs_handle_dup(zfs_handle_t *zhp_orig)
53119b94df9SMatthew Ahrens {
53219b94df9SMatthew Ahrens 	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
53319b94df9SMatthew Ahrens 
53419b94df9SMatthew Ahrens 	if (zhp == NULL)
53519b94df9SMatthew Ahrens 		return (NULL);
53619b94df9SMatthew Ahrens 
53719b94df9SMatthew Ahrens 	zhp->zfs_hdl = zhp_orig->zfs_hdl;
53819b94df9SMatthew Ahrens 	zhp->zpool_hdl = zhp_orig->zpool_hdl;
53919b94df9SMatthew Ahrens 	(void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
54019b94df9SMatthew Ahrens 	    sizeof (zhp->zfs_name));
54119b94df9SMatthew Ahrens 	zhp->zfs_type = zhp_orig->zfs_type;
54219b94df9SMatthew Ahrens 	zhp->zfs_head_type = zhp_orig->zfs_head_type;
54319b94df9SMatthew Ahrens 	zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
54419b94df9SMatthew Ahrens 	if (zhp_orig->zfs_props != NULL) {
54519b94df9SMatthew Ahrens 		if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
54619b94df9SMatthew Ahrens 			(void) no_memory(zhp->zfs_hdl);
54719b94df9SMatthew Ahrens 			zfs_close(zhp);
54819b94df9SMatthew Ahrens 			return (NULL);
54919b94df9SMatthew Ahrens 		}
55019b94df9SMatthew Ahrens 	}
55119b94df9SMatthew Ahrens 	if (zhp_orig->zfs_user_props != NULL) {
55219b94df9SMatthew Ahrens 		if (nvlist_dup(zhp_orig->zfs_user_props,
55319b94df9SMatthew Ahrens 		    &zhp->zfs_user_props, 0) != 0) {
55419b94df9SMatthew Ahrens 			(void) no_memory(zhp->zfs_hdl);
55519b94df9SMatthew Ahrens 			zfs_close(zhp);
55619b94df9SMatthew Ahrens 			return (NULL);
55719b94df9SMatthew Ahrens 		}
55819b94df9SMatthew Ahrens 	}
55919b94df9SMatthew Ahrens 	if (zhp_orig->zfs_recvd_props != NULL) {
56019b94df9SMatthew Ahrens 		if (nvlist_dup(zhp_orig->zfs_recvd_props,
56119b94df9SMatthew Ahrens 		    &zhp->zfs_recvd_props, 0)) {
56219b94df9SMatthew Ahrens 			(void) no_memory(zhp->zfs_hdl);
56319b94df9SMatthew Ahrens 			zfs_close(zhp);
56419b94df9SMatthew Ahrens 			return (NULL);
56519b94df9SMatthew Ahrens 		}
56619b94df9SMatthew Ahrens 	}
56719b94df9SMatthew Ahrens 	zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
56819b94df9SMatthew Ahrens 	if (zhp_orig->zfs_mntopts != NULL) {
56919b94df9SMatthew Ahrens 		zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
57019b94df9SMatthew Ahrens 		    zhp_orig->zfs_mntopts);
57119b94df9SMatthew Ahrens 	}
57219b94df9SMatthew Ahrens 	zhp->zfs_props_table = zhp_orig->zfs_props_table;
57319b94df9SMatthew Ahrens 	return (zhp);
57419b94df9SMatthew Ahrens }
57519b94df9SMatthew Ahrens 
57678f17100SMatthew Ahrens boolean_t
zfs_bookmark_exists(const char * path)57778f17100SMatthew Ahrens zfs_bookmark_exists(const char *path)
57878f17100SMatthew Ahrens {
57978f17100SMatthew Ahrens 	nvlist_t *bmarks;
58078f17100SMatthew Ahrens 	nvlist_t *props;
5819adfa60dSMatthew Ahrens 	char fsname[ZFS_MAX_DATASET_NAME_LEN];
58278f17100SMatthew Ahrens 	char *bmark_name;
58378f17100SMatthew Ahrens 	char *pound;
58478f17100SMatthew Ahrens 	int err;
58578f17100SMatthew Ahrens 	boolean_t rv;
58678f17100SMatthew Ahrens 
58778f17100SMatthew Ahrens 
58878f17100SMatthew Ahrens 	(void) strlcpy(fsname, path, sizeof (fsname));
58978f17100SMatthew Ahrens 	pound = strchr(fsname, '#');
59078f17100SMatthew Ahrens 	if (pound == NULL)
59178f17100SMatthew Ahrens 		return (B_FALSE);
59278f17100SMatthew Ahrens 
59378f17100SMatthew Ahrens 	*pound = '\0';
59478f17100SMatthew Ahrens 	bmark_name = pound + 1;
59578f17100SMatthew Ahrens 	props = fnvlist_alloc();
59678f17100SMatthew Ahrens 	err = lzc_get_bookmarks(fsname, props, &bmarks);
59778f17100SMatthew Ahrens 	nvlist_free(props);
59878f17100SMatthew Ahrens 	if (err != 0) {
59978f17100SMatthew Ahrens 		nvlist_free(bmarks);
60078f17100SMatthew Ahrens 		return (B_FALSE);
60178f17100SMatthew Ahrens 	}
60278f17100SMatthew Ahrens 
60378f17100SMatthew Ahrens 	rv = nvlist_exists(bmarks, bmark_name);
60478f17100SMatthew Ahrens 	nvlist_free(bmarks);
60578f17100SMatthew Ahrens 	return (rv);
60678f17100SMatthew Ahrens }
60778f17100SMatthew Ahrens 
60878f17100SMatthew Ahrens zfs_handle_t *
make_bookmark_handle(zfs_handle_t * parent,const char * path,nvlist_t * bmark_props)60978f17100SMatthew Ahrens make_bookmark_handle(zfs_handle_t *parent, const char *path,
61078f17100SMatthew Ahrens     nvlist_t *bmark_props)
61178f17100SMatthew Ahrens {
61278f17100SMatthew Ahrens 	zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
61378f17100SMatthew Ahrens 
61478f17100SMatthew Ahrens 	if (zhp == NULL)
61578f17100SMatthew Ahrens 		return (NULL);
61678f17100SMatthew Ahrens 
61778f17100SMatthew Ahrens 	/* Fill in the name. */
61878f17100SMatthew Ahrens 	zhp->zfs_hdl = parent->zfs_hdl;
61978f17100SMatthew Ahrens 	(void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
62078f17100SMatthew Ahrens 
62178f17100SMatthew Ahrens 	/* Set the property lists. */
62278f17100SMatthew Ahrens 	if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) {
62378f17100SMatthew Ahrens 		free(zhp);
62478f17100SMatthew Ahrens 		return (NULL);
62578f17100SMatthew Ahrens 	}
62678f17100SMatthew Ahrens 
62778f17100SMatthew Ahrens 	/* Set the types. */
62878f17100SMatthew Ahrens 	zhp->zfs_head_type = parent->zfs_head_type;
62978f17100SMatthew Ahrens 	zhp->zfs_type = ZFS_TYPE_BOOKMARK;
63078f17100SMatthew Ahrens 
63178f17100SMatthew Ahrens 	if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) {
63278f17100SMatthew Ahrens 		nvlist_free(zhp->zfs_props);
63378f17100SMatthew Ahrens 		free(zhp);
63478f17100SMatthew Ahrens 		return (NULL);
63578f17100SMatthew Ahrens 	}
63678f17100SMatthew Ahrens 
63778f17100SMatthew Ahrens 	return (zhp);
63878f17100SMatthew Ahrens }
63978f17100SMatthew Ahrens 
640edb901aaSMarcel Telka struct zfs_open_bookmarks_cb_data {
641edb901aaSMarcel Telka 	const char *path;
642edb901aaSMarcel Telka 	zfs_handle_t *zhp;
643edb901aaSMarcel Telka };
644edb901aaSMarcel Telka 
645edb901aaSMarcel Telka static int
zfs_open_bookmarks_cb(zfs_handle_t * zhp,void * data)646edb901aaSMarcel Telka zfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data)
647edb901aaSMarcel Telka {
648edb901aaSMarcel Telka 	struct zfs_open_bookmarks_cb_data *dp = data;
649edb901aaSMarcel Telka 
650edb901aaSMarcel Telka 	/*
651edb901aaSMarcel Telka 	 * Is it the one we are looking for?
652edb901aaSMarcel Telka 	 */
653edb901aaSMarcel Telka 	if (strcmp(dp->path, zfs_get_name(zhp)) == 0) {
654edb901aaSMarcel Telka 		/*
655edb901aaSMarcel Telka 		 * We found it.  Save it and let the caller know we are done.
656edb901aaSMarcel Telka 		 */
657edb901aaSMarcel Telka 		dp->zhp = zhp;
658edb901aaSMarcel Telka 		return (EEXIST);
659edb901aaSMarcel Telka 	}
660edb901aaSMarcel Telka 
661edb901aaSMarcel Telka 	/*
662edb901aaSMarcel Telka 	 * Not found.  Close the handle and ask for another one.
663edb901aaSMarcel Telka 	 */
664edb901aaSMarcel Telka 	zfs_close(zhp);
665edb901aaSMarcel Telka 	return (0);
666edb901aaSMarcel Telka }
667edb901aaSMarcel Telka 
668fa9e4066Sahrens /*
669edb901aaSMarcel Telka  * Opens the given snapshot, bookmark, filesystem, or volume.   The 'types'
670fa9e4066Sahrens  * argument is a mask of acceptable types.  The function will print an
671fa9e4066Sahrens  * appropriate error message and return NULL if it can't be opened.
672fa9e4066Sahrens  */
673fa9e4066Sahrens zfs_handle_t *
zfs_open(libzfs_handle_t * hdl,const char * path,int types)67499653d4eSeschrock zfs_open(libzfs_handle_t *hdl, const char *path, int types)
675fa9e4066Sahrens {
676fa9e4066Sahrens 	zfs_handle_t *zhp;
67799653d4eSeschrock 	char errbuf[1024];
678edb901aaSMarcel Telka 	char *bookp;
68099653d4eSeschrock 	(void) snprintf(errbuf, sizeof (errbuf),
68199653d4eSeschrock 	    dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
683fa9e4066Sahrens 	/*
68499653d4eSeschrock 	 * Validate the name before we even try to open it.
685fa9e4066Sahrens 	 */
686edb901aaSMarcel Telka 	if (!zfs_validate_name(hdl, path, types, B_FALSE)) {
68799653d4eSeschrock 		(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
688fa9e4066Sahrens 		return (NULL);
689fa9e4066Sahrens 	}
691fa9e4066Sahrens 	/*
692edb901aaSMarcel Telka 	 * Bookmarks needs to be handled separately.
693fa9e4066Sahrens 	 */
694edb901aaSMarcel Telka 	bookp = strchr(path, '#');
695edb901aaSMarcel Telka 	if (bookp == NULL) {
696edb901aaSMarcel Telka 		/*
697edb901aaSMarcel Telka 		 * Try to get stats for the dataset, which will tell us if it
698edb901aaSMarcel Telka 		 * exists.
699edb901aaSMarcel Telka 		 */
700edb901aaSMarcel Telka 		errno = 0;
701edb901aaSMarcel Telka 		if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
702edb901aaSMarcel Telka 			(void) zfs_standard_error(hdl, errno, errbuf);
703edb901aaSMarcel Telka 			return (NULL);
704edb901aaSMarcel Telka 		}
705edb901aaSMarcel Telka 	} else {
706edb901aaSMarcel Telka 		char dsname[ZFS_MAX_DATASET_NAME_LEN];
707edb901aaSMarcel Telka 		zfs_handle_t *pzhp;
708edb901aaSMarcel Telka 		struct zfs_open_bookmarks_cb_data cb_data = {path, NULL};