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 */ 25c3f7431dSDan Kruchinin /* 26c3f7431dSDan Kruchinin * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 27*33cde0d0SMatthew Ahrens * Copyright (c) 2012, 2014 by Delphix. All rights reserved. 28c3f7431dSDan Kruchinin */ 296185db85Sdougm 30a1ef5d63Smarks #include <stdio.h> 316185db85Sdougm #include <libzfs.h> 326185db85Sdougm #include <string.h> 33a3351425Sdougm #include <strings.h> 34a63214d6SBill Krier #include <errno.h> 356185db85Sdougm #include <libshare.h> 366185db85Sdougm #include "libshare_impl.h" 371cea05afSdougm #include <libintl.h> 38a1ef5d63Smarks #include <sys/mnttab.h> 39a1ef5d63Smarks #include <sys/mntent.h> 406185db85Sdougm 41da6c28aaSamw extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 426185db85Sdougm extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 436185db85Sdougm extern char *sa_fstype(char *); 446185db85Sdougm extern void set_node_attr(void *, char *, char *); 456185db85Sdougm extern int sa_is_share(void *); 465b6e0c46Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 471cea05afSdougm 486185db85Sdougm /* 491cea05afSdougm * File system specific code for ZFS. The original code was stolen 501cea05afSdougm * from the "zfs" command and modified to better suit this library's 511cea05afSdougm * usage. 526185db85Sdougm */ 536185db85Sdougm 541cea05afSdougm typedef struct get_all_cbdata { 551cea05afSdougm zfs_handle_t **cb_handles; 561cea05afSdougm size_t cb_alloc; 571cea05afSdougm size_t cb_used; 58a3351425Sdougm uint_t cb_types; 591cea05afSdougm } get_all_cbdata_t; 601cea05afSdougm 611cea05afSdougm /* 62549ec3ffSdougm * sa_zfs_init(impl_handle) 631cea05afSdougm * 64549ec3ffSdougm * Initialize an access handle into libzfs. The handle needs to stay 65549ec3ffSdougm * around until sa_zfs_fini() in order to maintain the cache of 66549ec3ffSdougm * mounts. 671cea05afSdougm */ 681cea05afSdougm 6957b448deSdougm int 70549ec3ffSdougm sa_zfs_init(sa_handle_impl_t impl_handle) 711cea05afSdougm { 72549ec3ffSdougm impl_handle->zfs_libhandle = libzfs_init(); 7357b448deSdougm if (impl_handle->zfs_libhandle != NULL) { 74549ec3ffSdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 7557b448deSdougm return (B_TRUE); 7657b448deSdougm } 7757b448deSdougm return (B_FALSE); 781cea05afSdougm } 791cea05afSdougm 801cea05afSdougm /* 81549ec3ffSdougm * sa_zfs_fini(impl_handle) 821cea05afSdougm * 831cea05afSdougm * cleanup data structures and the libzfs handle used for accessing 841cea05afSdougm * zfs file share info. 851cea05afSdougm */ 861cea05afSdougm 871cea05afSdougm void 88549ec3ffSdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 891cea05afSdougm { 90549ec3ffSdougm if (impl_handle->zfs_libhandle != NULL) { 91549ec3ffSdougm if (impl_handle->zfs_list != NULL) { 92a3351425Sdougm zfs_handle_t **zhp = impl_handle->zfs_list; 93a3351425Sdougm size_t i; 94a3351425Sdougm 951cea05afSdougm /* 96a3351425Sdougm * Contents of zfs_list need to be freed so we 97a3351425Sdougm * don't lose ZFS handles. 981cea05afSdougm */ 99a3351425Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) { 100a3351425Sdougm zfs_close(zhp[i]); 101a3351425Sdougm } 102549ec3ffSdougm free(impl_handle->zfs_list); 103549ec3ffSdougm impl_handle->zfs_list = NULL; 104549ec3ffSdougm impl_handle->zfs_list_count = 0; 1051cea05afSdougm } 106a3351425Sdougm 107a3351425Sdougm libzfs_fini(impl_handle->zfs_libhandle); 108a3351425Sdougm impl_handle->zfs_libhandle = NULL; 1091cea05afSdougm } 1101cea05afSdougm } 1111cea05afSdougm 1121cea05afSdougm /* 1131cea05afSdougm * get_one_filesystem(zfs_handle_t, data) 1141cea05afSdougm * 115da6c28aaSamw * an iterator function called while iterating through the ZFS 1161cea05afSdougm * root. It accumulates into an array of file system handles that can 1171cea05afSdougm * be used to derive info about those file systems. 118a3351425Sdougm * 119a3351425Sdougm * Note that as this function is called, we close all zhp handles that 120a3351425Sdougm * are not going to be places into the cp_handles list. We don't want 121a3351425Sdougm * to close the ones we are keeping, but all others would be leaked if 122a3351425Sdougm * not closed here. 1231cea05afSdougm */ 1241cea05afSdougm 1251cea05afSdougm static int 1261cea05afSdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1271cea05afSdougm { 1281cea05afSdougm get_all_cbdata_t *cbp = data; 129a3351425Sdougm zfs_type_t type = zfs_get_type(zhp); 1301cea05afSdougm 1311cea05afSdougm /* 132a3351425Sdougm * Interate over any nested datasets. 1331cea05afSdougm */ 134a3351425Sdougm if (type == ZFS_TYPE_FILESYSTEM && 135a3351425Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 136a3351425Sdougm zfs_close(zhp); 137a3351425Sdougm return (1); 138a3351425Sdougm } 139a3351425Sdougm 140a3351425Sdougm /* 141a3351425Sdougm * Skip any datasets whose type does not match. 142a3351425Sdougm */ 143a3351425Sdougm if ((type & cbp->cb_types) == 0) { 1441cea05afSdougm zfs_close(zhp); 1451cea05afSdougm return (0); 1461cea05afSdougm } 1471cea05afSdougm 1481cea05afSdougm if (cbp->cb_alloc == cbp->cb_used) { 1491cea05afSdougm zfs_handle_t **handles; 1501cea05afSdougm 1511cea05afSdougm if (cbp->cb_alloc == 0) 1521cea05afSdougm cbp->cb_alloc = 64; 1531cea05afSdougm else 1541cea05afSdougm cbp->cb_alloc *= 2; 1551cea05afSdougm 156a3351425Sdougm handles = (zfs_handle_t **)calloc(1, 157a3351425Sdougm cbp->cb_alloc * sizeof (void *)); 158a3351425Sdougm 1591cea05afSdougm if (handles == NULL) { 160a3351425Sdougm zfs_close(zhp); 1611cea05afSdougm return (0); 1621cea05afSdougm } 1631cea05afSdougm if (cbp->cb_handles) { 164a3351425Sdougm bcopy(cbp->cb_handles, handles, 1651cea05afSdougm cbp->cb_used * sizeof (void *)); 1661cea05afSdougm free(cbp->cb_handles); 1671cea05afSdougm } 1681cea05afSdougm 1691cea05afSdougm cbp->cb_handles = handles; 1701cea05afSdougm } 1711cea05afSdougm 1721cea05afSdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1731cea05afSdougm 174a3351425Sdougm return (0); 1751cea05afSdougm } 1761cea05afSdougm 1771cea05afSdougm /* 1781cea05afSdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1791cea05afSdougm * 1801cea05afSdougm * iterate through all ZFS file systems starting at the root. Returns 1811cea05afSdougm * a count and an array of handle pointers. Allocating is only done 1821cea05afSdougm * once. The caller does not need to free since it will be done at 1831cea05afSdougm * sa_zfs_fini() time. 1841cea05afSdougm */ 1851cea05afSdougm 1861cea05afSdougm static void 187549ec3ffSdougm get_all_filesystems(sa_handle_impl_t impl_handle, 188549ec3ffSdougm zfs_handle_t ***fslist, size_t *count) 1891cea05afSdougm { 1901cea05afSdougm get_all_cbdata_t cb = { 0 }; 191a3351425Sdougm cb.cb_types = ZFS_TYPE_FILESYSTEM; 1921cea05afSdougm 193549ec3ffSdougm if (impl_handle->zfs_list != NULL) { 194549ec3ffSdougm *fslist = impl_handle->zfs_list; 195549ec3ffSdougm *count = impl_handle->zfs_list_count; 1961cea05afSdougm return; 1971cea05afSdougm } 1981cea05afSdougm 199549ec3ffSdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 200549ec3ffSdougm get_one_filesystem, &cb); 2011cea05afSdougm 202549ec3ffSdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 203549ec3ffSdougm impl_handle->zfs_list_count = *count = cb.cb_used; 2041cea05afSdougm } 2051cea05afSdougm 2061cea05afSdougm /* 2071cea05afSdougm * mountpoint_compare(a, b) 2081cea05afSdougm * 2091cea05afSdougm * compares the mountpoint on two zfs file systems handles. 2101cea05afSdougm * returns values following strcmp() model. 2111cea05afSdougm */ 2121cea05afSdougm 2131cea05afSdougm static int 2141cea05afSdougm mountpoint_compare(const void *a, const void *b) 2151cea05afSdougm { 2161cea05afSdougm zfs_handle_t **za = (zfs_handle_t **)a; 2171cea05afSdougm zfs_handle_t **zb = (zfs_handle_t **)b; 2181cea05afSdougm char mounta[MAXPATHLEN]; 2191cea05afSdougm char mountb[MAXPATHLEN]; 2201cea05afSdougm 2211cea05afSdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2221cea05afSdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2231cea05afSdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2241cea05afSdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2251cea05afSdougm 2261cea05afSdougm return (strcmp(mounta, mountb)); 2271cea05afSdougm } 2281cea05afSdougm 2296185db85Sdougm /* 230743a77edSAlan Wright * return legacy mountpoint. Caller provides space for mountpoint and 231743a77edSAlan Wright * dataset. 232a1ef5d63Smarks */ 233a1ef5d63Smarks int 234743a77edSAlan Wright get_legacy_mountpoint(char *path, char *dataset, size_t dlen, 235743a77edSAlan Wright char *mountpoint, size_t mlen) 236a1ef5d63Smarks { 237a1ef5d63Smarks FILE *fp; 238a1ef5d63Smarks struct mnttab entry; 239a1ef5d63Smarks 240a1ef5d63Smarks if ((fp = fopen(MNTTAB, "r")) == NULL) { 241a1ef5d63Smarks return (1); 242a1ef5d63Smarks } 243a1ef5d63Smarks 244a1ef5d63Smarks while (getmntent(fp, &entry) == 0) { 245a1ef5d63Smarks 246a1ef5d63Smarks if (entry.mnt_fstype == NULL || 247a1ef5d63Smarks strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 248a1ef5d63Smarks continue; 249a1ef5d63Smarks 250a1ef5d63Smarks if (strcmp(entry.mnt_mountp, path) == 0) { 251743a77edSAlan Wright if (mlen > 0) 252743a77edSAlan Wright (void) strlcpy(mountpoint, entry.mnt_mountp, 253743a77edSAlan Wright mlen); 254743a77edSAlan Wright if (dlen > 0) 255743a77edSAlan Wright (void) strlcpy(dataset, entry.mnt_special, 256743a77edSAlan Wright dlen); 257743a77edSAlan Wright break; 258a1ef5d63Smarks } 259a1ef5d63Smarks } 260a1ef5d63Smarks (void) fclose(fp); 261a1ef5d63Smarks return (1); 262a1ef5d63Smarks } 263a1ef5d63Smarks 264a1ef5d63Smarks /* 265549ec3ffSdougm * get_zfs_dataset(impl_handle, path) 2666185db85Sdougm * 2676185db85Sdougm * get the name of the ZFS dataset the path is equivalent to. The 2686185db85Sdougm * dataset name is used for get/set of ZFS properties since libzfs 2696185db85Sdougm * requires a dataset to do a zfs_open(). 2706185db85Sdougm */ 2716185db85Sdougm 2726185db85Sdougm static char * 273a1ef5d63Smarks get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 274a1ef5d63Smarks boolean_t search_mnttab) 2756185db85Sdougm { 2761cea05afSdougm size_t i, count = 0; 2776185db85Sdougm char *dataset = NULL; 2781cea05afSdougm zfs_handle_t **zlist; 2791cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 28067331909Sdougm char canmount[ZFS_MAXPROPLEN]; 2816185db85Sdougm 282549ec3ffSdougm get_all_filesystems(impl_handle, &zlist, &count); 2831cea05afSdougm for (i = 0; i < count; i++) { 2841cea05afSdougm /* must have a mountpoint */ 2851cea05afSdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 2861cea05afSdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 2871cea05afSdougm /* no mountpoint */ 2881cea05afSdougm continue; 2891cea05afSdougm } 2901cea05afSdougm 2911cea05afSdougm /* mountpoint must be a path */ 2921cea05afSdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 293a1ef5d63Smarks strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 294a1ef5d63Smarks /* 295743a77edSAlan Wright * Search mmttab for mountpoint and get dataset. 296a1ef5d63Smarks */ 297a1ef5d63Smarks 298a1ef5d63Smarks if (search_mnttab == B_TRUE && 299a1ef5d63Smarks get_legacy_mountpoint(path, mountpoint, 300743a77edSAlan Wright sizeof (mountpoint), NULL, 0) == 0) { 301a1ef5d63Smarks dataset = mountpoint; 302a1ef5d63Smarks break; 303a1ef5d63Smarks } 3041cea05afSdougm continue; 305a1ef5d63Smarks } 3061cea05afSdougm 3071cea05afSdougm /* canmount must be set */ 30867331909Sdougm canmount[0] = '\0'; 309ecd6cf80Smarks if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 31067331909Sdougm sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 31167331909Sdougm strcmp(canmount, "off") == 0) 3121cea05afSdougm continue; 3131cea05afSdougm 3146185db85Sdougm /* 3151cea05afSdougm * have a mountable handle but want to skip those marked none 3161cea05afSdougm * and legacy 3176185db85Sdougm */ 3181cea05afSdougm if (strcmp(mountpoint, path) == 0) { 3191cea05afSdougm dataset = (char *)zfs_get_name(zlist[i]); 3201cea05afSdougm break; 3216185db85Sdougm } 3221cea05afSdougm 3236185db85Sdougm } 3241cea05afSdougm 32557b448deSdougm if (dataset != NULL) 3266185db85Sdougm dataset = strdup(dataset); 32757b448deSdougm 3286185db85Sdougm return (dataset); 3296185db85Sdougm } 3306185db85Sdougm 3316185db85Sdougm /* 3326185db85Sdougm * get_zfs_property(dataset, property) 3336185db85Sdougm * 3346185db85Sdougm * Get the file system property specified from the ZFS dataset. 3356185db85Sdougm */ 3366185db85Sdougm 3376185db85Sdougm static char * 3386185db85Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 3396185db85Sdougm { 3406185db85Sdougm zfs_handle_t *handle = NULL; 3416185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3426185db85Sdougm libzfs_handle_t *libhandle; 3436185db85Sdougm 3446185db85Sdougm libhandle = libzfs_init(); 3456185db85Sdougm if (libhandle != NULL) { 3466185db85Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 3476185db85Sdougm if (handle != NULL) { 3486185db85Sdougm if (zfs_prop_get(handle, property, shareopts, 3496185db85Sdougm sizeof (shareopts), NULL, NULL, 0, 3501cea05afSdougm B_FALSE) == 0) { 3516185db85Sdougm zfs_close(handle); 3526185db85Sdougm libzfs_fini(libhandle); 3536185db85Sdougm return (strdup(shareopts)); 3546185db85Sdougm } 3556185db85Sdougm zfs_close(handle); 3566185db85Sdougm } 3576185db85Sdougm libzfs_fini(libhandle); 3586185db85Sdougm } 3596185db85Sdougm return (NULL); 3606185db85Sdougm } 3616185db85Sdougm 3626185db85Sdougm /* 363549ec3ffSdougm * sa_zfs_is_shared(handle, path) 3646185db85Sdougm * 3656185db85Sdougm * Check to see if the ZFS path provided has the sharenfs option set 3666185db85Sdougm * or not. 3676185db85Sdougm */ 3686185db85Sdougm 3696185db85Sdougm int 370549ec3ffSdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 3716185db85Sdougm { 3726185db85Sdougm int ret = 0; 3736185db85Sdougm char *dataset; 3746185db85Sdougm zfs_handle_t *handle = NULL; 3756185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3766185db85Sdougm libzfs_handle_t *libhandle; 3776185db85Sdougm 378a1ef5d63Smarks dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 3796185db85Sdougm if (dataset != NULL) { 3806185db85Sdougm libhandle = libzfs_init(); 3816185db85Sdougm if (libhandle != NULL) { 38257b448deSdougm handle = zfs_open(libhandle, dataset, 38357b448deSdougm ZFS_TYPE_FILESYSTEM); 3846185db85Sdougm if (handle != NULL) { 38557b448deSdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 38657b448deSdougm shareopts, sizeof (shareopts), NULL, NULL, 38757b448deSdougm 0, B_FALSE) == 0 && 38857b448deSdougm strcmp(shareopts, "off") != 0) { 3896185db85Sdougm ret = 1; /* it is shared */ 39057b448deSdougm } 3916185db85Sdougm zfs_close(handle); 3926185db85Sdougm } 3936185db85Sdougm libzfs_fini(libhandle); 3946185db85Sdougm } 3956185db85Sdougm free(dataset); 3966185db85Sdougm } 3976185db85Sdougm return (ret); 3986185db85Sdougm } 3996185db85Sdougm 4006185db85Sdougm /* 401da6c28aaSamw * find_or_create_group(handle, groupname, proto, *err) 4026185db85Sdougm * 4036185db85Sdougm * While walking the ZFS tree, we need to add shares to a defined 4046185db85Sdougm * group. If the group doesn't exist, create it first, making sure it 4056185db85Sdougm * is marked as a ZFS group. 4066185db85Sdougm * 40793a6f655Sdougm * Note that all ZFS shares are in a subgroup of the top level group 40893a6f655Sdougm * called "zfs". 4096185db85Sdougm */ 4106185db85Sdougm 4116185db85Sdougm static sa_group_t 412549ec3ffSdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 4136185db85Sdougm { 4146185db85Sdougm sa_group_t group; 4156185db85Sdougm sa_optionset_t optionset; 4166185db85Sdougm int ret = SA_OK; 4176185db85Sdougm 4186185db85Sdougm /* 4196185db85Sdougm * we check to see if the "zfs" group exists. Since this 4206185db85Sdougm * should be the top level group, we don't want the 4216185db85Sdougm * parent. This is to make sure the zfs group has been created 4226185db85Sdougm * and to created if it hasn't been. 4236185db85Sdougm */ 424549ec3ffSdougm group = sa_get_group(handle, groupname); 4256185db85Sdougm if (group == NULL) { 426549ec3ffSdougm group = sa_create_group(handle, groupname, &ret); 42793a6f655Sdougm 42893a6f655Sdougm /* make sure this is flagged as a ZFS group */ 4296185db85Sdougm if (group != NULL) 4306185db85Sdougm ret = sa_set_group_attr(group, "zfs", "true"); 4316185db85Sdougm } 4326185db85Sdougm if (group != NULL) { 4336185db85Sdougm if (proto != NULL) { 4346185db85Sdougm optionset = sa_get_optionset(group, proto); 435da6c28aaSamw if (optionset == NULL) 4366185db85Sdougm optionset = sa_create_optionset(group, proto); 4376185db85Sdougm } 4386185db85Sdougm } 4396185db85Sdougm if (err != NULL) 4406185db85Sdougm *err = ret; 4416185db85Sdougm return (group); 4426185db85Sdougm } 4436185db85Sdougm 4446185db85Sdougm /* 44593a6f655Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 44693a6f655Sdougm * 44793a6f655Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 44893a6f655Sdougm * function looks to see if the groupname exists and returns it if it 44993a6f655Sdougm * does or else creates a new one with the specified name and returns 45093a6f655Sdougm * that. The "zfs" group will exist before we get here, but we make 45193a6f655Sdougm * sure just in case. 45293a6f655Sdougm * 45393a6f655Sdougm * err must be a valid pointer. 45493a6f655Sdougm */ 45593a6f655Sdougm 45693a6f655Sdougm static sa_group_t 457da6c28aaSamw find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 458549ec3ffSdougm char *optstring, int *err) 45993a6f655Sdougm { 46093a6f655Sdougm sa_group_t group = NULL; 46193a6f655Sdougm sa_group_t zfs; 46293a6f655Sdougm char *name; 46393a6f655Sdougm char *options; 46493a6f655Sdougm 46593a6f655Sdougm /* start with the top-level "zfs" group */ 466549ec3ffSdougm zfs = sa_get_group(handle, "zfs"); 46793a6f655Sdougm *err = SA_OK; 46893a6f655Sdougm if (zfs != NULL) { 46993a6f655Sdougm for (group = sa_get_sub_group(zfs); group != NULL; 47093a6f655Sdougm group = sa_get_next_group(group)) { 47193a6f655Sdougm name = sa_get_group_attr(group, "name"); 47293a6f655Sdougm if (name != NULL && strcmp(name, groupname) == 0) { 47393a6f655Sdougm /* have the group so break out of here */ 47493a6f655Sdougm sa_free_attr_string(name); 47593a6f655Sdougm break; 47693a6f655Sdougm } 47793a6f655Sdougm if (name != NULL) 47893a6f655Sdougm sa_free_attr_string(name); 47993a6f655Sdougm } 48093a6f655Sdougm 48193a6f655Sdougm if (group == NULL) { 48257b448deSdougm /* 4833c484793Sdougm * Need to create the sub-group since it doesn't exist 48457b448deSdougm */ 48593a6f655Sdougm group = _sa_create_zfs_group(zfs, groupname); 4863c484793Sdougm if (group == NULL) { 4873c484793Sdougm *err = SA_NO_MEMORY; 4883c484793Sdougm return (NULL); 4893c484793Sdougm } 49093a6f655Sdougm set_node_attr(group, "zfs", "true"); 4913c484793Sdougm } 49293a6f655Sdougm if (strcmp(optstring, "on") == 0) 49393a6f655Sdougm optstring = "rw"; 49493a6f655Sdougm options = strdup(optstring); 49593a6f655Sdougm if (options != NULL) { 4963c484793Sdougm *err = sa_parse_legacy_options(group, options, 4973c484793Sdougm proto); 4983c484793Sdougm /* If no optionset, add one. */ 4993c484793Sdougm if (sa_get_optionset(group, proto) == NULL) 5003c484793Sdougm (void) sa_create_optionset(group, proto); 501c3f7431dSDan Kruchinin 502c3f7431dSDan Kruchinin /* 503c3f7431dSDan Kruchinin * Do not forget to update an optionset of 504c3f7431dSDan Kruchinin * the parent group so that it contains 505c3f7431dSDan Kruchinin * all protocols its subgroups have. 506c3f7431dSDan Kruchinin */ 507c3f7431dSDan Kruchinin if (sa_get_optionset(zfs, proto) == NULL) 508c3f7431dSDan Kruchinin (void) sa_create_optionset(zfs, proto); 509c3f7431dSDan Kruchinin 51093a6f655Sdougm free(options); 51193a6f655Sdougm } else { 51293a6f655Sdougm *err = SA_NO_MEMORY; 51393a6f655Sdougm } 51493a6f655Sdougm } 51593a6f655Sdougm return (group); 51693a6f655Sdougm } 51793a6f655Sdougm 51893a6f655Sdougm /* 519da6c28aaSamw * zfs_construct_resource(share, name, base, dataset) 520da6c28aaSamw * 521da6c28aaSamw * Add a resource to the share using name as a template. If name == 522da6c28aaSamw * NULL, then construct a name based on the dataset value. 523da6c28aaSamw * name. 524da6c28aaSamw */ 525da6c28aaSamw static void 526da6c28aaSamw zfs_construct_resource(sa_share_t share, char *dataset) 527da6c28aaSamw { 528da6c28aaSamw char buff[SA_MAX_RESOURCE_NAME + 1]; 529da6c28aaSamw int ret = SA_OK; 530da6c28aaSamw 531da6c28aaSamw (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset); 532da6c28aaSamw sa_fix_resource_name(buff); 533da6c28aaSamw (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret); 534da6c28aaSamw } 535da6c28aaSamw 536da6c28aaSamw /* 53757b448deSdougm * zfs_inherited(handle, source, sourcestr) 53857b448deSdougm * 539da6c28aaSamw * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares 54057b448deSdougm * for readability. 54157b448deSdougm */ 54257b448deSdougm static int 54357b448deSdougm zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 544da6c28aaSamw char *shareopts, char *mountpoint, char *proto, char *dataset) 54557b448deSdougm { 54657b448deSdougm int doshopt = 0; 54757b448deSdougm int err = SA_OK; 54857b448deSdougm sa_group_t group; 549da6c28aaSamw sa_resource_t resource; 550da6c28aaSamw uint64_t features; 55157b448deSdougm 55257b448deSdougm /* 55357b448deSdougm * Need to find the "real" parent sub-group. It may not be 55457b448deSdougm * mounted, but it was identified in the "sourcestr" 55557b448deSdougm * variable. The real parent not mounted can occur if 55657b448deSdougm * "canmount=off and sharenfs=on". 55757b448deSdougm */ 558da6c28aaSamw group = find_or_create_zfs_subgroup(handle, sourcestr, proto, 559da6c28aaSamw shareopts, &doshopt); 56057b448deSdougm if (group != NULL) { 561da6c28aaSamw /* 562da6c28aaSamw * We may need the first share for resource 563da6c28aaSamw * prototype. We only care about it if it has a 564da6c28aaSamw * resource that sets a prefix value. 565da6c28aaSamw */ 566da6c28aaSamw if (share == NULL) 567da6c28aaSamw share = _sa_add_share(group, mountpoint, 568da6c28aaSamw SA_SHARE_TRANSIENT, &err, 569da6c28aaSamw (uint64_t)SA_FEATURE_NONE); 57057b448deSdougm /* 57157b448deSdougm * some options may only be on shares. If the opt 57257b448deSdougm * string contains one of those, we put it just on the 57357b448deSdougm * share. 57457b448deSdougm */ 57557b448deSdougm if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 57657b448deSdougm char *options; 57757b448deSdougm options = strdup(shareopts); 57857b448deSdougm if (options != NULL) { 579da6c28aaSamw set_node_attr(share, "dataset", dataset); 58057b448deSdougm err = sa_parse_legacy_options(share, options, 581da6c28aaSamw proto); 582da6c28aaSamw set_node_attr(share, "dataset", NULL); 58357b448deSdougm free(options); 58457b448deSdougm } 585da6c28aaSamw if (sa_get_optionset(group, proto) == NULL) 586da6c28aaSamw (void) sa_create_optionset(group, proto); 587da6c28aaSamw } 588da6c28aaSamw features = sa_proto_get_featureset(proto); 589da6c28aaSamw if (share != NULL && features & SA_FEATURE_RESOURCE) { 590da6c28aaSamw /* 591da6c28aaSamw * We have a share and the protocol requires 592da6c28aaSamw * that at least one resource exist (probably 593da6c28aaSamw * SMB). We need to make sure that there is at 594da6c28aaSamw * least one. 595da6c28aaSamw */ 596da6c28aaSamw resource = sa_get_share_resource(share, NULL); 597da6c28aaSamw if (resource == NULL) { 598da6c28aaSamw zfs_construct_resource(share, dataset); 599da6c28aaSamw } 60057b448deSdougm } 60157b448deSdougm } else { 60257b448deSdougm err = SA_NO_MEMORY; 60357b448deSdougm } 60457b448deSdougm return (err); 60557b448deSdougm } 60657b448deSdougm 60757b448deSdougm /* 60897df5ac9Sdougm * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset, 60997df5ac9Sdougm * grouperr) 61057b448deSdougm * 61157b448deSdougm * handle case where this is the top of a sub-group in ZFS. Pulled out 61297df5ac9Sdougm * of sa_get_zfs_shares for readability. We need the grouperr from the 61397df5ac9Sdougm * creation of the subgroup to know whether to add the public 61497df5ac9Sdougm * property, etc. to the specific share. 61557b448deSdougm */ 61657b448deSdougm static int 617da6c28aaSamw zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 61897df5ac9Sdougm char *shareopts, char *proto, char *dataset, int grouperr) 61957b448deSdougm { 62057b448deSdougm int err = SA_OK; 621da6c28aaSamw sa_resource_t resource; 622da6c28aaSamw uint64_t features; 62357b448deSdougm 62457b448deSdougm set_node_attr(group, "zfs", "true"); 625da6c28aaSamw if (share == NULL) 626da6c28aaSamw share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 627da6c28aaSamw &err, (uint64_t)SA_FEATURE_NONE); 6283c484793Sdougm 6293c484793Sdougm if (err != SA_OK) 6303c484793Sdougm return (err); 6313c484793Sdougm 632f8825440Sdougm if (strcmp(shareopts, "on") == 0) 633da6c28aaSamw shareopts = ""; 634da6c28aaSamw if (shareopts != NULL) { 635da6c28aaSamw char *options; 63697df5ac9Sdougm if (grouperr == SA_PROP_SHARE_ONLY) { 63757b448deSdougm /* 6383c484793Sdougm * Some properties may only be on shares, but 6393c484793Sdougm * due to the ZFS sub-groups being artificial, 6403c484793Sdougm * we sometimes get this and have to deal with 6413c484793Sdougm * it. We do it by attempting to put it on the 6423c484793Sdougm * share. 64357b448deSdougm */ 64457b448deSdougm options = strdup(shareopts); 645a3351425Sdougm if (options != NULL) { 64657b448deSdougm err = sa_parse_legacy_options(share, 647da6c28aaSamw options, proto); 64857b448deSdougm free(options); 64957b448deSdougm } 650a3351425Sdougm } 6513c484793Sdougm /* Unmark the share's changed state */ 65257b448deSdougm set_node_attr(share, "changed", NULL); 65357b448deSdougm } 654da6c28aaSamw features = sa_proto_get_featureset(proto); 655da6c28aaSamw if (share != NULL && features & SA_FEATURE_RESOURCE) { 656da6c28aaSamw /* 6573c484793Sdougm * We have a share and the protocol requires that at 6583c484793Sdougm * least one resource exist (probably SMB). We need to 6593c484793Sdougm * make sure that there is at least one. 660da6c28aaSamw */ 661da6c28aaSamw resource = sa_get_share_resource(share, NULL); 662da6c28aaSamw if (resource == NULL) { 663da6c28aaSamw zfs_construct_resource(share, dataset); 664da6c28aaSamw } 665da6c28aaSamw } 66657b448deSdougm return (err); 66757b448deSdougm } 66857b448deSdougm 66957b448deSdougm /* 67057b448deSdougm * zfs_grp_error(err) 67157b448deSdougm * 67257b448deSdougm * Print group create error, but only once. If err is 0 do the 67357b448deSdougm * print else don't. 67457b448deSdougm */ 67557b448deSdougm 67657b448deSdougm static void 67757b448deSdougm zfs_grp_error(int err) 67857b448deSdougm { 67957b448deSdougm if (err == 0) { 68057b448deSdougm /* only print error once */ 68157b448deSdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 68257b448deSdougm "Cannot create ZFS subgroup during initialization:" 68357b448deSdougm " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 68457b448deSdougm } 68557b448deSdougm } 68657b448deSdougm 68757b448deSdougm /* 688da6c28aaSamw * zfs_process_share(handle, share, mountpoint, proto, source, 689da6c28aaSamw * shareopts, sourcestr) 690da6c28aaSamw * 6915b6e0c46Sdougm * Creates the subgroup, if necessary and adds shares, resources 692da6c28aaSamw * and properties. 693da6c28aaSamw */ 6945b6e0c46Sdougm int 6955b6e0c46Sdougm sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 696da6c28aaSamw char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 697da6c28aaSamw char *sourcestr, char *dataset) 698da6c28aaSamw { 699da6c28aaSamw int err = SA_OK; 700da6c28aaSamw 701da6c28aaSamw if (source & ZPROP_SRC_INHERITED) { 702da6c28aaSamw err = zfs_inherited(handle, share, sourcestr, shareopts, 703da6c28aaSamw mountpoint, proto, dataset); 704da6c28aaSamw } else { 705da6c28aaSamw group = find_or_create_zfs_subgroup(handle, dataset, proto, 706da6c28aaSamw shareopts, &err); 707da6c28aaSamw if (group == NULL) { 70897df5ac9Sdougm static boolean_t reported_error = B_FALSE; 709da6c28aaSamw /* 71097df5ac9Sdougm * There is a problem, but we can't do 711da6c28aaSamw * anything about it at this point so we issue 71297df5ac9Sdougm * a warning and move on. 713da6c28aaSamw */ 71497df5ac9Sdougm zfs_grp_error(reported_error); 71597df5ac9Sdougm reported_error = B_TRUE; 716da6c28aaSamw } 717da6c28aaSamw set_node_attr(group, "zfs", "true"); 718da6c28aaSamw /* 719da6c28aaSamw * Add share with local opts via zfs_notinherited. 720da6c28aaSamw */ 721da6c28aaSamw err = zfs_notinherited(group, share, mountpoint, shareopts, 72297df5ac9Sdougm proto, dataset, err); 723da6c28aaSamw } 724da6c28aaSamw return (err); 725da6c28aaSamw } 726da6c28aaSamw 727da6c28aaSamw /* 728549ec3ffSdougm * sa_get_zfs_shares(handle, groupname) 7296185db85Sdougm * 7306185db85Sdougm * Walk the mnttab for all zfs mounts and determine which are 7316185db85Sdougm * shared. Find or create the appropriate group/sub-group to contain 7326185db85Sdougm * the shares. 7336185db85Sdougm * 7346185db85Sdougm * All shares are in a sub-group that will hold the properties. This 7356185db85Sdougm * allows representing the inherited property model. 7363c484793Sdougm * 7373c484793Sdougm * One area of complication is if "sharenfs" is set at one level of 7383c484793Sdougm * the directory tree and "sharesmb" is set at a different level, the 7393c484793Sdougm * a sub-group must be formed at the lower level for both 7403c484793Sdougm * protocols. That is the nature of the problem in CR 6667349. 7416185db85Sdougm */ 7426185db85Sdougm 7436185db85Sdougm int 744549ec3ffSdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 7456185db85Sdougm { 7466185db85Sdougm sa_group_t zfsgroup; 7473c484793Sdougm boolean_t nfs; 7483c484793Sdougm boolean_t nfs_inherited; 7493c484793Sdougm boolean_t smb; 7503c484793Sdougm boolean_t smb_inherited; 7511cea05afSdougm zfs_handle_t **zlist; 7523c484793Sdougm char nfsshareopts[ZFS_MAXPROPLEN]; 7533c484793Sdougm char smbshareopts[ZFS_MAXPROPLEN]; 7546185db85Sdougm sa_share_t share; 755990b4856Slling zprop_source_t source; 7563c484793Sdougm char nfssourcestr[ZFS_MAXPROPLEN]; 7573c484793Sdougm char smbsourcestr[ZFS_MAXPROPLEN]; 7581cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 7591cea05afSdougm size_t count = 0, i; 760549ec3ffSdougm libzfs_handle_t *zfs_libhandle; 7613c484793Sdougm int err = SA_OK; 7626185db85Sdougm 7636185db85Sdougm /* 764549ec3ffSdougm * If we can't access libzfs, don't bother doing anything. 7656185db85Sdougm */ 766549ec3ffSdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 7671cea05afSdougm if (zfs_libhandle == NULL) 7686185db85Sdougm return (SA_SYSTEM_ERR); 7696185db85Sdougm 770da6c28aaSamw zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 7713c484793Sdougm /* Not an error, this could be a legacy condition */ 772546405c3Sdougm if (zfsgroup == NULL) 7733c484793Sdougm return (SA_OK); 774546405c3Sdougm 7756185db85Sdougm /* 7766185db85Sdougm * need to walk the mounted ZFS pools and datasets to 7776185db85Sdougm * find shares that are possible. 7786185db85Sdougm */ 779549ec3ffSdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 7801cea05afSdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 7811cea05afSdougm 7821cea05afSdougm for (i = 0; i < count; i++) { 7831cea05afSdougm char *dataset; 7841cea05afSdougm 785990b4856Slling source = ZPROP_SRC_ALL; 786546405c3Sdougm /* If no mountpoint, skip. */ 78757b448deSdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 78857b448deSdougm mountpoint, sizeof (mountpoint), NULL, NULL, 0, 789546405c3Sdougm B_FALSE) != 0) 7901cea05afSdougm continue; 7911cea05afSdougm 7921cea05afSdougm /* 7931cea05afSdougm * zfs_get_name value must not be freed. It is just a 7941cea05afSdougm * pointer to a value in the handle. 7951cea05afSdougm */ 7961cea05afSdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 7971cea05afSdougm continue; 7981cea05afSdougm 7991cea05afSdougm /* 8001cea05afSdougm * only deal with "mounted" file systems since 8011cea05afSdougm * unmounted file systems can't actually be shared. 8021cea05afSdougm */ 8031cea05afSdougm 8041cea05afSdougm if (!zfs_is_mounted(zlist[i], NULL)) 8051cea05afSdougm continue; 8061cea05afSdougm 8073c484793Sdougm nfs = nfs_inherited = B_FALSE; 8083c484793Sdougm 8093c484793Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts, 8103c484793Sdougm sizeof (nfsshareopts), &source, nfssourcestr, 81157b448deSdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 8123c484793Sdougm strcmp(nfsshareopts, "off") != 0) { 8133c484793Sdougm if (source & ZPROP_SRC_INHERITED) 8143c484793Sdougm nfs_inherited = B_TRUE; 8153c484793Sdougm else 8163c484793Sdougm nfs = B_TRUE; 8173c484793Sdougm } 8183c484793Sdougm 8193c484793Sdougm smb = smb_inherited = B_FALSE; 8203c484793Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts, 8213c484793Sdougm sizeof (smbshareopts), &source, smbsourcestr, 8223c484793Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 8233c484793Sdougm strcmp(smbshareopts, "off") != 0) { 8243c484793Sdougm if (source & ZPROP_SRC_INHERITED) 8253c484793Sdougm smb_inherited = B_TRUE; 8263c484793Sdougm else 8273c484793Sdougm smb = B_TRUE; 8283c484793Sdougm } 8293c484793Sdougm 8306185db85Sdougm /* 8313c484793Sdougm * If the mountpoint is already shared, it must be a 8323c484793Sdougm * non-ZFS share. We want to remove the share from its 8333c484793Sdougm * parent group and reshare it under ZFS. 8346185db85Sdougm */ 8353c484793Sdougm share = sa_find_share(handle, mountpoint); 8363c484793Sdougm if (share != NULL && 8373c484793Sdougm (nfs || smb || nfs_inherited || smb_inherited)) { 8386185db85Sdougm err = sa_remove_share(share); 8396185db85Sdougm share = NULL; 8406185db85Sdougm } 8413c484793Sdougm 842da6c28aaSamw /* 8433c484793Sdougm * At this point, we have the information needed to 8443c484793Sdougm * determine what to do with the share. 8453c484793Sdougm * 8463c484793Sdougm * If smb or nfs is set, we have a new sub-group. 8473c484793Sdougm * If smb_inherit and/or nfs_inherit is set, then 8483c484793Sdougm * place on an existing sub-group. If both are set, 8493c484793Sdougm * the existing sub-group is the closest up the tree. 850da6c28aaSamw */ 8513c484793Sdougm if (nfs || smb) { 8523c484793Sdougm /* 8533c484793Sdougm * Non-inherited is the straightforward 8543c484793Sdougm * case. sa_zfs_process_share handles it 8553c484793Sdougm * directly. Make sure that if the "other" 8563c484793Sdougm * protocol is inherited, that we treat it as 8573c484793Sdougm * non-inherited as well. 8583c484793Sdougm */ 8593c484793Sdougm if (nfs || nfs_inherited) { 8603c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8613c484793Sdougm share, mountpoint, "nfs", 8623c484793Sdougm 0, nfsshareopts, 8633c484793Sdougm nfssourcestr, dataset); 8643c484793Sdougm share = sa_find_share(handle, mountpoint); 865da6c28aaSamw } 8663c484793Sdougm if (smb || smb_inherited) { 8673c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8683c484793Sdougm share, mountpoint, "smb", 8693c484793Sdougm 0, smbshareopts, 8703c484793Sdougm smbsourcestr, dataset); 8713c484793Sdougm } 8723c484793Sdougm } else if (nfs_inherited || smb_inherited) { 8733c484793Sdougm char *grpdataset; 8743c484793Sdougm /* 8753c484793Sdougm * If we only have inherited groups, it is 8763c484793Sdougm * important to find the closer of the two if 8773c484793Sdougm * the protocols are set at different 8783c484793Sdougm * levels. The closest sub-group is the one we 8793c484793Sdougm * want to work with. 8803c484793Sdougm */ 8813c484793Sdougm if (nfs_inherited && smb_inherited) { 8823c484793Sdougm if (strcmp(nfssourcestr, smbsourcestr) <= 0) 8833c484793Sdougm grpdataset = nfssourcestr; 8843c484793Sdougm else 8853c484793Sdougm grpdataset = smbsourcestr; 8863c484793Sdougm } else if (nfs_inherited) { 8873c484793Sdougm grpdataset = nfssourcestr; 8883c484793Sdougm } else if (smb_inherited) { 8893c484793Sdougm grpdataset = smbsourcestr; 8903c484793Sdougm } 8913c484793Sdougm if (nfs_inherited) { 8923c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8933c484793Sdougm share, mountpoint, "nfs", 8943c484793Sdougm ZPROP_SRC_INHERITED, nfsshareopts, 8953c484793Sdougm grpdataset, dataset); 8963c484793Sdougm share = sa_find_share(handle, mountpoint); 8973c484793Sdougm } 8983c484793Sdougm if (smb_inherited) { 8993c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 9003c484793Sdougm share, mountpoint, "smb", 9013c484793Sdougm ZPROP_SRC_INHERITED, smbshareopts, 9023c484793Sdougm grpdataset, dataset); 9036185db85Sdougm } 9046185db85Sdougm } 9056185db85Sdougm } 9061cea05afSdougm /* 9071cea05afSdougm * Don't need to free the "zlist" variable since it is only a 9081cea05afSdougm * pointer to a cached value that will be freed when 9091cea05afSdougm * sa_fini() is called. 9101cea05afSdougm */ 9113c484793Sdougm return (err); 9126185db85Sdougm } 9136185db85Sdougm 9146185db85Sdougm #define COMMAND "/usr/sbin/zfs" 9156185db85Sdougm 9166185db85Sdougm /* 9176185db85Sdougm * sa_zfs_set_sharenfs(group, path, on) 9186185db85Sdougm * 9196185db85Sdougm * Update the "sharenfs" property on the path. If on is true, then set 9206185db85Sdougm * to the properties on the group or "on" if no properties are 9216185db85Sdougm * defined. Set to "off" if on is false. 9226185db85Sdougm */ 9236185db85Sdougm 9246185db85Sdougm int 9256185db85Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 9266185db85Sdougm { 9276185db85Sdougm int ret = SA_NOT_IMPLEMENTED; 9286185db85Sdougm char *command; 9296185db85Sdougm 9306185db85Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 9316185db85Sdougm if (command != NULL) { 9326185db85Sdougm char *opts = NULL; 933549ec3ffSdougm char *dataset = NULL; 9346185db85Sdougm FILE *pfile; 935549ec3ffSdougm sa_handle_impl_t impl_handle; 9366185db85Sdougm /* for now, NFS is always available for "zfs" */ 9376185db85Sdougm if (on) { 9386185db85Sdougm opts = sa_proto_legacy_format("nfs", group, 1); 9396185db85Sdougm if (opts != NULL && strlen(opts) == 0) { 9406185db85Sdougm free(opts); 9416185db85Sdougm opts = strdup("on"); 9426185db85Sdougm } 9436185db85Sdougm } 944549ec3ffSdougm 945549ec3ffSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 94667331909Sdougm assert(impl_handle != NULL); 947549ec3ffSdougm if (impl_handle != NULL) 948a1ef5d63Smarks dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 949549ec3ffSdougm else 950549ec3ffSdougm ret = SA_SYSTEM_ERR; 951549ec3ffSdougm 9526185db85Sdougm if (dataset != NULL) { 9536185db85Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 9546185db85Sdougm "%s set sharenfs=\"%s\" %s", COMMAND, 95557b448deSdougm opts != NULL ? opts : "off", dataset); 9566185db85Sdougm pfile = popen(command, "r"); 9576185db85Sdougm if (pfile != NULL) { 9586185db85Sdougm ret = pclose(pfile); 9596185db85Sdougm if (ret != 0) 9606185db85Sdougm ret = SA_SYSTEM_ERR; 9616185db85Sdougm } 9626185db85Sdougm } 9636185db85Sdougm if (opts != NULL) 9646185db85Sdougm free(opts); 9656185db85Sdougm if (dataset != NULL) 9666185db85Sdougm free(dataset); 9676185db85Sdougm free(command); 9686185db85Sdougm } 9696185db85Sdougm return (ret); 9706185db85Sdougm } 9716185db85Sdougm 9726185db85Sdougm /* 973da6c28aaSamw * add_resources(share, opt) 974da6c28aaSamw * 975da6c28aaSamw * Add resource properties to those in "opt". Resources are prefixed 976da6c28aaSamw * with name=resourcename. 977da6c28aaSamw */ 978da6c28aaSamw static char * 979da6c28aaSamw add_resources(sa_share_t share, char *opt) 980da6c28aaSamw { 981da6c28aaSamw char *newopt = NULL; 982da6c28aaSamw char *propstr; 983da6c28aaSamw sa_resource_t resource; 984da6c28aaSamw 985da6c28aaSamw newopt = strdup(opt); 986da6c28aaSamw if (newopt == NULL) 987da6c28aaSamw return (newopt); 988da6c28aaSamw 989da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 990da6c28aaSamw resource != NULL; 991da6c28aaSamw resource = sa_get_next_resource(resource)) { 992da6c28aaSamw char *name; 993da6c28aaSamw size_t size; 994da6c28aaSamw 995da6c28aaSamw name = sa_get_resource_attr(resource, "name"); 996da6c28aaSamw if (name == NULL) { 997da6c28aaSamw free(newopt); 998da6c28aaSamw return (NULL); 999da6c28aaSamw } 1000da6c28aaSamw size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 1001da6c28aaSamw newopt = calloc(1, size); 1002da6c28aaSamw if (newopt != NULL) 1003da6c28aaSamw (void) snprintf(newopt, size, "%s,name=%s", opt, name); 1004fe1c642dSBill Krier sa_free_attr_string(name); 1005da6c28aaSamw free(opt); 1006da6c28aaSamw opt = newopt; 1007da6c28aaSamw propstr = sa_proto_legacy_format("smb", resource, 0); 1008da6c28aaSamw if (propstr == NULL) { 1009da6c28aaSamw free(opt); 1010da6c28aaSamw return (NULL); 1011da6c28aaSamw } 1012da6c28aaSamw size = strlen(propstr) + strlen(opt) + 2; 1013da6c28aaSamw newopt = calloc(1, size); 1014da6c28aaSamw if (newopt != NULL) 1015da6c28aaSamw (void) snprintf(newopt, size, "%s,%s", opt, propstr); 1016da6c28aaSamw free(opt); 1017da6c28aaSamw opt = newopt; 1018da6c28aaSamw } 1019da6c28aaSamw return (opt); 1020da6c28aaSamw } 1021da6c28aaSamw 1022da6c28aaSamw /* 1023da6c28aaSamw * sa_zfs_set_sharesmb(group, path, on) 1024da6c28aaSamw * 1025da6c28aaSamw * Update the "sharesmb" property on the path. If on is true, then set 1026da6c28aaSamw * to the properties on the group or "on" if no properties are 1027da6c28aaSamw * defined. Set to "off" if on is false. 1028da6c28aaSamw */ 1029da6c28aaSamw 1030da6c28aaSamw int 1031da6c28aaSamw sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 1032da6c28aaSamw { 1033da6c28aaSamw int ret = SA_NOT_IMPLEMENTED; 1034da6c28aaSamw char *command; 1035da6c28aaSamw sa_share_t share; 1036da6c28aaSamw 1037da6c28aaSamw /* In case SMB not enabled */ 1038da6c28aaSamw if (sa_get_optionset(group, "smb") == NULL) 1039da6c28aaSamw return (SA_NOT_SUPPORTED); 1040da6c28aaSamw 1041da6c28aaSamw command = malloc(ZFS_MAXPROPLEN * 2); 1042da6c28aaSamw if (command != NULL) { 1043da6c28aaSamw char *opts = NULL; 1044da6c28aaSamw char *dataset = NULL; 1045da6c28aaSamw FILE *pfile; 1046da6c28aaSamw sa_handle_impl_t impl_handle; 1047da6c28aaSamw 1048da6c28aaSamw if (on) { 1049da6c28aaSamw char *newopt; 1050da6c28aaSamw 1051da6c28aaSamw share = sa_get_share(group, NULL); 1052da6c28aaSamw opts = sa_proto_legacy_format("smb", share, 1); 1053da6c28aaSamw if (opts != NULL && strlen(opts) == 0) { 1054da6c28aaSamw free(opts); 1055da6c28aaSamw opts = strdup("on"); 1056da6c28aaSamw } 1057da6c28aaSamw newopt = add_resources(opts, share); 1058da6c28aaSamw free(opts); 1059da6c28aaSamw opts = newopt; 1060da6c28aaSamw } 1061da6c28aaSamw 1062da6c28aaSamw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1063da6c28aaSamw assert(impl_handle != NULL); 1064da6c28aaSamw if (impl_handle != NULL) 1065da6c28aaSamw dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1066da6c28aaSamw else 1067da6c28aaSamw ret = SA_SYSTEM_ERR; 1068da6c28aaSamw 1069da6c28aaSamw if (dataset != NULL) { 1070da6c28aaSamw (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1071da6c28aaSamw "echo %s set sharesmb=\"%s\" %s", COMMAND, 1072da6c28aaSamw opts != NULL ? opts : "off", dataset); 1073da6c28aaSamw pfile = popen(command, "r"); 1074da6c28aaSamw if (pfile != NULL) { 1075da6c28aaSamw ret = pclose(pfile); 1076da6c28aaSamw if (ret != 0) 1077da6c28aaSamw ret = SA_SYSTEM_ERR; 1078da6c28aaSamw } 1079da6c28aaSamw } 1080da6c28aaSamw if (opts != NULL) 1081da6c28aaSamw free(opts); 1082da6c28aaSamw if (dataset != NULL) 1083da6c28aaSamw free(dataset); 1084da6c28aaSamw free(command); 1085da6c28aaSamw } 1086da6c28aaSamw return (ret); 1087da6c28aaSamw } 1088da6c28aaSamw 1089da6c28aaSamw /* 10906185db85Sdougm * sa_zfs_update(group) 10916185db85Sdougm * 10926185db85Sdougm * call back to ZFS to update the share if necessary. 10936185db85Sdougm * Don't do it if it isn't a real change. 10946185db85Sdougm */ 10956185db85Sdougm int 10966185db85Sdougm sa_zfs_update(sa_group_t group) 10976185db85Sdougm { 10986185db85Sdougm sa_optionset_t protopt; 10996185db85Sdougm sa_group_t parent; 11006185db85Sdougm char *command; 11016185db85Sdougm char *optstring; 11026185db85Sdougm int ret = SA_OK; 11036185db85Sdougm int doupdate = 0; 11046185db85Sdougm FILE *pfile; 11056185db85Sdougm 11066185db85Sdougm if (sa_is_share(group)) 11076185db85Sdougm parent = sa_get_parent_group(group); 11086185db85Sdougm else 11096185db85Sdougm parent = group; 11106185db85Sdougm 11116185db85Sdougm if (parent != NULL) { 11126185db85Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 11136185db85Sdougm if (command == NULL) 11146185db85Sdougm return (SA_NO_MEMORY); 11156185db85Sdougm 11166185db85Sdougm *command = '\0'; 11176185db85Sdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 11186185db85Sdougm protopt = sa_get_next_optionset(protopt)) { 11196185db85Sdougm 11206185db85Sdougm char *proto = sa_get_optionset_attr(protopt, "type"); 11216185db85Sdougm char *path; 11226185db85Sdougm char *dataset = NULL; 11236185db85Sdougm char *zfsopts = NULL; 11246185db85Sdougm 11256185db85Sdougm if (sa_is_share(group)) { 112657b448deSdougm path = sa_get_share_attr((sa_share_t)group, 112757b448deSdougm "path"); 11286185db85Sdougm if (path != NULL) { 1129549ec3ffSdougm sa_handle_impl_t impl_handle; 1130549ec3ffSdougm 113157b448deSdougm impl_handle = sa_find_group_handle( 113257b448deSdougm group); 1133549ec3ffSdougm if (impl_handle != NULL) 113457b448deSdougm dataset = get_zfs_dataset( 1135a1ef5d63Smarks impl_handle, path, B_FALSE); 1136549ec3ffSdougm else 1137549ec3ffSdougm ret = SA_SYSTEM_ERR; 1138549ec3ffSdougm 11396185db85Sdougm sa_free_attr_string(path); 11406185db85Sdougm } 11416185db85Sdougm } else { 11426185db85Sdougm dataset = sa_get_group_attr(group, "name"); 11436185db85Sdougm } 11446185db85Sdougm /* update only when there is an optstring found */ 11456185db85Sdougm doupdate = 0; 11466185db85Sdougm if (proto != NULL && dataset != NULL) { 114757b448deSdougm optstring = sa_proto_legacy_format(proto, 114857b448deSdougm group, 1); 114957b448deSdougm zfsopts = get_zfs_property(dataset, 115057b448deSdougm ZFS_PROP_SHARENFS); 11516185db85Sdougm 11526185db85Sdougm if (optstring != NULL && zfsopts != NULL) { 11536185db85Sdougm if (strcmp(optstring, zfsopts) != 0) 11546185db85Sdougm doupdate++; 11556185db85Sdougm } 11566185db85Sdougm if (doupdate) { 115757b448deSdougm if (optstring != NULL && 115857b448deSdougm strlen(optstring) > 0) { 115957b448deSdougm (void) snprintf(command, 116057b448deSdougm ZFS_MAXPROPLEN * 2, 11611f713840SDoug McCallum "%s set share%s=%s %s", 11621f713840SDoug McCallum COMMAND, proto, 11636185db85Sdougm optstring, dataset); 11646185db85Sdougm } else { 116557b448deSdougm (void) snprintf(command, 116657b448deSdougm ZFS_MAXPROPLEN * 2, 11671f713840SDoug McCallum "%s set share%s=on %s", 11681f713840SDoug McCallum COMMAND, proto, 11696185db85Sdougm dataset); 11706185db85Sdougm } 11716185db85Sdougm pfile = popen(command, "r"); 11726185db85Sdougm if (pfile != NULL) 11736185db85Sdougm ret = pclose(pfile); 11746185db85Sdougm switch (ret) { 11756185db85Sdougm default: 11766185db85Sdougm case 1: 11776185db85Sdougm ret = SA_SYSTEM_ERR; 11786185db85Sdougm break; 11796185db85Sdougm case 2: 11806185db85Sdougm ret = SA_SYNTAX_ERR; 11816185db85Sdougm break; 11826185db85Sdougm case 0: 11836185db85Sdougm break; 11846185db85Sdougm } 11856185db85Sdougm } 118657b448deSdougm if (optstring != NULL) 11876185db85Sdougm free(optstring); 11886185db85Sdougm if (zfsopts != NULL) 11896185db85Sdougm free(zfsopts); 11906185db85Sdougm } 11916185db85Sdougm if (proto != NULL) 11926185db85Sdougm sa_free_attr_string(proto); 11936185db85Sdougm if (dataset != NULL) 11946185db85Sdougm free(dataset); 11956185db85Sdougm } 11966185db85Sdougm free(command); 11976185db85Sdougm } 11986185db85Sdougm return (ret); 11996185db85Sdougm } 12006185db85Sdougm 12016185db85Sdougm /* 12026185db85Sdougm * sa_group_is_zfs(group) 12036185db85Sdougm * 12046185db85Sdougm * Given the group, determine if the zfs attribute is set. 12056185db85Sdougm */ 12066185db85Sdougm 12076185db85Sdougm int 12086185db85Sdougm sa_group_is_zfs(sa_group_t group) 12096185db85Sdougm { 12106185db85Sdougm char *zfs; 12116185db85Sdougm int ret = 0; 12126185db85Sdougm 12136185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 12146185db85Sdougm if (zfs != NULL) { 12156185db85Sdougm ret = 1; 12166185db85Sdougm sa_free_attr_string(zfs); 12176185db85Sdougm } 12186185db85Sdougm return (ret); 12196185db85Sdougm } 12206185db85Sdougm 12216185db85Sdougm /* 12226185db85Sdougm * sa_path_is_zfs(path) 12236185db85Sdougm * 12246185db85Sdougm * Check to see if the file system path represents is of type "zfs". 12256185db85Sdougm */ 12266185db85Sdougm 12276185db85Sdougm int 12286185db85Sdougm sa_path_is_zfs(char *path) 12296185db85Sdougm { 12306185db85Sdougm char *fstype; 12316185db85Sdougm int ret = 0; 12326185db85Sdougm 12336185db85Sdougm fstype = sa_fstype(path); 123457b448deSdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) 12356185db85Sdougm ret = 1; 12366185db85Sdougm if (fstype != NULL) 12376185db85Sdougm sa_free_fstype(fstype); 12386185db85Sdougm return (ret); 12396185db85Sdougm } 1240ecd6cf80Smarks 1241ecd6cf80Smarks int 1242ecd6cf80Smarks sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1243ecd6cf80Smarks { 1244ecd6cf80Smarks char *path; 1245ecd6cf80Smarks 1246ed78bdc4Smarks /* Make sure path is valid */ 1247ed78bdc4Smarks 1248ecd6cf80Smarks path = sa_get_share_attr(share, "path"); 1249ecd6cf80Smarks if (path != NULL) { 1250ecd6cf80Smarks (void) memset(sh, 0, sizeof (sh)); 1251ecd6cf80Smarks (void) sa_fillshare(share, proto, sh); 1252ed78bdc4Smarks sa_free_attr_string(path); 1253ecd6cf80Smarks return (0); 1254ecd6cf80Smarks } else 1255ecd6cf80Smarks return (1); 1256ecd6cf80Smarks } 1257ecd6cf80Smarks 1258ecd6cf80Smarks #define SMAX(i, j) \ 1259ecd6cf80Smarks if ((j) > (i)) { \ 1260ecd6cf80Smarks (i) = (j); \ 1261ecd6cf80Smarks } 1262ecd6cf80Smarks 1263ecd6cf80Smarks int 1264743a77edSAlan Wright sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh, 1265da6c28aaSamw void *exportdata, zfs_share_op_t operation) 1266ecd6cf80Smarks { 1267ecd6cf80Smarks libzfs_handle_t *libhandle; 1268ecd6cf80Smarks sa_group_t group; 1269ecd6cf80Smarks sa_handle_t sahandle; 1270ecd6cf80Smarks char *dataset; 1271ecd6cf80Smarks int err = EINVAL; 1272ecd6cf80Smarks int i, j; 12734d79fe3bSmarks char newpath[MAXPATHLEN]; 1274a1ef5d63Smarks char *pathp; 1275ecd6cf80Smarks 1276ecd6cf80Smarks /* 1277ecd6cf80Smarks * First find the dataset name 1278ecd6cf80Smarks */ 1279ecd6cf80Smarks if ((group = sa_get_parent_group(share)) == NULL) { 1280a63214d6SBill Krier return (EINVAL); 1281ecd6cf80Smarks } 1282ecd6cf80Smarks if ((sahandle = sa_find_group_handle(group)) == NULL) { 1283a63214d6SBill Krier return (EINVAL); 1284ecd6cf80Smarks } 1285ecd6cf80Smarks 12864d79fe3bSmarks /* 12874d79fe3bSmarks * If get_zfs_dataset fails, see if it is a subdirectory 12884d79fe3bSmarks */ 1289a1ef5d63Smarks 1290a1ef5d63Smarks pathp = path; 1291a1ef5d63Smarks while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 12924d79fe3bSmarks char *p; 12934d79fe3bSmarks 1294a1ef5d63Smarks if (pathp == path) { 1295a1ef5d63Smarks (void) strlcpy(newpath, path, sizeof (newpath)); 1296a1ef5d63Smarks pathp = newpath; 1297a1ef5d63Smarks } 1298a1ef5d63Smarks 1299a1ef5d63Smarks /* 1300d34e4517SDoug McCallum * Make sure only one leading '/' This condition came 1301d34e4517SDoug McCallum * about when using HAStoragePlus which insisted on 1302d34e4517SDoug McCallum * putting an extra leading '/' in the ZFS path 1303d34e4517SDoug McCallum * name. The problem is fixed in other areas, but this 1304d34e4517SDoug McCallum * will catch any other ways that a double slash might 1305d34e4517SDoug McCallum * get introduced. 1306d34e4517SDoug McCallum */ 1307d34e4517SDoug McCallum while (*pathp == '/' && *(pathp + 1) == '/') 1308d34e4517SDoug McCallum pathp++; 1309d34e4517SDoug McCallum 1310d34e4517SDoug McCallum /* 1311a1ef5d63Smarks * chop off part of path, but if we are at root then 1312a1ef5d63Smarks * make sure path is a / 1313a1ef5d63Smarks */ 1314a1ef5d63Smarks if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1315a1ef5d63Smarks if (pathp == p) { 1316a1ef5d63Smarks *(p + 1) = '\0'; /* skip over /, root case */ 1317a1ef5d63Smarks } else { 13184d79fe3bSmarks *p = '\0'; 1319a1ef5d63Smarks } 1320a1ef5d63Smarks } else { 1321a63214d6SBill Krier return (EINVAL); 1322ecd6cf80Smarks } 1323a1ef5d63Smarks } 1324ecd6cf80Smarks 1325ecd6cf80Smarks libhandle = libzfs_init(); 1326ecd6cf80Smarks if (libhandle != NULL) { 1327743a77edSAlan Wright char *resource_name; 1328ecd6cf80Smarks 1329ecd6cf80Smarks i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1330ecd6cf80Smarks sh->sh_size = i; 1331ecd6cf80Smarks 1332ecd6cf80Smarks j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1333ecd6cf80Smarks sh->sh_size += j; 1334ecd6cf80Smarks SMAX(i, j); 1335ecd6cf80Smarks 1336ecd6cf80Smarks j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1337ecd6cf80Smarks sh->sh_size += j; 1338ecd6cf80Smarks SMAX(i, j); 1339ecd6cf80Smarks 1340ecd6cf80Smarks j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1341ecd6cf80Smarks sh->sh_size += j; 1342ecd6cf80Smarks SMAX(i, j); 1343ecd6cf80Smarks 1344ecd6cf80Smarks j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1345ecd6cf80Smarks sh->sh_size += j; 1346ecd6cf80Smarks SMAX(i, j); 1347743a77edSAlan Wright 1348743a77edSAlan Wright resource_name = sa_get_resource_attr(resource, "name"); 1349743a77edSAlan Wright 1350ecd6cf80Smarks err = zfs_deleg_share_nfs(libhandle, dataset, path, 1351743a77edSAlan Wright resource_name, exportdata, sh, i, operation); 13525b6e0c46Sdougm if (err == SA_OK) 13535b6e0c46Sdougm sa_update_sharetab_ts(sahandle); 1354a63214d6SBill Krier else 1355a63214d6SBill Krier err = errno; 1356743a77edSAlan Wright if (resource_name) 1357743a77edSAlan Wright sa_free_attr_string(resource_name); 1358743a77edSAlan Wright 1359ecd6cf80Smarks libzfs_fini(libhandle); 1360ecd6cf80Smarks } 1361ecd6cf80Smarks free(dataset); 1362ecd6cf80Smarks return (err); 1363ecd6cf80Smarks } 13645b6e0c46Sdougm 13655b6e0c46Sdougm /* 13665b6e0c46Sdougm * sa_get_zfs_handle(handle) 13675b6e0c46Sdougm * 13685b6e0c46Sdougm * Given an sa_handle_t, return the libzfs_handle_t *. This is only 13695b6e0c46Sdougm * used internally by libzfs. Needed in order to avoid including 13705b6e0c46Sdougm * libshare_impl.h in libzfs. 13715b6e0c46Sdougm */ 13725b6e0c46Sdougm 13735b6e0c46Sdougm libzfs_handle_t * 13745b6e0c46Sdougm sa_get_zfs_handle(sa_handle_t handle) 13755b6e0c46Sdougm { 13765b6e0c46Sdougm sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 13775b6e0c46Sdougm 13785b6e0c46Sdougm return (implhandle->zfs_libhandle); 13795b6e0c46Sdougm } 1380743a77edSAlan Wright 1381743a77edSAlan Wright /* 1382743a77edSAlan Wright * sa_get_zfs_info(libzfs, path, mountpoint, dataset) 1383743a77edSAlan Wright * 1384743a77edSAlan Wright * Find the ZFS dataset and mountpoint for a given path 1385743a77edSAlan Wright */ 1386743a77edSAlan Wright int 1387743a77edSAlan Wright sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp, 1388743a77edSAlan Wright char *datasetp) 1389743a77edSAlan Wright { 1390743a77edSAlan Wright get_all_cbdata_t cb = { 0 }; 1391743a77edSAlan Wright int i; 1392743a77edSAlan Wright char mountpoint[ZFS_MAXPROPLEN]; 1393743a77edSAlan Wright char dataset[ZFS_MAXPROPLEN]; 1394743a77edSAlan Wright char canmount[ZFS_MAXPROPLEN]; 1395743a77edSAlan Wright char *dp; 1396743a77edSAlan Wright int count; 1397743a77edSAlan Wright int ret = 0; 1398743a77edSAlan Wright 1399743a77edSAlan Wright cb.cb_types = ZFS_TYPE_FILESYSTEM; 1400743a77edSAlan Wright 1401743a77edSAlan Wright if (libzfs == NULL) 1402743a77edSAlan Wright return (0); 1403743a77edSAlan Wright 1404743a77edSAlan Wright (void) zfs_iter_root(libzfs, get_one_filesystem, &cb); 1405743a77edSAlan Wright count = cb.cb_used; 1406743a77edSAlan Wright 1407743a77edSAlan Wright qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare); 1408743a77edSAlan Wright for (i = 0; i < count; i++) { 1409743a77edSAlan Wright /* must have a mountpoint */ 1410743a77edSAlan Wright if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT, 1411743a77edSAlan Wright mountpoint, sizeof (mountpoint), 1412743a77edSAlan Wright NULL, NULL, 0, B_FALSE) != 0) { 1413743a77edSAlan Wright /* no mountpoint */ 1414743a77edSAlan Wright continue; 1415743a77edSAlan Wright } 1416743a77edSAlan Wright 1417743a77edSAlan Wright /* mountpoint must be a path */ 1418743a77edSAlan Wright if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 1419743a77edSAlan Wright strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 1420743a77edSAlan Wright /* 1421743a77edSAlan Wright * Search mmttab for mountpoint 1422743a77edSAlan Wright */ 1423743a77edSAlan Wright 1424743a77edSAlan Wright if (get_legacy_mountpoint(path, dataset, 1425743a77edSAlan Wright ZFS_MAXPROPLEN, mountpoint, 1426743a77edSAlan Wright ZFS_MAXPROPLEN) == 0) { 1427743a77edSAlan Wright ret = 1; 1428743a77edSAlan Wright break; 1429743a77edSAlan Wright } 1430743a77edSAlan Wright continue; 1431743a77edSAlan Wright } 1432743a77edSAlan Wright 1433743a77edSAlan Wright /* canmount must be set */ 1434743a77edSAlan Wright canmount[0] = '\0'; 1435743a77edSAlan Wright if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount, 1436743a77edSAlan Wright sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 1437743a77edSAlan Wright strcmp(canmount, "off") == 0) 1438743a77edSAlan Wright continue; 1439743a77edSAlan Wright 1440743a77edSAlan Wright /* 1441743a77edSAlan Wright * have a mountable handle but want to skip those marked none 1442743a77edSAlan Wright * and legacy 1443743a77edSAlan Wright */ 1444743a77edSAlan Wright if (strcmp(mountpoint, path) == 0) { 1445743a77edSAlan Wright dp = (char *)zfs_get_name(cb.cb_handles[i]); 1446743a77edSAlan Wright if (dp != NULL) { 1447743a77edSAlan Wright if (datasetp != NULL) 1448743a77edSAlan Wright (void) strcpy(datasetp, dp); 1449743a77edSAlan Wright if (mountpointp != NULL) 1450743a77edSAlan Wright (void) strcpy(mountpointp, mountpoint); 1451743a77edSAlan Wright ret = 1; 1452743a77edSAlan Wright } 1453743a77edSAlan Wright break; 1454743a77edSAlan Wright } 1455743a77edSAlan Wright 1456743a77edSAlan Wright } 1457743a77edSAlan Wright 1458743a77edSAlan Wright return (ret); 1459743a77edSAlan Wright } 1460148c5f43SAlan Wright 1461148c5f43SAlan Wright /* 1462148c5f43SAlan Wright * This method builds values for "sharesmb" property from the 1463148c5f43SAlan Wright * nvlist argument. The values are returned in sharesmb_val variable. 1464148c5f43SAlan Wright */ 1465148c5f43SAlan Wright static int 1466148c5f43SAlan Wright sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val) 1467148c5f43SAlan Wright { 1468148c5f43SAlan Wright char cur_val[MAXPATHLEN]; 1469148c5f43SAlan Wright char *name, *val; 1470148c5f43SAlan Wright nvpair_t *cur; 1471148c5f43SAlan Wright int err = 0; 1472148c5f43SAlan Wright 1473148c5f43SAlan Wright cur = nvlist_next_nvpair(nvl, NULL); 1474148c5f43SAlan Wright while (cur != NULL) { 1475148c5f43SAlan Wright name = nvpair_name(cur); 1476148c5f43SAlan Wright err = nvpair_value_string(cur, &val); 1477148c5f43SAlan Wright if ((err != 0) || (name == NULL) || (val == NULL)) 1478148c5f43SAlan Wright return (-1); 1479148c5f43SAlan Wright 1480148c5f43SAlan Wright (void) snprintf(cur_val, MAXPATHLEN, "%s=%s,", name, val); 1481148c5f43SAlan Wright (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1482148c5f43SAlan Wright 1483148c5f43SAlan Wright cur = nvlist_next_nvpair(nvl, cur); 1484148c5f43SAlan Wright } 1485148c5f43SAlan Wright 1486148c5f43SAlan Wright return (0); 1487148c5f43SAlan Wright } 1488148c5f43SAlan Wright 1489148c5f43SAlan Wright /* 1490148c5f43SAlan Wright * This method builds values for "sharesmb" property from values 1491148c5f43SAlan Wright * already existing on the share. The properties set via sa_zfs_sprint_new_prop 1492148c5f43SAlan Wright * method are passed in sharesmb_val. If a existing property is already 1493148c5f43SAlan Wright * set via sa_zfs_sprint_new_prop method, then they are not appended 1494148c5f43SAlan Wright * to the sharesmb_val string. The returned sharesmb_val string is a combination 1495148c5f43SAlan Wright * of new and existing values for 'sharesmb' property. 1496148c5f43SAlan Wright */ 1497148c5f43SAlan Wright static int 1498148c5f43SAlan Wright sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val) 1499148c5f43SAlan Wright { 1500148c5f43SAlan Wright char shareopts[ZFS_MAXPROPLEN], cur_val[MAXPATHLEN]; 1501148c5f43SAlan Wright char *token, *last, *value; 1502148c5f43SAlan Wright 1503148c5f43SAlan Wright if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts, 1504148c5f43SAlan Wright sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0) 1505148c5f43SAlan Wright return (-1); 1506148c5f43SAlan Wright 1507148c5f43SAlan Wright if (strstr(shareopts, "=") == NULL) 1508148c5f43SAlan Wright return (0); 1509148c5f43SAlan Wright 1510148c5f43SAlan Wright for (token = strtok_r(shareopts, ",", &last); token != NULL; 1511148c5f43SAlan Wright token = strtok_r(NULL, ",", &last)) { 1512148c5f43SAlan Wright value = strchr(token, '='); 1513148c5f43SAlan Wright if (value == NULL) 1514148c5f43SAlan Wright return (-1); 1515148c5f43SAlan Wright *value++ = '\0'; 1516148c5f43SAlan Wright 1517148c5f43SAlan Wright (void) snprintf(cur_val, MAXPATHLEN, "%s=", token); 1518148c5f43SAlan Wright if (strstr(sharesmb_val, cur_val) == NULL) { 1519148c5f43SAlan Wright (void) strlcat(cur_val, value, MAXPATHLEN); 1520148c5f43SAlan Wright (void) strlcat(cur_val, ",", MAXPATHLEN); 1521148c5f43SAlan Wright (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1522148c5f43SAlan Wright } 1523148c5f43SAlan Wright } 1524148c5f43SAlan Wright 1525148c5f43SAlan Wright return (0); 1526148c5f43SAlan Wright } 1527148c5f43SAlan Wright 1528148c5f43SAlan Wright /* 1529148c5f43SAlan Wright * Sets the share properties on a ZFS share. For now, this method sets only 1530148c5f43SAlan Wright * the "sharesmb" property. 1531148c5f43SAlan Wright * 1532148c5f43SAlan Wright * This method includes building a comma seperated name-value string to be 1533148c5f43SAlan Wright * set on the "sharesmb" property of a ZFS share. This name-value string is 1534148c5f43SAlan Wright * build in 2 steps: 1535148c5f43SAlan Wright * - New property values given as name-value pair are set first. 1536148c5f43SAlan Wright * - Existing optionset properties, which are not part of the new properties 1537148c5f43SAlan Wright * passed in step 1, are appended to the newly set properties. 1538148c5f43SAlan Wright */ 1539148c5f43SAlan Wright int 1540148c5f43SAlan Wright sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl) 1541148c5f43SAlan Wright { 1542148c5f43SAlan Wright zfs_handle_t *z_fs; 1543148c5f43SAlan Wright libzfs_handle_t *z_lib; 1544148c5f43SAlan Wright char sharesmb_val[MAXPATHLEN]; 1545148c5f43SAlan Wright char *dataset, *lastcomma; 1546148c5f43SAlan Wright 1547148c5f43SAlan Wright if (nvlist_empty(nvl)) 1548148c5f43SAlan Wright return (0); 1549148c5f43SAlan Wright 1550148c5f43SAlan Wright if ((handle == NULL) || (path == NULL)) 1551148c5f43SAlan Wright return (-1); 1552148c5f43SAlan Wright 1553148c5f43SAlan Wright if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL) 1554148c5f43SAlan Wright return (-1); 1555148c5f43SAlan Wright 1556148c5f43SAlan Wright if ((z_lib = libzfs_init()) == NULL) { 1557148c5f43SAlan Wright free(dataset); 1558148c5f43SAlan Wright return (-1); 1559148c5f43SAlan Wright } 1560148c5f43SAlan Wright 1561148c5f43SAlan Wright z_fs = zfs_open(z_lib, dataset, ZFS_TYPE_DATASET); 1562148c5f43SAlan Wright if (z_fs == NULL) { 1563148c5f43SAlan Wright free(dataset); 1564148c5f43SAlan Wright libzfs_fini(z_lib); 1565148c5f43SAlan Wright return (-1); 1566148c5f43SAlan Wright } 1567148c5f43SAlan Wright 1568148c5f43SAlan Wright bzero(sharesmb_val, MAXPATHLEN); 1569148c5f43SAlan Wright if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) { 1570148c5f43SAlan Wright free(dataset); 1571148c5f43SAlan Wright zfs_close(z_fs); 1572148c5f43SAlan Wright libzfs_fini(z_lib); 1573148c5f43SAlan Wright return (-1); 1574148c5f43SAlan Wright } 1575148c5f43SAlan Wright 1576148c5f43SAlan Wright if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) { 1577148c5f43SAlan Wright free(dataset); 1578148c5f43SAlan Wright zfs_close(z_fs); 1579148c5f43SAlan Wright libzfs_fini(z_lib); 1580148c5f43SAlan Wright return (-1); 1581148c5f43SAlan Wright } 1582148c5f43SAlan Wright 1583148c5f43SAlan Wright lastcomma = strrchr(sharesmb_val, ','); 1584148c5f43SAlan Wright if ((lastcomma != NULL) && (lastcomma[1] == '\0')) 1585148c5f43SAlan Wright *lastcomma = '\0'; 1586148c5f43SAlan Wright 1587148c5f43SAlan Wright (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB), 1588148c5f43SAlan Wright sharesmb_val); 1589148c5f43SAlan Wright free(dataset); 1590148c5f43SAlan Wright zfs_close(z_fs); 1591148c5f43SAlan Wright libzfs_fini(z_lib); 1592148c5f43SAlan Wright 1593148c5f43SAlan Wright return (0); 1594148c5f43SAlan Wright } 1595