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 /* 23*148c5f43SAlan Wright * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 246185db85Sdougm */ 256185db85Sdougm 26a1ef5d63Smarks #include <stdio.h> 276185db85Sdougm #include <libzfs.h> 286185db85Sdougm #include <string.h> 29a3351425Sdougm #include <strings.h> 30a63214d6SBill Krier #include <errno.h> 316185db85Sdougm #include <libshare.h> 326185db85Sdougm #include "libshare_impl.h" 331cea05afSdougm #include <libintl.h> 34a1ef5d63Smarks #include <sys/mnttab.h> 35a1ef5d63Smarks #include <sys/mntent.h> 366185db85Sdougm 37da6c28aaSamw extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 386185db85Sdougm extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 396185db85Sdougm extern char *sa_fstype(char *); 406185db85Sdougm extern void set_node_attr(void *, char *, char *); 416185db85Sdougm extern int sa_is_share(void *); 425b6e0c46Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 431cea05afSdougm 441cea05afSdougm /* 451cea05afSdougm * File system specific code for ZFS. The original code was stolen 461cea05afSdougm * from the "zfs" command and modified to better suit this library's 471cea05afSdougm * usage. 481cea05afSdougm */ 491cea05afSdougm 501cea05afSdougm typedef struct get_all_cbdata { 511cea05afSdougm zfs_handle_t **cb_handles; 521cea05afSdougm size_t cb_alloc; 531cea05afSdougm size_t cb_used; 54a3351425Sdougm uint_t cb_types; 551cea05afSdougm } get_all_cbdata_t; 561cea05afSdougm 571cea05afSdougm /* 58549ec3ffSdougm * sa_zfs_init(impl_handle) 591cea05afSdougm * 60549ec3ffSdougm * Initialize an access handle into libzfs. The handle needs to stay 61549ec3ffSdougm * around until sa_zfs_fini() in order to maintain the cache of 62549ec3ffSdougm * mounts. 631cea05afSdougm */ 641cea05afSdougm 6557b448deSdougm int 66549ec3ffSdougm sa_zfs_init(sa_handle_impl_t impl_handle) 671cea05afSdougm { 68549ec3ffSdougm impl_handle->zfs_libhandle = libzfs_init(); 6957b448deSdougm if (impl_handle->zfs_libhandle != NULL) { 7057b448deSdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 7157b448deSdougm return (B_TRUE); 7257b448deSdougm } 7357b448deSdougm return (B_FALSE); 741cea05afSdougm } 751cea05afSdougm 761cea05afSdougm /* 77549ec3ffSdougm * sa_zfs_fini(impl_handle) 781cea05afSdougm * 791cea05afSdougm * cleanup data structures and the libzfs handle used for accessing 801cea05afSdougm * zfs file share info. 811cea05afSdougm */ 821cea05afSdougm 831cea05afSdougm void 84549ec3ffSdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 851cea05afSdougm { 86549ec3ffSdougm if (impl_handle->zfs_libhandle != NULL) { 8757b448deSdougm if (impl_handle->zfs_list != NULL) { 88a3351425Sdougm zfs_handle_t **zhp = impl_handle->zfs_list; 89a3351425Sdougm size_t i; 90a3351425Sdougm 9157b448deSdougm /* 92a3351425Sdougm * Contents of zfs_list need to be freed so we 93a3351425Sdougm * don't lose ZFS handles. 9457b448deSdougm */ 95a3351425Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) { 96a3351425Sdougm zfs_close(zhp[i]); 97a3351425Sdougm } 9857b448deSdougm free(impl_handle->zfs_list); 9957b448deSdougm impl_handle->zfs_list = NULL; 10057b448deSdougm impl_handle->zfs_list_count = 0; 10157b448deSdougm } 102a3351425Sdougm 103a3351425Sdougm libzfs_fini(impl_handle->zfs_libhandle); 104a3351425Sdougm impl_handle->zfs_libhandle = NULL; 1051cea05afSdougm } 1061cea05afSdougm } 1071cea05afSdougm 1081cea05afSdougm /* 1091cea05afSdougm * get_one_filesystem(zfs_handle_t, data) 1101cea05afSdougm * 111da6c28aaSamw * an iterator function called while iterating through the ZFS 1121cea05afSdougm * root. It accumulates into an array of file system handles that can 1131cea05afSdougm * be used to derive info about those file systems. 114a3351425Sdougm * 115a3351425Sdougm * Note that as this function is called, we close all zhp handles that 116a3351425Sdougm * are not going to be places into the cp_handles list. We don't want 117a3351425Sdougm * to close the ones we are keeping, but all others would be leaked if 118a3351425Sdougm * not closed here. 1191cea05afSdougm */ 1201cea05afSdougm 1211cea05afSdougm static int 1221cea05afSdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1231cea05afSdougm { 1241cea05afSdougm get_all_cbdata_t *cbp = data; 125a3351425Sdougm zfs_type_t type = zfs_get_type(zhp); 1261cea05afSdougm 1271cea05afSdougm /* 128a3351425Sdougm * Interate over any nested datasets. 1291cea05afSdougm */ 130a3351425Sdougm if (type == ZFS_TYPE_FILESYSTEM && 131a3351425Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 132a3351425Sdougm zfs_close(zhp); 133a3351425Sdougm return (1); 134a3351425Sdougm } 135a3351425Sdougm 136a3351425Sdougm /* 137a3351425Sdougm * Skip any datasets whose type does not match. 138a3351425Sdougm */ 139a3351425Sdougm if ((type & cbp->cb_types) == 0) { 1401cea05afSdougm zfs_close(zhp); 1411cea05afSdougm return (0); 1421cea05afSdougm } 1431cea05afSdougm 1441cea05afSdougm if (cbp->cb_alloc == cbp->cb_used) { 1451cea05afSdougm zfs_handle_t **handles; 1461cea05afSdougm 1471cea05afSdougm if (cbp->cb_alloc == 0) 1481cea05afSdougm cbp->cb_alloc = 64; 1491cea05afSdougm else 1501cea05afSdougm cbp->cb_alloc *= 2; 1511cea05afSdougm 152a3351425Sdougm handles = (zfs_handle_t **)calloc(1, 153a3351425Sdougm cbp->cb_alloc * sizeof (void *)); 154a3351425Sdougm 1551cea05afSdougm if (handles == NULL) { 156a3351425Sdougm zfs_close(zhp); 15757b448deSdougm return (0); 1581cea05afSdougm } 1591cea05afSdougm if (cbp->cb_handles) { 160a3351425Sdougm bcopy(cbp->cb_handles, handles, 1611cea05afSdougm cbp->cb_used * sizeof (void *)); 1621cea05afSdougm free(cbp->cb_handles); 1631cea05afSdougm } 1641cea05afSdougm 1651cea05afSdougm cbp->cb_handles = handles; 1661cea05afSdougm } 1671cea05afSdougm 1681cea05afSdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1691cea05afSdougm 170a3351425Sdougm return (0); 1711cea05afSdougm } 1721cea05afSdougm 1731cea05afSdougm /* 1741cea05afSdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1751cea05afSdougm * 1761cea05afSdougm * iterate through all ZFS file systems starting at the root. Returns 1771cea05afSdougm * a count and an array of handle pointers. Allocating is only done 1781cea05afSdougm * once. The caller does not need to free since it will be done at 1791cea05afSdougm * sa_zfs_fini() time. 1801cea05afSdougm */ 1811cea05afSdougm 1821cea05afSdougm static void 183549ec3ffSdougm get_all_filesystems(sa_handle_impl_t impl_handle, 184549ec3ffSdougm zfs_handle_t ***fslist, size_t *count) 1851cea05afSdougm { 1861cea05afSdougm get_all_cbdata_t cb = { 0 }; 187a3351425Sdougm cb.cb_types = ZFS_TYPE_FILESYSTEM; 1881cea05afSdougm 189549ec3ffSdougm if (impl_handle->zfs_list != NULL) { 19057b448deSdougm *fslist = impl_handle->zfs_list; 19157b448deSdougm *count = impl_handle->zfs_list_count; 19257b448deSdougm return; 1931cea05afSdougm } 1941cea05afSdougm 195549ec3ffSdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 19657b448deSdougm get_one_filesystem, &cb); 1971cea05afSdougm 198549ec3ffSdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 199549ec3ffSdougm impl_handle->zfs_list_count = *count = cb.cb_used; 2001cea05afSdougm } 2011cea05afSdougm 2026185db85Sdougm /* 2031cea05afSdougm * mountpoint_compare(a, b) 2041cea05afSdougm * 2051cea05afSdougm * compares the mountpoint on two zfs file systems handles. 2061cea05afSdougm * returns values following strcmp() model. 2076185db85Sdougm */ 2086185db85Sdougm 2091cea05afSdougm static int 2101cea05afSdougm mountpoint_compare(const void *a, const void *b) 2111cea05afSdougm { 2121cea05afSdougm zfs_handle_t **za = (zfs_handle_t **)a; 2131cea05afSdougm zfs_handle_t **zb = (zfs_handle_t **)b; 2141cea05afSdougm char mounta[MAXPATHLEN]; 2151cea05afSdougm char mountb[MAXPATHLEN]; 2161cea05afSdougm 2171cea05afSdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2181cea05afSdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2191cea05afSdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2201cea05afSdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2211cea05afSdougm 2221cea05afSdougm return (strcmp(mounta, mountb)); 2231cea05afSdougm } 2241cea05afSdougm 225a1ef5d63Smarks /* 226743a77edSAlan Wright * return legacy mountpoint. Caller provides space for mountpoint and 227743a77edSAlan Wright * dataset. 228a1ef5d63Smarks */ 229a1ef5d63Smarks int 230743a77edSAlan Wright get_legacy_mountpoint(char *path, char *dataset, size_t dlen, 231743a77edSAlan Wright char *mountpoint, size_t mlen) 232a1ef5d63Smarks { 233a1ef5d63Smarks FILE *fp; 234a1ef5d63Smarks struct mnttab entry; 235a1ef5d63Smarks 236a1ef5d63Smarks if ((fp = fopen(MNTTAB, "r")) == NULL) { 237a1ef5d63Smarks return (1); 238a1ef5d63Smarks } 239a1ef5d63Smarks 240a1ef5d63Smarks while (getmntent(fp, &entry) == 0) { 241a1ef5d63Smarks 242a1ef5d63Smarks if (entry.mnt_fstype == NULL || 243a1ef5d63Smarks strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 244a1ef5d63Smarks continue; 245a1ef5d63Smarks 246a1ef5d63Smarks if (strcmp(entry.mnt_mountp, path) == 0) { 247743a77edSAlan Wright if (mlen > 0) 248743a77edSAlan Wright (void) strlcpy(mountpoint, entry.mnt_mountp, 249743a77edSAlan Wright mlen); 250743a77edSAlan Wright if (dlen > 0) 251743a77edSAlan Wright (void) strlcpy(dataset, entry.mnt_special, 252743a77edSAlan Wright dlen); 253743a77edSAlan Wright break; 254a1ef5d63Smarks } 255a1ef5d63Smarks } 256a1ef5d63Smarks (void) fclose(fp); 257a1ef5d63Smarks return (1); 258a1ef5d63Smarks } 259a1ef5d63Smarks 2606185db85Sdougm /* 261549ec3ffSdougm * get_zfs_dataset(impl_handle, path) 2626185db85Sdougm * 2636185db85Sdougm * get the name of the ZFS dataset the path is equivalent to. The 2646185db85Sdougm * dataset name is used for get/set of ZFS properties since libzfs 2656185db85Sdougm * requires a dataset to do a zfs_open(). 2666185db85Sdougm */ 2676185db85Sdougm 2686185db85Sdougm static char * 269a1ef5d63Smarks get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 270a1ef5d63Smarks boolean_t search_mnttab) 2716185db85Sdougm { 2721cea05afSdougm size_t i, count = 0; 2736185db85Sdougm char *dataset = NULL; 2741cea05afSdougm zfs_handle_t **zlist; 2751cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 27667331909Sdougm char canmount[ZFS_MAXPROPLEN]; 2776185db85Sdougm 278549ec3ffSdougm get_all_filesystems(impl_handle, &zlist, &count); 2791cea05afSdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2801cea05afSdougm for (i = 0; i < count; i++) { 28157b448deSdougm /* must have a mountpoint */ 28257b448deSdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 28357b448deSdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 28457b448deSdougm /* no mountpoint */ 28557b448deSdougm continue; 28657b448deSdougm } 28757b448deSdougm 28857b448deSdougm /* mountpoint must be a path */ 28957b448deSdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 290a1ef5d63Smarks strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 291a1ef5d63Smarks /* 292743a77edSAlan Wright * Search mmttab for mountpoint and get dataset. 293a1ef5d63Smarks */ 294a1ef5d63Smarks 295a1ef5d63Smarks if (search_mnttab == B_TRUE && 296a1ef5d63Smarks get_legacy_mountpoint(path, mountpoint, 297743a77edSAlan Wright sizeof (mountpoint), NULL, 0) == 0) { 298a1ef5d63Smarks dataset = mountpoint; 299a1ef5d63Smarks break; 300a1ef5d63Smarks } 30157b448deSdougm continue; 302a1ef5d63Smarks } 30357b448deSdougm 30457b448deSdougm /* canmount must be set */ 30557b448deSdougm canmount[0] = '\0'; 306ecd6cf80Smarks if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 30767331909Sdougm sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 30857b448deSdougm strcmp(canmount, "off") == 0) 30957b448deSdougm continue; 3101cea05afSdougm 31157b448deSdougm /* 31257b448deSdougm * have a mountable handle but want to skip those marked none 31357b448deSdougm * and legacy 31457b448deSdougm */ 31557b448deSdougm if (strcmp(mountpoint, path) == 0) { 31657b448deSdougm dataset = (char *)zfs_get_name(zlist[i]); 31757b448deSdougm break; 31857b448deSdougm } 3191cea05afSdougm 3206185db85Sdougm } 3211cea05afSdougm 32257b448deSdougm if (dataset != NULL) 32357b448deSdougm dataset = strdup(dataset); 32457b448deSdougm 3256185db85Sdougm return (dataset); 3266185db85Sdougm } 3276185db85Sdougm 3286185db85Sdougm /* 3296185db85Sdougm * get_zfs_property(dataset, property) 3306185db85Sdougm * 3316185db85Sdougm * Get the file system property specified from the ZFS dataset. 3326185db85Sdougm */ 3336185db85Sdougm 3346185db85Sdougm static char * 3356185db85Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 3366185db85Sdougm { 3376185db85Sdougm zfs_handle_t *handle = NULL; 3386185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3396185db85Sdougm libzfs_handle_t *libhandle; 3406185db85Sdougm 3416185db85Sdougm libhandle = libzfs_init(); 3426185db85Sdougm if (libhandle != NULL) { 34357b448deSdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 34457b448deSdougm if (handle != NULL) { 34557b448deSdougm if (zfs_prop_get(handle, property, shareopts, 34657b448deSdougm sizeof (shareopts), NULL, NULL, 0, 34757b448deSdougm B_FALSE) == 0) { 34857b448deSdougm zfs_close(handle); 34957b448deSdougm libzfs_fini(libhandle); 35057b448deSdougm return (strdup(shareopts)); 35157b448deSdougm } 35257b448deSdougm zfs_close(handle); 3536185db85Sdougm } 35457b448deSdougm libzfs_fini(libhandle); 3556185db85Sdougm } 3566185db85Sdougm return (NULL); 3576185db85Sdougm } 3586185db85Sdougm 3596185db85Sdougm /* 360549ec3ffSdougm * sa_zfs_is_shared(handle, path) 3616185db85Sdougm * 3626185db85Sdougm * Check to see if the ZFS path provided has the sharenfs option set 3636185db85Sdougm * or not. 3646185db85Sdougm */ 3656185db85Sdougm 3666185db85Sdougm int 367549ec3ffSdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 3686185db85Sdougm { 3696185db85Sdougm int ret = 0; 3706185db85Sdougm char *dataset; 3716185db85Sdougm zfs_handle_t *handle = NULL; 3726185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3736185db85Sdougm libzfs_handle_t *libhandle; 3746185db85Sdougm 375a1ef5d63Smarks dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 3766185db85Sdougm if (dataset != NULL) { 37757b448deSdougm libhandle = libzfs_init(); 37857b448deSdougm if (libhandle != NULL) { 37957b448deSdougm handle = zfs_open(libhandle, dataset, 38057b448deSdougm ZFS_TYPE_FILESYSTEM); 38157b448deSdougm if (handle != NULL) { 38257b448deSdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 38357b448deSdougm shareopts, sizeof (shareopts), NULL, NULL, 38457b448deSdougm 0, B_FALSE) == 0 && 38557b448deSdougm strcmp(shareopts, "off") != 0) { 38657b448deSdougm ret = 1; /* it is shared */ 38757b448deSdougm } 38857b448deSdougm zfs_close(handle); 38957b448deSdougm } 39057b448deSdougm libzfs_fini(libhandle); 3916185db85Sdougm } 39257b448deSdougm free(dataset); 3936185db85Sdougm } 3946185db85Sdougm return (ret); 3956185db85Sdougm } 3966185db85Sdougm 3976185db85Sdougm /* 398da6c28aaSamw * find_or_create_group(handle, groupname, proto, *err) 3996185db85Sdougm * 4006185db85Sdougm * While walking the ZFS tree, we need to add shares to a defined 4016185db85Sdougm * group. If the group doesn't exist, create it first, making sure it 4026185db85Sdougm * is marked as a ZFS group. 4036185db85Sdougm * 40493a6f655Sdougm * Note that all ZFS shares are in a subgroup of the top level group 40593a6f655Sdougm * called "zfs". 4066185db85Sdougm */ 4076185db85Sdougm 4086185db85Sdougm static sa_group_t 409549ec3ffSdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 4106185db85Sdougm { 4116185db85Sdougm sa_group_t group; 4126185db85Sdougm sa_optionset_t optionset; 4136185db85Sdougm int ret = SA_OK; 4146185db85Sdougm 4156185db85Sdougm /* 4166185db85Sdougm * we check to see if the "zfs" group exists. Since this 4176185db85Sdougm * should be the top level group, we don't want the 4186185db85Sdougm * parent. This is to make sure the zfs group has been created 4196185db85Sdougm * and to created if it hasn't been. 4206185db85Sdougm */ 421549ec3ffSdougm group = sa_get_group(handle, groupname); 4226185db85Sdougm if (group == NULL) { 42357b448deSdougm group = sa_create_group(handle, groupname, &ret); 42493a6f655Sdougm 42557b448deSdougm /* make sure this is flagged as a ZFS group */ 42657b448deSdougm if (group != NULL) 42757b448deSdougm ret = sa_set_group_attr(group, "zfs", "true"); 4286185db85Sdougm } 4296185db85Sdougm if (group != NULL) { 43057b448deSdougm if (proto != NULL) { 43157b448deSdougm optionset = sa_get_optionset(group, proto); 432da6c28aaSamw if (optionset == NULL) 43357b448deSdougm optionset = sa_create_optionset(group, proto); 4346185db85Sdougm } 4356185db85Sdougm } 4366185db85Sdougm if (err != NULL) 43757b448deSdougm *err = ret; 4386185db85Sdougm return (group); 4396185db85Sdougm } 4406185db85Sdougm 44193a6f655Sdougm /* 44293a6f655Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 44393a6f655Sdougm * 44493a6f655Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 44593a6f655Sdougm * function looks to see if the groupname exists and returns it if it 44693a6f655Sdougm * does or else creates a new one with the specified name and returns 44793a6f655Sdougm * that. The "zfs" group will exist before we get here, but we make 44893a6f655Sdougm * sure just in case. 44993a6f655Sdougm * 45093a6f655Sdougm * err must be a valid pointer. 45193a6f655Sdougm */ 45293a6f655Sdougm 45393a6f655Sdougm static sa_group_t 454da6c28aaSamw find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 455da6c28aaSamw char *optstring, int *err) 45693a6f655Sdougm { 45793a6f655Sdougm sa_group_t group = NULL; 45893a6f655Sdougm sa_group_t zfs; 45993a6f655Sdougm char *name; 46093a6f655Sdougm char *options; 46193a6f655Sdougm 46293a6f655Sdougm /* start with the top-level "zfs" group */ 463549ec3ffSdougm zfs = sa_get_group(handle, "zfs"); 46493a6f655Sdougm *err = SA_OK; 46593a6f655Sdougm if (zfs != NULL) { 46657b448deSdougm for (group = sa_get_sub_group(zfs); group != NULL; 46757b448deSdougm group = sa_get_next_group(group)) { 46857b448deSdougm name = sa_get_group_attr(group, "name"); 46957b448deSdougm if (name != NULL && strcmp(name, groupname) == 0) { 47057b448deSdougm /* have the group so break out of here */ 47157b448deSdougm sa_free_attr_string(name); 47257b448deSdougm break; 47357b448deSdougm } 47457b448deSdougm if (name != NULL) 47557b448deSdougm sa_free_attr_string(name); 47693a6f655Sdougm } 47757b448deSdougm 47857b448deSdougm if (group == NULL) { 47957b448deSdougm /* 4803c484793Sdougm * Need to create the sub-group since it doesn't exist 48157b448deSdougm */ 48257b448deSdougm group = _sa_create_zfs_group(zfs, groupname); 4833c484793Sdougm if (group == NULL) { 4843c484793Sdougm *err = SA_NO_MEMORY; 4853c484793Sdougm return (NULL); 48657b448deSdougm } 4873c484793Sdougm set_node_attr(group, "zfs", "true"); 4883c484793Sdougm } 4893c484793Sdougm if (strcmp(optstring, "on") == 0) 4903c484793Sdougm optstring = "rw"; 4913c484793Sdougm options = strdup(optstring); 4923c484793Sdougm if (options != NULL) { 4933c484793Sdougm *err = sa_parse_legacy_options(group, options, 4943c484793Sdougm proto); 4953c484793Sdougm /* If no optionset, add one. */ 4963c484793Sdougm if (sa_get_optionset(group, proto) == NULL) 4973c484793Sdougm (void) sa_create_optionset(group, proto); 4983c484793Sdougm free(options); 4993c484793Sdougm } else { 5003c484793Sdougm *err = SA_NO_MEMORY; 50193a6f655Sdougm } 50293a6f655Sdougm } 50393a6f655Sdougm return (group); 50493a6f655Sdougm } 50593a6f655Sdougm 506da6c28aaSamw /* 507da6c28aaSamw * zfs_construct_resource(share, name, base, dataset) 508da6c28aaSamw * 509da6c28aaSamw * Add a resource to the share using name as a template. If name == 510da6c28aaSamw * NULL, then construct a name based on the dataset value. 511da6c28aaSamw * name. 512da6c28aaSamw */ 513da6c28aaSamw static void 514da6c28aaSamw zfs_construct_resource(sa_share_t share, char *dataset) 515da6c28aaSamw { 516da6c28aaSamw char buff[SA_MAX_RESOURCE_NAME + 1]; 517da6c28aaSamw int ret = SA_OK; 518da6c28aaSamw 519da6c28aaSamw (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset); 520da6c28aaSamw sa_fix_resource_name(buff); 521da6c28aaSamw (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret); 522da6c28aaSamw } 523da6c28aaSamw 52457b448deSdougm /* 52557b448deSdougm * zfs_inherited(handle, source, sourcestr) 52657b448deSdougm * 527da6c28aaSamw * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares 52857b448deSdougm * for readability. 52957b448deSdougm */ 53057b448deSdougm static int 53157b448deSdougm zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 532da6c28aaSamw char *shareopts, char *mountpoint, char *proto, char *dataset) 53357b448deSdougm { 53457b448deSdougm int doshopt = 0; 53557b448deSdougm int err = SA_OK; 53657b448deSdougm sa_group_t group; 537da6c28aaSamw sa_resource_t resource; 538da6c28aaSamw uint64_t features; 53957b448deSdougm 54057b448deSdougm /* 54157b448deSdougm * Need to find the "real" parent sub-group. It may not be 54257b448deSdougm * mounted, but it was identified in the "sourcestr" 54357b448deSdougm * variable. The real parent not mounted can occur if 54457b448deSdougm * "canmount=off and sharenfs=on". 54557b448deSdougm */ 546da6c28aaSamw group = find_or_create_zfs_subgroup(handle, sourcestr, proto, 547da6c28aaSamw shareopts, &doshopt); 54857b448deSdougm if (group != NULL) { 549da6c28aaSamw /* 550da6c28aaSamw * We may need the first share for resource 551da6c28aaSamw * prototype. We only care about it if it has a 552da6c28aaSamw * resource that sets a prefix value. 553da6c28aaSamw */ 554da6c28aaSamw if (share == NULL) 555da6c28aaSamw share = _sa_add_share(group, mountpoint, 556da6c28aaSamw SA_SHARE_TRANSIENT, &err, 557da6c28aaSamw (uint64_t)SA_FEATURE_NONE); 55857b448deSdougm /* 55957b448deSdougm * some options may only be on shares. If the opt 56057b448deSdougm * string contains one of those, we put it just on the 56157b448deSdougm * share. 56257b448deSdougm */ 56357b448deSdougm if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 56457b448deSdougm char *options; 56557b448deSdougm options = strdup(shareopts); 56657b448deSdougm if (options != NULL) { 567da6c28aaSamw set_node_attr(share, "dataset", dataset); 56857b448deSdougm err = sa_parse_legacy_options(share, options, 569da6c28aaSamw proto); 570da6c28aaSamw set_node_attr(share, "dataset", NULL); 57157b448deSdougm free(options); 57257b448deSdougm } 573da6c28aaSamw if (sa_get_optionset(group, proto) == NULL) 574da6c28aaSamw (void) sa_create_optionset(group, proto); 575da6c28aaSamw } 576da6c28aaSamw features = sa_proto_get_featureset(proto); 577da6c28aaSamw if (share != NULL && features & SA_FEATURE_RESOURCE) { 578da6c28aaSamw /* 579da6c28aaSamw * We have a share and the protocol requires 580da6c28aaSamw * that at least one resource exist (probably 581da6c28aaSamw * SMB). We need to make sure that there is at 582da6c28aaSamw * least one. 583da6c28aaSamw */ 584da6c28aaSamw resource = sa_get_share_resource(share, NULL); 585da6c28aaSamw if (resource == NULL) { 586da6c28aaSamw zfs_construct_resource(share, dataset); 587da6c28aaSamw } 58857b448deSdougm } 58957b448deSdougm } else { 59057b448deSdougm err = SA_NO_MEMORY; 59157b448deSdougm } 59257b448deSdougm return (err); 59357b448deSdougm } 59457b448deSdougm 59557b448deSdougm /* 59697df5ac9Sdougm * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset, 59797df5ac9Sdougm * grouperr) 59857b448deSdougm * 59957b448deSdougm * handle case where this is the top of a sub-group in ZFS. Pulled out 60097df5ac9Sdougm * of sa_get_zfs_shares for readability. We need the grouperr from the 60197df5ac9Sdougm * creation of the subgroup to know whether to add the public 60297df5ac9Sdougm * property, etc. to the specific share. 60357b448deSdougm */ 60457b448deSdougm static int 605da6c28aaSamw zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 60697df5ac9Sdougm char *shareopts, char *proto, char *dataset, int grouperr) 60757b448deSdougm { 60857b448deSdougm int err = SA_OK; 609da6c28aaSamw sa_resource_t resource; 610da6c28aaSamw uint64_t features; 61157b448deSdougm 61257b448deSdougm set_node_attr(group, "zfs", "true"); 613da6c28aaSamw if (share == NULL) 614da6c28aaSamw share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 615da6c28aaSamw &err, (uint64_t)SA_FEATURE_NONE); 6163c484793Sdougm 6173c484793Sdougm if (err != SA_OK) 6183c484793Sdougm return (err); 6193c484793Sdougm 6203c484793Sdougm if (strcmp(shareopts, "on") == 0) 6213c484793Sdougm shareopts = ""; 6223c484793Sdougm if (shareopts != NULL) { 6233c484793Sdougm char *options; 6243c484793Sdougm if (grouperr == SA_PROP_SHARE_ONLY) { 625da6c28aaSamw /* 6263c484793Sdougm * Some properties may only be on shares, but 6273c484793Sdougm * due to the ZFS sub-groups being artificial, 6283c484793Sdougm * we sometimes get this and have to deal with 6293c484793Sdougm * it. We do it by attempting to put it on the 6303c484793Sdougm * share. 631da6c28aaSamw */ 6323c484793Sdougm options = strdup(shareopts); 6333c484793Sdougm if (options != NULL) { 6343c484793Sdougm err = sa_parse_legacy_options(share, 6353c484793Sdougm options, proto); 6363c484793Sdougm free(options); 637da6c28aaSamw } 63857b448deSdougm } 6393c484793Sdougm /* Unmark the share's changed state */ 6403c484793Sdougm set_node_attr(share, "changed", NULL); 6413c484793Sdougm } 6423c484793Sdougm features = sa_proto_get_featureset(proto); 6433c484793Sdougm if (share != NULL && features & SA_FEATURE_RESOURCE) { 6443c484793Sdougm /* 6453c484793Sdougm * We have a share and the protocol requires that at 6463c484793Sdougm * least one resource exist (probably SMB). We need to 6473c484793Sdougm * make sure that there is at least one. 6483c484793Sdougm */ 6493c484793Sdougm resource = sa_get_share_resource(share, NULL); 6503c484793Sdougm if (resource == NULL) { 6513c484793Sdougm zfs_construct_resource(share, dataset); 6523c484793Sdougm } 65357b448deSdougm } 65457b448deSdougm return (err); 65557b448deSdougm } 65657b448deSdougm 65757b448deSdougm /* 65857b448deSdougm * zfs_grp_error(err) 65957b448deSdougm * 66057b448deSdougm * Print group create error, but only once. If err is 0 do the 66157b448deSdougm * print else don't. 66257b448deSdougm */ 66357b448deSdougm 66457b448deSdougm static void 66557b448deSdougm zfs_grp_error(int err) 66657b448deSdougm { 66757b448deSdougm if (err == 0) { 66857b448deSdougm /* only print error once */ 66957b448deSdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 67057b448deSdougm "Cannot create ZFS subgroup during initialization:" 67157b448deSdougm " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 67257b448deSdougm } 67357b448deSdougm } 67457b448deSdougm 675da6c28aaSamw /* 676da6c28aaSamw * zfs_process_share(handle, share, mountpoint, proto, source, 677da6c28aaSamw * shareopts, sourcestr) 678da6c28aaSamw * 6795b6e0c46Sdougm * Creates the subgroup, if necessary and adds shares, resources 680da6c28aaSamw * and properties. 681da6c28aaSamw */ 6825b6e0c46Sdougm int 6835b6e0c46Sdougm sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 684da6c28aaSamw char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 685da6c28aaSamw char *sourcestr, char *dataset) 686da6c28aaSamw { 687da6c28aaSamw int err = SA_OK; 688da6c28aaSamw 689da6c28aaSamw if (source & ZPROP_SRC_INHERITED) { 690da6c28aaSamw err = zfs_inherited(handle, share, sourcestr, shareopts, 691da6c28aaSamw mountpoint, proto, dataset); 692da6c28aaSamw } else { 693da6c28aaSamw group = find_or_create_zfs_subgroup(handle, dataset, proto, 694da6c28aaSamw shareopts, &err); 695da6c28aaSamw if (group == NULL) { 69697df5ac9Sdougm static boolean_t reported_error = B_FALSE; 697da6c28aaSamw /* 69897df5ac9Sdougm * There is a problem, but we can't do 699da6c28aaSamw * anything about it at this point so we issue 70097df5ac9Sdougm * a warning and move on. 701da6c28aaSamw */ 70297df5ac9Sdougm zfs_grp_error(reported_error); 70397df5ac9Sdougm reported_error = B_TRUE; 704da6c28aaSamw } 705da6c28aaSamw set_node_attr(group, "zfs", "true"); 706da6c28aaSamw /* 707da6c28aaSamw * Add share with local opts via zfs_notinherited. 708da6c28aaSamw */ 709da6c28aaSamw err = zfs_notinherited(group, share, mountpoint, shareopts, 71097df5ac9Sdougm proto, dataset, err); 711da6c28aaSamw } 712da6c28aaSamw return (err); 713da6c28aaSamw } 714da6c28aaSamw 7156185db85Sdougm /* 716549ec3ffSdougm * sa_get_zfs_shares(handle, groupname) 7176185db85Sdougm * 7186185db85Sdougm * Walk the mnttab for all zfs mounts and determine which are 7196185db85Sdougm * shared. Find or create the appropriate group/sub-group to contain 7206185db85Sdougm * the shares. 7216185db85Sdougm * 7226185db85Sdougm * All shares are in a sub-group that will hold the properties. This 7236185db85Sdougm * allows representing the inherited property model. 7243c484793Sdougm * 7253c484793Sdougm * One area of complication is if "sharenfs" is set at one level of 7263c484793Sdougm * the directory tree and "sharesmb" is set at a different level, the 7273c484793Sdougm * a sub-group must be formed at the lower level for both 7283c484793Sdougm * protocols. That is the nature of the problem in CR 6667349. 7296185db85Sdougm */ 7306185db85Sdougm 7316185db85Sdougm int 732549ec3ffSdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 7336185db85Sdougm { 7346185db85Sdougm sa_group_t zfsgroup; 7353c484793Sdougm boolean_t nfs; 7363c484793Sdougm boolean_t nfs_inherited; 7373c484793Sdougm boolean_t smb; 7383c484793Sdougm boolean_t smb_inherited; 7391cea05afSdougm zfs_handle_t **zlist; 7403c484793Sdougm char nfsshareopts[ZFS_MAXPROPLEN]; 7413c484793Sdougm char smbshareopts[ZFS_MAXPROPLEN]; 7426185db85Sdougm sa_share_t share; 743990b4856Slling zprop_source_t source; 7443c484793Sdougm char nfssourcestr[ZFS_MAXPROPLEN]; 7453c484793Sdougm char smbsourcestr[ZFS_MAXPROPLEN]; 7461cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 7471cea05afSdougm size_t count = 0, i; 748549ec3ffSdougm libzfs_handle_t *zfs_libhandle; 7493c484793Sdougm int err = SA_OK; 7506185db85Sdougm 7516185db85Sdougm /* 752549ec3ffSdougm * If we can't access libzfs, don't bother doing anything. 7536185db85Sdougm */ 754549ec3ffSdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 7551cea05afSdougm if (zfs_libhandle == NULL) 75657b448deSdougm return (SA_SYSTEM_ERR); 7576185db85Sdougm 758da6c28aaSamw zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 7593c484793Sdougm /* Not an error, this could be a legacy condition */ 760546405c3Sdougm if (zfsgroup == NULL) 7613c484793Sdougm return (SA_OK); 762546405c3Sdougm 763546405c3Sdougm /* 764546405c3Sdougm * need to walk the mounted ZFS pools and datasets to 765546405c3Sdougm * find shares that are possible. 766546405c3Sdougm */ 767546405c3Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 768546405c3Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 769546405c3Sdougm 770546405c3Sdougm for (i = 0; i < count; i++) { 771546405c3Sdougm char *dataset; 772546405c3Sdougm 773990b4856Slling source = ZPROP_SRC_ALL; 774546405c3Sdougm /* If no mountpoint, skip. */ 775546405c3Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 776546405c3Sdougm mountpoint, sizeof (mountpoint), NULL, NULL, 0, 777546405c3Sdougm B_FALSE) != 0) 778546405c3Sdougm continue; 779546405c3Sdougm 7806185db85Sdougm /* 781546405c3Sdougm * zfs_get_name value must not be freed. It is just a 782546405c3Sdougm * pointer to a value in the handle. 7836185db85Sdougm */ 784546405c3Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 785546405c3Sdougm continue; 7861cea05afSdougm 787546405c3Sdougm /* 788546405c3Sdougm * only deal with "mounted" file systems since 789546405c3Sdougm * unmounted file systems can't actually be shared. 790546405c3Sdougm */ 79157b448deSdougm 792546405c3Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 793546405c3Sdougm continue; 79457b448deSdougm 7953c484793Sdougm nfs = nfs_inherited = B_FALSE; 7963c484793Sdougm 7973c484793Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts, 7983c484793Sdougm sizeof (nfsshareopts), &source, nfssourcestr, 799546405c3Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 8003c484793Sdougm strcmp(nfsshareopts, "off") != 0) { 8013c484793Sdougm if (source & ZPROP_SRC_INHERITED) 8023c484793Sdougm nfs_inherited = B_TRUE; 8033c484793Sdougm else 8043c484793Sdougm nfs = B_TRUE; 805da6c28aaSamw } 8063c484793Sdougm 8073c484793Sdougm smb = smb_inherited = B_FALSE; 8083c484793Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts, 8093c484793Sdougm sizeof (smbshareopts), &source, smbsourcestr, 810da6c28aaSamw ZFS_MAXPROPLEN, B_FALSE) == 0 && 8113c484793Sdougm strcmp(smbshareopts, "off") != 0) { 8123c484793Sdougm if (source & ZPROP_SRC_INHERITED) 8133c484793Sdougm smb_inherited = B_TRUE; 8143c484793Sdougm else 8153c484793Sdougm smb = B_TRUE; 8163c484793Sdougm } 8173c484793Sdougm 8183c484793Sdougm /* 8193c484793Sdougm * If the mountpoint is already shared, it must be a 8203c484793Sdougm * non-ZFS share. We want to remove the share from its 8213c484793Sdougm * parent group and reshare it under ZFS. 8223c484793Sdougm */ 8233c484793Sdougm share = sa_find_share(handle, mountpoint); 8243c484793Sdougm if (share != NULL && 8253c484793Sdougm (nfs || smb || nfs_inherited || smb_inherited)) { 8263c484793Sdougm err = sa_remove_share(share); 8273c484793Sdougm share = NULL; 8283c484793Sdougm } 8293c484793Sdougm 8303c484793Sdougm /* 8313c484793Sdougm * At this point, we have the information needed to 8323c484793Sdougm * determine what to do with the share. 8333c484793Sdougm * 8343c484793Sdougm * If smb or nfs is set, we have a new sub-group. 8353c484793Sdougm * If smb_inherit and/or nfs_inherit is set, then 8363c484793Sdougm * place on an existing sub-group. If both are set, 8373c484793Sdougm * the existing sub-group is the closest up the tree. 8383c484793Sdougm */ 8393c484793Sdougm if (nfs || smb) { 8403c484793Sdougm /* 8413c484793Sdougm * Non-inherited is the straightforward 8423c484793Sdougm * case. sa_zfs_process_share handles it 8433c484793Sdougm * directly. Make sure that if the "other" 8443c484793Sdougm * protocol is inherited, that we treat it as 8453c484793Sdougm * non-inherited as well. 8463c484793Sdougm */ 8473c484793Sdougm if (nfs || nfs_inherited) { 8483c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8493c484793Sdougm share, mountpoint, "nfs", 8503c484793Sdougm 0, nfsshareopts, 8513c484793Sdougm nfssourcestr, dataset); 8523c484793Sdougm share = sa_find_share(handle, mountpoint); 853da6c28aaSamw } 8543c484793Sdougm if (smb || smb_inherited) { 8553c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8563c484793Sdougm share, mountpoint, "smb", 8573c484793Sdougm 0, smbshareopts, 8583c484793Sdougm smbsourcestr, dataset); 8593c484793Sdougm } 8603c484793Sdougm } else if (nfs_inherited || smb_inherited) { 8613c484793Sdougm char *grpdataset; 8623c484793Sdougm /* 8633c484793Sdougm * If we only have inherited groups, it is 8643c484793Sdougm * important to find the closer of the two if 8653c484793Sdougm * the protocols are set at different 8663c484793Sdougm * levels. The closest sub-group is the one we 8673c484793Sdougm * want to work with. 8683c484793Sdougm */ 8693c484793Sdougm if (nfs_inherited && smb_inherited) { 8703c484793Sdougm if (strcmp(nfssourcestr, smbsourcestr) <= 0) 8713c484793Sdougm grpdataset = nfssourcestr; 8723c484793Sdougm else 8733c484793Sdougm grpdataset = smbsourcestr; 8743c484793Sdougm } else if (nfs_inherited) { 8753c484793Sdougm grpdataset = nfssourcestr; 8763c484793Sdougm } else if (smb_inherited) { 8773c484793Sdougm grpdataset = smbsourcestr; 8783c484793Sdougm } 8793c484793Sdougm if (nfs_inherited) { 8803c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8813c484793Sdougm share, mountpoint, "nfs", 8823c484793Sdougm ZPROP_SRC_INHERITED, nfsshareopts, 8833c484793Sdougm grpdataset, dataset); 8843c484793Sdougm share = sa_find_share(handle, mountpoint); 8853c484793Sdougm } 8863c484793Sdougm if (smb_inherited) { 8873c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8883c484793Sdougm share, mountpoint, "smb", 8893c484793Sdougm ZPROP_SRC_INHERITED, smbshareopts, 8903c484793Sdougm grpdataset, dataset); 8916185db85Sdougm } 8926185db85Sdougm } 8936185db85Sdougm } 8941cea05afSdougm /* 8951cea05afSdougm * Don't need to free the "zlist" variable since it is only a 8961cea05afSdougm * pointer to a cached value that will be freed when 8971cea05afSdougm * sa_fini() is called. 8981cea05afSdougm */ 8993c484793Sdougm return (err); 9006185db85Sdougm } 9016185db85Sdougm 9026185db85Sdougm #define COMMAND "/usr/sbin/zfs" 9036185db85Sdougm 9046185db85Sdougm /* 9056185db85Sdougm * sa_zfs_set_sharenfs(group, path, on) 9066185db85Sdougm * 9076185db85Sdougm * Update the "sharenfs" property on the path. If on is true, then set 9086185db85Sdougm * to the properties on the group or "on" if no properties are 9096185db85Sdougm * defined. Set to "off" if on is false. 9106185db85Sdougm */ 9116185db85Sdougm 9126185db85Sdougm int 9136185db85Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 9146185db85Sdougm { 9156185db85Sdougm int ret = SA_NOT_IMPLEMENTED; 9166185db85Sdougm char *command; 9176185db85Sdougm 9186185db85Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 9196185db85Sdougm if (command != NULL) { 92057b448deSdougm char *opts = NULL; 92157b448deSdougm char *dataset = NULL; 92257b448deSdougm FILE *pfile; 92357b448deSdougm sa_handle_impl_t impl_handle; 92457b448deSdougm /* for now, NFS is always available for "zfs" */ 92557b448deSdougm if (on) { 92657b448deSdougm opts = sa_proto_legacy_format("nfs", group, 1); 92757b448deSdougm if (opts != NULL && strlen(opts) == 0) { 92857b448deSdougm free(opts); 92957b448deSdougm opts = strdup("on"); 93057b448deSdougm } 9316185db85Sdougm } 93257b448deSdougm 93357b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 93457b448deSdougm assert(impl_handle != NULL); 93557b448deSdougm if (impl_handle != NULL) 936a1ef5d63Smarks dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 93757b448deSdougm else 9386185db85Sdougm ret = SA_SYSTEM_ERR; 93957b448deSdougm 94057b448deSdougm if (dataset != NULL) { 94157b448deSdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 94257b448deSdougm "%s set sharenfs=\"%s\" %s", COMMAND, 94357b448deSdougm opts != NULL ? opts : "off", dataset); 94457b448deSdougm pfile = popen(command, "r"); 94557b448deSdougm if (pfile != NULL) { 94657b448deSdougm ret = pclose(pfile); 94757b448deSdougm if (ret != 0) 94857b448deSdougm ret = SA_SYSTEM_ERR; 94957b448deSdougm } 9506185db85Sdougm } 95157b448deSdougm if (opts != NULL) 95257b448deSdougm free(opts); 95357b448deSdougm if (dataset != NULL) 95457b448deSdougm free(dataset); 95557b448deSdougm free(command); 9566185db85Sdougm } 9576185db85Sdougm return (ret); 9586185db85Sdougm } 9596185db85Sdougm 960da6c28aaSamw /* 961da6c28aaSamw * add_resources(share, opt) 962da6c28aaSamw * 963da6c28aaSamw * Add resource properties to those in "opt". Resources are prefixed 964da6c28aaSamw * with name=resourcename. 965da6c28aaSamw */ 966da6c28aaSamw static char * 967da6c28aaSamw add_resources(sa_share_t share, char *opt) 968da6c28aaSamw { 969da6c28aaSamw char *newopt = NULL; 970da6c28aaSamw char *propstr; 971da6c28aaSamw sa_resource_t resource; 972da6c28aaSamw 973da6c28aaSamw newopt = strdup(opt); 974da6c28aaSamw if (newopt == NULL) 975da6c28aaSamw return (newopt); 976da6c28aaSamw 977da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 978da6c28aaSamw resource != NULL; 979da6c28aaSamw resource = sa_get_next_resource(resource)) { 980da6c28aaSamw char *name; 981da6c28aaSamw size_t size; 982da6c28aaSamw 983da6c28aaSamw name = sa_get_resource_attr(resource, "name"); 984da6c28aaSamw if (name == NULL) { 985da6c28aaSamw free(newopt); 986da6c28aaSamw return (NULL); 987da6c28aaSamw } 988da6c28aaSamw size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 989da6c28aaSamw newopt = calloc(1, size); 990da6c28aaSamw if (newopt != NULL) 991da6c28aaSamw (void) snprintf(newopt, size, "%s,name=%s", opt, name); 992fe1c642dSBill Krier sa_free_attr_string(name); 993da6c28aaSamw free(opt); 994da6c28aaSamw opt = newopt; 995da6c28aaSamw propstr = sa_proto_legacy_format("smb", resource, 0); 996da6c28aaSamw if (propstr == NULL) { 997da6c28aaSamw free(opt); 998da6c28aaSamw return (NULL); 999da6c28aaSamw } 1000da6c28aaSamw size = strlen(propstr) + strlen(opt) + 2; 1001da6c28aaSamw newopt = calloc(1, size); 1002da6c28aaSamw if (newopt != NULL) 1003da6c28aaSamw (void) snprintf(newopt, size, "%s,%s", opt, propstr); 1004da6c28aaSamw free(opt); 1005da6c28aaSamw opt = newopt; 1006da6c28aaSamw } 1007da6c28aaSamw return (opt); 1008da6c28aaSamw } 1009da6c28aaSamw 1010da6c28aaSamw /* 1011da6c28aaSamw * sa_zfs_set_sharesmb(group, path, on) 1012da6c28aaSamw * 1013da6c28aaSamw * Update the "sharesmb" property on the path. If on is true, then set 1014da6c28aaSamw * to the properties on the group or "on" if no properties are 1015da6c28aaSamw * defined. Set to "off" if on is false. 1016da6c28aaSamw */ 1017da6c28aaSamw 1018da6c28aaSamw int 1019da6c28aaSamw sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 1020da6c28aaSamw { 1021da6c28aaSamw int ret = SA_NOT_IMPLEMENTED; 1022da6c28aaSamw char *command; 1023da6c28aaSamw sa_share_t share; 1024da6c28aaSamw 1025da6c28aaSamw /* In case SMB not enabled */ 1026da6c28aaSamw if (sa_get_optionset(group, "smb") == NULL) 1027da6c28aaSamw return (SA_NOT_SUPPORTED); 1028da6c28aaSamw 1029da6c28aaSamw command = malloc(ZFS_MAXPROPLEN * 2); 1030da6c28aaSamw if (command != NULL) { 1031da6c28aaSamw char *opts = NULL; 1032da6c28aaSamw char *dataset = NULL; 1033da6c28aaSamw FILE *pfile; 1034da6c28aaSamw sa_handle_impl_t impl_handle; 1035da6c28aaSamw 1036da6c28aaSamw if (on) { 1037da6c28aaSamw char *newopt; 1038da6c28aaSamw 1039da6c28aaSamw share = sa_get_share(group, NULL); 1040da6c28aaSamw opts = sa_proto_legacy_format("smb", share, 1); 1041da6c28aaSamw if (opts != NULL && strlen(opts) == 0) { 1042da6c28aaSamw free(opts); 1043da6c28aaSamw opts = strdup("on"); 1044da6c28aaSamw } 1045da6c28aaSamw newopt = add_resources(opts, share); 1046da6c28aaSamw free(opts); 1047da6c28aaSamw opts = newopt; 1048da6c28aaSamw } 1049da6c28aaSamw 1050da6c28aaSamw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1051da6c28aaSamw assert(impl_handle != NULL); 1052da6c28aaSamw if (impl_handle != NULL) 1053da6c28aaSamw dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1054da6c28aaSamw else 1055da6c28aaSamw ret = SA_SYSTEM_ERR; 1056da6c28aaSamw 1057da6c28aaSamw if (dataset != NULL) { 1058da6c28aaSamw (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1059da6c28aaSamw "echo %s set sharesmb=\"%s\" %s", COMMAND, 1060da6c28aaSamw opts != NULL ? opts : "off", dataset); 1061da6c28aaSamw pfile = popen(command, "r"); 1062da6c28aaSamw if (pfile != NULL) { 1063da6c28aaSamw ret = pclose(pfile); 1064da6c28aaSamw if (ret != 0) 1065da6c28aaSamw ret = SA_SYSTEM_ERR; 1066da6c28aaSamw } 1067da6c28aaSamw } 1068da6c28aaSamw if (opts != NULL) 1069da6c28aaSamw free(opts); 1070da6c28aaSamw if (dataset != NULL) 1071da6c28aaSamw free(dataset); 1072da6c28aaSamw free(command); 1073da6c28aaSamw } 1074da6c28aaSamw return (ret); 1075da6c28aaSamw } 1076da6c28aaSamw 10776185db85Sdougm /* 10786185db85Sdougm * sa_zfs_update(group) 10796185db85Sdougm * 10806185db85Sdougm * call back to ZFS to update the share if necessary. 10816185db85Sdougm * Don't do it if it isn't a real change. 10826185db85Sdougm */ 10836185db85Sdougm int 10846185db85Sdougm sa_zfs_update(sa_group_t group) 10856185db85Sdougm { 10866185db85Sdougm sa_optionset_t protopt; 10876185db85Sdougm sa_group_t parent; 10886185db85Sdougm char *command; 10896185db85Sdougm char *optstring; 10906185db85Sdougm int ret = SA_OK; 10916185db85Sdougm int doupdate = 0; 10926185db85Sdougm FILE *pfile; 10936185db85Sdougm 10946185db85Sdougm if (sa_is_share(group)) 109557b448deSdougm parent = sa_get_parent_group(group); 10966185db85Sdougm else 109757b448deSdougm parent = group; 10986185db85Sdougm 10996185db85Sdougm if (parent != NULL) { 110057b448deSdougm command = malloc(ZFS_MAXPROPLEN * 2); 110157b448deSdougm if (command == NULL) 110257b448deSdougm return (SA_NO_MEMORY); 110357b448deSdougm 110457b448deSdougm *command = '\0'; 110557b448deSdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 110657b448deSdougm protopt = sa_get_next_optionset(protopt)) { 110757b448deSdougm 110857b448deSdougm char *proto = sa_get_optionset_attr(protopt, "type"); 110957b448deSdougm char *path; 111057b448deSdougm char *dataset = NULL; 111157b448deSdougm char *zfsopts = NULL; 111257b448deSdougm 111357b448deSdougm if (sa_is_share(group)) { 111457b448deSdougm path = sa_get_share_attr((sa_share_t)group, 111557b448deSdougm "path"); 111657b448deSdougm if (path != NULL) { 111757b448deSdougm sa_handle_impl_t impl_handle; 111857b448deSdougm 111957b448deSdougm impl_handle = sa_find_group_handle( 112057b448deSdougm group); 112157b448deSdougm if (impl_handle != NULL) 112257b448deSdougm dataset = get_zfs_dataset( 1123a1ef5d63Smarks impl_handle, path, B_FALSE); 112457b448deSdougm else 112557b448deSdougm ret = SA_SYSTEM_ERR; 112657b448deSdougm 112757b448deSdougm sa_free_attr_string(path); 112857b448deSdougm } 11296185db85Sdougm } else { 113057b448deSdougm dataset = sa_get_group_attr(group, "name"); 11316185db85Sdougm } 113257b448deSdougm /* update only when there is an optstring found */ 113357b448deSdougm doupdate = 0; 113457b448deSdougm if (proto != NULL && dataset != NULL) { 113557b448deSdougm optstring = sa_proto_legacy_format(proto, 113657b448deSdougm group, 1); 113757b448deSdougm zfsopts = get_zfs_property(dataset, 113857b448deSdougm ZFS_PROP_SHARENFS); 113957b448deSdougm 114057b448deSdougm if (optstring != NULL && zfsopts != NULL) { 114157b448deSdougm if (strcmp(optstring, zfsopts) != 0) 114257b448deSdougm doupdate++; 114357b448deSdougm } 114457b448deSdougm if (doupdate) { 114557b448deSdougm if (optstring != NULL && 114657b448deSdougm strlen(optstring) > 0) { 114757b448deSdougm (void) snprintf(command, 114857b448deSdougm ZFS_MAXPROPLEN * 2, 11491f713840SDoug McCallum "%s set share%s=%s %s", 11501f713840SDoug McCallum COMMAND, proto, 115157b448deSdougm optstring, dataset); 115257b448deSdougm } else { 115357b448deSdougm (void) snprintf(command, 115457b448deSdougm ZFS_MAXPROPLEN * 2, 11551f713840SDoug McCallum "%s set share%s=on %s", 11561f713840SDoug McCallum COMMAND, proto, 115757b448deSdougm dataset); 115857b448deSdougm } 115957b448deSdougm pfile = popen(command, "r"); 116057b448deSdougm if (pfile != NULL) 116157b448deSdougm ret = pclose(pfile); 116257b448deSdougm switch (ret) { 116357b448deSdougm default: 116457b448deSdougm case 1: 116557b448deSdougm ret = SA_SYSTEM_ERR; 116657b448deSdougm break; 116757b448deSdougm case 2: 116857b448deSdougm ret = SA_SYNTAX_ERR; 116957b448deSdougm break; 117057b448deSdougm case 0: 117157b448deSdougm break; 117257b448deSdougm } 117357b448deSdougm } 117457b448deSdougm if (optstring != NULL) 117557b448deSdougm free(optstring); 117657b448deSdougm if (zfsopts != NULL) 117757b448deSdougm free(zfsopts); 11786185db85Sdougm } 117957b448deSdougm if (proto != NULL) 118057b448deSdougm sa_free_attr_string(proto); 118157b448deSdougm if (dataset != NULL) 118257b448deSdougm free(dataset); 11836185db85Sdougm } 118457b448deSdougm free(command); 11856185db85Sdougm } 11866185db85Sdougm return (ret); 11876185db85Sdougm } 11886185db85Sdougm 11896185db85Sdougm /* 11906185db85Sdougm * sa_group_is_zfs(group) 11916185db85Sdougm * 11926185db85Sdougm * Given the group, determine if the zfs attribute is set. 11936185db85Sdougm */ 11946185db85Sdougm 11956185db85Sdougm int 11966185db85Sdougm sa_group_is_zfs(sa_group_t group) 11976185db85Sdougm { 11986185db85Sdougm char *zfs; 11996185db85Sdougm int ret = 0; 12006185db85Sdougm 12016185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 12026185db85Sdougm if (zfs != NULL) { 120357b448deSdougm ret = 1; 120457b448deSdougm sa_free_attr_string(zfs); 12056185db85Sdougm } 12066185db85Sdougm return (ret); 12076185db85Sdougm } 12086185db85Sdougm 12096185db85Sdougm /* 12106185db85Sdougm * sa_path_is_zfs(path) 12116185db85Sdougm * 12126185db85Sdougm * Check to see if the file system path represents is of type "zfs". 12136185db85Sdougm */ 12146185db85Sdougm 12156185db85Sdougm int 12166185db85Sdougm sa_path_is_zfs(char *path) 12176185db85Sdougm { 12186185db85Sdougm char *fstype; 12196185db85Sdougm int ret = 0; 12206185db85Sdougm 12216185db85Sdougm fstype = sa_fstype(path); 122257b448deSdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) 122357b448deSdougm ret = 1; 12246185db85Sdougm if (fstype != NULL) 122557b448deSdougm sa_free_fstype(fstype); 12266185db85Sdougm return (ret); 12276185db85Sdougm } 1228ecd6cf80Smarks 1229ecd6cf80Smarks int 1230ecd6cf80Smarks sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1231ecd6cf80Smarks { 1232ecd6cf80Smarks char *path; 1233ecd6cf80Smarks 1234ed78bdc4Smarks /* Make sure path is valid */ 1235ed78bdc4Smarks 1236ecd6cf80Smarks path = sa_get_share_attr(share, "path"); 1237ecd6cf80Smarks if (path != NULL) { 1238ecd6cf80Smarks (void) memset(sh, 0, sizeof (sh)); 1239ecd6cf80Smarks (void) sa_fillshare(share, proto, sh); 1240ed78bdc4Smarks sa_free_attr_string(path); 1241ecd6cf80Smarks return (0); 1242ecd6cf80Smarks } else 1243ecd6cf80Smarks return (1); 1244ecd6cf80Smarks } 1245ecd6cf80Smarks 1246ecd6cf80Smarks #define SMAX(i, j) \ 1247ecd6cf80Smarks if ((j) > (i)) { \ 1248ecd6cf80Smarks (i) = (j); \ 1249ecd6cf80Smarks } 1250ecd6cf80Smarks 1251ecd6cf80Smarks int 1252743a77edSAlan Wright sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh, 1253da6c28aaSamw void *exportdata, zfs_share_op_t operation) 1254ecd6cf80Smarks { 1255ecd6cf80Smarks libzfs_handle_t *libhandle; 1256ecd6cf80Smarks sa_group_t group; 1257ecd6cf80Smarks sa_handle_t sahandle; 1258ecd6cf80Smarks char *dataset; 1259ecd6cf80Smarks int err = EINVAL; 1260ecd6cf80Smarks int i, j; 12614d79fe3bSmarks char newpath[MAXPATHLEN]; 1262a1ef5d63Smarks char *pathp; 1263ecd6cf80Smarks 1264ecd6cf80Smarks /* 1265ecd6cf80Smarks * First find the dataset name 1266ecd6cf80Smarks */ 1267ecd6cf80Smarks if ((group = sa_get_parent_group(share)) == NULL) { 1268a63214d6SBill Krier return (EINVAL); 1269ecd6cf80Smarks } 1270ecd6cf80Smarks if ((sahandle = sa_find_group_handle(group)) == NULL) { 1271a63214d6SBill Krier return (EINVAL); 1272ecd6cf80Smarks } 1273ecd6cf80Smarks 12744d79fe3bSmarks /* 12754d79fe3bSmarks * If get_zfs_dataset fails, see if it is a subdirectory 12764d79fe3bSmarks */ 1277a1ef5d63Smarks 1278a1ef5d63Smarks pathp = path; 1279a1ef5d63Smarks while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 12804d79fe3bSmarks char *p; 12814d79fe3bSmarks 1282a1ef5d63Smarks if (pathp == path) { 1283a1ef5d63Smarks (void) strlcpy(newpath, path, sizeof (newpath)); 1284a1ef5d63Smarks pathp = newpath; 1285a1ef5d63Smarks } 1286a1ef5d63Smarks 1287d34e4517SDoug McCallum /* 1288d34e4517SDoug McCallum * Make sure only one leading '/' This condition came 1289d34e4517SDoug McCallum * about when using HAStoragePlus which insisted on 1290d34e4517SDoug McCallum * putting an extra leading '/' in the ZFS path 1291d34e4517SDoug McCallum * name. The problem is fixed in other areas, but this 1292d34e4517SDoug McCallum * will catch any other ways that a double slash might 1293d34e4517SDoug McCallum * get introduced. 1294d34e4517SDoug McCallum */ 1295d34e4517SDoug McCallum while (*pathp == '/' && *(pathp + 1) == '/') 1296d34e4517SDoug McCallum pathp++; 1297d34e4517SDoug McCallum 1298a1ef5d63Smarks /* 1299a1ef5d63Smarks * chop off part of path, but if we are at root then 1300a1ef5d63Smarks * make sure path is a / 1301a1ef5d63Smarks */ 1302a1ef5d63Smarks if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1303a1ef5d63Smarks if (pathp == p) { 1304a1ef5d63Smarks *(p + 1) = '\0'; /* skip over /, root case */ 1305a1ef5d63Smarks } else { 1306a1ef5d63Smarks *p = '\0'; 1307a1ef5d63Smarks } 1308a1ef5d63Smarks } else { 1309a63214d6SBill Krier return (EINVAL); 1310a1ef5d63Smarks } 1311ecd6cf80Smarks } 1312ecd6cf80Smarks 1313ecd6cf80Smarks libhandle = libzfs_init(); 1314ecd6cf80Smarks if (libhandle != NULL) { 1315743a77edSAlan Wright char *resource_name; 1316ecd6cf80Smarks 1317ecd6cf80Smarks i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1318ecd6cf80Smarks sh->sh_size = i; 1319ecd6cf80Smarks 1320ecd6cf80Smarks j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1321ecd6cf80Smarks sh->sh_size += j; 1322ecd6cf80Smarks SMAX(i, j); 1323ecd6cf80Smarks 1324ecd6cf80Smarks j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1325ecd6cf80Smarks sh->sh_size += j; 1326ecd6cf80Smarks SMAX(i, j); 1327ecd6cf80Smarks 1328ecd6cf80Smarks j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1329ecd6cf80Smarks sh->sh_size += j; 1330ecd6cf80Smarks SMAX(i, j); 1331ecd6cf80Smarks 1332ecd6cf80Smarks j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1333ecd6cf80Smarks sh->sh_size += j; 1334ecd6cf80Smarks SMAX(i, j); 1335743a77edSAlan Wright 1336743a77edSAlan Wright resource_name = sa_get_resource_attr(resource, "name"); 1337743a77edSAlan Wright 1338ecd6cf80Smarks err = zfs_deleg_share_nfs(libhandle, dataset, path, 1339743a77edSAlan Wright resource_name, exportdata, sh, i, operation); 13405b6e0c46Sdougm if (err == SA_OK) 13415b6e0c46Sdougm sa_update_sharetab_ts(sahandle); 1342a63214d6SBill Krier else 1343a63214d6SBill Krier err = errno; 1344743a77edSAlan Wright if (resource_name) 1345743a77edSAlan Wright sa_free_attr_string(resource_name); 1346743a77edSAlan Wright 1347ecd6cf80Smarks libzfs_fini(libhandle); 1348ecd6cf80Smarks } 1349ecd6cf80Smarks free(dataset); 1350ecd6cf80Smarks return (err); 1351ecd6cf80Smarks } 13525b6e0c46Sdougm 13535b6e0c46Sdougm /* 13545b6e0c46Sdougm * sa_get_zfs_handle(handle) 13555b6e0c46Sdougm * 13565b6e0c46Sdougm * Given an sa_handle_t, return the libzfs_handle_t *. This is only 13575b6e0c46Sdougm * used internally by libzfs. Needed in order to avoid including 13585b6e0c46Sdougm * libshare_impl.h in libzfs. 13595b6e0c46Sdougm */ 13605b6e0c46Sdougm 13615b6e0c46Sdougm libzfs_handle_t * 13625b6e0c46Sdougm sa_get_zfs_handle(sa_handle_t handle) 13635b6e0c46Sdougm { 13645b6e0c46Sdougm sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 13655b6e0c46Sdougm 13665b6e0c46Sdougm return (implhandle->zfs_libhandle); 13675b6e0c46Sdougm } 1368743a77edSAlan Wright 1369743a77edSAlan Wright /* 1370743a77edSAlan Wright * sa_get_zfs_info(libzfs, path, mountpoint, dataset) 1371743a77edSAlan Wright * 1372743a77edSAlan Wright * Find the ZFS dataset and mountpoint for a given path 1373743a77edSAlan Wright */ 1374743a77edSAlan Wright int 1375743a77edSAlan Wright sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp, 1376743a77edSAlan Wright char *datasetp) 1377743a77edSAlan Wright { 1378743a77edSAlan Wright get_all_cbdata_t cb = { 0 }; 1379743a77edSAlan Wright int i; 1380743a77edSAlan Wright char mountpoint[ZFS_MAXPROPLEN]; 1381743a77edSAlan Wright char dataset[ZFS_MAXPROPLEN]; 1382743a77edSAlan Wright char canmount[ZFS_MAXPROPLEN]; 1383743a77edSAlan Wright char *dp; 1384743a77edSAlan Wright int count; 1385743a77edSAlan Wright int ret = 0; 1386743a77edSAlan Wright 1387743a77edSAlan Wright cb.cb_types = ZFS_TYPE_FILESYSTEM; 1388743a77edSAlan Wright 1389743a77edSAlan Wright if (libzfs == NULL) 1390743a77edSAlan Wright return (0); 1391743a77edSAlan Wright 1392743a77edSAlan Wright (void) zfs_iter_root(libzfs, get_one_filesystem, &cb); 1393743a77edSAlan Wright count = cb.cb_used; 1394743a77edSAlan Wright 1395743a77edSAlan Wright qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare); 1396743a77edSAlan Wright for (i = 0; i < count; i++) { 1397743a77edSAlan Wright /* must have a mountpoint */ 1398743a77edSAlan Wright if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT, 1399743a77edSAlan Wright mountpoint, sizeof (mountpoint), 1400743a77edSAlan Wright NULL, NULL, 0, B_FALSE) != 0) { 1401743a77edSAlan Wright /* no mountpoint */ 1402743a77edSAlan Wright continue; 1403743a77edSAlan Wright } 1404743a77edSAlan Wright 1405743a77edSAlan Wright /* mountpoint must be a path */ 1406743a77edSAlan Wright if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 1407743a77edSAlan Wright strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 1408743a77edSAlan Wright /* 1409743a77edSAlan Wright * Search mmttab for mountpoint 1410743a77edSAlan Wright */ 1411743a77edSAlan Wright 1412743a77edSAlan Wright if (get_legacy_mountpoint(path, dataset, 1413743a77edSAlan Wright ZFS_MAXPROPLEN, mountpoint, 1414743a77edSAlan Wright ZFS_MAXPROPLEN) == 0) { 1415743a77edSAlan Wright ret = 1; 1416743a77edSAlan Wright break; 1417743a77edSAlan Wright } 1418743a77edSAlan Wright continue; 1419743a77edSAlan Wright } 1420743a77edSAlan Wright 1421743a77edSAlan Wright /* canmount must be set */ 1422743a77edSAlan Wright canmount[0] = '\0'; 1423743a77edSAlan Wright if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount, 1424743a77edSAlan Wright sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 1425743a77edSAlan Wright strcmp(canmount, "off") == 0) 1426743a77edSAlan Wright continue; 1427743a77edSAlan Wright 1428743a77edSAlan Wright /* 1429743a77edSAlan Wright * have a mountable handle but want to skip those marked none 1430743a77edSAlan Wright * and legacy 1431743a77edSAlan Wright */ 1432743a77edSAlan Wright if (strcmp(mountpoint, path) == 0) { 1433743a77edSAlan Wright dp = (char *)zfs_get_name(cb.cb_handles[i]); 1434743a77edSAlan Wright if (dp != NULL) { 1435743a77edSAlan Wright if (datasetp != NULL) 1436743a77edSAlan Wright (void) strcpy(datasetp, dp); 1437743a77edSAlan Wright if (mountpointp != NULL) 1438743a77edSAlan Wright (void) strcpy(mountpointp, mountpoint); 1439743a77edSAlan Wright ret = 1; 1440743a77edSAlan Wright } 1441743a77edSAlan Wright break; 1442743a77edSAlan Wright } 1443743a77edSAlan Wright 1444743a77edSAlan Wright } 1445743a77edSAlan Wright 1446743a77edSAlan Wright return (ret); 1447743a77edSAlan Wright } 1448*148c5f43SAlan Wright 1449*148c5f43SAlan Wright /* 1450*148c5f43SAlan Wright * This method builds values for "sharesmb" property from the 1451*148c5f43SAlan Wright * nvlist argument. The values are returned in sharesmb_val variable. 1452*148c5f43SAlan Wright */ 1453*148c5f43SAlan Wright static int 1454*148c5f43SAlan Wright sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val) 1455*148c5f43SAlan Wright { 1456*148c5f43SAlan Wright char cur_val[MAXPATHLEN]; 1457*148c5f43SAlan Wright char *name, *val; 1458*148c5f43SAlan Wright nvpair_t *cur; 1459*148c5f43SAlan Wright int err = 0; 1460*148c5f43SAlan Wright 1461*148c5f43SAlan Wright cur = nvlist_next_nvpair(nvl, NULL); 1462*148c5f43SAlan Wright while (cur != NULL) { 1463*148c5f43SAlan Wright name = nvpair_name(cur); 1464*148c5f43SAlan Wright err = nvpair_value_string(cur, &val); 1465*148c5f43SAlan Wright if ((err != 0) || (name == NULL) || (val == NULL)) 1466*148c5f43SAlan Wright return (-1); 1467*148c5f43SAlan Wright 1468*148c5f43SAlan Wright (void) snprintf(cur_val, MAXPATHLEN, "%s=%s,", name, val); 1469*148c5f43SAlan Wright (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1470*148c5f43SAlan Wright 1471*148c5f43SAlan Wright cur = nvlist_next_nvpair(nvl, cur); 1472*148c5f43SAlan Wright } 1473*148c5f43SAlan Wright 1474*148c5f43SAlan Wright return (0); 1475*148c5f43SAlan Wright } 1476*148c5f43SAlan Wright 1477*148c5f43SAlan Wright /* 1478*148c5f43SAlan Wright * This method builds values for "sharesmb" property from values 1479*148c5f43SAlan Wright * already existing on the share. The properties set via sa_zfs_sprint_new_prop 1480*148c5f43SAlan Wright * method are passed in sharesmb_val. If a existing property is already 1481*148c5f43SAlan Wright * set via sa_zfs_sprint_new_prop method, then they are not appended 1482*148c5f43SAlan Wright * to the sharesmb_val string. The returned sharesmb_val string is a combination 1483*148c5f43SAlan Wright * of new and existing values for 'sharesmb' property. 1484*148c5f43SAlan Wright */ 1485*148c5f43SAlan Wright static int 1486*148c5f43SAlan Wright sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val) 1487*148c5f43SAlan Wright { 1488*148c5f43SAlan Wright char shareopts[ZFS_MAXPROPLEN], cur_val[MAXPATHLEN]; 1489*148c5f43SAlan Wright char *token, *last, *value; 1490*148c5f43SAlan Wright 1491*148c5f43SAlan Wright if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts, 1492*148c5f43SAlan Wright sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0) 1493*148c5f43SAlan Wright return (-1); 1494*148c5f43SAlan Wright 1495*148c5f43SAlan Wright if (strstr(shareopts, "=") == NULL) 1496*148c5f43SAlan Wright return (0); 1497*148c5f43SAlan Wright 1498*148c5f43SAlan Wright for (token = strtok_r(shareopts, ",", &last); token != NULL; 1499*148c5f43SAlan Wright token = strtok_r(NULL, ",", &last)) { 1500*148c5f43SAlan Wright value = strchr(token, '='); 1501*148c5f43SAlan Wright if (value == NULL) 1502*148c5f43SAlan Wright return (-1); 1503*148c5f43SAlan Wright *value++ = '\0'; 1504*148c5f43SAlan Wright 1505*148c5f43SAlan Wright (void) snprintf(cur_val, MAXPATHLEN, "%s=", token); 1506*148c5f43SAlan Wright if (strstr(sharesmb_val, cur_val) == NULL) { 1507*148c5f43SAlan Wright (void) strlcat(cur_val, value, MAXPATHLEN); 1508*148c5f43SAlan Wright (void) strlcat(cur_val, ",", MAXPATHLEN); 1509*148c5f43SAlan Wright (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1510*148c5f43SAlan Wright } 1511*148c5f43SAlan Wright } 1512*148c5f43SAlan Wright 1513*148c5f43SAlan Wright return (0); 1514*148c5f43SAlan Wright } 1515*148c5f43SAlan Wright 1516*148c5f43SAlan Wright /* 1517*148c5f43SAlan Wright * Sets the share properties on a ZFS share. For now, this method sets only 1518*148c5f43SAlan Wright * the "sharesmb" property. 1519*148c5f43SAlan Wright * 1520*148c5f43SAlan Wright * This method includes building a comma seperated name-value string to be 1521*148c5f43SAlan Wright * set on the "sharesmb" property of a ZFS share. This name-value string is 1522*148c5f43SAlan Wright * build in 2 steps: 1523*148c5f43SAlan Wright * - New property values given as name-value pair are set first. 1524*148c5f43SAlan Wright * - Existing optionset properties, which are not part of the new properties 1525*148c5f43SAlan Wright * passed in step 1, are appended to the newly set properties. 1526*148c5f43SAlan Wright */ 1527*148c5f43SAlan Wright int 1528*148c5f43SAlan Wright sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl) 1529*148c5f43SAlan Wright { 1530*148c5f43SAlan Wright zfs_handle_t *z_fs; 1531*148c5f43SAlan Wright libzfs_handle_t *z_lib; 1532*148c5f43SAlan Wright char sharesmb_val[MAXPATHLEN]; 1533*148c5f43SAlan Wright char *dataset, *lastcomma; 1534*148c5f43SAlan Wright 1535*148c5f43SAlan Wright if (nvlist_empty(nvl)) 1536*148c5f43SAlan Wright return (0); 1537*148c5f43SAlan Wright 1538*148c5f43SAlan Wright if ((handle == NULL) || (path == NULL)) 1539*148c5f43SAlan Wright return (-1); 1540*148c5f43SAlan Wright 1541*148c5f43SAlan Wright if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL) 1542*148c5f43SAlan Wright return (-1); 1543*148c5f43SAlan Wright 1544*148c5f43SAlan Wright if ((z_lib = libzfs_init()) == NULL) { 1545*148c5f43SAlan Wright free(dataset); 1546*148c5f43SAlan Wright return (-1); 1547*148c5f43SAlan Wright } 1548*148c5f43SAlan Wright 1549*148c5f43SAlan Wright z_fs = zfs_open(z_lib, dataset, ZFS_TYPE_DATASET); 1550*148c5f43SAlan Wright if (z_fs == NULL) { 1551*148c5f43SAlan Wright free(dataset); 1552*148c5f43SAlan Wright libzfs_fini(z_lib); 1553*148c5f43SAlan Wright return (-1); 1554*148c5f43SAlan Wright } 1555*148c5f43SAlan Wright 1556*148c5f43SAlan Wright bzero(sharesmb_val, MAXPATHLEN); 1557*148c5f43SAlan Wright if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) { 1558*148c5f43SAlan Wright free(dataset); 1559*148c5f43SAlan Wright zfs_close(z_fs); 1560*148c5f43SAlan Wright libzfs_fini(z_lib); 1561*148c5f43SAlan Wright return (-1); 1562*148c5f43SAlan Wright } 1563*148c5f43SAlan Wright 1564*148c5f43SAlan Wright if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) { 1565*148c5f43SAlan Wright free(dataset); 1566*148c5f43SAlan Wright zfs_close(z_fs); 1567*148c5f43SAlan Wright libzfs_fini(z_lib); 1568*148c5f43SAlan Wright return (-1); 1569*148c5f43SAlan Wright } 1570*148c5f43SAlan Wright 1571*148c5f43SAlan Wright lastcomma = strrchr(sharesmb_val, ','); 1572*148c5f43SAlan Wright if ((lastcomma != NULL) && (lastcomma[1] == '\0')) 1573*148c5f43SAlan Wright *lastcomma = '\0'; 1574*148c5f43SAlan Wright 1575*148c5f43SAlan Wright (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB), 1576*148c5f43SAlan Wright sharesmb_val); 1577*148c5f43SAlan Wright free(dataset); 1578*148c5f43SAlan Wright zfs_close(z_fs); 1579*148c5f43SAlan Wright libzfs_fini(z_lib); 1580*148c5f43SAlan Wright 1581*148c5f43SAlan Wright return (0); 1582*148c5f43SAlan Wright } 1583