16185db85Sdougm /*
26185db85Sdougm * CDDL HEADER START
36185db85Sdougm *
46185db85Sdougm * The contents of this file are subject to the terms of the
56185db85Sdougm * Common Development and Distribution License (the "License").
66185db85Sdougm * You may not use this file except in compliance with the License.
76185db85Sdougm *
86185db85Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96185db85Sdougm * or http://www.opensolaris.org/os/licensing.
106185db85Sdougm * See the License for the specific language governing permissions
116185db85Sdougm * and limitations under the License.
126185db85Sdougm *
136185db85Sdougm * When distributing Covered Code, include this CDDL HEADER in each
146185db85Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156185db85Sdougm * If applicable, add the following below this CDDL HEADER, with the
166185db85Sdougm * fields enclosed by brackets "[]" replaced with your own identifying
176185db85Sdougm * information: Portions Copyright [yyyy] [name of copyright owner]
186185db85Sdougm *
196185db85Sdougm * CDDL HEADER END
206185db85Sdougm */
216185db85Sdougm
226185db85Sdougm /*
23148c5f43SAlan Wright * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
246185db85Sdougm */
25*0dfe541eSEvan Layton
26c3f7431dSDan Kruchinin /*
2795e79c0bSDaniel Hoffman * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
28ff524b23SAndrew Stormont * Copyright 2017 RackTop Systems.
29*0dfe541eSEvan Layton * Copyright 2019 Nexenta Systems, Inc.
30c3f7431dSDan Kruchinin */
316185db85Sdougm
32a1ef5d63Smarks #include <stdio.h>
336185db85Sdougm #include <libzfs.h>
346185db85Sdougm #include <string.h>
35a3351425Sdougm #include <strings.h>
36a63214d6SBill Krier #include <errno.h>
37*0dfe541eSEvan Layton #include <zone.h>
386185db85Sdougm #include <libshare.h>
396185db85Sdougm #include "libshare_impl.h"
401cea05afSdougm #include <libintl.h>
41a1ef5d63Smarks #include <sys/mnttab.h>
42a1ef5d63Smarks #include <sys/mntent.h>
4395e79c0bSDaniel Hoffman #include <assert.h>
446185db85Sdougm
45da6c28aaSamw extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
466185db85Sdougm extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
476185db85Sdougm extern char *sa_fstype(char *);
486185db85Sdougm extern void set_node_attr(void *, char *, char *);
496185db85Sdougm extern int sa_is_share(void *);
505b6e0c46Sdougm extern void sa_update_sharetab_ts(sa_handle_t);
511cea05afSdougm
521cea05afSdougm /*
531cea05afSdougm * File system specific code for ZFS. The original code was stolen
541cea05afSdougm * from the "zfs" command and modified to better suit this library's
551cea05afSdougm * usage.
561cea05afSdougm */
571cea05afSdougm
581cea05afSdougm typedef struct get_all_cbdata {
591cea05afSdougm zfs_handle_t **cb_handles;
601cea05afSdougm size_t cb_alloc;
611cea05afSdougm size_t cb_used;
62a3351425Sdougm uint_t cb_types;
631cea05afSdougm } get_all_cbdata_t;
641cea05afSdougm
651cea05afSdougm /*
66549ec3ffSdougm * sa_zfs_init(impl_handle)
671cea05afSdougm *
68549ec3ffSdougm * Initialize an access handle into libzfs. The handle needs to stay
69549ec3ffSdougm * around until sa_zfs_fini() in order to maintain the cache of
70549ec3ffSdougm * mounts.
711cea05afSdougm */
721cea05afSdougm
7357b448deSdougm int
sa_zfs_init(sa_handle_impl_t impl_handle)74549ec3ffSdougm sa_zfs_init(sa_handle_impl_t impl_handle)
751cea05afSdougm {
76549ec3ffSdougm impl_handle->zfs_libhandle = libzfs_init();
7757b448deSdougm if (impl_handle->zfs_libhandle != NULL) {
7857b448deSdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
7957b448deSdougm return (B_TRUE);
8057b448deSdougm }
8157b448deSdougm return (B_FALSE);
821cea05afSdougm }
831cea05afSdougm
841cea05afSdougm /*
85549ec3ffSdougm * sa_zfs_fini(impl_handle)
861cea05afSdougm *
871cea05afSdougm * cleanup data structures and the libzfs handle used for accessing
881cea05afSdougm * zfs file share info.
891cea05afSdougm */
901cea05afSdougm
911cea05afSdougm void
sa_zfs_fini(sa_handle_impl_t impl_handle)92549ec3ffSdougm sa_zfs_fini(sa_handle_impl_t impl_handle)
931cea05afSdougm {
94549ec3ffSdougm if (impl_handle->zfs_libhandle != NULL) {
9557b448deSdougm if (impl_handle->zfs_list != NULL) {
96a3351425Sdougm zfs_handle_t **zhp = impl_handle->zfs_list;
97a3351425Sdougm size_t i;
98a3351425Sdougm
9957b448deSdougm /*
100a3351425Sdougm * Contents of zfs_list need to be freed so we
101a3351425Sdougm * don't lose ZFS handles.
10257b448deSdougm */
103a3351425Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) {
104a3351425Sdougm zfs_close(zhp[i]);
105a3351425Sdougm }
10657b448deSdougm free(impl_handle->zfs_list);
10757b448deSdougm impl_handle->zfs_list = NULL;
10857b448deSdougm impl_handle->zfs_list_count = 0;
10957b448deSdougm }
110a3351425Sdougm
111a3351425Sdougm libzfs_fini(impl_handle->zfs_libhandle);
112a3351425Sdougm impl_handle->zfs_libhandle = NULL;
1131cea05afSdougm }
1141cea05afSdougm }
1151cea05afSdougm
1161cea05afSdougm /*
1171cea05afSdougm * get_one_filesystem(zfs_handle_t, data)
1181cea05afSdougm *
119da6c28aaSamw * an iterator function called while iterating through the ZFS
1201cea05afSdougm * root. It accumulates into an array of file system handles that can
1211cea05afSdougm * be used to derive info about those file systems.
122a3351425Sdougm *
123a3351425Sdougm * Note that as this function is called, we close all zhp handles that
124a3351425Sdougm * are not going to be places into the cp_handles list. We don't want
125a3351425Sdougm * to close the ones we are keeping, but all others would be leaked if
126a3351425Sdougm * not closed here.
1271cea05afSdougm */
1281cea05afSdougm
1291cea05afSdougm static int
get_one_filesystem(zfs_handle_t * zhp,void * data)1301cea05afSdougm get_one_filesystem(zfs_handle_t *zhp, void *data)
1311cea05afSdougm {
1321cea05afSdougm get_all_cbdata_t *cbp = data;
133a3351425Sdougm zfs_type_t type = zfs_get_type(zhp);
1341cea05afSdougm
1351cea05afSdougm /*
136a3351425Sdougm * Interate over any nested datasets.
1371cea05afSdougm */
138a3351425Sdougm if (type == ZFS_TYPE_FILESYSTEM &&
139a3351425Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) {
140a3351425Sdougm zfs_close(zhp);
141a3351425Sdougm return (1);
142a3351425Sdougm }
143a3351425Sdougm
144a3351425Sdougm /*
145a3351425Sdougm * Skip any datasets whose type does not match.
146a3351425Sdougm */
147a3351425Sdougm if ((type & cbp->cb_types) == 0) {
1481cea05afSdougm zfs_close(zhp);
1491cea05afSdougm return (0);
1501cea05afSdougm }
1511cea05afSdougm
1521cea05afSdougm if (cbp->cb_alloc == cbp->cb_used) {
1531cea05afSdougm zfs_handle_t **handles;
1541cea05afSdougm
1551cea05afSdougm if (cbp->cb_alloc == 0)
1561cea05afSdougm cbp->cb_alloc = 64;
1571cea05afSdougm else
1581cea05afSdougm cbp->cb_alloc *= 2;
1591cea05afSdougm
160a3351425Sdougm handles = (zfs_handle_t **)calloc(1,
161a3351425Sdougm cbp->cb_alloc * sizeof (void *));
162a3351425Sdougm
1631cea05afSdougm if (handles == NULL) {
164a3351425Sdougm zfs_close(zhp);
16557b448deSdougm return (0);
1661cea05afSdougm }
1671cea05afSdougm if (cbp->cb_handles) {
168a3351425Sdougm bcopy(cbp->cb_handles, handles,
1691cea05afSdougm cbp->cb_used * sizeof (void *));
1701cea05afSdougm free(cbp->cb_handles);
1711cea05afSdougm }
1721cea05afSdougm
1731cea05afSdougm cbp->cb_handles = handles;
1741cea05afSdougm }
1751cea05afSdougm
1761cea05afSdougm cbp->cb_handles[cbp->cb_used++] = zhp;
1771cea05afSdougm
178a3351425Sdougm return (0);
1791cea05afSdougm }
1801cea05afSdougm
1811cea05afSdougm /*
1821cea05afSdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
1831cea05afSdougm *
1841cea05afSdougm * iterate through all ZFS file systems starting at the root. Returns
1851cea05afSdougm * a count and an array of handle pointers. Allocating is only done
1861cea05afSdougm * once. The caller does not need to free since it will be done at
1871cea05afSdougm * sa_zfs_fini() time.
1881cea05afSdougm */
1891cea05afSdougm
1901cea05afSdougm static void
get_all_filesystems(sa_handle_impl_t impl_handle,zfs_handle_t *** fslist,size_t * count)191549ec3ffSdougm get_all_filesystems(sa_handle_impl_t impl_handle,
19295e79c0bSDaniel Hoffman zfs_handle_t ***fslist, size_t *count)
1931cea05afSdougm {
1941cea05afSdougm get_all_cbdata_t cb = { 0 };
195a3351425Sdougm cb.cb_types = ZFS_TYPE_FILESYSTEM;
1961cea05afSdougm
197549ec3ffSdougm if (impl_handle->zfs_list != NULL) {
19857b448deSdougm *fslist = impl_handle->zfs_list;
19957b448deSdougm *count = impl_handle->zfs_list_count;
20057b448deSdougm return;
2011cea05afSdougm }
2021cea05afSdougm
203549ec3ffSdougm (void) zfs_iter_root(impl_handle->zfs_libhandle,
20457b448deSdougm get_one_filesystem, &cb);
2051cea05afSdougm
206549ec3ffSdougm impl_handle->zfs_list = *fslist = cb.cb_handles;
207549ec3ffSdougm impl_handle->zfs_list_count = *count = cb.cb_used;
2081cea05afSdougm }
2091cea05afSdougm
2106185db85Sdougm /*
2111cea05afSdougm * mountpoint_compare(a, b)
2121cea05afSdougm *
2131cea05afSdougm * compares the mountpoint on two zfs file systems handles.
2141cea05afSdougm * returns values following strcmp() model.
2156185db85Sdougm */
2166185db85Sdougm
2171cea05afSdougm static int
mountpoint_compare(const void * a,const void * b)2181cea05afSdougm mountpoint_compare(const void *a, const void *b)
2191cea05afSdougm {
2201cea05afSdougm zfs_handle_t **za = (zfs_handle_t **)a;
2211cea05afSdougm zfs_handle_t **zb = (zfs_handle_t **)b;
2221cea05afSdougm char mounta[MAXPATHLEN];
2231cea05afSdougm char mountb[MAXPATHLEN];
2241cea05afSdougm
2251cea05afSdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
2261cea05afSdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
2271cea05afSdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
2281cea05afSdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
2291cea05afSdougm
2301cea05afSdougm return (strcmp(mounta, mountb));
2311cea05afSdougm }
2321cea05afSdougm
233a1ef5d63Smarks /*
234743a77edSAlan Wright * return legacy mountpoint. Caller provides space for mountpoint and
235743a77edSAlan Wright * dataset.
236a1ef5d63Smarks */
237a1ef5d63Smarks int
get_legacy_mountpoint(const char * path,char * dataset,size_t dlen,char * mountpoint,size_t mlen)23895e79c0bSDaniel Hoffman get_legacy_mountpoint(const char *path, char *dataset, size_t dlen,
239743a77edSAlan Wright char *mountpoint, size_t mlen)
240a1ef5d63Smarks {
241a1ef5d63Smarks FILE *fp;
242a1ef5d63Smarks struct mnttab entry;
243*0dfe541eSEvan Layton int rc = 1;
244a1ef5d63Smarks
245a1ef5d63Smarks if ((fp = fopen(MNTTAB, "r")) == NULL) {
246a1ef5d63Smarks return (1);
247a1ef5d63Smarks }
248a1ef5d63Smarks
249a1ef5d63Smarks while (getmntent(fp, &entry) == 0) {
250a1ef5d63Smarks
251a1ef5d63Smarks if (entry.mnt_fstype == NULL ||
252a1ef5d63Smarks strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
253a1ef5d63Smarks continue;
254a1ef5d63Smarks
255a1ef5d63Smarks if (strcmp(entry.mnt_mountp, path) == 0) {
256743a77edSAlan Wright if (mlen > 0)
257743a77edSAlan Wright (void) strlcpy(mountpoint, entry.mnt_mountp,
258743a77edSAlan Wright mlen);
259743a77edSAlan Wright if (dlen > 0)
260743a77edSAlan Wright (void) strlcpy(dataset, entry.mnt_special,
261743a77edSAlan Wright dlen);
262*0dfe541eSEvan Layton rc = 0;
263743a77edSAlan Wright break;
264a1ef5d63Smarks }
265a1ef5d63Smarks }
266a1ef5d63Smarks (void) fclose(fp);
267*0dfe541eSEvan Layton return (rc);
268a1ef5d63Smarks }
269a1ef5d63Smarks
27095e79c0bSDaniel Hoffman
2718a981c33SDaniel Hoffman /*
2728a981c33SDaniel Hoffman * Verifies that a specific zfs filesystem handle meets the criteria necessary
2738a981c33SDaniel Hoffman * to be used by libshare operations. See get_zfs_dataset.
2748a981c33SDaniel Hoffman */
27595e79c0bSDaniel Hoffman static char *
verify_zfs_handle(zfs_handle_t * hdl,const char * path,boolean_t search_mnttab)27695e79c0bSDaniel Hoffman verify_zfs_handle(zfs_handle_t *hdl, const char *path, boolean_t search_mnttab)
27795e79c0bSDaniel Hoffman {
27895e79c0bSDaniel Hoffman char mountpoint[ZFS_MAXPROPLEN];
27995e79c0bSDaniel Hoffman char canmount[ZFS_MAXPROPLEN] = { 0 };
28095e79c0bSDaniel Hoffman /* must have a mountpoint */
28195e79c0bSDaniel Hoffman if (zfs_prop_get(hdl, ZFS_PROP_MOUNTPOINT, mountpoint,
28295e79c0bSDaniel Hoffman sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
28395e79c0bSDaniel Hoffman /* no mountpoint */
28495e79c0bSDaniel Hoffman return (NULL);
28595e79c0bSDaniel Hoffman }
28695e79c0bSDaniel Hoffman
28795e79c0bSDaniel Hoffman /* mountpoint must be a path */
28895e79c0bSDaniel Hoffman if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
28995e79c0bSDaniel Hoffman strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
29095e79c0bSDaniel Hoffman /*
29195e79c0bSDaniel Hoffman * Search mmttab for mountpoint and get dataset.
29295e79c0bSDaniel Hoffman */
29395e79c0bSDaniel Hoffman
29495e79c0bSDaniel Hoffman if (search_mnttab == B_TRUE &&
29595e79c0bSDaniel Hoffman get_legacy_mountpoint(path, mountpoint,
29695e79c0bSDaniel Hoffman sizeof (mountpoint), NULL, 0) == 0) {
29795e79c0bSDaniel Hoffman return (strdup(mountpoint));
29895e79c0bSDaniel Hoffman }
29995e79c0bSDaniel Hoffman return (NULL);
30095e79c0bSDaniel Hoffman }
30195e79c0bSDaniel Hoffman
30295e79c0bSDaniel Hoffman /* canmount must be set */
30395e79c0bSDaniel Hoffman if (zfs_prop_get(hdl, ZFS_PROP_CANMOUNT, canmount,
30495e79c0bSDaniel Hoffman sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
30595e79c0bSDaniel Hoffman strcmp(canmount, "off") == 0)
30695e79c0bSDaniel Hoffman return (NULL);
30795e79c0bSDaniel Hoffman
30895e79c0bSDaniel Hoffman /*
30995e79c0bSDaniel Hoffman * have a mountable handle but want to skip those marked none
31095e79c0bSDaniel Hoffman * and legacy
31195e79c0bSDaniel Hoffman */
31295e79c0bSDaniel Hoffman if (strcmp(mountpoint, path) == 0) {
31395e79c0bSDaniel Hoffman return (strdup((char *)zfs_get_name(hdl)));
31495e79c0bSDaniel Hoffman }
31595e79c0bSDaniel Hoffman
31695e79c0bSDaniel Hoffman return (NULL);
31795e79c0bSDaniel Hoffman }
31895e79c0bSDaniel Hoffman
3196185db85Sdougm /*
320549ec3ffSdougm * get_zfs_dataset(impl_handle, path)
3216185db85Sdougm *
3226185db85Sdougm * get the name of the ZFS dataset the path is equivalent to. The
3236185db85Sdougm * dataset name is used for get/set of ZFS properties since libzfs
3246185db85Sdougm * requires a dataset to do a zfs_open().
3256185db85Sdougm */
3266185db85Sdougm
3276185db85Sdougm static char *
get_zfs_dataset(sa_handle_impl_t impl_handle,char * path,boolean_t search_mnttab)328a1ef5d63Smarks get_zfs_dataset(sa_handle_impl_t impl_handle, char *path,
329a1ef5d63Smarks boolean_t search_mnttab)
3306185db85Sdougm {
3311cea05afSdougm size_t i, count = 0;
3321cea05afSdougm zfs_handle_t **zlist;
33395e79c0bSDaniel Hoffman char *cutpath;
33495e79c0bSDaniel Hoffman zfs_handle_t *handle_from_path;
33595e79c0bSDaniel Hoffman char *ret = NULL;
3366185db85Sdougm
33795e79c0bSDaniel Hoffman /*
33895e79c0bSDaniel Hoffman * First we optimistically assume that the mount path for the filesystem
33995e79c0bSDaniel Hoffman * is the same as the name of the filesystem (minus some number of
34095e79c0bSDaniel Hoffman * leading slashes). If this is true, then zfs_open should properly open
34195e79c0bSDaniel Hoffman * the filesystem. We duplicate the error checking done later in the
34295e79c0bSDaniel Hoffman * function for consistency. If anything fails, we resort to the
34395e79c0bSDaniel Hoffman * (extremely slow) search of all the filesystems.
34495e79c0bSDaniel Hoffman */
34595e79c0bSDaniel Hoffman cutpath = path + strspn(path, "/");
34695e79c0bSDaniel Hoffman
34795e79c0bSDaniel Hoffman assert(impl_handle->zfs_libhandle != NULL);
348ff524b23SAndrew Stormont libzfs_print_on_error(impl_handle->zfs_libhandle, B_FALSE);
3498a981c33SDaniel Hoffman handle_from_path = zfs_open(impl_handle->zfs_libhandle, cutpath,
3508a981c33SDaniel Hoffman ZFS_TYPE_FILESYSTEM);
3518a981c33SDaniel Hoffman libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
3528a981c33SDaniel Hoffman if (handle_from_path != NULL) {
3538a981c33SDaniel Hoffman ret = verify_zfs_handle(handle_from_path, path, search_mnttab);
3548a981c33SDaniel Hoffman zfs_close(handle_from_path);
3558a981c33SDaniel Hoffman if (ret != NULL) {
35695e79c0bSDaniel Hoffman return (ret);
357ff524b23SAndrew Stormont }
358ff524b23SAndrew Stormont }
35995e79c0bSDaniel Hoffman /*
36095e79c0bSDaniel Hoffman * Couldn't find a filesystem optimistically, check all the handles we
36195e79c0bSDaniel Hoffman * can.
36295e79c0bSDaniel Hoffman */
363549ec3ffSdougm get_all_filesystems(impl_handle, &zlist, &count);
3641cea05afSdougm for (i = 0; i < count; i++) {
36595e79c0bSDaniel Hoffman assert(zlist[i]);
36695e79c0bSDaniel Hoffman if ((ret = verify_zfs_handle(zlist[i], path,
36795e79c0bSDaniel Hoffman search_mnttab)) != NULL)
36895e79c0bSDaniel Hoffman return (ret);
3696185db85Sdougm }
3701cea05afSdougm
37195e79c0bSDaniel Hoffman /* Couldn't find a matching dataset */
37295e79c0bSDaniel Hoffman return (NULL);
3736185db85Sdougm }
3746185db85Sdougm
3756185db85Sdougm /*
3766185db85Sdougm * get_zfs_property(dataset, property)
3776185db85Sdougm *
3786185db85Sdougm * Get the file system property specified from the ZFS dataset.
3796185db85Sdougm */
3806185db85Sdougm
3816185db85Sdougm static char *
get_zfs_property(char * dataset,zfs_prop_t property)3826185db85Sdougm get_zfs_property(char *dataset, zfs_prop_t property)
3836185db85Sdougm {
3846185db85Sdougm zfs_handle_t *handle = NULL;
3856185db85Sdougm char shareopts[ZFS_MAXPROPLEN];
3866185db85Sdougm libzfs_handle_t *libhandle;
3876185db85Sdougm
3886185db85Sdougm libhandle = libzfs_init();
3896185db85Sdougm if (libhandle != NULL) {
39057b448deSdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM);
39157b448deSdougm if (handle != NULL) {
39257b448deSdougm if (zfs_prop_get(handle, property, shareopts,
39357b448deSdougm sizeof (shareopts), NULL, NULL, 0,
39457b448deSdougm B_FALSE) == 0) {
39557b448deSdougm zfs_close(handle);
39657b448deSdougm libzfs_fini(libhandle);
39757b448deSdougm return (strdup(shareopts));
39857b448deSdougm }
39957b448deSdougm zfs_close(handle);
4006185db85Sdougm }
40157b448deSdougm libzfs_fini(libhandle);
4026185db85Sdougm }
4036185db85Sdougm return (NULL);
4046185db85Sdougm }
4056185db85Sdougm
4066185db85Sdougm /*
407549ec3ffSdougm * sa_zfs_is_shared(handle, path)
4086185db85Sdougm *
4096185db85Sdougm * Check to see if the ZFS path provided has the sharenfs option set
4106185db85Sdougm * or not.
4116185db85Sdougm */
4126185db85Sdougm
4136185db85Sdougm int
sa_zfs_is_shared(sa_handle_t sahandle,char * path)414549ec3ffSdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path)
4156185db85Sdougm {
4166185db85Sdougm int ret = 0;
4176185db85Sdougm char *dataset;
4186185db85Sdougm zfs_handle_t *handle = NULL;
4196185db85Sdougm char shareopts[ZFS_MAXPROPLEN];
4206185db85Sdougm libzfs_handle_t *libhandle;
4216185db85Sdougm
422a1ef5d63Smarks dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE);
4236185db85Sdougm if (dataset != NULL) {
42457b448deSdougm libhandle = libzfs_init();
42557b448deSdougm if (libhandle != NULL) {
42657b448deSdougm handle = zfs_open(libhandle, dataset,
42757b448deSdougm ZFS_TYPE_FILESYSTEM);
42857b448deSdougm if (handle != NULL) {
42957b448deSdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS,
43057b448deSdougm shareopts, sizeof (shareopts), NULL, NULL,
43157b448deSdougm 0, B_FALSE) == 0 &&
43257b448deSdougm strcmp(shareopts, "off") != 0) {
43357b448deSdougm ret = 1; /* it is shared */
43457b448deSdougm }
43557b448deSdougm zfs_close(handle);
43657b448deSdougm }
43757b448deSdougm libzfs_fini(libhandle);
4386185db85Sdougm }
43957b448deSdougm free(dataset);
4406185db85Sdougm }
4416185db85Sdougm return (ret);
4426185db85Sdougm }
4436185db85Sdougm
4446185db85Sdougm /*
445da6c28aaSamw * find_or_create_group(handle, groupname, proto, *err)
4466185db85Sdougm *
4476185db85Sdougm * While walking the ZFS tree, we need to add shares to a defined
4486185db85Sdougm * group. If the group doesn't exist, create it first, making sure it
4496185db85Sdougm * is marked as a ZFS group.
4506185db85Sdougm *
45193a6f655Sdougm * Note that all ZFS shares are in a subgroup of the top level group
45293a6f655Sdougm * called "zfs".
4536185db85Sdougm */
4546185db85Sdougm
4556185db85Sdougm static sa_group_t
find_or_create_group(sa_handle_t handle,char * groupname,char * proto,int * err)456549ec3ffSdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
4576185db85Sdougm {
4586185db85Sdougm sa_group_t group;
4596185db85Sdougm sa_optionset_t optionset;
4606185db85Sdougm int ret = SA_OK;
4616185db85Sdougm
4626185db85Sdougm /*
4636185db85Sdougm * we check to see if the "zfs" group exists. Since this
4646185db85Sdougm * should be the top level group, we don't want the
4656185db85Sdougm * parent. This is to make sure the zfs group has been created
4666185db85Sdougm * and to created if it hasn't been.
4676185db85Sdougm */
468549ec3ffSdougm group = sa_get_group(handle, groupname);
4696185db85Sdougm if (group == NULL) {
47057b448deSdougm group = sa_create_group(handle, groupname, &ret);
47193a6f655Sdougm
47257b448deSdougm /* make sure this is flagged as a ZFS group */
47357b448deSdougm if (group != NULL)
47457b448deSdougm ret = sa_set_group_attr(group, "zfs", "true");
4756185db85Sdougm }
4766185db85Sdougm if (group != NULL) {
47757b448deSdougm if (proto != NULL) {
47857b448deSdougm optionset = sa_get_optionset(group, proto);
479da6c28aaSamw if (optionset == NULL)
48057b448deSdougm optionset = sa_create_optionset(group, proto);
4816185db85Sdougm }
4826185db85Sdougm }
4836185db85Sdougm if (err != NULL)
48457b448deSdougm *err = ret;
4856185db85Sdougm return (group);
4866185db85Sdougm }
4876185db85Sdougm
48893a6f655Sdougm /*
48993a6f655Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err)
49093a6f655Sdougm *
49193a6f655Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This
49293a6f655Sdougm * function looks to see if the groupname exists and returns it if it
49393a6f655Sdougm * does or else creates a new one with the specified name and returns
49493a6f655Sdougm * that. The "zfs" group will exist before we get here, but we make
49593a6f655Sdougm * sure just in case.
49693a6f655Sdougm *
49793a6f655Sdougm * err must be a valid pointer.
49893a6f655Sdougm */
49993a6f655Sdougm
50093a6f655Sdougm static sa_group_t
find_or_create_zfs_subgroup(sa_handle_t handle,char * groupname,char * proto,char * optstring,int * err)501da6c28aaSamw find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto,
502da6c28aaSamw char *optstring, int *err)
50393a6f655Sdougm {
50493a6f655Sdougm sa_group_t group = NULL;
50593a6f655Sdougm sa_group_t zfs;
50693a6f655Sdougm char *name;
50793a6f655Sdougm char *options;
50893a6f655Sdougm
50993a6f655Sdougm /* start with the top-level "zfs" group */
510549ec3ffSdougm zfs = sa_get_group(handle, "zfs");
51193a6f655Sdougm *err = SA_OK;
51293a6f655Sdougm if (zfs != NULL) {
51357b448deSdougm for (group = sa_get_sub_group(zfs); group != NULL;
51457b448deSdougm group = sa_get_next_group(group)) {
51557b448deSdougm name = sa_get_group_attr(group, "name");
51657b448deSdougm if (name != NULL && strcmp(name, groupname) == 0) {
51757b448deSdougm /* have the group so break out of here */
51857b448deSdougm sa_free_attr_string(name);
51957b448deSdougm break;
52057b448deSdougm }
52157b448deSdougm if (name != NULL)
52257b448deSdougm sa_free_attr_string(name);
52393a6f655Sdougm }
52457b448deSdougm
52557b448deSdougm if (group == NULL) {
52657b448deSdougm /*
5273c484793Sdougm * Need to create the sub-group since it doesn't exist
52857b448deSdougm */
52957b448deSdougm group = _sa_create_zfs_group(zfs, groupname);
5303c484793Sdougm if (group == NULL) {
5313c484793Sdougm *err = SA_NO_MEMORY;
5323c484793Sdougm return (NULL);
53357b448deSdougm }
5343c484793Sdougm set_node_attr(group, "zfs", "true");
5353c484793Sdougm }
5363c484793Sdougm if (strcmp(optstring, "on") == 0)
5373c484793Sdougm optstring = "rw";
5383c484793Sdougm options = strdup(optstring);
5393c484793Sdougm if (options != NULL) {
5403c484793Sdougm *err = sa_parse_legacy_options(group, options,
5413c484793Sdougm proto);
5423c484793Sdougm /* If no optionset, add one. */
5433c484793Sdougm if (sa_get_optionset(group, proto) == NULL)
5443c484793Sdougm (void) sa_create_optionset(group, proto);
545c3f7431dSDan Kruchinin
546c3f7431dSDan Kruchinin /*
547c3f7431dSDan Kruchinin * Do not forget to update an optionset of
548c3f7431dSDan Kruchinin * the parent group so that it contains
549c3f7431dSDan Kruchinin * all protocols its subgroups have.
550c3f7431dSDan Kruchinin */
551c3f7431dSDan Kruchinin if (sa_get_optionset(zfs, proto) == NULL)
552c3f7431dSDan Kruchinin (void) sa_create_optionset(zfs, proto);
553c3f7431dSDan Kruchinin
5543c484793Sdougm free(options);
5553c484793Sdougm } else {
5563c484793Sdougm *err = SA_NO_MEMORY;
55793a6f655Sdougm }
55893a6f655Sdougm }
55993a6f655Sdougm return (group);
56093a6f655Sdougm }
56193a6f655Sdougm
562da6c28aaSamw /*
563da6c28aaSamw * zfs_construct_resource(share, name, base, dataset)
564da6c28aaSamw *
565da6c28aaSamw * Add a resource to the share using name as a template. If name ==
566da6c28aaSamw * NULL, then construct a name based on the dataset value.
567da6c28aaSamw * name.
568da6c28aaSamw */
569da6c28aaSamw static void
zfs_construct_resource(sa_share_t share,char * dataset)570da6c28aaSamw zfs_construct_resource(sa_share_t share, char *dataset)
571da6c28aaSamw {
572da6c28aaSamw char buff[SA_MAX_RESOURCE_NAME + 1];
573da6c28aaSamw int ret = SA_OK;
574da6c28aaSamw
575da6c28aaSamw (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset);
576da6c28aaSamw sa_fix_resource_name(buff);
577da6c28aaSamw (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret);
578da6c28aaSamw }
579da6c28aaSamw
58057b448deSdougm /*
58157b448deSdougm * zfs_inherited(handle, source, sourcestr)
58257b448deSdougm *
583da6c28aaSamw * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares
58457b448deSdougm * for readability.
58557b448deSdougm */
58657b448deSdougm static int
zfs_inherited(sa_handle_t handle,sa_share_t share,char * sourcestr,char * shareopts,char * mountpoint,char * proto,char * dataset)58757b448deSdougm zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
588da6c28aaSamw char *shareopts, char *mountpoint, char *proto, char *dataset)
58957b448deSdougm {
59057b448deSdougm int doshopt = 0;
59157b448deSdougm int err = SA_OK;
59257b448deSdougm sa_group_t group;
593da6c28aaSamw sa_resource_t resource;
594da6c28aaSamw uint64_t features;
59557b448deSdougm
59657b448deSdougm /*
59757b448deSdougm * Need to find the "real" parent sub-group. It may not be
59857b448deSdougm * mounted, but it was identified in the "sourcestr"
59957b448deSdougm * variable. The real parent not mounted can occur if
60057b448deSdougm * "canmount=off and sharenfs=on".
60157b448deSdougm */
602da6c28aaSamw group = find_or_create_zfs_subgroup(handle, sourcestr, proto,
603da6c28aaSamw shareopts, &doshopt);
60457b448deSdougm if (group != NULL) {
605da6c28aaSamw /*
606da6c28aaSamw * We may need the first share for resource
607da6c28aaSamw * prototype. We only care about it if it has a
608da6c28aaSamw * resource that sets a prefix value.
609da6c28aaSamw */
610da6c28aaSamw if (share == NULL)
611da6c28aaSamw share = _sa_add_share(group, mountpoint,
612da6c28aaSamw SA_SHARE_TRANSIENT, &err,
613da6c28aaSamw (uint64_t)SA_FEATURE_NONE);
61457b448deSdougm /*
61557b448deSdougm * some options may only be on shares. If the opt
61657b448deSdougm * string contains one of those, we put it just on the
61757b448deSdougm * share.
61857b448deSdougm */
61957b448deSdougm if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) {
62057b448deSdougm char *options;
62157b448deSdougm options = strdup(shareopts);
62257b448deSdougm if (options != NULL) {
623da6c28aaSamw set_node_attr(share, "dataset", dataset);
62457b448deSdougm err = sa_parse_legacy_options(share, options,
625da6c28aaSamw proto);
626da6c28aaSamw set_node_attr(share, "dataset", NULL);
62757b448deSdougm free(options);
62857b448deSdougm }
629da6c28aaSamw if (sa_get_optionset(group, proto) == NULL)
630da6c28aaSamw (void) sa_create_optionset(group, proto);
631da6c28aaSamw }
632da6c28aaSamw features = sa_proto_get_featureset(proto);
633da6c28aaSamw if (share != NULL && features & SA_FEATURE_RESOURCE) {
634da6c28aaSamw /*
635da6c28aaSamw * We have a share and the protocol requires
636da6c28aaSamw * that at least one resource exist (probably
637da6c28aaSamw * SMB). We need to make sure that there is at
638da6c28aaSamw * least one.
639da6c28aaSamw */
640da6c28aaSamw resource = sa_get_share_resource(share, NULL);
641da6c28aaSamw if (resource == NULL) {
642da6c28aaSamw zfs_construct_resource(share, dataset);
643da6c28aaSamw }
64457b448deSdougm }
64557b448deSdougm } else {
64657b448deSdougm err = SA_NO_MEMORY;
64757b448deSdougm }
64857b448deSdougm return (err);
64957b448deSdougm }
65057b448deSdougm
65157b448deSdougm /*
65297df5ac9Sdougm * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset,
65397df5ac9Sdougm * grouperr)
65457b448deSdougm *
65557b448deSdougm * handle case where this is the top of a sub-group in ZFS. Pulled out
65697df5ac9Sdougm * of sa_get_zfs_shares for readability. We need the grouperr from the
65797df5ac9Sdougm * creation of the subgroup to know whether to add the public
65897df5ac9Sdougm * property, etc. to the specific share.
65957b448deSdougm */
66057b448deSdougm static int
zfs_notinherited(sa_group_t group,sa_share_t share,char * mountpoint,char * shareopts,char * proto,char * dataset,int grouperr)661da6c28aaSamw zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint,
66297df5ac9Sdougm char *shareopts, char *proto, char *dataset, int grouperr)
66357b448deSdougm {
66457b448deSdougm int err = SA_OK;
665da6c28aaSamw sa_resource_t resource;
666da6c28aaSamw uint64_t features;
66757b448deSdougm
66857b448deSdougm set_node_attr(group, "zfs", "true");
669da6c28aaSamw if (share == NULL)
670da6c28aaSamw share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
671da6c28aaSamw &err, (uint64_t)SA_FEATURE_NONE);
6723c484793Sdougm
6733c484793Sdougm if (err != SA_OK)
6743c484793Sdougm return (err);
6753c484793Sdougm
6763c484793Sdougm if (strcmp(shareopts, "on") == 0)
6773c484793Sdougm shareopts = "";
6783c484793Sdougm if (shareopts != NULL) {
6793c484793Sdougm char *options;
6803c484793Sdougm if (grouperr == SA_PROP_SHARE_ONLY) {
681da6c28aaSamw /*
6823c484793Sdougm * Some properties may only be on shares, but
6833c484793Sdougm * due to the ZFS sub-groups being artificial,
6843c484793Sdougm * we sometimes get this and have to deal with
6853c484793Sdougm * it. We do it by attempting to put it on the
6863c484793Sdougm * share.
687da6c28aaSamw */
6883c484793Sdougm options = strdup(shareopts);
6893c484793Sdougm if (options != NULL) {
6903c484793Sdougm err = sa_parse_legacy_options(share,
6913c484793Sdougm options, proto);
6923c484793Sdougm free(options);
693da6c28aaSamw }
69457b448deSdougm }
6953c484793Sdougm /* Unmark the share's changed state */
6963c484793Sdougm set_node_attr(share, "changed", NULL);
6973c484793Sdougm }
6983c484793Sdougm features = sa_proto_get_featureset(proto);
6993c484793Sdougm if (share != NULL && features & SA_FEATURE_RESOURCE) {
7003c484793Sdougm /*
7013c484793Sdougm * We have a share and the protocol requires that at
7023c484793Sdougm * least one resource exist (probably SMB). We need to
7033c484793Sdougm * make sure that there is at least one.
7043c484793Sdougm */
7053c484793Sdougm resource = sa_get_share_resource(share, NULL);
7063c484793Sdougm if (resource == NULL) {
7073c484793Sdougm zfs_construct_resource(share, dataset);
7083c484793Sdougm }
70957b448deSdougm }
71057b448deSdougm return (err);
71157b448deSdougm }
71257b448deSdougm
71357b448deSdougm /*
71457b448deSdougm * zfs_grp_error(err)
71557b448deSdougm *
71657b448deSdougm * Print group create error, but only once. If err is 0 do the
71757b448deSdougm * print else don't.
71857b448deSdougm */
71957b448deSdougm
72057b448deSdougm static void
zfs_grp_error(int err)72157b448deSdougm zfs_grp_error(int err)
72257b448deSdougm {
72357b448deSdougm if (err == 0) {
72457b448deSdougm /* only print error once */
72557b448deSdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
72657b448deSdougm "Cannot create ZFS subgroup during initialization:"
72757b448deSdougm " %s\n"), sa_errorstr(SA_SYSTEM_ERR));
72857b448deSdougm }
72957b448deSdougm }
73057b448deSdougm
731da6c28aaSamw /*
732da6c28aaSamw * zfs_process_share(handle, share, mountpoint, proto, source,
733da6c28aaSamw * shareopts, sourcestr)
734da6c28aaSamw *
7355b6e0c46Sdougm * Creates the subgroup, if necessary and adds shares, resources
736da6c28aaSamw * and properties.
737da6c28aaSamw */
7385b6e0c46Sdougm int
sa_zfs_process_share(sa_handle_t handle,sa_group_t group,sa_share_t share,char * mountpoint,char * proto,zprop_source_t source,char * shareopts,char * sourcestr,char * dataset)7395b6e0c46Sdougm sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
740da6c28aaSamw char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
741da6c28aaSamw char *sourcestr, char *dataset)
742da6c28aaSamw {
743da6c28aaSamw int err = SA_OK;
744da6c28aaSamw
745da6c28aaSamw if (source & ZPROP_SRC_INHERITED) {
746da6c28aaSamw err = zfs_inherited(handle, share, sourcestr, shareopts,
747da6c28aaSamw mountpoint, proto, dataset);
748da6c28aaSamw } else {
749da6c28aaSamw group = find_or_create_zfs_subgroup(handle, dataset, proto,
750da6c28aaSamw shareopts, &err);
751da6c28aaSamw if (group == NULL) {
75297df5ac9Sdougm static boolean_t reported_error = B_FALSE;
753da6c28aaSamw /*
75497df5ac9Sdougm * There is a problem, but we can't do
755da6c28aaSamw * anything about it at this point so we issue
75697df5ac9Sdougm * a warning and move on.
757da6c28aaSamw */
75897df5ac9Sdougm zfs_grp_error(reported_error);
75997df5ac9Sdougm reported_error = B_TRUE;
760da6c28aaSamw }
761da6c28aaSamw set_node_attr(group, "zfs", "true");
762da6c28aaSamw /*
763da6c28aaSamw * Add share with local opts via zfs_notinherited.
764da6c28aaSamw */
765da6c28aaSamw err = zfs_notinherited(group, share, mountpoint, shareopts,
76697df5ac9Sdougm proto, dataset, err);
767da6c28aaSamw }
768da6c28aaSamw return (err);
769da6c28aaSamw }
770da6c28aaSamw
7716185db85Sdougm /*
7726185db85Sdougm * Walk the mnttab for all zfs mounts and determine which are
7736185db85Sdougm * shared. Find or create the appropriate group/sub-group to contain
7746185db85Sdougm * the shares.
7756185db85Sdougm *
7766185db85Sdougm * All shares are in a sub-group that will hold the properties. This
7776185db85Sdougm * allows representing the inherited property model.
7783c484793Sdougm *
7793c484793Sdougm * One area of complication is if "sharenfs" is set at one level of
7803c484793Sdougm * the directory tree and "sharesmb" is set at a different level, the
7813c484793Sdougm * a sub-group must be formed at the lower level for both
7823c484793Sdougm * protocols. That is the nature of the problem in CR 6667349.
7836185db85Sdougm */
7848a981c33SDaniel Hoffman static int
sa_get_zfs_share_common(sa_handle_t handle,zfs_handle_t * fs_handle,char * path,sa_group_t zfsgroup)7858a981c33SDaniel Hoffman sa_get_zfs_share_common(sa_handle_t handle, zfs_handle_t *fs_handle, char *path,
7868a981c33SDaniel Hoffman sa_group_t zfsgroup)
7876185db85Sdougm {
7888a981c33SDaniel Hoffman boolean_t smb, nfs;
7898a981c33SDaniel Hoffman boolean_t smb_inherited, nfs_inherited;
7903c484793Sdougm char nfsshareopts[ZFS_MAXPROPLEN];
7913c484793Sdougm char smbshareopts[ZFS_MAXPROPLEN];
7923c484793Sdougm char nfssourcestr[ZFS_MAXPROPLEN];
7933c484793Sdougm char smbsourcestr[ZFS_MAXPROPLEN];
7941cea05afSdougm char mountpoint[ZFS_MAXPROPLEN];
7953c484793Sdougm int err = SA_OK;
7968a981c33SDaniel Hoffman zprop_source_t source;
7978a981c33SDaniel Hoffman sa_share_t share;
7988a981c33SDaniel Hoffman char *dataset;
7998a981c33SDaniel Hoffman
8008a981c33SDaniel Hoffman source = ZPROP_SRC_ALL;
8018a981c33SDaniel Hoffman /* If no mountpoint, skip. */
8028a981c33SDaniel Hoffman if (zfs_prop_get(fs_handle, ZFS_PROP_MOUNTPOINT,
8038a981c33SDaniel Hoffman mountpoint, sizeof (mountpoint), NULL, NULL, 0,
8048a981c33SDaniel Hoffman B_FALSE) != 0)
8058a981c33SDaniel Hoffman return (SA_SYSTEM_ERR);
8066185db85Sdougm
8078a981c33SDaniel Hoffman if (path != NULL)
8088a981c33SDaniel Hoffman (void) strncpy(path, mountpoint, sizeof (mountpoint));
8096185db85Sdougm /*
8108a981c33SDaniel Hoffman * zfs_get_name value must not be freed. It is just a
8118a981c33SDaniel Hoffman * pointer to a value in the handle.
8126185db85Sdougm */
8138a981c33SDaniel Hoffman if ((dataset = (char *)zfs_get_name(fs_handle)) == NULL)
81457b448deSdougm return (SA_SYSTEM_ERR);
8156185db85Sdougm
816546405c3Sdougm /*
8178a981c33SDaniel Hoffman * only deal with "mounted" file systems since
8188a981c33SDaniel Hoffman * unmounted file systems can't actually be shared.
819546405c3Sdougm */
820546405c3Sdougm
8218a981c33SDaniel Hoffman if (!zfs_is_mounted(fs_handle, NULL))
8228a981c33SDaniel Hoffman return (SA_SYSTEM_ERR);
8231cea05afSdougm
824*0dfe541eSEvan Layton /*
825*0dfe541eSEvan Layton * Ignore "zoned" datasets in global zone.
826*0dfe541eSEvan Layton */
827*0dfe541eSEvan Layton if (getzoneid() == GLOBAL_ZONEID &&
828*0dfe541eSEvan Layton zfs_prop_get_int(fs_handle, ZFS_PROP_ZONED))
829*0dfe541eSEvan Layton return (SA_SYSTEM_ERR);
830*0dfe541eSEvan Layton
8318a981c33SDaniel Hoffman nfs = nfs_inherited = B_FALSE;
83257b448deSdougm
8338a981c33SDaniel Hoffman if (zfs_prop_get(fs_handle, ZFS_PROP_SHARENFS, nfsshareopts,
8348a981c33SDaniel Hoffman sizeof (nfsshareopts), &source, nfssourcestr,
8358a981c33SDaniel Hoffman ZFS_MAXPROPLEN, B_FALSE) == 0 &&
8368a981c33SDaniel Hoffman strcmp(nfsshareopts, "off") != 0) {
8378a981c33SDaniel Hoffman if (source & ZPROP_SRC_INHERITED)
8388a981c33SDaniel Hoffman nfs_inherited = B_TRUE;
8398a981c33SDaniel Hoffman else
8408a981c33SDaniel Hoffman nfs = B_TRUE;
8418a981c33SDaniel Hoffman }
8423c484793Sdougm
8438a981c33SDaniel Hoffman smb = smb_inherited = B_FALSE;
8448a981c33SDaniel Hoffman if (zfs_prop_get(fs_handle, ZFS_PROP_SHARESMB, smbshareopts,
8458a981c33SDaniel Hoffman sizeof (smbshareopts), &source, smbsourcestr,
8468a981c33SDaniel Hoffman ZFS_MAXPROPLEN, B_FALSE) == 0 &&
8478a981c33SDaniel Hoffman strcmp(smbshareopts, "off") != 0) {
8488a981c33SDaniel Hoffman if (source & ZPROP_SRC_INHERITED)
8498a981c33SDaniel Hoffman smb_inherited = B_TRUE;
8508a981c33SDaniel Hoffman else
8518a981c33SDaniel Hoffman smb = B_TRUE;
8528a981c33SDaniel Hoffman }
8533c484793Sdougm
8548a981c33SDaniel Hoffman /*
8558a981c33SDaniel Hoffman * If the mountpoint is already shared, it must be a
8568a981c33SDaniel Hoffman * non-ZFS share. We want to remove the share from its
8578a981c33SDaniel Hoffman * parent group and reshare it under ZFS.
8588a981c33SDaniel Hoffman */
8598a981c33SDaniel Hoffman share = sa_find_share(handle, mountpoint);
8608a981c33SDaniel Hoffman if (share != NULL &&
8618a981c33SDaniel Hoffman (nfs || smb || nfs_inherited || smb_inherited)) {
8628a981c33SDaniel Hoffman err = sa_remove_share(share);
8638a981c33SDaniel Hoffman share = NULL;
8648a981c33SDaniel Hoffman }
8653c484793Sdougm
8668a981c33SDaniel Hoffman /*
8678a981c33SDaniel Hoffman * At this point, we have the information needed to
8688a981c33SDaniel Hoffman * determine what to do with the share.
8698a981c33SDaniel Hoffman *
8708a981c33SDaniel Hoffman * If smb or nfs is set, we have a new sub-group.
8718a981c33SDaniel Hoffman * If smb_inherit and/or nfs_inherit is set, then
8728a981c33SDaniel Hoffman * place on an existing sub-group. If both are set,
8738a981c33SDaniel Hoffman * the existing sub-group is the closest up the tree.
8748a981c33SDaniel Hoffman */
8758a981c33SDaniel Hoffman if (nfs || smb) {
8763c484793Sdougm /*
8778a981c33SDaniel Hoffman * Non-inherited is the straightforward
8788a981c33SDaniel Hoffman * case. sa_zfs_process_share handles it
8798a981c33SDaniel Hoffman * directly. Make sure that if the "other"
8808a981c33SDaniel Hoffman * protocol is inherited, that we treat it as
8818a981c33SDaniel Hoffman * non-inherited as well.
8823c484793Sdougm */
8838a981c33SDaniel Hoffman if (nfs || nfs_inherited) {
8848a981c33SDaniel Hoffman err = sa_zfs_process_share(handle, zfsgroup,
8858a981c33SDaniel Hoffman share, mountpoint, "nfs",
8868a981c33SDaniel Hoffman 0, nfsshareopts,
8878a981c33SDaniel Hoffman nfssourcestr, dataset);
8888a981c33SDaniel Hoffman share = sa_find_share(handle, mountpoint);
8893c484793Sdougm }
8908a981c33SDaniel Hoffman if (smb || smb_inherited) {
8918a981c33SDaniel Hoffman err = sa_zfs_process_share(handle, zfsgroup,
8928a981c33SDaniel Hoffman share, mountpoint, "smb",
8938a981c33SDaniel Hoffman 0, smbshareopts,
8948a981c33SDaniel Hoffman smbsourcestr, dataset);
8958a981c33SDaniel Hoffman }
8968a981c33SDaniel Hoffman } else if (nfs_inherited || smb_inherited) {
8978a981c33SDaniel Hoffman char *grpdataset;
8983c484793Sdougm /*
8998a981c33SDaniel Hoffman * If we only have inherited groups, it is
9008a981c33SDaniel Hoffman * important to find the closer of the two if
9018a981c33SDaniel Hoffman * the protocols are set at different
9028a981c33SDaniel Hoffman * levels. The closest sub-group is the one we
9038a981c33SDaniel Hoffman * want to work with.
9043c484793Sdougm */
9058a981c33SDaniel Hoffman if (nfs_inherited && smb_inherited) {
9068a981c33SDaniel Hoffman if (strcmp(nfssourcestr, smbsourcestr) <= 0)
9073c484793Sdougm grpdataset = nfssourcestr;
9088a981c33SDaniel Hoffman else
9093c484793Sdougm grpdataset = smbsourcestr;
9108a981c33SDaniel Hoffman } else if (nfs_inherited) {
9118a981c33SDaniel Hoffman grpdataset = nfssourcestr;
9128a981c33SDaniel Hoffman } else if (smb_inherited) {
9138a981c33SDaniel Hoffman grpdataset = smbsourcestr;
9148a981c33SDaniel Hoffman }
9158a981c33SDaniel Hoffman if (nfs_inherited) {
9168a981c33SDaniel Hoffman err = sa_zfs_process_share(handle, zfsgroup,
9178a981c33SDaniel Hoffman share, mountpoint, "nfs",
9188a981c33SDaniel Hoffman ZPROP_SRC_INHERITED, nfsshareopts,
9198a981c33SDaniel Hoffman grpdataset, dataset);
9208a981c33SDaniel Hoffman share = sa_find_share(handle, mountpoint);
9218a981c33SDaniel Hoffman }
9228a981c33SDaniel Hoffman if (smb_inherited) {
9238a981c33SDaniel Hoffman err = sa_zfs_process_share(handle, zfsgroup,
9248a981c33SDaniel Hoffman share, mountpoint, "smb",
9258a981c33SDaniel Hoffman ZPROP_SRC_INHERITED, smbshareopts,
9268a981c33SDaniel Hoffman grpdataset, dataset);
9276185db85Sdougm }
9286185db85Sdougm }
9298a981c33SDaniel Hoffman return (err);
9308a981c33SDaniel Hoffman }
9318a981c33SDaniel Hoffman
9328a981c33SDaniel Hoffman /*
9338a981c33SDaniel Hoffman * Handles preparing generic objects such as the libzfs handle and group for
9348a981c33SDaniel Hoffman * sa_get_one_zfs_share, sa_get_zfs_share_for_name, and sa_get_zfs_shares.
9358a981c33SDaniel Hoffman */
9368a981c33SDaniel Hoffman static int
prep_zfs_handle_and_group(sa_handle_t handle,char * groupname,libzfs_handle_t ** zfs_libhandle,sa_group_t * zfsgroup,int * err)9378a981c33SDaniel Hoffman prep_zfs_handle_and_group(sa_handle_t handle, char *groupname,
9388a981c33SDaniel Hoffman libzfs_handle_t **zfs_libhandle, sa_group_t *zfsgroup, int *err)
9398a981c33SDaniel Hoffman {
9408a981c33SDaniel Hoffman /*
9418a981c33SDaniel Hoffman * If we can't access libzfs, don't bother doing anything.
9428a981c33SDaniel Hoffman */
9438a981c33SDaniel Hoffman *zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle;
9448a981c33SDaniel Hoffman if (*zfs_libhandle == NULL)
9458a981c33SDaniel Hoffman return (SA_SYSTEM_ERR);
9468a981c33SDaniel Hoffman
9478a981c33SDaniel Hoffman *zfsgroup = find_or_create_group(handle, groupname, NULL, err);
9488a981c33SDaniel Hoffman return (SA_OK);
9498a981c33SDaniel Hoffman }
9508a981c33SDaniel Hoffman
9518a981c33SDaniel Hoffman /*
9528a981c33SDaniel Hoffman * The O.G. zfs share preparation function. This initializes all zfs shares for
9538a981c33SDaniel Hoffman * use with libshare.
9548a981c33SDaniel Hoffman */
9558a981c33SDaniel Hoffman int
sa_get_zfs_shares(sa_handle_t handle,char * groupname)9568a981c33SDaniel Hoffman sa_get_zfs_shares(sa_handle_t handle, char *groupname)
9578a981c33SDaniel Hoffman {
9588a981c33SDaniel Hoffman sa_group_t zfsgroup;
9598a981c33SDaniel Hoffman zfs_handle_t **zlist;
9608a981c33SDaniel Hoffman size_t count = 0;
9618a981c33SDaniel Hoffman libzfs_handle_t *zfs_libhandle;
9628a981c33SDaniel Hoffman int err;
9638a981c33SDaniel Hoffman
9648a981c33SDaniel Hoffman if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
9658a981c33SDaniel Hoffman &zfsgroup, &err)) != SA_OK) {
9668a981c33SDaniel Hoffman return (err);
9678a981c33SDaniel Hoffman }
9688a981c33SDaniel Hoffman /* Not an error, this could be a legacy condition */
9698a981c33SDaniel Hoffman if (zfsgroup == NULL)
9708a981c33SDaniel Hoffman return (SA_OK);
9718a981c33SDaniel Hoffman
9728a981c33SDaniel Hoffman /*
9738a981c33SDaniel Hoffman * need to walk the mounted ZFS pools and datasets to
9748a981c33SDaniel Hoffman * find shares that are possible.
9758a981c33SDaniel Hoffman */
9768a981c33SDaniel Hoffman get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count);
9778a981c33SDaniel Hoffman qsort(zlist, count, sizeof (void *), mountpoint_compare);
9788a981c33SDaniel Hoffman
9798a981c33SDaniel Hoffman for (int i = 0; i < count; i++) {
9808a981c33SDaniel Hoffman err = sa_get_zfs_share_common(handle, zlist[i], NULL, zfsgroup);
9818a981c33SDaniel Hoffman }
9821cea05afSdougm /*
9831cea05afSdougm * Don't need to free the "zlist" variable since it is only a
9841cea05afSdougm * pointer to a cached value that will be freed when
9851cea05afSdougm * sa_fini() is called.
9861cea05afSdougm */
9873c484793Sdougm return (err);
9886185db85Sdougm }
9896185db85Sdougm
990*0dfe541eSEvan Layton /*
991*0dfe541eSEvan Layton * Initializes shares for only the dataset specified fs_handle.
992*0dfe541eSEvan Layton * This is used as a performance optimization relative to sa_get_zfs_shares.
993*0dfe541eSEvan Layton */
994*0dfe541eSEvan Layton int
sa_get_zfs_share(sa_handle_t handle,char * groupname,zfs_handle_t * fs_handle)995*0dfe541eSEvan Layton sa_get_zfs_share(sa_handle_t handle, char *groupname, zfs_handle_t *fs_handle)
996*0dfe541eSEvan Layton {
997*0dfe541eSEvan Layton sa_group_t zfsgroup;
998*0dfe541eSEvan Layton libzfs_handle_t *zfs_libhandle;
999*0dfe541eSEvan Layton int err;
1000*0dfe541eSEvan Layton
1001*0dfe541eSEvan Layton if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
1002*0dfe541eSEvan Layton &zfsgroup, &err)) != SA_OK) {
1003*0dfe541eSEvan Layton return (err);
1004*0dfe541eSEvan Layton }
1005*0dfe541eSEvan Layton /* Not an error, this could be a legacy condition */
1006*0dfe541eSEvan Layton if (zfsgroup == NULL)
1007*0dfe541eSEvan Layton return (SA_OK);
1008*0dfe541eSEvan Layton
1009*0dfe541eSEvan Layton err = sa_get_zfs_share_common(handle, fs_handle, NULL, zfsgroup);
1010*0dfe541eSEvan Layton return (err);
1011*0dfe541eSEvan Layton }
1012*0dfe541eSEvan Layton
10138a981c33SDaniel Hoffman /*
10148a981c33SDaniel Hoffman * Initializes only the handles specified in the sharearg for use with libshare.
10158a981c33SDaniel Hoffman * This is used as a performance optimization relative to sa_get_zfs_shares.
10168a981c33SDaniel Hoffman */
10178a981c33SDaniel Hoffman int
sa_get_one_zfs_share(sa_handle_t handle,char * groupname,sa_init_selective_arg_t * sharearg,char *** paths,size_t * paths_len)10188a981c33SDaniel Hoffman sa_get_one_zfs_share(sa_handle_t handle, char *groupname,
10198a981c33SDaniel Hoffman sa_init_selective_arg_t *sharearg, char ***paths, size_t *paths_len)
10208a981c33SDaniel Hoffman {
10218a981c33SDaniel Hoffman sa_group_t zfsgroup;
10228a981c33SDaniel Hoffman libzfs_handle_t *zfs_libhandle;
10238a981c33SDaniel Hoffman int err;
10248a981c33SDaniel Hoffman
10258a981c33SDaniel Hoffman if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
10268a981c33SDaniel Hoffman &zfsgroup, &err)) != SA_OK) {
10278a981c33SDaniel Hoffman return (err);
10288a981c33SDaniel Hoffman }
10298a981c33SDaniel Hoffman /* Not an error, this could be a legacy condition */
10308a981c33SDaniel Hoffman if (zfsgroup == NULL)
10318a981c33SDaniel Hoffman return (SA_OK);
10328a981c33SDaniel Hoffman
10338a981c33SDaniel Hoffman *paths_len = sharearg->zhandle_len;
1034569c0494SDaniel Hoffman *paths = calloc(*paths_len, sizeof (char *));
10358a981c33SDaniel Hoffman for (int i = 0; i < sharearg->zhandle_len; ++i) {
10368a981c33SDaniel Hoffman zfs_handle_t *fs_handle =
10378a981c33SDaniel Hoffman ((zfs_handle_t **)(sharearg->zhandle_arr))[i];
10388a981c33SDaniel Hoffman if (fs_handle == NULL) {
1039569c0494SDaniel Hoffman /* Free non-null elements of the paths array */
1040569c0494SDaniel Hoffman for (int free_idx = 0; free_idx < *paths_len;
1041569c0494SDaniel Hoffman ++free_idx) {
1042569c0494SDaniel Hoffman if ((*paths)[free_idx] != NULL)
1043569c0494SDaniel Hoffman free((*paths)[free_idx]);
1044569c0494SDaniel Hoffman }
1045569c0494SDaniel Hoffman free(*paths);
1046569c0494SDaniel Hoffman *paths = NULL;
1047569c0494SDaniel Hoffman *paths_len = 0;
10488a981c33SDaniel Hoffman return (SA_SYSTEM_ERR);
10498a981c33SDaniel Hoffman }
10508a981c33SDaniel Hoffman (*paths)[i] = malloc(sizeof (char) * ZFS_MAXPROPLEN);
10518a981c33SDaniel Hoffman err |= sa_get_zfs_share_common(handle, fs_handle, (*paths)[i],
10528a981c33SDaniel Hoffman zfsgroup);
10538a981c33SDaniel Hoffman }
1054569c0494SDaniel Hoffman
10558a981c33SDaniel Hoffman return (err);
10568a981c33SDaniel Hoffman }
10578a981c33SDaniel Hoffman
10588a981c33SDaniel Hoffman /*
10598a981c33SDaniel Hoffman * Initializes only the share with the specified sharename for use with
10608a981c33SDaniel Hoffman * libshare.
10618a981c33SDaniel Hoffman */
10628a981c33SDaniel Hoffman int
sa_get_zfs_share_for_name(sa_handle_t handle,char * groupname,const char * sharename,char * outpath)10638a981c33SDaniel Hoffman sa_get_zfs_share_for_name(sa_handle_t handle, char *groupname,
10648a981c33SDaniel Hoffman const char *sharename, char *outpath)
10658a981c33SDaniel Hoffman {
10668a981c33SDaniel Hoffman sa_group_t zfsgroup;
10678a981c33SDaniel Hoffman libzfs_handle_t *zfs_libhandle;
10688a981c33SDaniel Hoffman int err;
10698a981c33SDaniel Hoffman
10708a981c33SDaniel Hoffman if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
10718a981c33SDaniel Hoffman &zfsgroup, &err)) != SA_OK) {
10728a981c33SDaniel Hoffman return (err);
10738a981c33SDaniel Hoffman }
10748a981c33SDaniel Hoffman /* Not an error, this could be a legacy condition */
10758a981c33SDaniel Hoffman if (zfsgroup == NULL)
10768a981c33SDaniel Hoffman return (SA_OK);
10778a981c33SDaniel Hoffman
10788a981c33SDaniel Hoffman zfs_handle_t *fs_handle = zfs_open(zfs_libhandle,
10798a981c33SDaniel Hoffman sharename + strspn(sharename, "/"), ZFS_TYPE_DATASET);
10808a981c33SDaniel Hoffman if (fs_handle == NULL)
10818a981c33SDaniel Hoffman return (SA_SYSTEM_ERR);
10828a981c33SDaniel Hoffman
10838a981c33SDaniel Hoffman err = sa_get_zfs_share_common(handle, fs_handle, outpath, zfsgroup);
10848a981c33SDaniel Hoffman zfs_close(fs_handle);
10858a981c33SDaniel Hoffman return (err);
10868a981c33SDaniel Hoffman }
10878a981c33SDaniel Hoffman
10888a981c33SDaniel Hoffman
10898a981c33SDaniel Hoffman
10906185db85Sdougm #define COMMAND "/usr/sbin/zfs"
10916185db85Sdougm
10926185db85Sdougm /*
10936185db85Sdougm * sa_zfs_set_sharenfs(group, path, on)
10946185db85Sdougm *
10956185db85Sdougm * Update the "sharenfs" property on the path. If on is true, then set
10966185db85Sdougm * to the properties on the group or "on" if no properties are
10976185db85Sdougm * defined. Set to "off" if on is false.
10986185db85Sdougm */
10996185db85Sdougm
11006185db85Sdougm int
sa_zfs_set_sharenfs(sa_group_t group,char * path,int on)11016185db85Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on)
11026185db85Sdougm {
11036185db85Sdougm int ret = SA_NOT_IMPLEMENTED;
11046185db85Sdougm char *command;
11056185db85Sdougm
11066185db85Sdougm command = malloc(ZFS_MAXPROPLEN * 2);
11076185db85Sdougm if (command != NULL) {
110857b448deSdougm char *opts = NULL;
110957b448deSdougm char *dataset = NULL;
111057b448deSdougm FILE *pfile;
111157b448deSdougm sa_handle_impl_t impl_handle;
111257b448deSdougm /* for now, NFS is always available for "zfs" */
111357b448deSdougm if (on) {
111457b448deSdougm opts = sa_proto_legacy_format("nfs", group, 1);
111557b448deSdougm if (opts != NULL && strlen(opts) == 0) {
111657b448deSdougm free(opts);
111757b448deSdougm opts = strdup("on");
111857b448deSdougm }
11196185db85Sdougm }
112057b448deSdougm
112157b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
112257b448deSdougm assert(impl_handle != NULL);
112357b448deSdougm if (impl_handle != NULL)
1124a1ef5d63Smarks dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
112557b448deSdougm else
11266185db85Sdougm ret = SA_SYSTEM_ERR;
112757b448deSdougm
112857b448deSdougm if (dataset != NULL) {
112957b448deSdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2,
113057b448deSdougm "%s set sharenfs=\"%s\" %s", COMMAND,
113157b448deSdougm opts != NULL ? opts : "off", dataset);
113257b448deSdougm pfile = popen(command, "r");
113357b448deSdougm if (pfile != NULL) {
113457b448deSdougm ret = pclose(pfile);
113557b448deSdougm if (ret != 0)
113657b448deSdougm ret = SA_SYSTEM_ERR;
113757b448deSdougm }
11386185db85Sdougm }
113957b448deSdougm if (opts != NULL)
114057b448deSdougm free(opts);
114157b448deSdougm if (dataset != NULL)
114257b448deSdougm free(dataset);
114357b448deSdougm free(command);
11446185db85Sdougm }
11456185db85Sdougm return (ret);
11466185db85Sdougm }
11476185db85Sdougm
1148da6c28aaSamw /*
1149da6c28aaSamw * add_resources(share, opt)
1150da6c28aaSamw *
1151da6c28aaSamw * Add resource properties to those in "opt". Resources are prefixed
1152da6c28aaSamw * with name=resourcename.
1153da6c28aaSamw */
1154da6c28aaSamw static char *
add_resources(sa_share_t share,char * opt)1155da6c28aaSamw add_resources(sa_share_t share, char *opt)
1156da6c28aaSamw {
1157da6c28aaSamw char *newopt = NULL;
1158da6c28aaSamw char *propstr;
1159da6c28aaSamw sa_resource_t resource;
1160da6c28aaSamw
1161da6c28aaSamw newopt = strdup(opt);
1162da6c28aaSamw if (newopt == NULL)
1163da6c28aaSamw return (newopt);
1164da6c28aaSamw
1165da6c28aaSamw for (resource = sa_get_share_resource(share, NULL);
1166da6c28aaSamw resource != NULL;
1167da6c28aaSamw resource = sa_get_next_resource(resource)) {
1168da6c28aaSamw char *name;
1169da6c28aaSamw size_t size;
1170da6c28aaSamw
1171da6c28aaSamw name = sa_get_resource_attr(resource, "name");
1172da6c28aaSamw if (name == NULL) {
1173da6c28aaSamw free(newopt);
1174da6c28aaSamw return (NULL);
1175da6c28aaSamw }
1176da6c28aaSamw size = strlen(name) + strlen(opt) + sizeof ("name=") + 1;
1177da6c28aaSamw newopt = calloc(1, size);
1178da6c28aaSamw if (newopt != NULL)
1179da6c28aaSamw (void) snprintf(newopt, size, "%s,name=%s", opt, name);
1180fe1c642dSBill Krier sa_free_attr_string(name);
1181da6c28aaSamw free(opt);
1182da6c28aaSamw opt = newopt;
1183da6c28aaSamw propstr = sa_proto_legacy_format("smb", resource, 0);
1184da6c28aaSamw if (propstr == NULL) {
1185da6c28aaSamw free(opt);
1186da6c28aaSamw return (NULL);
1187da6c28aaSamw }
1188da6c28aaSamw size = strlen(propstr) + strlen(opt) + 2;
1189da6c28aaSamw newopt = calloc(1, size);
1190da6c28aaSamw if (newopt != NULL)
1191da6c28aaSamw (void) snprintf(newopt, size, "%s,%s", opt, propstr);
1192da6c28aaSamw free(opt);
1193da6c28aaSamw opt = newopt;
1194da6c28aaSamw }
1195da6c28aaSamw return (opt);
1196da6c28aaSamw }
1197da6c28aaSamw
1198da6c28aaSamw /*
1199da6c28aaSamw * sa_zfs_set_sharesmb(group, path, on)
1200da6c28aaSamw *
1201da6c28aaSamw * Update the "sharesmb" property on the path. If on is true, then set
1202da6c28aaSamw * to the properties on the group or "on" if no properties are
1203da6c28aaSamw * defined. Set to "off" if on is false.
1204da6c28aaSamw */
1205da6c28aaSamw
1206da6c28aaSamw int
sa_zfs_set_sharesmb(sa_group_t group,char * path,int on)1207da6c28aaSamw sa_zfs_set_sharesmb(sa_group_t group, char *path, int on)
1208da6c28aaSamw {
1209da6c28aaSamw int ret = SA_NOT_IMPLEMENTED;
1210da6c28aaSamw char *command;
1211da6c28aaSamw sa_share_t share;
1212da6c28aaSamw
1213da6c28aaSamw /* In case SMB not enabled */
1214da6c28aaSamw if (sa_get_optionset(group, "smb") == NULL)
1215da6c28aaSamw return (SA_NOT_SUPPORTED);
1216da6c28aaSamw
1217da6c28aaSamw command = malloc(ZFS_MAXPROPLEN * 2);
1218da6c28aaSamw if (command != NULL) {
1219da6c28aaSamw char *opts = NULL;
1220da6c28aaSamw char *dataset = NULL;
1221da6c28aaSamw FILE *pfile;
1222da6c28aaSamw sa_handle_impl_t impl_handle;
1223da6c28aaSamw
1224da6c28aaSamw if (on) {
1225da6c28aaSamw char *newopt;
1226da6c28aaSamw
1227da6c28aaSamw share = sa_get_share(group, NULL);
1228da6c28aaSamw opts = sa_proto_legacy_format("smb", share, 1);
1229da6c28aaSamw if (opts != NULL && strlen(opts) == 0) {
1230da6c28aaSamw free(opts);
1231da6c28aaSamw opts = strdup("on");
1232da6c28aaSamw }
1233da6c28aaSamw newopt = add_resources(opts, share);
1234da6c28aaSamw free(opts);
1235da6c28aaSamw opts = newopt;
1236da6c28aaSamw }
1237da6c28aaSamw
1238da6c28aaSamw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
1239da6c28aaSamw assert(impl_handle != NULL);
1240da6c28aaSamw if (impl_handle != NULL)
1241da6c28aaSamw dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
1242da6c28aaSamw else
1243da6c28aaSamw ret = SA_SYSTEM_ERR;
1244da6c28aaSamw
1245da6c28aaSamw if (dataset != NULL) {
1246da6c28aaSamw (void) snprintf(command, ZFS_MAXPROPLEN * 2,
1247da6c28aaSamw "echo %s set sharesmb=\"%s\" %s", COMMAND,
1248da6c28aaSamw opts != NULL ? opts : "off", dataset);
1249da6c28aaSamw pfile = popen(command, "r");
1250da6c28aaSamw if (pfile != NULL) {
1251da6c28aaSamw ret = pclose(pfile);
1252da6c28aaSamw if (ret != 0)
1253da6c28aaSamw ret = SA_SYSTEM_ERR;
1254da6c28aaSamw }
1255da6c28aaSamw }
1256da6c28aaSamw if (opts != NULL)
1257da6c28aaSamw free(opts);
1258da6c28aaSamw if (dataset != NULL)
1259da6c28aaSamw free(dataset);
1260da6c28aaSamw free(command);
1261da6c28aaSamw }
1262da6c28aaSamw return (ret);
1263da6c28aaSamw }
1264da6c28aaSamw
12656185db85Sdougm /*
12666185db85Sdougm * sa_zfs_update(group)
12676185db85Sdougm *
12686185db85Sdougm * call back to ZFS to update the share if necessary.
12696185db85Sdougm * Don't do it if it isn't a real change.
12706185db85Sdougm */
12716185db85Sdougm int
sa_zfs_update(sa_group_t group)12726185db85Sdougm sa_zfs_update(sa_group_t group)
12736185db85Sdougm {
12746185db85Sdougm sa_optionset_t protopt;
12756185db85Sdougm sa_group_t parent;
12766185db85Sdougm char *command;
12776185db85Sdougm char *optstring;
12786185db85Sdougm int ret = SA_OK;
12796185db85Sdougm int doupdate = 0;
12806185db85Sdougm FILE *pfile;
12816185db85Sdougm
12826185db85Sdougm if (sa_is_share(group))
128357b448deSdougm parent = sa_get_parent_group(group);
12846185db85Sdougm else
128557b448deSdougm parent = group;
12866185db85Sdougm
12876185db85Sdougm if (parent != NULL) {
128857b448deSdougm command = malloc(ZFS_MAXPROPLEN * 2);
128957b448deSdougm if (command == NULL)
129057b448deSdougm return (SA_NO_MEMORY);
129157b448deSdougm
129257b448deSdougm *command = '\0';
129357b448deSdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL;
129457b448deSdougm protopt = sa_get_next_optionset(protopt)) {
129557b448deSdougm
129657b448deSdougm char *proto = sa_get_optionset_attr(protopt, "type");
129757b448deSdougm char *path;
129857b448deSdougm char *dataset = NULL;
129957b448deSdougm char *zfsopts = NULL;
130057b448deSdougm
130157b448deSdougm if (sa_is_share(group)) {
130257b448deSdougm path = sa_get_share_attr((sa_share_t)group,
130357b448deSdougm "path");
130457b448deSdougm if (path != NULL) {
130557b448deSdougm sa_handle_impl_t impl_handle;
130657b448deSdougm
130757b448deSdougm impl_handle = sa_find_group_handle(
130857b448deSdougm group);
130957b448deSdougm if (impl_handle != NULL)
131057b448deSdougm dataset = get_zfs_dataset(
1311a1ef5d63Smarks impl_handle, path, B_FALSE);
131257b448deSdougm else
131357b448deSdougm ret = SA_SYSTEM_ERR;
131457b448deSdougm
131557b448deSdougm sa_free_attr_string(path);
131657b448deSdougm }
13176185db85Sdougm } else {
131857b448deSdougm dataset = sa_get_group_attr(group, "name");
13196185db85Sdougm }
132057b448deSdougm /* update only when there is an optstring found */
132157b448deSdougm doupdate = 0;
132257b448deSdougm if (proto != NULL && dataset != NULL) {
132357b448deSdougm optstring = sa_proto_legacy_format(proto,
132457b448deSdougm group, 1);
132557b448deSdougm zfsopts = get_zfs_property(dataset,
132657b448deSdougm ZFS_PROP_SHARENFS);
132757b448deSdougm
132857b448deSdougm if (optstring != NULL && zfsopts != NULL) {
132957b448deSdougm if (strcmp(optstring, zfsopts) != 0)
133057b448deSdougm doupdate++;
133157b448deSdougm }
133257b448deSdougm if (doupdate) {
133357b448deSdougm if (optstring != NULL &&
133457b448deSdougm strlen(optstring) > 0) {
133557b448deSdougm (void) snprintf(command,
133657b448deSdougm ZFS_MAXPROPLEN * 2,
13371f713840SDoug McCallum "%s set share%s=%s %s",
13381f713840SDoug McCallum COMMAND, proto,
133957b448deSdougm optstring, dataset);
134057b448deSdougm } else {
134157b448deSdougm (void) snprintf(command,
134257b448deSdougm ZFS_MAXPROPLEN * 2,
13431f713840SDoug McCallum "%s set share%s=on %s",
13441f713840SDoug McCallum COMMAND, proto,
134557b448deSdougm dataset);
134657b448deSdougm }
134757b448deSdougm pfile = popen(command, "r");
134857b448deSdougm if (pfile != NULL)
134957b448deSdougm ret = pclose(pfile);
135057b448deSdougm switch (ret) {
135157b448deSdougm default:
135257b448deSdougm case 1:
135357b448deSdougm ret = SA_SYSTEM_ERR;
135457b448deSdougm break;
135557b448deSdougm case 2:
135657b448deSdougm ret = SA_SYNTAX_ERR;
135757b448deSdougm break;
135857b448deSdougm case 0:
135957b448deSdougm break;
136057b448deSdougm }
136157b448deSdougm }
136257b448deSdougm if (optstring != NULL)
136357b448deSdougm free(optstring);
136457b448deSdougm if (zfsopts != NULL)
136557b448deSdougm free(zfsopts);
13666185db85Sdougm }
136757b448deSdougm if (proto != NULL)
136857b448deSdougm sa_free_attr_string(proto);
136957b448deSdougm if (dataset != NULL)
137057b448deSdougm free(dataset);
13716185db85Sdougm }
137257b448deSdougm free(command);
13736185db85Sdougm }
13746185db85Sdougm return (ret);
13756185db85Sdougm }
13766185db85Sdougm
13776185db85Sdougm /*
13786185db85Sdougm * sa_group_is_zfs(group)
13796185db85Sdougm *
13806185db85Sdougm * Given the group, determine if the zfs attribute is set.
13816185db85Sdougm */
13826185db85Sdougm
13836185db85Sdougm int
sa_group_is_zfs(sa_group_t group)13846185db85Sdougm sa_group_is_zfs(sa_group_t group)
13856185db85Sdougm {
13866185db85Sdougm char *zfs;
13876185db85Sdougm int ret = 0;
13886185db85Sdougm
13896185db85Sdougm zfs = sa_get_group_attr(group, "zfs");
13906185db85Sdougm if (zfs != NULL) {
139157b448deSdougm ret = 1;
139257b448deSdougm sa_free_attr_string(zfs);
13936185db85Sdougm }
13946185db85Sdougm return (ret);
13956185db85Sdougm }
13966185db85Sdougm
13976185db85Sdougm /*
13986185db85Sdougm * sa_path_is_zfs(path)
13996185db85Sdougm *
14006185db85Sdougm * Check to see if the file system path represents is of type "zfs".
14016185db85Sdougm */
14026185db85Sdougm
14036185db85Sdougm int
sa_path_is_zfs(char * path)14046185db85Sdougm sa_path_is_zfs(char *path)
14056185db85Sdougm {
14066185db85Sdougm char *fstype;
14076185db85Sdougm int ret = 0;
14086185db85Sdougm
14096185db85Sdougm fstype = sa_fstype(path);
141057b448deSdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0)
141157b448deSdougm ret = 1;
14126185db85Sdougm if (fstype != NULL)
141357b448deSdougm sa_free_fstype(fstype);
14146185db85Sdougm return (ret);
14156185db85Sdougm }
1416ecd6cf80Smarks
1417ecd6cf80Smarks int
sa_sharetab_fill_zfs(sa_share_t share,share_t * sh,char * proto)1418ecd6cf80Smarks sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
1419ecd6cf80Smarks {
1420ecd6cf80Smarks char *path;
1421ecd6cf80Smarks
1422ed78bdc4Smarks /* Make sure path is valid */
1423ed78bdc4Smarks
1424ecd6cf80Smarks path = sa_get_share_attr(share, "path");
1425ecd6cf80Smarks if (path != NULL) {
1426ecd6cf80Smarks (void) memset(sh, 0, sizeof (sh));
1427ecd6cf80Smarks (void) sa_fillshare(share, proto, sh);
1428ed78bdc4Smarks sa_free_attr_string(path);
1429ecd6cf80Smarks return (0);
1430ecd6cf80Smarks } else
1431ecd6cf80Smarks return (1);
1432ecd6cf80Smarks }
1433ecd6cf80Smarks
1434ecd6cf80Smarks #define SMAX(i, j) \
1435ecd6cf80Smarks if ((j) > (i)) { \
1436ecd6cf80Smarks (i) = (j); \
1437ecd6cf80Smarks }
1438ecd6cf80Smarks
1439ecd6cf80Smarks int
sa_share_zfs(sa_share_t share,sa_resource_t resource,char * path,share_t * sh,void * exportdata,zfs_share_op_t operation)1440743a77edSAlan Wright sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh,
1441da6c28aaSamw void *exportdata, zfs_share_op_t operation)
1442ecd6cf80Smarks {
1443ecd6cf80Smarks libzfs_handle_t *libhandle;
1444ecd6cf80Smarks sa_group_t group;
1445ecd6cf80Smarks sa_handle_t sahandle;
1446ecd6cf80Smarks char *dataset;
1447ecd6cf80Smarks int err = EINVAL;
1448ecd6cf80Smarks int i, j;
14494d79fe3bSmarks char newpath[MAXPATHLEN];
1450a1ef5d63Smarks char *pathp;
1451ecd6cf80Smarks
1452ecd6cf80Smarks /*
1453ecd6cf80Smarks * First find the dataset name
1454ecd6cf80Smarks */
1455ecd6cf80Smarks if ((group = sa_get_parent_group(share)) == NULL) {
1456a63214d6SBill Krier return (EINVAL);
1457ecd6cf80Smarks }
1458ecd6cf80Smarks if ((sahandle = sa_find_group_handle(group)) == NULL) {
1459a63214d6SBill Krier return (EINVAL);
1460ecd6cf80Smarks }
1461ecd6cf80Smarks
14624d79fe3bSmarks /*
14634d79fe3bSmarks * If get_zfs_dataset fails, see if it is a subdirectory
14644d79fe3bSmarks */
1465a1ef5d63Smarks
1466a1ef5d63Smarks pathp = path;
1467a1ef5d63Smarks while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) {
14684d79fe3bSmarks char *p;
14694d79fe3bSmarks
1470a1ef5d63Smarks if (pathp == path) {
1471a1ef5d63Smarks (void) strlcpy(newpath, path, sizeof (newpath));
1472a1ef5d63Smarks pathp = newpath;
1473a1ef5d63Smarks }
1474a1ef5d63Smarks
1475d34e4517SDoug McCallum /*
1476d34e4517SDoug McCallum * Make sure only one leading '/' This condition came
1477d34e4517SDoug McCallum * about when using HAStoragePlus which insisted on
1478d34e4517SDoug McCallum * putting an extra leading '/' in the ZFS path
1479d34e4517SDoug McCallum * name. The problem is fixed in other areas, but this
1480d34e4517SDoug McCallum * will catch any other ways that a double slash might
1481d34e4517SDoug McCallum * get introduced.
1482d34e4517SDoug McCallum */
1483d34e4517SDoug McCallum while (*pathp == '/' && *(pathp + 1) == '/')
1484d34e4517SDoug McCallum pathp++;
1485d34e4517SDoug McCallum
1486a1ef5d63Smarks /*
1487a1ef5d63Smarks * chop off part of path, but if we are at root then
1488a1ef5d63Smarks * make sure path is a /
1489a1ef5d63Smarks */
1490a1ef5d63Smarks if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) {
1491a1ef5d63Smarks if (pathp == p) {
1492a1ef5d63Smarks *(p + 1) = '\0'; /* skip over /, root case */
1493a1ef5d63Smarks } else {
1494a1ef5d63Smarks *p = '\0';
1495a1ef5d63Smarks }
1496a1ef5d63Smarks } else {
1497a63214d6SBill Krier return (EINVAL);
1498a1ef5d63Smarks }
1499ecd6cf80Smarks }
1500ecd6cf80Smarks
1501ecd6cf80Smarks libhandle = libzfs_init();
1502ecd6cf80Smarks if (libhandle != NULL) {
1503743a77edSAlan Wright char *resource_name;
1504ecd6cf80Smarks
1505ecd6cf80Smarks i = (sh->sh_path ? strlen(sh->sh_path) : 0);
1506ecd6cf80Smarks sh->sh_size = i;
1507ecd6cf80Smarks
1508ecd6cf80Smarks j = (sh->sh_res ? strlen(sh->sh_res) : 0);
1509ecd6cf80Smarks sh->sh_size += j;
1510ecd6cf80Smarks SMAX(i, j);
1511ecd6cf80Smarks
1512ecd6cf80Smarks j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0);
1513ecd6cf80Smarks sh->sh_size += j;
1514ecd6cf80Smarks SMAX(i, j);
1515ecd6cf80Smarks
1516ecd6cf80Smarks j = (sh->sh_opts ? strlen(sh->sh_opts) : 0);
1517ecd6cf80Smarks sh->sh_size += j;
1518ecd6cf80Smarks SMAX(i, j);
1519ecd6cf80Smarks
1520ecd6cf80Smarks j = (sh->sh_descr ? strlen(sh->sh_descr) : 0);
1521ecd6cf80Smarks sh->sh_size += j;
1522ecd6cf80Smarks SMAX(i, j);
1523743a77edSAlan Wright
1524743a77edSAlan Wright resource_name = sa_get_resource_attr(resource, "name");
1525743a77edSAlan Wright
1526ecd6cf80Smarks err = zfs_deleg_share_nfs(libhandle, dataset, path,
1527743a77edSAlan Wright resource_name, exportdata, sh, i, operation);
15285b6e0c46Sdougm if (err == SA_OK)
15295b6e0c46Sdougm sa_update_sharetab_ts(sahandle);
1530a63214d6SBill Krier else
1531a63214d6SBill Krier err = errno;
1532743a77edSAlan Wright if (resource_name)
1533743a77edSAlan Wright sa_free_attr_string(resource_name);
1534743a77edSAlan Wright
1535ecd6cf80Smarks libzfs_fini(libhandle);
1536ecd6cf80Smarks }
1537ecd6cf80Smarks free(dataset);
1538ecd6cf80Smarks return (err);
1539ecd6cf80Smarks }
15405b6e0c46Sdougm
15415b6e0c46Sdougm /*
15425b6e0c46Sdougm * sa_get_zfs_handle(handle)
15435b6e0c46Sdougm *
15445b6e0c46Sdougm * Given an sa_handle_t, return the libzfs_handle_t *. This is only
15455b6e0c46Sdougm * used internally by libzfs. Needed in order to avoid including
15465b6e0c46Sdougm * libshare_impl.h in libzfs.
15475b6e0c46Sdougm */
15485b6e0c46Sdougm
15495b6e0c46Sdougm libzfs_handle_t *
sa_get_zfs_handle(sa_handle_t handle)15505b6e0c46Sdougm sa_get_zfs_handle(sa_handle_t handle)
15515b6e0c46Sdougm {
15525b6e0c46Sdougm sa_handle_impl_t implhandle = (sa_handle_impl_t)handle;
15535b6e0c46Sdougm
15545b6e0c46Sdougm return (implhandle->zfs_libhandle);
15555b6e0c46Sdougm }
1556743a77edSAlan Wright
1557743a77edSAlan Wright /*
1558743a77edSAlan Wright * sa_get_zfs_info(libzfs, path, mountpoint, dataset)
1559743a77edSAlan Wright *
1560743a77edSAlan Wright * Find the ZFS dataset and mountpoint for a given path
1561743a77edSAlan Wright */
1562743a77edSAlan Wright int
sa_zfs_get_info(libzfs_handle_t * libzfs,char * path,char * mountpointp,char * datasetp)1563743a77edSAlan Wright sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp,
1564743a77edSAlan Wright char *datasetp)
1565743a77edSAlan Wright {
1566743a77edSAlan Wright get_all_cbdata_t cb = { 0 };
1567743a77edSAlan Wright int i;
1568743a77edSAlan Wright char mountpoint[ZFS_MAXPROPLEN];
1569743a77edSAlan Wright char dataset[ZFS_MAXPROPLEN];
1570743a77edSAlan Wright char canmount[ZFS_MAXPROPLEN];
1571743a77edSAlan Wright char *dp;
1572743a77edSAlan Wright int count;
1573743a77edSAlan Wright int ret = 0;
1574743a77edSAlan Wright
1575743a77edSAlan Wright cb.cb_types = ZFS_TYPE_FILESYSTEM;
1576743a77edSAlan Wright
1577743a77edSAlan Wright if (libzfs == NULL)
1578743a77edSAlan Wright return (0);
1579743a77edSAlan Wright
1580743a77edSAlan Wright (void) zfs_iter_root(libzfs, get_one_filesystem, &cb);
1581743a77edSAlan Wright count = cb.cb_used;
1582743a77edSAlan Wright
1583743a77edSAlan Wright qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare);
1584743a77edSAlan Wright for (i = 0; i < count; i++) {
1585743a77edSAlan Wright /* must have a mountpoint */
1586743a77edSAlan Wright if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT,
1587743a77edSAlan Wright mountpoint, sizeof (mountpoint),
1588743a77edSAlan Wright NULL, NULL, 0, B_FALSE) != 0) {
1589743a77edSAlan Wright /* no mountpoint */
1590743a77edSAlan Wright continue;
1591743a77edSAlan Wright }
1592743a77edSAlan Wright
1593743a77edSAlan Wright /* mountpoint must be a path */
1594743a77edSAlan Wright if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
1595743a77edSAlan Wright strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1596743a77edSAlan Wright /*
1597743a77edSAlan Wright * Search mmttab for mountpoint
1598743a77edSAlan Wright */
1599743a77edSAlan Wright
1600743a77edSAlan Wright if (get_legacy_mountpoint(path, dataset,
1601743a77edSAlan Wright ZFS_MAXPROPLEN, mountpoint,
1602743a77edSAlan Wright ZFS_MAXPROPLEN) == 0) {
1603743a77edSAlan Wright ret = 1;
1604743a77edSAlan Wright break;
1605743a77edSAlan Wright }
1606743a77edSAlan Wright continue;
1607743a77edSAlan Wright }
1608743a77edSAlan Wright
1609743a77edSAlan Wright /* canmount must be set */
1610743a77edSAlan Wright canmount[0] = '\0';
1611743a77edSAlan Wright if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount,
1612743a77edSAlan Wright sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
1613743a77edSAlan Wright strcmp(canmount, "off") == 0)
1614743a77edSAlan Wright continue;
1615743a77edSAlan Wright
1616743a77edSAlan Wright /*
1617743a77edSAlan Wright * have a mountable handle but want to skip those marked none
1618743a77edSAlan Wright * and legacy
1619743a77edSAlan Wright */
1620743a77edSAlan Wright if (strcmp(mountpoint, path) == 0) {
1621743a77edSAlan Wright dp = (char *)zfs_get_name(cb.cb_handles[i]);
1622743a77edSAlan Wright if (dp != NULL) {
1623743a77edSAlan Wright if (datasetp != NULL)
1624743a77edSAlan Wright (void) strcpy(datasetp, dp);
1625743a77edSAlan Wright if (mountpointp != NULL)
1626743a77edSAlan Wright (void) strcpy(mountpointp, mountpoint);
1627743a77edSAlan Wright ret = 1;
1628743a77edSAlan Wright }
1629743a77edSAlan Wright break;
1630743a77edSAlan Wright }
1631743a77edSAlan Wright
1632743a77edSAlan Wright }
1633743a77edSAlan Wright
1634743a77edSAlan Wright return (ret);
1635743a77edSAlan Wright }
1636148c5f43SAlan Wright
1637148c5f43SAlan Wright /*
1638148c5f43SAlan Wright * This method builds values for "sharesmb" property from the
1639148c5f43SAlan Wright * nvlist argument. The values are returned in sharesmb_val variable.
1640148c5f43SAlan Wright */
1641148c5f43SAlan Wright static int
sa_zfs_sprintf_new_prop(nvlist_t * nvl,char * sharesmb_val)1642148c5f43SAlan Wright sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val)
1643148c5f43SAlan Wright {
1644148c5f43SAlan Wright char cur_val[MAXPATHLEN];
1645148c5f43SAlan Wright char *name, *val;
1646148c5f43SAlan Wright nvpair_t *cur;
1647148c5f43SAlan Wright int err = 0;
1648148c5f43SAlan Wright
1649148c5f43SAlan Wright cur = nvlist_next_nvpair(nvl, NULL);
1650148c5f43SAlan Wright while (cur != NULL) {
1651148c5f43SAlan Wright name = nvpair_name(cur);
1652148c5f43SAlan Wright err = nvpair_value_string(cur, &val);
1653148c5f43SAlan Wright if ((err != 0) || (name == NULL) || (val == NULL))
1654148c5f43SAlan Wright return (-1);
1655148c5f43SAlan Wright
1656148c5f43SAlan Wright (void) snprintf(cur_val, MAXPATHLEN, "%s=%s,", name, val);
1657148c5f43SAlan Wright (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN);
1658148c5f43SAlan Wright
1659148c5f43SAlan Wright cur = nvlist_next_nvpair(nvl, cur);
1660148c5f43SAlan Wright }
1661148c5f43SAlan Wright
1662148c5f43SAlan Wright return (0);
1663148c5f43SAlan Wright }
1664148c5f43SAlan Wright
1665148c5f43SAlan Wright /*
1666148c5f43SAlan Wright * This method builds values for "sharesmb" property from values
1667148c5f43SAlan Wright * already existing on the share. The properties set via sa_zfs_sprint_new_prop
1668148c5f43SAlan Wright * method are passed in sharesmb_val. If a existing property is already
1669148c5f43SAlan Wright * set via sa_zfs_sprint_new_prop method, then they are not appended
1670148c5f43SAlan Wright * to the sharesmb_val string. The returned sharesmb_val string is a combination
1671148c5f43SAlan Wright * of new and existing values for 'sharesmb' property.
1672148c5f43SAlan Wright */
1673148c5f43SAlan Wright static int
sa_zfs_sprintf_existing_prop(zfs_handle_t * handle,char * sharesmb_val)1674148c5f43SAlan Wright sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val)
1675148c5f43SAlan Wright {
1676148c5f43SAlan Wright char shareopts[ZFS_MAXPROPLEN], cur_val[MAXPATHLEN];
1677148c5f43SAlan Wright char *token, *last, *value;
1678148c5f43SAlan Wright
1679148c5f43SAlan Wright if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts,
1680148c5f43SAlan Wright sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0)
1681148c5f43SAlan Wright return (-1);
1682148c5f43SAlan Wright
1683148c5f43SAlan Wright if (strstr(shareopts, "=") == NULL)
1684148c5f43SAlan Wright return (0);
1685148c5f43SAlan Wright
1686148c5f43SAlan Wright for (token = strtok_r(shareopts, ",", &last); token != NULL;
1687148c5f43SAlan Wright token = strtok_r(NULL, ",", &last)) {
1688148c5f43SAlan Wright value = strchr(token, '=');
1689148c5f43SAlan Wright if (value == NULL)
1690148c5f43SAlan Wright return (-1);
1691148c5f43SAlan Wright *value++ = '\0';
1692148c5f43SAlan Wright
1693148c5f43SAlan Wright (void) snprintf(cur_val, MAXPATHLEN, "%s=", token);
1694148c5f43SAlan Wright if (strstr(sharesmb_val, cur_val) == NULL) {
1695148c5f43SAlan Wright (void) strlcat(cur_val, value, MAXPATHLEN);
1696148c5f43SAlan Wright (void) strlcat(cur_val, ",", MAXPATHLEN);
1697148c5f43SAlan Wright (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN);
1698148c5f43SAlan Wright }
1699148c5f43SAlan Wright }
1700148c5f43SAlan Wright
1701148c5f43SAlan Wright return (0);
1702148c5f43SAlan Wright }
1703148c5f43SAlan Wright
1704148c5f43SAlan Wright /*
1705148c5f43SAlan Wright * Sets the share properties on a ZFS share. For now, this method sets only
1706148c5f43SAlan Wright * the "sharesmb" property.
1707148c5f43SAlan Wright *
1708148c5f43SAlan Wright * This method includes building a comma seperated name-value string to be
1709148c5f43SAlan Wright * set on the "sharesmb" property of a ZFS share. This name-value string is
1710148c5f43SAlan Wright * build in 2 steps:
1711148c5f43SAlan Wright * - New property values given as name-value pair are set first.
1712148c5f43SAlan Wright * - Existing optionset properties, which are not part of the new properties
1713148c5f43SAlan Wright * passed in step 1, are appended to the newly set properties.
1714148c5f43SAlan Wright */
1715148c5f43SAlan Wright int
sa_zfs_setprop(sa_handle_t handle,char * path,nvlist_t * nvl)1716148c5f43SAlan Wright sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl)
1717148c5f43SAlan Wright {
1718148c5f43SAlan Wright zfs_handle_t *z_fs;
1719148c5f43SAlan Wright libzfs_handle_t *z_lib;
1720148c5f43SAlan Wright char sharesmb_val[MAXPATHLEN];
1721148c5f43SAlan Wright char *dataset, *lastcomma;
1722148c5f43SAlan Wright
1723148c5f43SAlan Wright if (nvlist_empty(nvl))
1724148c5f43SAlan Wright return (0);
1725148c5f43SAlan Wright
1726148c5f43SAlan Wright if ((handle == NULL) || (path == NULL))
1727148c5f43SAlan Wright return (-1);
1728148c5f43SAlan Wright
1729148c5f43SAlan Wright if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL)
1730148c5f43SAlan Wright return (-1);
1731148c5f43SAlan Wright
1732148c5f43SAlan Wright if ((z_lib = libzfs_init()) == NULL) {
1733148c5f43SAlan Wright free(dataset);
1734148c5f43SAlan Wright return (-1);
1735148c5f43SAlan Wright }
1736148c5f43SAlan Wright
1737148c5f43SAlan Wright z_fs = zfs_open(z_lib, dataset, ZFS_TYPE_DATASET);
1738148c5f43SAlan Wright if (z_fs == NULL) {
1739148c5f43SAlan Wright free(dataset);
1740148c5f43SAlan Wright libzfs_fini(z_lib);
1741148c5f43SAlan Wright return (-1);
1742148c5f43SAlan Wright }
1743148c5f43SAlan Wright
1744148c5f43SAlan Wright bzero(sharesmb_val, MAXPATHLEN);
1745148c5f43SAlan Wright if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) {
1746148c5f43SAlan Wright free(dataset);
1747148c5f43SAlan Wright zfs_close(z_fs);
1748148c5f43SAlan Wright libzfs_fini(z_lib);
1749148c5f43SAlan Wright return (-1);
1750148c5f43SAlan Wright }
1751148c5f43SAlan Wright
1752148c5f43SAlan Wright if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) {
1753148c5f43SAlan Wright free(dataset);
1754148c5f43SAlan Wright zfs_close(z_fs);
1755148c5f43SAlan Wright libzfs_fini(z_lib);
1756148c5f43SAlan Wright return (-1);
1757148c5f43SAlan Wright }
1758148c5f43SAlan Wright
1759148c5f43SAlan Wright lastcomma = strrchr(sharesmb_val, ',');
1760148c5f43SAlan Wright if ((lastcomma != NULL) && (lastcomma[1] == '\0'))
1761148c5f43SAlan Wright *lastcomma = '\0';
1762148c5f43SAlan Wright
1763148c5f43SAlan Wright (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB),
1764148c5f43SAlan Wright sharesmb_val);
1765148c5f43SAlan Wright free(dataset);
1766148c5f43SAlan Wright zfs_close(z_fs);
1767148c5f43SAlan Wright libzfs_fini(z_lib);
1768148c5f43SAlan Wright
1769148c5f43SAlan Wright return (0);
1770148c5f43SAlan Wright }
1771