Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <stdio.h>
     28 #include <libzfs.h>
     29 #include <string.h>
     30 #include <strings.h>
     31 #include <errno.h>
     32 #include <libshare.h>
     33 #include "libshare_impl.h"
     34 #include <libintl.h>
     35 #include <sys/mnttab.h>
     36 #include <sys/mntent.h>
     37 
     38 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
     39 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
     40 extern char *sa_fstype(char *);
     41 extern void set_node_attr(void *, char *, char *);
     42 extern int sa_is_share(void *);
     43 extern void sa_update_sharetab_ts(sa_handle_t);
     44 
     45 /*
     46  * File system specific code for ZFS. The original code was stolen
     47  * from the "zfs" command and modified to better suit this library's
     48  * usage.
     49  */
     50 
     51 typedef struct get_all_cbdata {
     52 	zfs_handle_t	**cb_handles;
     53 	size_t		cb_alloc;
     54 	size_t		cb_used;
     55 	uint_t		cb_types;
     56 } get_all_cbdata_t;
     57 
     58 /*
     59  * sa_zfs_init(impl_handle)
     60  *
     61  * Initialize an access handle into libzfs.  The handle needs to stay
     62  * around until sa_zfs_fini() in order to maintain the cache of
     63  * mounts.
     64  */
     65 
     66 int
     67 sa_zfs_init(sa_handle_impl_t impl_handle)
     68 {
     69 	impl_handle->zfs_libhandle = libzfs_init();
     70 	if (impl_handle->zfs_libhandle != NULL) {
     71 		libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
     72 		return (B_TRUE);
     73 	}
     74 	return (B_FALSE);
     75 }
     76 
     77 /*
     78  * sa_zfs_fini(impl_handle)
     79  *
     80  * cleanup data structures and the libzfs handle used for accessing
     81  * zfs file share info.
     82  */
     83 
     84 void
     85 sa_zfs_fini(sa_handle_impl_t impl_handle)
     86 {
     87 	if (impl_handle->zfs_libhandle != NULL) {
     88 		if (impl_handle->zfs_list != NULL) {
     89 			zfs_handle_t **zhp = impl_handle->zfs_list;
     90 			size_t i;
     91 
     92 			/*
     93 			 * Contents of zfs_list need to be freed so we
     94 			 * don't lose ZFS handles.
     95 			 */
     96 			for (i = 0; i < impl_handle->zfs_list_count; i++) {
     97 				zfs_close(zhp[i]);
     98 			}
     99 			free(impl_handle->zfs_list);
    100 			impl_handle->zfs_list = NULL;
    101 			impl_handle->zfs_list_count = 0;
    102 		}
    103 
    104 		libzfs_fini(impl_handle->zfs_libhandle);
    105 		impl_handle->zfs_libhandle = NULL;
    106 	}
    107 }
    108 
    109 /*
    110  * get_one_filesystem(zfs_handle_t, data)
    111  *
    112  * an iterator function called while iterating through the ZFS
    113  * root. It accumulates into an array of file system handles that can
    114  * be used to derive info about those file systems.
    115  *
    116  * Note that as this function is called, we close all zhp handles that
    117  * are not going to be places into the cp_handles list. We don't want
    118  * to close the ones we are keeping, but all others would be leaked if
    119  * not closed here.
    120  */
    121 
    122 static int
    123 get_one_filesystem(zfs_handle_t *zhp, void *data)
    124 {
    125 	get_all_cbdata_t *cbp = data;
    126 	zfs_type_t type = zfs_get_type(zhp);
    127 
    128 	/*
    129 	 * Interate over any nested datasets.
    130 	 */
    131 	if (type == ZFS_TYPE_FILESYSTEM &&
    132 	    zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) {
    133 		zfs_close(zhp);
    134 		return (1);
    135 	}
    136 
    137 	/*
    138 	 * Skip any datasets whose type does not match.
    139 	 */
    140 	if ((type & cbp->cb_types) == 0) {
    141 		zfs_close(zhp);
    142 		return (0);
    143 	}
    144 
    145 	if (cbp->cb_alloc == cbp->cb_used) {
    146 		zfs_handle_t **handles;
    147 
    148 		if (cbp->cb_alloc == 0)
    149 			cbp->cb_alloc = 64;
    150 		else
    151 			cbp->cb_alloc *= 2;
    152 
    153 		handles = (zfs_handle_t **)calloc(1,
    154 		    cbp->cb_alloc * sizeof (void *));
    155 
    156 		if (handles == NULL) {
    157 			zfs_close(zhp);
    158 			return (0);
    159 		}
    160 		if (cbp->cb_handles) {
    161 			bcopy(cbp->cb_handles, handles,
    162 			    cbp->cb_used * sizeof (void *));
    163 			free(cbp->cb_handles);
    164 		}
    165 
    166 		cbp->cb_handles = handles;
    167 	}
    168 
    169 	cbp->cb_handles[cbp->cb_used++] = zhp;
    170 
    171 	return (0);
    172 }
    173 
    174 /*
    175  * get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
    176  *
    177  * iterate through all ZFS file systems starting at the root. Returns
    178  * a count and an array of handle pointers. Allocating is only done
    179  * once. The caller does not need to free since it will be done at
    180  * sa_zfs_fini() time.
    181  */
    182 
    183 static void
    184 get_all_filesystems(sa_handle_impl_t impl_handle,
    185 			zfs_handle_t ***fslist, size_t *count)
    186 {
    187 	get_all_cbdata_t cb = { 0 };
    188 	cb.cb_types = ZFS_TYPE_FILESYSTEM;
    189 
    190 	if (impl_handle->zfs_list != NULL) {
    191 		*fslist = impl_handle->zfs_list;
    192 		*count = impl_handle->zfs_list_count;
    193 		return;
    194 	}
    195 
    196 	(void) zfs_iter_root(impl_handle->zfs_libhandle,
    197 	    get_one_filesystem, &cb);
    198 
    199 	impl_handle->zfs_list = *fslist = cb.cb_handles;
    200 	impl_handle->zfs_list_count = *count = cb.cb_used;
    201 }
    202 
    203 /*
    204  * mountpoint_compare(a, b)
    205  *
    206  * compares the mountpoint on two zfs file systems handles.
    207  * returns values following strcmp() model.
    208  */
    209 
    210 static int
    211 mountpoint_compare(const void *a, const void *b)
    212 {
    213 	zfs_handle_t **za = (zfs_handle_t **)a;
    214 	zfs_handle_t **zb = (zfs_handle_t **)b;
    215 	char mounta[MAXPATHLEN];
    216 	char mountb[MAXPATHLEN];
    217 
    218 	verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
    219 	    sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
    220 	verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
    221 	    sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
    222 
    223 	return (strcmp(mounta, mountb));
    224 }
    225 
    226 /*
    227  * return legacy mountpoint.  Caller provides space for mountpoint and
    228  * dataset.
    229  */
    230 int
    231 get_legacy_mountpoint(char *path, char *dataset, size_t dlen,
    232     char *mountpoint, size_t mlen)
    233 {
    234 	FILE *fp;
    235 	struct mnttab entry;
    236 
    237 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
    238 		return (1);
    239 	}
    240 
    241 	while (getmntent(fp, &entry) == 0) {
    242 
    243 		if (entry.mnt_fstype == NULL ||
    244 		    strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
    245 			continue;
    246 
    247 		if (strcmp(entry.mnt_mountp, path) == 0) {
    248 			if (mlen > 0)
    249 				(void) strlcpy(mountpoint, entry.mnt_mountp,
    250 				    mlen);
    251 			if (dlen > 0)
    252 				(void) strlcpy(dataset, entry.mnt_special,
    253 				    dlen);
    254 			break;
    255 		}
    256 	}
    257 	(void) fclose(fp);
    258 	return (1);
    259 }
    260 
    261 /*
    262  * get_zfs_dataset(impl_handle, path)
    263  *
    264  * get the name of the ZFS dataset the path is equivalent to.  The
    265  * dataset name is used for get/set of ZFS properties since libzfs
    266  * requires a dataset to do a zfs_open().
    267  */
    268 
    269 static char *
    270 get_zfs_dataset(sa_handle_impl_t impl_handle, char *path,
    271     boolean_t search_mnttab)
    272 {
    273 	size_t i, count = 0;
    274 	char *dataset = NULL;
    275 	zfs_handle_t **zlist;
    276 	char mountpoint[ZFS_MAXPROPLEN];
    277 	char canmount[ZFS_MAXPROPLEN];
    278 
    279 	get_all_filesystems(impl_handle, &zlist, &count);
    280 	qsort(zlist, count, sizeof (void *), mountpoint_compare);
    281 	for (i = 0; i < count; i++) {
    282 		/* must have a mountpoint */
    283 		if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint,
    284 		    sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
    285 			/* no mountpoint */
    286 			continue;
    287 		}
    288 
    289 		/* mountpoint must be a path */
    290 		if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
    291 		    strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
    292 			/*
    293 			 * Search mmttab for mountpoint and get dataset.
    294 			 */
    295 
    296 			if (search_mnttab == B_TRUE &&
    297 			    get_legacy_mountpoint(path, mountpoint,
    298 			    sizeof (mountpoint), NULL, 0) == 0) {
    299 				dataset = mountpoint;
    300 				break;
    301 			}
    302 			continue;
    303 		}
    304 
    305 		/* canmount must be set */
    306 		canmount[0] = '\0';
    307 		if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount,
    308 		    sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
    309 		    strcmp(canmount, "off") == 0)
    310 			continue;
    311 
    312 		/*
    313 		 * have a mountable handle but want to skip those marked none
    314 		 * and legacy
    315 		 */
    316 		if (strcmp(mountpoint, path) == 0) {
    317 			dataset = (char *)zfs_get_name(zlist[i]);
    318 			break;
    319 		}
    320 
    321 	}
    322 
    323 	if (dataset != NULL)
    324 		dataset = strdup(dataset);
    325 
    326 	return (dataset);
    327 }
    328 
    329 /*
    330  * get_zfs_property(dataset, property)
    331  *
    332  * Get the file system property specified from the ZFS dataset.
    333  */
    334 
    335 static char *
    336 get_zfs_property(char *dataset, zfs_prop_t property)
    337 {
    338 	zfs_handle_t *handle = NULL;
    339 	char shareopts[ZFS_MAXPROPLEN];
    340 	libzfs_handle_t *libhandle;
    341 
    342 	libhandle = libzfs_init();
    343 	if (libhandle != NULL) {
    344 		handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM);
    345 		if (handle != NULL) {
    346 			if (zfs_prop_get(handle, property, shareopts,
    347 			    sizeof (shareopts), NULL, NULL, 0,
    348 			    B_FALSE) == 0) {
    349 				zfs_close(handle);
    350 				libzfs_fini(libhandle);
    351 				return (strdup(shareopts));
    352 			}
    353 			zfs_close(handle);
    354 		}
    355 		libzfs_fini(libhandle);
    356 	}
    357 	return (NULL);
    358 }
    359 
    360 /*
    361  * sa_zfs_is_shared(handle, path)
    362  *
    363  * Check to see if the ZFS path provided has the sharenfs option set
    364  * or not.
    365  */
    366 
    367 int
    368 sa_zfs_is_shared(sa_handle_t sahandle, char *path)
    369 {
    370 	int ret = 0;
    371 	char *dataset;
    372 	zfs_handle_t *handle = NULL;
    373 	char shareopts[ZFS_MAXPROPLEN];
    374 	libzfs_handle_t *libhandle;
    375 
    376 	dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE);
    377 	if (dataset != NULL) {
    378 		libhandle = libzfs_init();
    379 		if (libhandle != NULL) {
    380 			handle = zfs_open(libhandle, dataset,
    381 			    ZFS_TYPE_FILESYSTEM);
    382 			if (handle != NULL) {
    383 				if (zfs_prop_get(handle, ZFS_PROP_SHARENFS,
    384 				    shareopts, sizeof (shareopts), NULL, NULL,
    385 				    0, B_FALSE) == 0 &&
    386 				    strcmp(shareopts, "off") != 0) {
    387 					ret = 1; /* it is shared */
    388 				}
    389 				zfs_close(handle);
    390 			}
    391 			libzfs_fini(libhandle);
    392 		}
    393 		free(dataset);
    394 	}
    395 	return (ret);
    396 }
    397 
    398 /*
    399  * find_or_create_group(handle, groupname, proto, *err)
    400  *
    401  * While walking the ZFS tree, we need to add shares to a defined
    402  * group. If the group doesn't exist, create it first, making sure it
    403  * is marked as a ZFS group.
    404  *
    405  * Note that all ZFS shares are in a subgroup of the top level group
    406  * called "zfs".
    407  */
    408 
    409 static sa_group_t
    410 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
    411 {
    412 	sa_group_t group;
    413 	sa_optionset_t optionset;
    414 	int ret = SA_OK;
    415 
    416 	/*
    417 	 * we check to see if the "zfs" group exists. Since this
    418 	 * should be the top level group, we don't want the
    419 	 * parent. This is to make sure the zfs group has been created
    420 	 * and to created if it hasn't been.
    421 	 */
    422 	group = sa_get_group(handle, groupname);
    423 	if (group == NULL) {
    424 		group = sa_create_group(handle, groupname, &ret);
    425 
    426 		/* make sure this is flagged as a ZFS group */
    427 		if (group != NULL)
    428 			ret = sa_set_group_attr(group, "zfs", "true");
    429 	}
    430 	if (group != NULL) {
    431 		if (proto != NULL) {
    432 			optionset = sa_get_optionset(group, proto);
    433 			if (optionset == NULL)
    434 				optionset = sa_create_optionset(group, proto);
    435 		}
    436 	}
    437 	if (err != NULL)
    438 		*err = ret;
    439 	return (group);
    440 }
    441 
    442 /*
    443  * find_or_create_zfs_subgroup(groupname, optstring, *err)
    444  *
    445  * ZFS shares will be in a subgroup of the "zfs" master group.  This
    446  * function looks to see if the groupname exists and returns it if it
    447  * does or else creates a new one with the specified name and returns
    448  * that.  The "zfs" group will exist before we get here, but we make
    449  * sure just in case.
    450  *
    451  * err must be a valid pointer.
    452  */
    453 
    454 static sa_group_t
    455 find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto,
    456     char *optstring, int *err)
    457 {
    458 	sa_group_t group = NULL;
    459 	sa_group_t zfs;
    460 	char *name;
    461 	char *options;
    462 
    463 	/* start with the top-level "zfs" group */
    464 	zfs = sa_get_group(handle, "zfs");
    465 	*err = SA_OK;
    466 	if (zfs != NULL) {
    467 		for (group = sa_get_sub_group(zfs); group != NULL;
    468 		    group = sa_get_next_group(group)) {
    469 			name = sa_get_group_attr(group, "name");
    470 			if (name != NULL && strcmp(name, groupname) == 0) {
    471 				/* have the group so break out of here */
    472 				sa_free_attr_string(name);
    473 				break;
    474 			}
    475 			if (name != NULL)
    476 				sa_free_attr_string(name);
    477 		}
    478 
    479 		if (group == NULL) {
    480 			/*
    481 			 * Need to create the sub-group since it doesn't exist
    482 			 */
    483 			group = _sa_create_zfs_group(zfs, groupname);
    484 			if (group == NULL) {
    485 				*err = SA_NO_MEMORY;
    486 				return (NULL);
    487 			}
    488 			set_node_attr(group, "zfs", "true");
    489 		}
    490 		if (strcmp(optstring, "on") == 0)
    491 			optstring = "rw";
    492 		options = strdup(optstring);
    493 		if (options != NULL) {
    494 			*err = sa_parse_legacy_options(group, options,
    495 			    proto);
    496 			/* If no optionset, add one. */
    497 			if (sa_get_optionset(group, proto) == NULL)
    498 				(void) sa_create_optionset(group, proto);
    499 			free(options);
    500 		} else {
    501 			*err = SA_NO_MEMORY;
    502 		}
    503 	}
    504 	return (group);
    505 }
    506 
    507 /*
    508  * zfs_construct_resource(share, name, base, dataset)
    509  *
    510  * Add a resource to the share using name as a template. If name ==
    511  * NULL, then construct a name based on the dataset value.
    512  * name.
    513  */
    514 static void
    515 zfs_construct_resource(sa_share_t share, char *dataset)
    516 {
    517 	char buff[SA_MAX_RESOURCE_NAME + 1];
    518 	int ret = SA_OK;
    519 
    520 	(void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset);
    521 	sa_fix_resource_name(buff);
    522 	(void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret);
    523 }
    524 
    525 /*
    526  * zfs_inherited(handle, source, sourcestr)
    527  *
    528  * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares
    529  * for readability.
    530  */
    531 static int
    532 zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
    533     char *shareopts, char *mountpoint, char *proto, char *dataset)
    534 {
    535 	int doshopt = 0;
    536 	int err = SA_OK;
    537 	sa_group_t group;
    538 	sa_resource_t resource;
    539 	uint64_t features;
    540 
    541 	/*
    542 	 * Need to find the "real" parent sub-group. It may not be
    543 	 * mounted, but it was identified in the "sourcestr"
    544 	 * variable. The real parent not mounted can occur if
    545 	 * "canmount=off and sharenfs=on".
    546 	 */
    547 	group = find_or_create_zfs_subgroup(handle, sourcestr, proto,
    548 	    shareopts, &doshopt);
    549 	if (group != NULL) {
    550 		/*
    551 		 * We may need the first share for resource
    552 		 * prototype. We only care about it if it has a
    553 		 * resource that sets a prefix value.
    554 		 */
    555 		if (share == NULL)
    556 			share = _sa_add_share(group, mountpoint,
    557 			    SA_SHARE_TRANSIENT, &err,
    558 			    (uint64_t)SA_FEATURE_NONE);
    559 		/*
    560 		 * some options may only be on shares. If the opt
    561 		 * string contains one of those, we put it just on the
    562 		 * share.
    563 		 */
    564 		if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) {
    565 			char *options;
    566 			options = strdup(shareopts);
    567 			if (options != NULL) {
    568 				set_node_attr(share, "dataset", dataset);
    569 				err = sa_parse_legacy_options(share, options,
    570 				    proto);
    571 				set_node_attr(share, "dataset", NULL);
    572 				free(options);
    573 			}
    574 			if (sa_get_optionset(group, proto) == NULL)
    575 				(void) sa_create_optionset(group, proto);
    576 		}
    577 		features = sa_proto_get_featureset(proto);
    578 		if (share != NULL && features & SA_FEATURE_RESOURCE) {
    579 			/*
    580 			 * We have a share and the protocol requires
    581 			 * that at least one resource exist (probably
    582 			 * SMB). We need to make sure that there is at
    583 			 * least one.
    584 			 */
    585 			resource = sa_get_share_resource(share, NULL);
    586 			if (resource == NULL) {
    587 				zfs_construct_resource(share, dataset);
    588 			}
    589 		}
    590 	} else {
    591 		err = SA_NO_MEMORY;
    592 	}
    593 	return (err);
    594 }
    595 
    596 /*
    597  * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset,
    598  *     grouperr)
    599  *
    600  * handle case where this is the top of a sub-group in ZFS. Pulled out
    601  * of sa_get_zfs_shares for readability. We need the grouperr from the
    602  * creation of the subgroup to know whether to add the public
    603  * property, etc. to the specific share.
    604  */
    605 static int
    606 zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint,
    607     char *shareopts, char *proto, char *dataset, int grouperr)
    608 {
    609 	int err = SA_OK;
    610 	sa_resource_t resource;
    611 	uint64_t features;
    612 
    613 	set_node_attr(group, "zfs", "true");
    614 	if (share == NULL)
    615 		share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
    616 		    &err, (uint64_t)SA_FEATURE_NONE);
    617 
    618 	if (err != SA_OK)
    619 		return (err);
    620 
    621 	if (strcmp(shareopts, "on") == 0)
    622 		shareopts = "";
    623 	if (shareopts != NULL) {
    624 		char *options;
    625 		if (grouperr == SA_PROP_SHARE_ONLY) {
    626 			/*
    627 			 * Some properties may only be on shares, but
    628 			 * due to the ZFS sub-groups being artificial,
    629 			 * we sometimes get this and have to deal with
    630 			 * it. We do it by attempting to put it on the
    631 			 * share.
    632 			 */
    633 			options = strdup(shareopts);
    634 			if (options != NULL) {
    635 				err = sa_parse_legacy_options(share,
    636 				    options, proto);
    637 				free(options);
    638 			}
    639 		}
    640 		/* Unmark the share's changed state */
    641 		set_node_attr(share, "changed", NULL);
    642 	}
    643 	features = sa_proto_get_featureset(proto);
    644 	if (share != NULL && features & SA_FEATURE_RESOURCE) {
    645 		/*
    646 		 * We have a share and the protocol requires that at
    647 		 * least one resource exist (probably SMB). We need to
    648 		 * make sure that there is at least one.
    649 		 */
    650 		resource = sa_get_share_resource(share, NULL);
    651 		if (resource == NULL) {
    652 			zfs_construct_resource(share, dataset);
    653 		}
    654 	}
    655 	return (err);
    656 }
    657 
    658 /*
    659  * zfs_grp_error(err)
    660  *
    661  * Print group create error, but only once. If err is 0 do the
    662  * print else don't.
    663  */
    664 
    665 static void
    666 zfs_grp_error(int err)
    667 {
    668 	if (err == 0) {
    669 		/* only print error once */
    670 		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
    671 		    "Cannot create ZFS subgroup during initialization:"
    672 		    " %s\n"), sa_errorstr(SA_SYSTEM_ERR));
    673 	}
    674 }
    675 
    676 /*
    677  * zfs_process_share(handle, share, mountpoint, proto, source,
    678  *     shareopts, sourcestr)
    679  *
    680  * Creates the subgroup, if necessary and adds shares, resources
    681  * and properties.
    682  */
    683 int
    684 sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
    685     char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
    686     char *sourcestr, char *dataset)
    687 {
    688 	int err = SA_OK;
    689 
    690 	if (source & ZPROP_SRC_INHERITED) {
    691 		err = zfs_inherited(handle, share, sourcestr, shareopts,
    692 		    mountpoint, proto, dataset);
    693 	} else {
    694 		group = find_or_create_zfs_subgroup(handle, dataset, proto,
    695 		    shareopts, &err);
    696 		if (group == NULL) {
    697 			static boolean_t reported_error = B_FALSE;
    698 			/*
    699 			 * There is a problem, but we can't do
    700 			 * anything about it at this point so we issue
    701 			 * a warning and move on.
    702 			 */
    703 			zfs_grp_error(reported_error);
    704 			reported_error = B_TRUE;
    705 		}
    706 		set_node_attr(group, "zfs", "true");
    707 		/*
    708 		 * Add share with local opts via zfs_notinherited.
    709 		 */
    710 		err = zfs_notinherited(group, share, mountpoint, shareopts,
    711 		    proto, dataset, err);
    712 	}
    713 	return (err);
    714 }
    715 
    716 /*
    717  * sa_get_zfs_shares(handle, groupname)
    718  *
    719  * Walk the mnttab for all zfs mounts and determine which are
    720  * shared. Find or create the appropriate group/sub-group to contain
    721  * the shares.
    722  *
    723  * All shares are in a sub-group that will hold the properties. This
    724  * allows representing the inherited property model.
    725  *
    726  * One area of complication is if "sharenfs" is set at one level of
    727  * the directory tree and "sharesmb" is set at a different level, the
    728  * a sub-group must be formed at the lower level for both
    729  * protocols. That is the nature of the problem in CR 6667349.
    730  */
    731 
    732 int
    733 sa_get_zfs_shares(sa_handle_t handle, char *groupname)
    734 {
    735 	sa_group_t zfsgroup;
    736 	boolean_t nfs;
    737 	boolean_t nfs_inherited;
    738 	boolean_t smb;
    739 	boolean_t smb_inherited;
    740 	zfs_handle_t **zlist;
    741 	char nfsshareopts[ZFS_MAXPROPLEN];
    742 	char smbshareopts[ZFS_MAXPROPLEN];
    743 	sa_share_t share;
    744 	zprop_source_t source;
    745 	char nfssourcestr[ZFS_MAXPROPLEN];
    746 	char smbsourcestr[ZFS_MAXPROPLEN];
    747 	char mountpoint[ZFS_MAXPROPLEN];
    748 	size_t count = 0, i;
    749 	libzfs_handle_t *zfs_libhandle;
    750 	int err = SA_OK;
    751 
    752 	/*
    753 	 * If we can't access libzfs, don't bother doing anything.
    754 	 */
    755 	zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle;
    756 	if (zfs_libhandle == NULL)
    757 		return (SA_SYSTEM_ERR);
    758 
    759 	zfsgroup = find_or_create_group(handle, groupname, NULL, &err);
    760 	/* Not an error, this could be a legacy condition */
    761 	if (zfsgroup == NULL)
    762 		return (SA_OK);
    763 
    764 	/*
    765 	 * need to walk the mounted ZFS pools and datasets to
    766 	 * find shares that are possible.
    767 	 */
    768 	get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count);
    769 	qsort(zlist, count, sizeof (void *), mountpoint_compare);
    770 
    771 	for (i = 0; i < count; i++) {
    772 		char *dataset;
    773 
    774 		source = ZPROP_SRC_ALL;
    775 		/* If no mountpoint, skip. */
    776 		if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT,
    777 		    mountpoint, sizeof (mountpoint), NULL, NULL, 0,
    778 		    B_FALSE) != 0)
    779 			continue;
    780 
    781 		/*
    782 		 * zfs_get_name value must not be freed. It is just a
    783 		 * pointer to a value in the handle.
    784 		 */
    785 		if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL)
    786 			continue;
    787 
    788 		/*
    789 		 * only deal with "mounted" file systems since
    790 		 * unmounted file systems can't actually be shared.
    791 		 */
    792 
    793 		if (!zfs_is_mounted(zlist[i], NULL))
    794 			continue;
    795 
    796 		nfs = nfs_inherited = B_FALSE;
    797 
    798 		if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts,
    799 		    sizeof (nfsshareopts), &source, nfssourcestr,
    800 		    ZFS_MAXPROPLEN, B_FALSE) == 0 &&
    801 		    strcmp(nfsshareopts, "off") != 0) {
    802 			if (source & ZPROP_SRC_INHERITED)
    803 				nfs_inherited = B_TRUE;
    804 			else
    805 				nfs = B_TRUE;
    806 		}
    807 
    808 		smb = smb_inherited = B_FALSE;
    809 		if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts,
    810 		    sizeof (smbshareopts), &source, smbsourcestr,
    811 		    ZFS_MAXPROPLEN, B_FALSE) == 0 &&
    812 		    strcmp(smbshareopts, "off") != 0) {
    813 			if (source & ZPROP_SRC_INHERITED)
    814 				smb_inherited = B_TRUE;
    815 			else
    816 				smb = B_TRUE;
    817 		}
    818 
    819 		/*
    820 		 * If the mountpoint is already shared, it must be a
    821 		 * non-ZFS share. We want to remove the share from its
    822 		 * parent group and reshare it under ZFS.
    823 		 */
    824 		share = sa_find_share(handle, mountpoint);
    825 		if (share != NULL &&
    826 		    (nfs || smb || nfs_inherited || smb_inherited)) {
    827 			err = sa_remove_share(share);
    828 			share = NULL;
    829 		}
    830 
    831 		/*
    832 		 * At this point, we have the information needed to
    833 		 * determine what to do with the share.
    834 		 *
    835 		 * If smb or nfs is set, we have a new sub-group.
    836 		 * If smb_inherit and/or nfs_inherit is set, then
    837 		 * place on an existing sub-group. If both are set,
    838 		 * the existing sub-group is the closest up the tree.
    839 		 */
    840 		if (nfs || smb) {
    841 			/*
    842 			 * Non-inherited is the straightforward
    843 			 * case. sa_zfs_process_share handles it
    844 			 * directly. Make sure that if the "other"
    845 			 * protocol is inherited, that we treat it as
    846 			 * non-inherited as well.
    847 			 */
    848 			if (nfs || nfs_inherited) {
    849 				err = sa_zfs_process_share(handle, zfsgroup,
    850 				    share, mountpoint, "nfs",
    851 				    0, nfsshareopts,
    852 				    nfssourcestr, dataset);
    853 				share = sa_find_share(handle, mountpoint);
    854 			}
    855 			if (smb || smb_inherited) {
    856 				err = sa_zfs_process_share(handle, zfsgroup,
    857 				    share, mountpoint, "smb",
    858 				    0, smbshareopts,
    859 				    smbsourcestr, dataset);
    860 			}
    861 		} else if (nfs_inherited || smb_inherited) {
    862 			char *grpdataset;
    863 			/*
    864 			 * If we only have inherited groups, it is
    865 			 * important to find the closer of the two if
    866 			 * the protocols are set at different
    867 			 * levels. The closest sub-group is the one we
    868 			 * want to work with.
    869 			 */
    870 			if (nfs_inherited && smb_inherited) {
    871 				if (strcmp(nfssourcestr, smbsourcestr) <= 0)
    872 					grpdataset = nfssourcestr;
    873 				else
    874 					grpdataset = smbsourcestr;
    875 			} else if (nfs_inherited) {
    876 				grpdataset = nfssourcestr;
    877 			} else if (smb_inherited) {
    878 				grpdataset = smbsourcestr;
    879 			}
    880 			if (nfs_inherited) {
    881 				err = sa_zfs_process_share(handle, zfsgroup,
    882 				    share, mountpoint, "nfs",
    883 				    ZPROP_SRC_INHERITED, nfsshareopts,
    884 				    grpdataset, dataset);
    885 				share = sa_find_share(handle, mountpoint);
    886 			}
    887 			if (smb_inherited) {
    888 				err = sa_zfs_process_share(handle, zfsgroup,
    889 				    share, mountpoint, "smb",
    890 				    ZPROP_SRC_INHERITED, smbshareopts,
    891 				    grpdataset, dataset);
    892 			}
    893 		}
    894 	}
    895 	/*
    896 	 * Don't need to free the "zlist" variable since it is only a
    897 	 * pointer to a cached value that will be freed when
    898 	 * sa_fini() is called.
    899 	 */
    900 	return (err);
    901 }
    902 
    903 #define	COMMAND		"/usr/sbin/zfs"
    904 
    905 /*
    906  * sa_zfs_set_sharenfs(group, path, on)
    907  *
    908  * Update the "sharenfs" property on the path. If on is true, then set
    909  * to the properties on the group or "on" if no properties are
    910  * defined. Set to "off" if on is false.
    911  */
    912 
    913 int
    914 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on)
    915 {
    916 	int ret = SA_NOT_IMPLEMENTED;
    917 	char *command;
    918 
    919 	command = malloc(ZFS_MAXPROPLEN * 2);
    920 	if (command != NULL) {
    921 		char *opts = NULL;
    922 		char *dataset = NULL;
    923 		FILE *pfile;
    924 		sa_handle_impl_t impl_handle;
    925 		/* for now, NFS is always available for "zfs" */
    926 		if (on) {
    927 			opts = sa_proto_legacy_format("nfs", group, 1);
    928 			if (opts != NULL && strlen(opts) == 0) {
    929 				free(opts);
    930 				opts = strdup("on");
    931 			}
    932 		}
    933 
    934 		impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
    935 		assert(impl_handle != NULL);
    936 		if (impl_handle != NULL)
    937 			dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
    938 		else
    939 			ret = SA_SYSTEM_ERR;
    940 
    941 		if (dataset != NULL) {
    942 			(void) snprintf(command, ZFS_MAXPROPLEN * 2,
    943 			    "%s set sharenfs=\"%s\" %s", COMMAND,
    944 			    opts != NULL ? opts : "off", dataset);
    945 			pfile = popen(command, "r");
    946 			if (pfile != NULL) {
    947 				ret = pclose(pfile);
    948 				if (ret != 0)
    949 					ret = SA_SYSTEM_ERR;
    950 			}
    951 		}
    952 		if (opts != NULL)
    953 			free(opts);
    954 		if (dataset != NULL)
    955 			free(dataset);
    956 		free(command);
    957 	}
    958 	return (ret);
    959 }
    960 
    961 /*
    962  * add_resources(share, opt)
    963  *
    964  * Add resource properties to those in "opt".  Resources are prefixed
    965  * with name=resourcename.
    966  */
    967 static char *
    968 add_resources(sa_share_t share, char *opt)
    969 {
    970 	char *newopt = NULL;
    971 	char *propstr;
    972 	sa_resource_t resource;
    973 
    974 	newopt = strdup(opt);
    975 	if (newopt == NULL)
    976 		return (newopt);
    977 
    978 	for (resource = sa_get_share_resource(share, NULL);
    979 	    resource != NULL;
    980 	    resource = sa_get_next_resource(resource)) {
    981 		char *name;
    982 		size_t size;
    983 
    984 		name = sa_get_resource_attr(resource, "name");
    985 		if (name == NULL) {
    986 			free(newopt);
    987 			return (NULL);
    988 		}
    989 		size = strlen(name) + strlen(opt) + sizeof ("name=") + 1;
    990 		newopt = calloc(1, size);
    991 		if (newopt != NULL)
    992 			(void) snprintf(newopt, size, "%s,name=%s", opt, name);
    993 		sa_free_attr_string(name);
    994 		free(opt);
    995 		opt = newopt;
    996 		propstr = sa_proto_legacy_format("smb", resource, 0);
    997 		if (propstr == NULL) {
    998 			free(opt);
    999 			return (NULL);
   1000 		}
   1001 		size = strlen(propstr) + strlen(opt) + 2;
   1002 		newopt = calloc(1, size);
   1003 		if (newopt != NULL)
   1004 			(void) snprintf(newopt, size, "%s,%s", opt, propstr);
   1005 		free(opt);
   1006 		opt = newopt;
   1007 	}
   1008 	return (opt);
   1009 }
   1010 
   1011 /*
   1012  * sa_zfs_set_sharesmb(group, path, on)
   1013  *
   1014  * Update the "sharesmb" property on the path. If on is true, then set
   1015  * to the properties on the group or "on" if no properties are
   1016  * defined. Set to "off" if on is false.
   1017  */
   1018 
   1019 int
   1020 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on)
   1021 {
   1022 	int ret = SA_NOT_IMPLEMENTED;
   1023 	char *command;
   1024 	sa_share_t share;
   1025 
   1026 	/* In case SMB not enabled */
   1027 	if (sa_get_optionset(group, "smb") == NULL)
   1028 		return (SA_NOT_SUPPORTED);
   1029 
   1030 	command = malloc(ZFS_MAXPROPLEN * 2);
   1031 	if (command != NULL) {
   1032 		char *opts = NULL;
   1033 		char *dataset = NULL;
   1034 		FILE *pfile;
   1035 		sa_handle_impl_t impl_handle;
   1036 
   1037 		if (on) {
   1038 			char *newopt;
   1039 
   1040 			share = sa_get_share(group, NULL);
   1041 			opts = sa_proto_legacy_format("smb", share, 1);
   1042 			if (opts != NULL && strlen(opts) == 0) {
   1043 				free(opts);
   1044 				opts = strdup("on");
   1045 			}
   1046 			newopt = add_resources(opts, share);
   1047 			free(opts);
   1048 			opts = newopt;
   1049 		}
   1050 
   1051 		impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
   1052 		assert(impl_handle != NULL);
   1053 		if (impl_handle != NULL)
   1054 			dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
   1055 		else
   1056 			ret = SA_SYSTEM_ERR;
   1057 
   1058 		if (dataset != NULL) {
   1059 			(void) snprintf(command, ZFS_MAXPROPLEN * 2,
   1060 			    "echo %s set sharesmb=\"%s\" %s", COMMAND,
   1061 			    opts != NULL ? opts : "off", dataset);
   1062 			pfile = popen(command, "r");
   1063 			if (pfile != NULL) {
   1064 				ret = pclose(pfile);
   1065 				if (ret != 0)
   1066 					ret = SA_SYSTEM_ERR;
   1067 			}
   1068 		}
   1069 		if (opts != NULL)
   1070 			free(opts);
   1071 		if (dataset != NULL)
   1072 			free(dataset);
   1073 		free(command);
   1074 	}
   1075 	return (ret);
   1076 }
   1077 
   1078 /*
   1079  * sa_zfs_update(group)
   1080  *
   1081  * call back to ZFS to update the share if necessary.
   1082  * Don't do it if it isn't a real change.
   1083  */
   1084 int
   1085 sa_zfs_update(sa_group_t group)
   1086 {
   1087 	sa_optionset_t protopt;
   1088 	sa_group_t parent;
   1089 	char *command;
   1090 	char *optstring;
   1091 	int ret = SA_OK;
   1092 	int doupdate = 0;
   1093 	FILE *pfile;
   1094 
   1095 	if (sa_is_share(group))
   1096 		parent = sa_get_parent_group(group);
   1097 	else
   1098 		parent = group;
   1099 
   1100 	if (parent != NULL) {
   1101 		command = malloc(ZFS_MAXPROPLEN * 2);
   1102 		if (command == NULL)
   1103 			return (SA_NO_MEMORY);
   1104 
   1105 		*command = '\0';
   1106 		for (protopt = sa_get_optionset(parent, NULL); protopt != NULL;
   1107 		    protopt = sa_get_next_optionset(protopt)) {
   1108 
   1109 			char *proto = sa_get_optionset_attr(protopt, "type");
   1110 			char *path;
   1111 			char *dataset = NULL;
   1112 			char *zfsopts = NULL;
   1113 
   1114 			if (sa_is_share(group)) {
   1115 				path = sa_get_share_attr((sa_share_t)group,
   1116 				    "path");
   1117 				if (path != NULL) {
   1118 					sa_handle_impl_t impl_handle;
   1119 
   1120 					impl_handle = sa_find_group_handle(
   1121 					    group);
   1122 					if (impl_handle != NULL)
   1123 						dataset = get_zfs_dataset(
   1124 						    impl_handle, path, B_FALSE);
   1125 					else
   1126 						ret = SA_SYSTEM_ERR;
   1127 
   1128 					sa_free_attr_string(path);
   1129 				}
   1130 			} else {
   1131 				dataset = sa_get_group_attr(group, "name");
   1132 			}
   1133 			/* update only when there is an optstring found */
   1134 			doupdate = 0;
   1135 			if (proto != NULL && dataset != NULL) {
   1136 				optstring = sa_proto_legacy_format(proto,
   1137 				    group, 1);
   1138 				zfsopts = get_zfs_property(dataset,
   1139 				    ZFS_PROP_SHARENFS);
   1140 
   1141 				if (optstring != NULL && zfsopts != NULL) {
   1142 					if (strcmp(optstring, zfsopts) != 0)
   1143 						doupdate++;
   1144 				}
   1145 				if (doupdate) {
   1146 					if (optstring != NULL &&
   1147 					    strlen(optstring) > 0) {
   1148 						(void) snprintf(command,
   1149 						    ZFS_MAXPROPLEN * 2,
   1150 						    "%s set share%s=%s %s",
   1151 						    COMMAND, proto,
   1152 						    optstring, dataset);
   1153 					} else {
   1154 						(void) snprintf(command,
   1155 						    ZFS_MAXPROPLEN * 2,
   1156 						    "%s set share%s=on %s",
   1157 						    COMMAND, proto,
   1158 						    dataset);
   1159 					}
   1160 					pfile = popen(command, "r");
   1161 					if (pfile != NULL)
   1162 						ret = pclose(pfile);
   1163 					switch (ret) {
   1164 					default:
   1165 					case 1:
   1166 						ret = SA_SYSTEM_ERR;
   1167 						break;
   1168 					case 2:
   1169 						ret = SA_SYNTAX_ERR;
   1170 						break;
   1171 					case 0:
   1172 						break;
   1173 					}
   1174 				}
   1175 				if (optstring != NULL)
   1176 					free(optstring);
   1177 				if (zfsopts != NULL)
   1178 					free(zfsopts);
   1179 			}
   1180 			if (proto != NULL)
   1181 				sa_free_attr_string(proto);
   1182 			if (dataset != NULL)
   1183 				free(dataset);
   1184 		}
   1185 		free(command);
   1186 	}
   1187 	return (ret);
   1188 }
   1189 
   1190 /*
   1191  * sa_group_is_zfs(group)
   1192  *
   1193  * Given the group, determine if the zfs attribute is set.
   1194  */
   1195 
   1196 int
   1197 sa_group_is_zfs(sa_group_t group)
   1198 {
   1199 	char *zfs;
   1200 	int ret = 0;
   1201 
   1202 	zfs = sa_get_group_attr(group, "zfs");
   1203 	if (zfs != NULL) {
   1204 		ret = 1;
   1205 		sa_free_attr_string(zfs);
   1206 	}
   1207 	return (ret);
   1208 }
   1209 
   1210 /*
   1211  * sa_path_is_zfs(path)
   1212  *
   1213  * Check to see if the file system path represents is of type "zfs".
   1214  */
   1215 
   1216 int
   1217 sa_path_is_zfs(char *path)
   1218 {
   1219 	char *fstype;
   1220 	int ret = 0;
   1221 
   1222 	fstype = sa_fstype(path);
   1223 	if (fstype != NULL && strcmp(fstype, "zfs") == 0)
   1224 		ret = 1;
   1225 	if (fstype != NULL)
   1226 		sa_free_fstype(fstype);
   1227 	return (ret);
   1228 }
   1229 
   1230 int
   1231 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
   1232 {
   1233 	char *path;
   1234 
   1235 	/* Make sure path is valid */
   1236 
   1237 	path = sa_get_share_attr(share, "path");
   1238 	if (path != NULL) {
   1239 		(void) memset(sh, 0, sizeof (sh));
   1240 		(void) sa_fillshare(share, proto, sh);
   1241 		sa_free_attr_string(path);
   1242 		return (0);
   1243 	} else
   1244 		return (1);
   1245 }
   1246 
   1247 #define	SMAX(i, j)	\
   1248 	if ((j) > (i)) { \
   1249 		(i) = (j); \
   1250 	}
   1251 
   1252 int
   1253 sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh,
   1254     void *exportdata, zfs_share_op_t operation)
   1255 {
   1256 	libzfs_handle_t *libhandle;
   1257 	sa_group_t group;
   1258 	sa_handle_t sahandle;
   1259 	char *dataset;
   1260 	int err = EINVAL;
   1261 	int i, j;
   1262 	char newpath[MAXPATHLEN];
   1263 	char *pathp;
   1264 
   1265 	/*
   1266 	 * First find the dataset name
   1267 	 */
   1268 	if ((group = sa_get_parent_group(share)) == NULL)  {
   1269 		return (EINVAL);
   1270 	}
   1271 	if ((sahandle = sa_find_group_handle(group)) == NULL) {
   1272 		return (EINVAL);
   1273 	}
   1274 
   1275 	/*
   1276 	 * If get_zfs_dataset fails, see if it is a subdirectory
   1277 	 */
   1278 
   1279 	pathp = path;
   1280 	while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) {
   1281 		char *p;
   1282 
   1283 		if (pathp == path) {
   1284 			(void) strlcpy(newpath, path, sizeof (newpath));
   1285 			pathp = newpath;
   1286 		}
   1287 
   1288 		/*
   1289 		 * Make sure only one leading '/' This condition came
   1290 		 * about when using HAStoragePlus which insisted on
   1291 		 * putting an extra leading '/' in the ZFS path
   1292 		 * name. The problem is fixed in other areas, but this
   1293 		 * will catch any other ways that a double slash might
   1294 		 * get introduced.
   1295 		 */
   1296 		while (*pathp == '/' && *(pathp + 1) == '/')
   1297 			pathp++;
   1298 
   1299 		/*
   1300 		 * chop off part of path, but if we are at root then
   1301 		 * make sure path is a /
   1302 		 */
   1303 		if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) {
   1304 			if (pathp == p) {
   1305 				*(p + 1) = '\0';  /* skip over /, root case */
   1306 			} else {
   1307 				*p = '\0';
   1308 			}
   1309 		} else {
   1310 			return (EINVAL);
   1311 		}
   1312 	}
   1313 
   1314 	libhandle = libzfs_init();
   1315 	if (libhandle != NULL) {
   1316 		char *resource_name;
   1317 
   1318 		i = (sh->sh_path ? strlen(sh->sh_path) : 0);
   1319 		sh->sh_size = i;
   1320 
   1321 		j = (sh->sh_res ? strlen(sh->sh_res) : 0);
   1322 		sh->sh_size += j;
   1323 		SMAX(i, j);
   1324 
   1325 		j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0);
   1326 		sh->sh_size += j;
   1327 		SMAX(i, j);
   1328 
   1329 		j = (sh->sh_opts ? strlen(sh->sh_opts) : 0);
   1330 		sh->sh_size += j;
   1331 		SMAX(i, j);
   1332 
   1333 		j = (sh->sh_descr ? strlen(sh->sh_descr) : 0);
   1334 		sh->sh_size += j;
   1335 		SMAX(i, j);
   1336 
   1337 		resource_name = sa_get_resource_attr(resource, "name");
   1338 
   1339 		err = zfs_deleg_share_nfs(libhandle, dataset, path,
   1340 		    resource_name, exportdata, sh, i, operation);
   1341 		if (err == SA_OK)
   1342 			sa_update_sharetab_ts(sahandle);
   1343 		else
   1344 			err = errno;
   1345 		if (resource_name)
   1346 			sa_free_attr_string(resource_name);
   1347 
   1348 		libzfs_fini(libhandle);
   1349 	}
   1350 	free(dataset);
   1351 	return (err);
   1352 }
   1353 
   1354 /*
   1355  * sa_get_zfs_handle(handle)
   1356  *
   1357  * Given an sa_handle_t, return the libzfs_handle_t *. This is only
   1358  * used internally by libzfs. Needed in order to avoid including
   1359  * libshare_impl.h in libzfs.
   1360  */
   1361 
   1362 libzfs_handle_t *
   1363 sa_get_zfs_handle(sa_handle_t handle)
   1364 {
   1365 	sa_handle_impl_t implhandle = (sa_handle_impl_t)handle;
   1366 
   1367 	return (implhandle->zfs_libhandle);
   1368 }
   1369 
   1370 /*
   1371  * sa_get_zfs_info(libzfs, path, mountpoint, dataset)
   1372  *
   1373  * Find the ZFS dataset and mountpoint for a given path
   1374  */
   1375 int
   1376 sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp,
   1377     char *datasetp)
   1378 {
   1379 	get_all_cbdata_t cb = { 0 };
   1380 	int i;
   1381 	char mountpoint[ZFS_MAXPROPLEN];
   1382 	char dataset[ZFS_MAXPROPLEN];
   1383 	char canmount[ZFS_MAXPROPLEN];
   1384 	char *dp;
   1385 	int count;
   1386 	int ret = 0;
   1387 
   1388 	cb.cb_types = ZFS_TYPE_FILESYSTEM;
   1389 
   1390 	if (libzfs == NULL)
   1391 		return (0);
   1392 
   1393 	(void) zfs_iter_root(libzfs, get_one_filesystem, &cb);
   1394 	count = cb.cb_used;
   1395 
   1396 	qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare);
   1397 	for (i = 0; i < count; i++) {
   1398 		/* must have a mountpoint */
   1399 		if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT,
   1400 		    mountpoint, sizeof (mountpoint),
   1401 		    NULL, NULL, 0, B_FALSE) != 0) {
   1402 			/* no mountpoint */
   1403 			continue;
   1404 		}
   1405 
   1406 		/* mountpoint must be a path */
   1407 		if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
   1408 		    strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
   1409 			/*
   1410 			 * Search mmttab for mountpoint
   1411 			 */
   1412 
   1413 			if (get_legacy_mountpoint(path, dataset,
   1414 			    ZFS_MAXPROPLEN, mountpoint,
   1415 			    ZFS_MAXPROPLEN) == 0) {
   1416 				ret = 1;
   1417 				break;
   1418 			}
   1419 			continue;
   1420 		}
   1421 
   1422 		/* canmount must be set */
   1423 		canmount[0] = '\0';
   1424 		if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount,
   1425 		    sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
   1426 		    strcmp(canmount, "off") == 0)
   1427 			continue;
   1428 
   1429 		/*
   1430 		 * have a mountable handle but want to skip those marked none
   1431 		 * and legacy
   1432 		 */
   1433 		if (strcmp(mountpoint, path) == 0) {
   1434 			dp = (char *)zfs_get_name(cb.cb_handles[i]);
   1435 			if (dp != NULL) {
   1436 				if (datasetp != NULL)
   1437 					(void) strcpy(datasetp, dp);
   1438 				if (mountpointp != NULL)
   1439 					(void) strcpy(mountpointp, mountpoint);
   1440 				ret = 1;
   1441 			}
   1442 			break;
   1443 		}
   1444 
   1445 	}
   1446 
   1447 	return (ret);
   1448 }
   1449