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 /* 2324424a35Sdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 246185db85Sdougm * Use is subject to license terms. 256185db85Sdougm */ 266185db85Sdougm 276185db85Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 286185db85Sdougm 29a1ef5d63Smarks #include <stdio.h> 306185db85Sdougm #include <libzfs.h> 316185db85Sdougm #include <string.h> 32a3351425Sdougm #include <strings.h> 336185db85Sdougm #include <libshare.h> 346185db85Sdougm #include "libshare_impl.h" 351cea05afSdougm #include <libintl.h> 36a1ef5d63Smarks #include <sys/mnttab.h> 37a1ef5d63Smarks #include <sys/mntent.h> 386185db85Sdougm 39*da6c28aaSamw extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 406185db85Sdougm extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 416185db85Sdougm extern char *sa_fstype(char *); 426185db85Sdougm extern void set_node_attr(void *, char *, char *); 436185db85Sdougm extern int sa_is_share(void *); 441cea05afSdougm 451cea05afSdougm /* 461cea05afSdougm * File system specific code for ZFS. The original code was stolen 471cea05afSdougm * from the "zfs" command and modified to better suit this library's 481cea05afSdougm * usage. 491cea05afSdougm */ 501cea05afSdougm 511cea05afSdougm typedef struct get_all_cbdata { 521cea05afSdougm zfs_handle_t **cb_handles; 531cea05afSdougm size_t cb_alloc; 541cea05afSdougm size_t cb_used; 55a3351425Sdougm uint_t cb_types; 561cea05afSdougm } get_all_cbdata_t; 571cea05afSdougm 581cea05afSdougm /* 59549ec3ffSdougm * sa_zfs_init(impl_handle) 601cea05afSdougm * 61549ec3ffSdougm * Initialize an access handle into libzfs. The handle needs to stay 62549ec3ffSdougm * around until sa_zfs_fini() in order to maintain the cache of 63549ec3ffSdougm * mounts. 641cea05afSdougm */ 651cea05afSdougm 6657b448deSdougm int 67549ec3ffSdougm sa_zfs_init(sa_handle_impl_t impl_handle) 681cea05afSdougm { 69549ec3ffSdougm impl_handle->zfs_libhandle = libzfs_init(); 7057b448deSdougm if (impl_handle->zfs_libhandle != NULL) { 7157b448deSdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 7257b448deSdougm return (B_TRUE); 7357b448deSdougm } 7457b448deSdougm return (B_FALSE); 751cea05afSdougm } 761cea05afSdougm 771cea05afSdougm /* 78549ec3ffSdougm * sa_zfs_fini(impl_handle) 791cea05afSdougm * 801cea05afSdougm * cleanup data structures and the libzfs handle used for accessing 811cea05afSdougm * zfs file share info. 821cea05afSdougm */ 831cea05afSdougm 841cea05afSdougm void 85549ec3ffSdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 861cea05afSdougm { 87549ec3ffSdougm if (impl_handle->zfs_libhandle != NULL) { 8857b448deSdougm if (impl_handle->zfs_list != NULL) { 89a3351425Sdougm zfs_handle_t **zhp = impl_handle->zfs_list; 90a3351425Sdougm size_t i; 91a3351425Sdougm 9257b448deSdougm /* 93a3351425Sdougm * Contents of zfs_list need to be freed so we 94a3351425Sdougm * don't lose ZFS handles. 9557b448deSdougm */ 96a3351425Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) { 97a3351425Sdougm zfs_close(zhp[i]); 98a3351425Sdougm } 9957b448deSdougm free(impl_handle->zfs_list); 10057b448deSdougm impl_handle->zfs_list = NULL; 10157b448deSdougm impl_handle->zfs_list_count = 0; 10257b448deSdougm } 103a3351425Sdougm 104a3351425Sdougm libzfs_fini(impl_handle->zfs_libhandle); 105a3351425Sdougm impl_handle->zfs_libhandle = NULL; 1061cea05afSdougm } 1071cea05afSdougm } 1081cea05afSdougm 1091cea05afSdougm /* 1101cea05afSdougm * get_one_filesystem(zfs_handle_t, data) 1111cea05afSdougm * 112*da6c28aaSamw * an iterator function called while iterating through the ZFS 1131cea05afSdougm * root. It accumulates into an array of file system handles that can 1141cea05afSdougm * be used to derive info about those file systems. 115a3351425Sdougm * 116a3351425Sdougm * Note that as this function is called, we close all zhp handles that 117a3351425Sdougm * are not going to be places into the cp_handles list. We don't want 118a3351425Sdougm * to close the ones we are keeping, but all others would be leaked if 119a3351425Sdougm * not closed here. 1201cea05afSdougm */ 1211cea05afSdougm 1221cea05afSdougm static int 1231cea05afSdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1241cea05afSdougm { 1251cea05afSdougm get_all_cbdata_t *cbp = data; 126a3351425Sdougm zfs_type_t type = zfs_get_type(zhp); 1271cea05afSdougm 1281cea05afSdougm /* 129a3351425Sdougm * Interate over any nested datasets. 1301cea05afSdougm */ 131a3351425Sdougm if (type == ZFS_TYPE_FILESYSTEM && 132a3351425Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 133a3351425Sdougm zfs_close(zhp); 134a3351425Sdougm return (1); 135a3351425Sdougm } 136a3351425Sdougm 137a3351425Sdougm /* 138a3351425Sdougm * Skip any datasets whose type does not match. 139a3351425Sdougm */ 140a3351425Sdougm if ((type & cbp->cb_types) == 0) { 1411cea05afSdougm zfs_close(zhp); 1421cea05afSdougm return (0); 1431cea05afSdougm } 1441cea05afSdougm 1451cea05afSdougm if (cbp->cb_alloc == cbp->cb_used) { 1461cea05afSdougm zfs_handle_t **handles; 1471cea05afSdougm 1481cea05afSdougm if (cbp->cb_alloc == 0) 1491cea05afSdougm cbp->cb_alloc = 64; 1501cea05afSdougm else 1511cea05afSdougm cbp->cb_alloc *= 2; 1521cea05afSdougm 153a3351425Sdougm handles = (zfs_handle_t **)calloc(1, 154a3351425Sdougm cbp->cb_alloc * sizeof (void *)); 155a3351425Sdougm 1561cea05afSdougm if (handles == NULL) { 157a3351425Sdougm zfs_close(zhp); 15857b448deSdougm return (0); 1591cea05afSdougm } 1601cea05afSdougm if (cbp->cb_handles) { 161a3351425Sdougm bcopy(cbp->cb_handles, handles, 1621cea05afSdougm cbp->cb_used * sizeof (void *)); 1631cea05afSdougm free(cbp->cb_handles); 1641cea05afSdougm } 1651cea05afSdougm 1661cea05afSdougm cbp->cb_handles = handles; 1671cea05afSdougm } 1681cea05afSdougm 1691cea05afSdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1701cea05afSdougm 171a3351425Sdougm return (0); 1721cea05afSdougm } 1731cea05afSdougm 1741cea05afSdougm /* 1751cea05afSdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1761cea05afSdougm * 1771cea05afSdougm * iterate through all ZFS file systems starting at the root. Returns 1781cea05afSdougm * a count and an array of handle pointers. Allocating is only done 1791cea05afSdougm * once. The caller does not need to free since it will be done at 1801cea05afSdougm * sa_zfs_fini() time. 1811cea05afSdougm */ 1821cea05afSdougm 1831cea05afSdougm static void 184549ec3ffSdougm get_all_filesystems(sa_handle_impl_t impl_handle, 185549ec3ffSdougm zfs_handle_t ***fslist, size_t *count) 1861cea05afSdougm { 1871cea05afSdougm get_all_cbdata_t cb = { 0 }; 188a3351425Sdougm cb.cb_types = ZFS_TYPE_FILESYSTEM; 1891cea05afSdougm 190549ec3ffSdougm if (impl_handle->zfs_list != NULL) { 19157b448deSdougm *fslist = impl_handle->zfs_list; 19257b448deSdougm *count = impl_handle->zfs_list_count; 19357b448deSdougm return; 1941cea05afSdougm } 1951cea05afSdougm 196549ec3ffSdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 19757b448deSdougm get_one_filesystem, &cb); 1981cea05afSdougm 199549ec3ffSdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 200549ec3ffSdougm impl_handle->zfs_list_count = *count = cb.cb_used; 2011cea05afSdougm } 2021cea05afSdougm 2036185db85Sdougm /* 2041cea05afSdougm * mountpoint_compare(a, b) 2051cea05afSdougm * 2061cea05afSdougm * compares the mountpoint on two zfs file systems handles. 2071cea05afSdougm * returns values following strcmp() model. 2086185db85Sdougm */ 2096185db85Sdougm 2101cea05afSdougm static int 2111cea05afSdougm mountpoint_compare(const void *a, const void *b) 2121cea05afSdougm { 2131cea05afSdougm zfs_handle_t **za = (zfs_handle_t **)a; 2141cea05afSdougm zfs_handle_t **zb = (zfs_handle_t **)b; 2151cea05afSdougm char mounta[MAXPATHLEN]; 2161cea05afSdougm char mountb[MAXPATHLEN]; 2171cea05afSdougm 2181cea05afSdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2191cea05afSdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2201cea05afSdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2211cea05afSdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2221cea05afSdougm 2231cea05afSdougm return (strcmp(mounta, mountb)); 2241cea05afSdougm } 2251cea05afSdougm 226a1ef5d63Smarks /* 227a1ef5d63Smarks * return legacy mountpoint. Caller provides space for mountpoint. 228a1ef5d63Smarks */ 229a1ef5d63Smarks int 230a1ef5d63Smarks get_legacy_mountpoint(char *path, char *mountpoint, size_t len) 231a1ef5d63Smarks { 232a1ef5d63Smarks FILE *fp; 233a1ef5d63Smarks struct mnttab entry; 234a1ef5d63Smarks 235a1ef5d63Smarks if ((fp = fopen(MNTTAB, "r")) == NULL) { 236a1ef5d63Smarks return (1); 237a1ef5d63Smarks } 238a1ef5d63Smarks 239a1ef5d63Smarks while (getmntent(fp, &entry) == 0) { 240a1ef5d63Smarks 241a1ef5d63Smarks if (entry.mnt_fstype == NULL || 242a1ef5d63Smarks strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 243a1ef5d63Smarks continue; 244a1ef5d63Smarks 245a1ef5d63Smarks if (strcmp(entry.mnt_mountp, path) == 0) { 246a1ef5d63Smarks (void) strlcpy(mountpoint, entry.mnt_special, len); 247a1ef5d63Smarks (void) fclose(fp); 248a1ef5d63Smarks return (0); 249a1ef5d63Smarks } 250a1ef5d63Smarks } 251a1ef5d63Smarks (void) fclose(fp); 252a1ef5d63Smarks return (1); 253a1ef5d63Smarks } 254a1ef5d63Smarks 2556185db85Sdougm /* 256549ec3ffSdougm * get_zfs_dataset(impl_handle, path) 2576185db85Sdougm * 2586185db85Sdougm * get the name of the ZFS dataset the path is equivalent to. The 2596185db85Sdougm * dataset name is used for get/set of ZFS properties since libzfs 2606185db85Sdougm * requires a dataset to do a zfs_open(). 2616185db85Sdougm */ 2626185db85Sdougm 2636185db85Sdougm static char * 264a1ef5d63Smarks get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 265a1ef5d63Smarks boolean_t search_mnttab) 2666185db85Sdougm { 2671cea05afSdougm size_t i, count = 0; 2686185db85Sdougm char *dataset = NULL; 2691cea05afSdougm zfs_handle_t **zlist; 2701cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 27167331909Sdougm char canmount[ZFS_MAXPROPLEN]; 2726185db85Sdougm 273549ec3ffSdougm get_all_filesystems(impl_handle, &zlist, &count); 2741cea05afSdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2751cea05afSdougm for (i = 0; i < count; i++) { 27657b448deSdougm /* must have a mountpoint */ 27757b448deSdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 27857b448deSdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 27957b448deSdougm /* no mountpoint */ 28057b448deSdougm continue; 28157b448deSdougm } 28257b448deSdougm 28357b448deSdougm /* mountpoint must be a path */ 28457b448deSdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 285a1ef5d63Smarks strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 286a1ef5d63Smarks /* 287a1ef5d63Smarks * Search mmttab for mountpoint 288a1ef5d63Smarks */ 289a1ef5d63Smarks 290a1ef5d63Smarks if (search_mnttab == B_TRUE && 291a1ef5d63Smarks get_legacy_mountpoint(path, mountpoint, 292a1ef5d63Smarks sizeof (mountpoint)) == 0) { 293a1ef5d63Smarks dataset = mountpoint; 294a1ef5d63Smarks break; 295a1ef5d63Smarks } 29657b448deSdougm continue; 297a1ef5d63Smarks } 29857b448deSdougm 29957b448deSdougm /* canmount must be set */ 30057b448deSdougm canmount[0] = '\0'; 301ecd6cf80Smarks if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 30267331909Sdougm sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 30357b448deSdougm strcmp(canmount, "off") == 0) 30457b448deSdougm continue; 3051cea05afSdougm 30657b448deSdougm /* 30757b448deSdougm * have a mountable handle but want to skip those marked none 30857b448deSdougm * and legacy 30957b448deSdougm */ 31057b448deSdougm if (strcmp(mountpoint, path) == 0) { 31157b448deSdougm dataset = (char *)zfs_get_name(zlist[i]); 31257b448deSdougm break; 31357b448deSdougm } 3141cea05afSdougm 3156185db85Sdougm } 3161cea05afSdougm 31757b448deSdougm if (dataset != NULL) 31857b448deSdougm dataset = strdup(dataset); 31957b448deSdougm 3206185db85Sdougm return (dataset); 3216185db85Sdougm } 3226185db85Sdougm 3236185db85Sdougm /* 3246185db85Sdougm * get_zfs_property(dataset, property) 3256185db85Sdougm * 3266185db85Sdougm * Get the file system property specified from the ZFS dataset. 3276185db85Sdougm */ 3286185db85Sdougm 3296185db85Sdougm static char * 3306185db85Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 3316185db85Sdougm { 3326185db85Sdougm zfs_handle_t *handle = NULL; 3336185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3346185db85Sdougm libzfs_handle_t *libhandle; 3356185db85Sdougm 3366185db85Sdougm libhandle = libzfs_init(); 3376185db85Sdougm if (libhandle != NULL) { 33857b448deSdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 33957b448deSdougm if (handle != NULL) { 34057b448deSdougm if (zfs_prop_get(handle, property, shareopts, 34157b448deSdougm sizeof (shareopts), NULL, NULL, 0, 34257b448deSdougm B_FALSE) == 0) { 34357b448deSdougm zfs_close(handle); 34457b448deSdougm libzfs_fini(libhandle); 34557b448deSdougm return (strdup(shareopts)); 34657b448deSdougm } 34757b448deSdougm zfs_close(handle); 3486185db85Sdougm } 34957b448deSdougm libzfs_fini(libhandle); 3506185db85Sdougm } 3516185db85Sdougm return (NULL); 3526185db85Sdougm } 3536185db85Sdougm 3546185db85Sdougm /* 355549ec3ffSdougm * sa_zfs_is_shared(handle, path) 3566185db85Sdougm * 3576185db85Sdougm * Check to see if the ZFS path provided has the sharenfs option set 3586185db85Sdougm * or not. 3596185db85Sdougm */ 3606185db85Sdougm 3616185db85Sdougm int 362549ec3ffSdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 3636185db85Sdougm { 3646185db85Sdougm int ret = 0; 3656185db85Sdougm char *dataset; 3666185db85Sdougm zfs_handle_t *handle = NULL; 3676185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3686185db85Sdougm libzfs_handle_t *libhandle; 3696185db85Sdougm 370a1ef5d63Smarks dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 3716185db85Sdougm if (dataset != NULL) { 37257b448deSdougm libhandle = libzfs_init(); 37357b448deSdougm if (libhandle != NULL) { 37457b448deSdougm handle = zfs_open(libhandle, dataset, 37557b448deSdougm ZFS_TYPE_FILESYSTEM); 37657b448deSdougm if (handle != NULL) { 37757b448deSdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 37857b448deSdougm shareopts, sizeof (shareopts), NULL, NULL, 37957b448deSdougm 0, B_FALSE) == 0 && 38057b448deSdougm strcmp(shareopts, "off") != 0) { 38157b448deSdougm ret = 1; /* it is shared */ 38257b448deSdougm } 38357b448deSdougm zfs_close(handle); 38457b448deSdougm } 38557b448deSdougm libzfs_fini(libhandle); 3866185db85Sdougm } 38757b448deSdougm free(dataset); 3886185db85Sdougm } 3896185db85Sdougm return (ret); 3906185db85Sdougm } 3916185db85Sdougm 3926185db85Sdougm /* 393*da6c28aaSamw * find_or_create_group(handle, groupname, proto, *err) 3946185db85Sdougm * 3956185db85Sdougm * While walking the ZFS tree, we need to add shares to a defined 3966185db85Sdougm * group. If the group doesn't exist, create it first, making sure it 3976185db85Sdougm * is marked as a ZFS group. 3986185db85Sdougm * 39993a6f655Sdougm * Note that all ZFS shares are in a subgroup of the top level group 40093a6f655Sdougm * called "zfs". 4016185db85Sdougm */ 4026185db85Sdougm 4036185db85Sdougm static sa_group_t 404549ec3ffSdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 4056185db85Sdougm { 4066185db85Sdougm sa_group_t group; 4076185db85Sdougm sa_optionset_t optionset; 4086185db85Sdougm int ret = SA_OK; 4096185db85Sdougm 4106185db85Sdougm /* 4116185db85Sdougm * we check to see if the "zfs" group exists. Since this 4126185db85Sdougm * should be the top level group, we don't want the 4136185db85Sdougm * parent. This is to make sure the zfs group has been created 4146185db85Sdougm * and to created if it hasn't been. 4156185db85Sdougm */ 416549ec3ffSdougm group = sa_get_group(handle, groupname); 4176185db85Sdougm if (group == NULL) { 41857b448deSdougm group = sa_create_group(handle, groupname, &ret); 41993a6f655Sdougm 42057b448deSdougm /* make sure this is flagged as a ZFS group */ 42157b448deSdougm if (group != NULL) 42257b448deSdougm ret = sa_set_group_attr(group, "zfs", "true"); 4236185db85Sdougm } 4246185db85Sdougm if (group != NULL) { 42557b448deSdougm if (proto != NULL) { 42657b448deSdougm optionset = sa_get_optionset(group, proto); 427*da6c28aaSamw if (optionset == NULL) 42857b448deSdougm optionset = sa_create_optionset(group, proto); 4296185db85Sdougm } 4306185db85Sdougm } 4316185db85Sdougm if (err != NULL) 43257b448deSdougm *err = ret; 4336185db85Sdougm return (group); 4346185db85Sdougm } 4356185db85Sdougm 43693a6f655Sdougm /* 43793a6f655Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 43893a6f655Sdougm * 43993a6f655Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 44093a6f655Sdougm * function looks to see if the groupname exists and returns it if it 44193a6f655Sdougm * does or else creates a new one with the specified name and returns 44293a6f655Sdougm * that. The "zfs" group will exist before we get here, but we make 44393a6f655Sdougm * sure just in case. 44493a6f655Sdougm * 44593a6f655Sdougm * err must be a valid pointer. 44693a6f655Sdougm */ 44793a6f655Sdougm 44893a6f655Sdougm static sa_group_t 449*da6c28aaSamw find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 450*da6c28aaSamw char *optstring, int *err) 45193a6f655Sdougm { 45293a6f655Sdougm sa_group_t group = NULL; 45393a6f655Sdougm sa_group_t zfs; 45493a6f655Sdougm char *name; 45593a6f655Sdougm char *options; 45693a6f655Sdougm 45793a6f655Sdougm /* start with the top-level "zfs" group */ 458549ec3ffSdougm zfs = sa_get_group(handle, "zfs"); 45993a6f655Sdougm *err = SA_OK; 46093a6f655Sdougm if (zfs != NULL) { 46157b448deSdougm for (group = sa_get_sub_group(zfs); group != NULL; 46257b448deSdougm group = sa_get_next_group(group)) { 46357b448deSdougm name = sa_get_group_attr(group, "name"); 46457b448deSdougm if (name != NULL && strcmp(name, groupname) == 0) { 46557b448deSdougm /* have the group so break out of here */ 46657b448deSdougm sa_free_attr_string(name); 46757b448deSdougm break; 46857b448deSdougm } 46957b448deSdougm if (name != NULL) 47057b448deSdougm sa_free_attr_string(name); 47193a6f655Sdougm } 47257b448deSdougm 47357b448deSdougm if (group == NULL) { 47457b448deSdougm /* 47557b448deSdougm * need to create the sub-group since it doesn't exist 47657b448deSdougm */ 47757b448deSdougm group = _sa_create_zfs_group(zfs, groupname); 47857b448deSdougm if (group != NULL) 47957b448deSdougm set_node_attr(group, "zfs", "true"); 48057b448deSdougm if (strcmp(optstring, "on") == 0) 48157b448deSdougm optstring = "rw"; 48257b448deSdougm if (group != NULL) { 48357b448deSdougm options = strdup(optstring); 48457b448deSdougm if (options != NULL) { 48557b448deSdougm *err = sa_parse_legacy_options(group, 486*da6c28aaSamw options, proto); 487*da6c28aaSamw 488*da6c28aaSamw /* If no optionset, add one */ 489*da6c28aaSamw if (sa_get_optionset(group, proto) == 490*da6c28aaSamw NULL) 491*da6c28aaSamw (void) sa_create_optionset( 492*da6c28aaSamw group, proto); 49357b448deSdougm free(options); 49457b448deSdougm } else { 49557b448deSdougm *err = SA_NO_MEMORY; 49657b448deSdougm } 49757b448deSdougm } 498*da6c28aaSamw } else if (proto != NULL && strcmp(proto, "smb") == 0) { 499*da6c28aaSamw *err = SA_PROP_SHARE_ONLY; 50093a6f655Sdougm } 50193a6f655Sdougm } 50293a6f655Sdougm return (group); 50393a6f655Sdougm } 50493a6f655Sdougm 505*da6c28aaSamw /* 506*da6c28aaSamw * zfs_construct_resource(share, name, base, dataset) 507*da6c28aaSamw * 508*da6c28aaSamw * Add a resource to the share using name as a template. If name == 509*da6c28aaSamw * NULL, then construct a name based on the dataset value. 510*da6c28aaSamw * name. 511*da6c28aaSamw */ 512*da6c28aaSamw static void 513*da6c28aaSamw zfs_construct_resource(sa_share_t share, char *dataset) 514*da6c28aaSamw { 515*da6c28aaSamw char buff[SA_MAX_RESOURCE_NAME + 1]; 516*da6c28aaSamw int ret = SA_OK; 517*da6c28aaSamw 518*da6c28aaSamw (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset); 519*da6c28aaSamw sa_fix_resource_name(buff); 520*da6c28aaSamw (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret); 521*da6c28aaSamw } 522*da6c28aaSamw 52357b448deSdougm /* 52457b448deSdougm * zfs_inherited(handle, source, sourcestr) 52557b448deSdougm * 526*da6c28aaSamw * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares 52757b448deSdougm * for readability. 52857b448deSdougm */ 52957b448deSdougm static int 53057b448deSdougm zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 531*da6c28aaSamw char *shareopts, char *mountpoint, char *proto, char *dataset) 53257b448deSdougm { 53357b448deSdougm int doshopt = 0; 53457b448deSdougm int err = SA_OK; 53557b448deSdougm sa_group_t group; 536*da6c28aaSamw sa_resource_t resource; 537*da6c28aaSamw uint64_t features; 53857b448deSdougm 53957b448deSdougm /* 54057b448deSdougm * Need to find the "real" parent sub-group. It may not be 54157b448deSdougm * mounted, but it was identified in the "sourcestr" 54257b448deSdougm * variable. The real parent not mounted can occur if 54357b448deSdougm * "canmount=off and sharenfs=on". 54457b448deSdougm */ 545*da6c28aaSamw group = find_or_create_zfs_subgroup(handle, sourcestr, proto, 546*da6c28aaSamw shareopts, &doshopt); 54757b448deSdougm if (group != NULL) { 548*da6c28aaSamw /* 549*da6c28aaSamw * We may need the first share for resource 550*da6c28aaSamw * prototype. We only care about it if it has a 551*da6c28aaSamw * resource that sets a prefix value. 552*da6c28aaSamw */ 553*da6c28aaSamw if (share == NULL) 554*da6c28aaSamw share = _sa_add_share(group, mountpoint, 555*da6c28aaSamw SA_SHARE_TRANSIENT, &err, 556*da6c28aaSamw (uint64_t)SA_FEATURE_NONE); 55757b448deSdougm /* 55857b448deSdougm * some options may only be on shares. If the opt 55957b448deSdougm * string contains one of those, we put it just on the 56057b448deSdougm * share. 56157b448deSdougm */ 56257b448deSdougm if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 56357b448deSdougm char *options; 56457b448deSdougm options = strdup(shareopts); 56557b448deSdougm if (options != NULL) { 566*da6c28aaSamw set_node_attr(share, "dataset", dataset); 56757b448deSdougm err = sa_parse_legacy_options(share, options, 568*da6c28aaSamw proto); 569*da6c28aaSamw set_node_attr(share, "dataset", NULL); 57057b448deSdougm free(options); 57157b448deSdougm } 572*da6c28aaSamw if (sa_get_optionset(group, proto) == NULL) 573*da6c28aaSamw (void) sa_create_optionset(group, proto); 574*da6c28aaSamw } 575*da6c28aaSamw features = sa_proto_get_featureset(proto); 576*da6c28aaSamw if (share != NULL && features & SA_FEATURE_RESOURCE) { 577*da6c28aaSamw /* 578*da6c28aaSamw * We have a share and the protocol requires 579*da6c28aaSamw * that at least one resource exist (probably 580*da6c28aaSamw * SMB). We need to make sure that there is at 581*da6c28aaSamw * least one. 582*da6c28aaSamw */ 583*da6c28aaSamw resource = sa_get_share_resource(share, NULL); 584*da6c28aaSamw if (resource == NULL) { 585*da6c28aaSamw zfs_construct_resource(share, dataset); 586*da6c28aaSamw } 58757b448deSdougm } 58857b448deSdougm } else { 58957b448deSdougm err = SA_NO_MEMORY; 59057b448deSdougm } 59157b448deSdougm return (err); 59257b448deSdougm } 59357b448deSdougm 59457b448deSdougm /* 59557b448deSdougm * zfs_notinherited() 59657b448deSdougm * 59757b448deSdougm * handle case where this is the top of a sub-group in ZFS. Pulled out 59857b448deSdougm * of sa_get_zfs_shares for readability. 59957b448deSdougm */ 60057b448deSdougm static int 601*da6c28aaSamw zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 602*da6c28aaSamw char *shareopts, char *proto, char *dataset) 60357b448deSdougm { 60457b448deSdougm int err = SA_OK; 605*da6c28aaSamw sa_resource_t resource; 606*da6c28aaSamw uint64_t features; 60757b448deSdougm 60857b448deSdougm set_node_attr(group, "zfs", "true"); 609*da6c28aaSamw if (share == NULL) 610*da6c28aaSamw share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 611*da6c28aaSamw &err, (uint64_t)SA_FEATURE_NONE); 61257b448deSdougm if (err == SA_OK) { 613f8825440Sdougm if (strcmp(shareopts, "on") == 0) 614*da6c28aaSamw shareopts = ""; 615*da6c28aaSamw if (shareopts != NULL) { 616*da6c28aaSamw char *options; 61757b448deSdougm options = strdup(shareopts); 61857b448deSdougm if (options != NULL) { 619*da6c28aaSamw err = sa_parse_legacy_options(group, options, 620*da6c28aaSamw proto); 62157b448deSdougm free(options); 62257b448deSdougm } 623*da6c28aaSamw if (err == SA_PROP_SHARE_ONLY) { 624*da6c28aaSamw /* 625*da6c28aaSamw * Same as above, some properties may 626*da6c28aaSamw * only be on shares, but due to the 627*da6c28aaSamw * ZFS sub-groups being artificial, we 628*da6c28aaSamw * sometimes get this and have to deal 629*da6c28aaSamw * with it. We do it by attempting to 630*da6c28aaSamw * put it on the share. 631*da6c28aaSamw */ 632*da6c28aaSamw options = strdup(shareopts); 633*da6c28aaSamw if (options != NULL) { 634*da6c28aaSamw err = sa_parse_legacy_options(share, 635*da6c28aaSamw options, proto); 636*da6c28aaSamw free(options); 637*da6c28aaSamw } 638*da6c28aaSamw } 639*da6c28aaSamw /* unmark the share's changed state */ 640*da6c28aaSamw set_node_attr(share, "changed", NULL); 641*da6c28aaSamw } 642*da6c28aaSamw features = sa_proto_get_featureset(proto); 643*da6c28aaSamw if (share != NULL && features & SA_FEATURE_RESOURCE) { 644*da6c28aaSamw /* 645*da6c28aaSamw * We have a share and the protocol requires 646*da6c28aaSamw * that at least one resource exist (probably 647*da6c28aaSamw * SMB). We need to make sure that there is at 648*da6c28aaSamw * least one. 649*da6c28aaSamw */ 650*da6c28aaSamw resource = sa_get_share_resource(share, NULL); 651*da6c28aaSamw if (resource == NULL) { 652*da6c28aaSamw zfs_construct_resource(share, dataset); 653*da6c28aaSamw } 65457b448deSdougm } 65557b448deSdougm } 65657b448deSdougm return (err); 65757b448deSdougm } 65857b448deSdougm 65957b448deSdougm /* 66057b448deSdougm * zfs_grp_error(err) 66157b448deSdougm * 66257b448deSdougm * Print group create error, but only once. If err is 0 do the 66357b448deSdougm * print else don't. 66457b448deSdougm */ 66557b448deSdougm 66657b448deSdougm static void 66757b448deSdougm zfs_grp_error(int err) 66857b448deSdougm { 66957b448deSdougm if (err == 0) { 67057b448deSdougm /* only print error once */ 67157b448deSdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 67257b448deSdougm "Cannot create ZFS subgroup during initialization:" 67357b448deSdougm " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 67457b448deSdougm } 67557b448deSdougm } 67657b448deSdougm 677*da6c28aaSamw /* 678*da6c28aaSamw * zfs_process_share(handle, share, mountpoint, proto, source, 679*da6c28aaSamw * shareopts, sourcestr) 680*da6c28aaSamw * 681*da6c28aaSamw * Creates the subgroup, if necessary and adds shares and adds shares 682*da6c28aaSamw * and properties. 683*da6c28aaSamw */ 684*da6c28aaSamw static int 685*da6c28aaSamw zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 686*da6c28aaSamw char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 687*da6c28aaSamw char *sourcestr, char *dataset) 688*da6c28aaSamw { 689*da6c28aaSamw int err = SA_OK; 690*da6c28aaSamw 691*da6c28aaSamw if (source & ZPROP_SRC_INHERITED) { 692*da6c28aaSamw err = zfs_inherited(handle, share, sourcestr, shareopts, 693*da6c28aaSamw mountpoint, proto, dataset); 694*da6c28aaSamw } else { 695*da6c28aaSamw group = find_or_create_zfs_subgroup(handle, dataset, proto, 696*da6c28aaSamw shareopts, &err); 697*da6c28aaSamw if (group == NULL) { 698*da6c28aaSamw static int err = 0; 699*da6c28aaSamw /* 700*da6c28aaSamw * there is a problem, but we can't do 701*da6c28aaSamw * anything about it at this point so we issue 702*da6c28aaSamw * a warning an move on. 703*da6c28aaSamw */ 704*da6c28aaSamw zfs_grp_error(err); 705*da6c28aaSamw err = 1; 706*da6c28aaSamw } 707*da6c28aaSamw set_node_attr(group, "zfs", "true"); 708*da6c28aaSamw /* 709*da6c28aaSamw * Add share with local opts via zfs_notinherited. 710*da6c28aaSamw */ 711*da6c28aaSamw err = zfs_notinherited(group, share, mountpoint, shareopts, 712*da6c28aaSamw proto, dataset); 713*da6c28aaSamw } 714*da6c28aaSamw return (err); 715*da6c28aaSamw } 716*da6c28aaSamw 7176185db85Sdougm /* 718549ec3ffSdougm * sa_get_zfs_shares(handle, groupname) 7196185db85Sdougm * 7206185db85Sdougm * Walk the mnttab for all zfs mounts and determine which are 7216185db85Sdougm * shared. Find or create the appropriate group/sub-group to contain 7226185db85Sdougm * the shares. 7236185db85Sdougm * 7246185db85Sdougm * All shares are in a sub-group that will hold the properties. This 7256185db85Sdougm * allows representing the inherited property model. 7266185db85Sdougm */ 7276185db85Sdougm 7286185db85Sdougm int 729549ec3ffSdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 7306185db85Sdougm { 7316185db85Sdougm sa_group_t group; 7326185db85Sdougm sa_group_t zfsgroup; 7336185db85Sdougm int legacy = 0; 7346185db85Sdougm int err; 7351cea05afSdougm zfs_handle_t **zlist; 7366185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 7376185db85Sdougm sa_share_t share; 738990b4856Slling zprop_source_t source; 7396185db85Sdougm char sourcestr[ZFS_MAXPROPLEN]; 7401cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 7411cea05afSdougm size_t count = 0, i; 742549ec3ffSdougm libzfs_handle_t *zfs_libhandle; 7436185db85Sdougm 7446185db85Sdougm /* 745549ec3ffSdougm * If we can't access libzfs, don't bother doing anything. 7466185db85Sdougm */ 747549ec3ffSdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 7481cea05afSdougm if (zfs_libhandle == NULL) 74957b448deSdougm return (SA_SYSTEM_ERR); 7506185db85Sdougm 751*da6c28aaSamw zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 752546405c3Sdougm if (zfsgroup == NULL) 753546405c3Sdougm return (legacy); 754546405c3Sdougm 755546405c3Sdougm /* 756546405c3Sdougm * need to walk the mounted ZFS pools and datasets to 757546405c3Sdougm * find shares that are possible. 758546405c3Sdougm */ 759546405c3Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 760546405c3Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 761546405c3Sdougm 762546405c3Sdougm group = zfsgroup; 763546405c3Sdougm for (i = 0; i < count; i++) { 764546405c3Sdougm char *dataset; 765*da6c28aaSamw int foundnfs = 0; 766546405c3Sdougm 767990b4856Slling source = ZPROP_SRC_ALL; 768546405c3Sdougm /* If no mountpoint, skip. */ 769546405c3Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 770546405c3Sdougm mountpoint, sizeof (mountpoint), NULL, NULL, 0, 771546405c3Sdougm B_FALSE) != 0) 772546405c3Sdougm continue; 773546405c3Sdougm 7746185db85Sdougm /* 775546405c3Sdougm * zfs_get_name value must not be freed. It is just a 776546405c3Sdougm * pointer to a value in the handle. 7776185db85Sdougm */ 778546405c3Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 779546405c3Sdougm continue; 7801cea05afSdougm 781546405c3Sdougm /* 782546405c3Sdougm * only deal with "mounted" file systems since 783546405c3Sdougm * unmounted file systems can't actually be shared. 784546405c3Sdougm */ 78557b448deSdougm 786546405c3Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 787546405c3Sdougm continue; 78857b448deSdougm 789546405c3Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 790546405c3Sdougm sizeof (shareopts), &source, sourcestr, 791546405c3Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 792546405c3Sdougm strcmp(shareopts, "off") != 0) { 793546405c3Sdougm /* it is shared so add to list */ 794546405c3Sdougm err = SA_OK; 795*da6c28aaSamw foundnfs = 1; 796*da6c28aaSamw share = sa_find_share(handle, mountpoint); 797546405c3Sdougm if (share != NULL) { 798546405c3Sdougm /* 799546405c3Sdougm * A zfs file system had been shared 800546405c3Sdougm * through traditional methods 801546405c3Sdougm * (share/dfstab or added to a non-zfs 802546405c3Sdougm * group. Now it has been added to a 803546405c3Sdougm * ZFS group via the zfs 804546405c3Sdougm * command. Remove from previous 805546405c3Sdougm * config and setup with current 806546405c3Sdougm * options. 807546405c3Sdougm */ 808546405c3Sdougm err = sa_remove_share(share); 809546405c3Sdougm share = NULL; 810546405c3Sdougm } 811546405c3Sdougm if (err == SA_OK) { 812*da6c28aaSamw err = zfs_process_share(handle, group, 813*da6c28aaSamw share, mountpoint, "nfs", source, 814*da6c28aaSamw shareopts, sourcestr, dataset); 815*da6c28aaSamw } 816*da6c28aaSamw } 817*da6c28aaSamw if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, shareopts, 818*da6c28aaSamw sizeof (shareopts), &source, sourcestr, 819*da6c28aaSamw ZFS_MAXPROPLEN, B_FALSE) == 0 && 820*da6c28aaSamw strcmp(shareopts, "off") != 0) { 821*da6c28aaSamw /* it is shared so add to list */ 822*da6c28aaSamw err = SA_OK; 823*da6c28aaSamw share = sa_find_share(handle, mountpoint); 824*da6c28aaSamw if (share != NULL && !foundnfs) { 825*da6c28aaSamw /* 826*da6c28aaSamw * A zfs file system had been shared 827*da6c28aaSamw * through traditional methods 828*da6c28aaSamw * (share/dfstab or added to a non-zfs 829*da6c28aaSamw * group. Now it has been added to a 830*da6c28aaSamw * ZFS group via the zfs 831*da6c28aaSamw * command. Remove from previous 832*da6c28aaSamw * config and setup with current 833*da6c28aaSamw * options. 834*da6c28aaSamw */ 835*da6c28aaSamw err = sa_remove_share(share); 836*da6c28aaSamw share = NULL; 837*da6c28aaSamw } 838*da6c28aaSamw if (err == SA_OK) { 839*da6c28aaSamw err = zfs_process_share(handle, group, 840*da6c28aaSamw share, mountpoint, "smb", source, 841*da6c28aaSamw shareopts, sourcestr, dataset); 8426185db85Sdougm } 8436185db85Sdougm } 8446185db85Sdougm } 8451cea05afSdougm /* 8461cea05afSdougm * Don't need to free the "zlist" variable since it is only a 8471cea05afSdougm * pointer to a cached value that will be freed when 8481cea05afSdougm * sa_fini() is called. 8491cea05afSdougm */ 8506185db85Sdougm return (legacy); 8516185db85Sdougm } 8526185db85Sdougm 8536185db85Sdougm #define COMMAND "/usr/sbin/zfs" 8546185db85Sdougm 8556185db85Sdougm /* 8566185db85Sdougm * sa_zfs_set_sharenfs(group, path, on) 8576185db85Sdougm * 8586185db85Sdougm * Update the "sharenfs" property on the path. If on is true, then set 8596185db85Sdougm * to the properties on the group or "on" if no properties are 8606185db85Sdougm * defined. Set to "off" if on is false. 8616185db85Sdougm */ 8626185db85Sdougm 8636185db85Sdougm int 8646185db85Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 8656185db85Sdougm { 8666185db85Sdougm int ret = SA_NOT_IMPLEMENTED; 8676185db85Sdougm char *command; 8686185db85Sdougm 8696185db85Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 8706185db85Sdougm if (command != NULL) { 87157b448deSdougm char *opts = NULL; 87257b448deSdougm char *dataset = NULL; 87357b448deSdougm FILE *pfile; 87457b448deSdougm sa_handle_impl_t impl_handle; 87557b448deSdougm /* for now, NFS is always available for "zfs" */ 87657b448deSdougm if (on) { 87757b448deSdougm opts = sa_proto_legacy_format("nfs", group, 1); 87857b448deSdougm if (opts != NULL && strlen(opts) == 0) { 87957b448deSdougm free(opts); 88057b448deSdougm opts = strdup("on"); 88157b448deSdougm } 8826185db85Sdougm } 88357b448deSdougm 88457b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 88557b448deSdougm assert(impl_handle != NULL); 88657b448deSdougm if (impl_handle != NULL) 887a1ef5d63Smarks dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 88857b448deSdougm else 8896185db85Sdougm ret = SA_SYSTEM_ERR; 89057b448deSdougm 89157b448deSdougm if (dataset != NULL) { 89257b448deSdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 89357b448deSdougm "%s set sharenfs=\"%s\" %s", COMMAND, 89457b448deSdougm opts != NULL ? opts : "off", dataset); 89557b448deSdougm pfile = popen(command, "r"); 89657b448deSdougm if (pfile != NULL) { 89757b448deSdougm ret = pclose(pfile); 89857b448deSdougm if (ret != 0) 89957b448deSdougm ret = SA_SYSTEM_ERR; 90057b448deSdougm } 9016185db85Sdougm } 90257b448deSdougm if (opts != NULL) 90357b448deSdougm free(opts); 90457b448deSdougm if (dataset != NULL) 90557b448deSdougm free(dataset); 90657b448deSdougm free(command); 9076185db85Sdougm } 9086185db85Sdougm return (ret); 9096185db85Sdougm } 9106185db85Sdougm 911*da6c28aaSamw /* 912*da6c28aaSamw * add_resources(share, opt) 913*da6c28aaSamw * 914*da6c28aaSamw * Add resource properties to those in "opt". Resources are prefixed 915*da6c28aaSamw * with name=resourcename. 916*da6c28aaSamw */ 917*da6c28aaSamw static char * 918*da6c28aaSamw add_resources(sa_share_t share, char *opt) 919*da6c28aaSamw { 920*da6c28aaSamw char *newopt = NULL; 921*da6c28aaSamw char *propstr; 922*da6c28aaSamw sa_resource_t resource; 923*da6c28aaSamw 924*da6c28aaSamw newopt = strdup(opt); 925*da6c28aaSamw if (newopt == NULL) 926*da6c28aaSamw return (newopt); 927*da6c28aaSamw 928*da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 929*da6c28aaSamw resource != NULL; 930*da6c28aaSamw resource = sa_get_next_resource(resource)) { 931*da6c28aaSamw char *name; 932*da6c28aaSamw size_t size; 933*da6c28aaSamw 934*da6c28aaSamw name = sa_get_resource_attr(resource, "name"); 935*da6c28aaSamw if (name == NULL) { 936*da6c28aaSamw free(newopt); 937*da6c28aaSamw return (NULL); 938*da6c28aaSamw } 939*da6c28aaSamw size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 940*da6c28aaSamw newopt = calloc(1, size); 941*da6c28aaSamw if (newopt != NULL) 942*da6c28aaSamw (void) snprintf(newopt, size, "%s,name=%s", opt, name); 943*da6c28aaSamw free(opt); 944*da6c28aaSamw opt = newopt; 945*da6c28aaSamw propstr = sa_proto_legacy_format("smb", resource, 0); 946*da6c28aaSamw if (propstr == NULL) { 947*da6c28aaSamw free(opt); 948*da6c28aaSamw return (NULL); 949*da6c28aaSamw } 950*da6c28aaSamw size = strlen(propstr) + strlen(opt) + 2; 951*da6c28aaSamw newopt = calloc(1, size); 952*da6c28aaSamw if (newopt != NULL) 953*da6c28aaSamw (void) snprintf(newopt, size, "%s,%s", opt, propstr); 954*da6c28aaSamw free(opt); 955*da6c28aaSamw opt = newopt; 956*da6c28aaSamw } 957*da6c28aaSamw return (opt); 958*da6c28aaSamw } 959*da6c28aaSamw 960*da6c28aaSamw /* 961*da6c28aaSamw * sa_zfs_set_sharesmb(group, path, on) 962*da6c28aaSamw * 963*da6c28aaSamw * Update the "sharesmb" property on the path. If on is true, then set 964*da6c28aaSamw * to the properties on the group or "on" if no properties are 965*da6c28aaSamw * defined. Set to "off" if on is false. 966*da6c28aaSamw */ 967*da6c28aaSamw 968*da6c28aaSamw int 969*da6c28aaSamw sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 970*da6c28aaSamw { 971*da6c28aaSamw int ret = SA_NOT_IMPLEMENTED; 972*da6c28aaSamw char *command; 973*da6c28aaSamw sa_share_t share; 974*da6c28aaSamw 975*da6c28aaSamw /* In case SMB not enabled */ 976*da6c28aaSamw if (sa_get_optionset(group, "smb") == NULL) 977*da6c28aaSamw return (SA_NOT_SUPPORTED); 978*da6c28aaSamw 979*da6c28aaSamw command = malloc(ZFS_MAXPROPLEN * 2); 980*da6c28aaSamw if (command != NULL) { 981*da6c28aaSamw char *opts = NULL; 982*da6c28aaSamw char *dataset = NULL; 983*da6c28aaSamw FILE *pfile; 984*da6c28aaSamw sa_handle_impl_t impl_handle; 985*da6c28aaSamw 986*da6c28aaSamw if (on) { 987*da6c28aaSamw char *newopt; 988*da6c28aaSamw 989*da6c28aaSamw share = sa_get_share(group, NULL); 990*da6c28aaSamw opts = sa_proto_legacy_format("smb", share, 1); 991*da6c28aaSamw if (opts != NULL && strlen(opts) == 0) { 992*da6c28aaSamw free(opts); 993*da6c28aaSamw opts = strdup("on"); 994*da6c28aaSamw } 995*da6c28aaSamw newopt = add_resources(opts, share); 996*da6c28aaSamw free(opts); 997*da6c28aaSamw opts = newopt; 998*da6c28aaSamw } 999*da6c28aaSamw 1000*da6c28aaSamw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1001*da6c28aaSamw assert(impl_handle != NULL); 1002*da6c28aaSamw if (impl_handle != NULL) 1003*da6c28aaSamw dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1004*da6c28aaSamw else 1005*da6c28aaSamw ret = SA_SYSTEM_ERR; 1006*da6c28aaSamw 1007*da6c28aaSamw if (dataset != NULL) { 1008*da6c28aaSamw (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1009*da6c28aaSamw "echo %s set sharesmb=\"%s\" %s", COMMAND, 1010*da6c28aaSamw opts != NULL ? opts : "off", dataset); 1011*da6c28aaSamw pfile = popen(command, "r"); 1012*da6c28aaSamw if (pfile != NULL) { 1013*da6c28aaSamw ret = pclose(pfile); 1014*da6c28aaSamw if (ret != 0) 1015*da6c28aaSamw ret = SA_SYSTEM_ERR; 1016*da6c28aaSamw } 1017*da6c28aaSamw } 1018*da6c28aaSamw if (opts != NULL) 1019*da6c28aaSamw free(opts); 1020*da6c28aaSamw if (dataset != NULL) 1021*da6c28aaSamw free(dataset); 1022*da6c28aaSamw free(command); 1023*da6c28aaSamw } 1024*da6c28aaSamw return (ret); 1025*da6c28aaSamw } 1026*da6c28aaSamw 10276185db85Sdougm /* 10286185db85Sdougm * sa_zfs_update(group) 10296185db85Sdougm * 10306185db85Sdougm * call back to ZFS to update the share if necessary. 10316185db85Sdougm * Don't do it if it isn't a real change. 10326185db85Sdougm */ 10336185db85Sdougm int 10346185db85Sdougm sa_zfs_update(sa_group_t group) 10356185db85Sdougm { 10366185db85Sdougm sa_optionset_t protopt; 10376185db85Sdougm sa_group_t parent; 10386185db85Sdougm char *command; 10396185db85Sdougm char *optstring; 10406185db85Sdougm int ret = SA_OK; 10416185db85Sdougm int doupdate = 0; 10426185db85Sdougm FILE *pfile; 10436185db85Sdougm 10446185db85Sdougm if (sa_is_share(group)) 104557b448deSdougm parent = sa_get_parent_group(group); 10466185db85Sdougm else 104757b448deSdougm parent = group; 10486185db85Sdougm 10496185db85Sdougm if (parent != NULL) { 105057b448deSdougm command = malloc(ZFS_MAXPROPLEN * 2); 105157b448deSdougm if (command == NULL) 105257b448deSdougm return (SA_NO_MEMORY); 105357b448deSdougm 105457b448deSdougm *command = '\0'; 105557b448deSdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 105657b448deSdougm protopt = sa_get_next_optionset(protopt)) { 105757b448deSdougm 105857b448deSdougm char *proto = sa_get_optionset_attr(protopt, "type"); 105957b448deSdougm char *path; 106057b448deSdougm char *dataset = NULL; 106157b448deSdougm char *zfsopts = NULL; 106257b448deSdougm 106357b448deSdougm if (sa_is_share(group)) { 106457b448deSdougm path = sa_get_share_attr((sa_share_t)group, 106557b448deSdougm "path"); 106657b448deSdougm if (path != NULL) { 106757b448deSdougm sa_handle_impl_t impl_handle; 106857b448deSdougm 106957b448deSdougm impl_handle = sa_find_group_handle( 107057b448deSdougm group); 107157b448deSdougm if (impl_handle != NULL) 107257b448deSdougm dataset = get_zfs_dataset( 1073a1ef5d63Smarks impl_handle, path, B_FALSE); 107457b448deSdougm else 107557b448deSdougm ret = SA_SYSTEM_ERR; 107657b448deSdougm 107757b448deSdougm sa_free_attr_string(path); 107857b448deSdougm } 10796185db85Sdougm } else { 108057b448deSdougm dataset = sa_get_group_attr(group, "name"); 10816185db85Sdougm } 108257b448deSdougm /* update only when there is an optstring found */ 108357b448deSdougm doupdate = 0; 108457b448deSdougm if (proto != NULL && dataset != NULL) { 108557b448deSdougm optstring = sa_proto_legacy_format(proto, 108657b448deSdougm group, 1); 108757b448deSdougm zfsopts = get_zfs_property(dataset, 108857b448deSdougm ZFS_PROP_SHARENFS); 108957b448deSdougm 109057b448deSdougm if (optstring != NULL && zfsopts != NULL) { 109157b448deSdougm if (strcmp(optstring, zfsopts) != 0) 109257b448deSdougm doupdate++; 109357b448deSdougm } 109457b448deSdougm if (doupdate) { 109557b448deSdougm if (optstring != NULL && 109657b448deSdougm strlen(optstring) > 0) { 109757b448deSdougm (void) snprintf(command, 109857b448deSdougm ZFS_MAXPROPLEN * 2, 10992b53ee1cSdougm "%s set sharenfs=%s %s", 110057b448deSdougm COMMAND, 110157b448deSdougm optstring, dataset); 110257b448deSdougm } else { 110357b448deSdougm (void) snprintf(command, 110457b448deSdougm ZFS_MAXPROPLEN * 2, 110557b448deSdougm "%s set sharenfs=on %s", 110657b448deSdougm COMMAND, 110757b448deSdougm dataset); 110857b448deSdougm } 110957b448deSdougm pfile = popen(command, "r"); 111057b448deSdougm if (pfile != NULL) 111157b448deSdougm ret = pclose(pfile); 111257b448deSdougm switch (ret) { 111357b448deSdougm default: 111457b448deSdougm case 1: 111557b448deSdougm ret = SA_SYSTEM_ERR; 111657b448deSdougm break; 111757b448deSdougm case 2: 111857b448deSdougm ret = SA_SYNTAX_ERR; 111957b448deSdougm break; 112057b448deSdougm case 0: 112157b448deSdougm break; 112257b448deSdougm } 112357b448deSdougm } 112457b448deSdougm if (optstring != NULL) 112557b448deSdougm free(optstring); 112657b448deSdougm if (zfsopts != NULL) 112757b448deSdougm free(zfsopts); 11286185db85Sdougm } 112957b448deSdougm if (proto != NULL) 113057b448deSdougm sa_free_attr_string(proto); 113157b448deSdougm if (dataset != NULL) 113257b448deSdougm free(dataset); 11336185db85Sdougm } 113457b448deSdougm free(command); 11356185db85Sdougm } 11366185db85Sdougm return (ret); 11376185db85Sdougm } 11386185db85Sdougm 11396185db85Sdougm /* 11406185db85Sdougm * sa_group_is_zfs(group) 11416185db85Sdougm * 11426185db85Sdougm * Given the group, determine if the zfs attribute is set. 11436185db85Sdougm */ 11446185db85Sdougm 11456185db85Sdougm int 11466185db85Sdougm sa_group_is_zfs(sa_group_t group) 11476185db85Sdougm { 11486185db85Sdougm char *zfs; 11496185db85Sdougm int ret = 0; 11506185db85Sdougm 11516185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 11526185db85Sdougm if (zfs != NULL) { 115357b448deSdougm ret = 1; 115457b448deSdougm sa_free_attr_string(zfs); 11556185db85Sdougm } 11566185db85Sdougm return (ret); 11576185db85Sdougm } 11586185db85Sdougm 11596185db85Sdougm /* 11606185db85Sdougm * sa_path_is_zfs(path) 11616185db85Sdougm * 11626185db85Sdougm * Check to see if the file system path represents is of type "zfs". 11636185db85Sdougm */ 11646185db85Sdougm 11656185db85Sdougm int 11666185db85Sdougm sa_path_is_zfs(char *path) 11676185db85Sdougm { 11686185db85Sdougm char *fstype; 11696185db85Sdougm int ret = 0; 11706185db85Sdougm 11716185db85Sdougm fstype = sa_fstype(path); 117257b448deSdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) 117357b448deSdougm ret = 1; 11746185db85Sdougm if (fstype != NULL) 117557b448deSdougm sa_free_fstype(fstype); 11766185db85Sdougm return (ret); 11776185db85Sdougm } 1178ecd6cf80Smarks 1179ecd6cf80Smarks int 1180ecd6cf80Smarks sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1181ecd6cf80Smarks { 1182ecd6cf80Smarks char *path; 1183ecd6cf80Smarks 1184ed78bdc4Smarks /* Make sure path is valid */ 1185ed78bdc4Smarks 1186ecd6cf80Smarks path = sa_get_share_attr(share, "path"); 1187ecd6cf80Smarks if (path != NULL) { 1188ecd6cf80Smarks (void) memset(sh, 0, sizeof (sh)); 1189ecd6cf80Smarks (void) sa_fillshare(share, proto, sh); 1190ed78bdc4Smarks sa_free_attr_string(path); 1191ecd6cf80Smarks return (0); 1192ecd6cf80Smarks } else 1193ecd6cf80Smarks return (1); 1194ecd6cf80Smarks } 1195ecd6cf80Smarks 1196ecd6cf80Smarks #define SMAX(i, j) \ 1197ecd6cf80Smarks if ((j) > (i)) { \ 1198ecd6cf80Smarks (i) = (j); \ 1199ecd6cf80Smarks } 1200ecd6cf80Smarks 1201ecd6cf80Smarks int 1202ecd6cf80Smarks sa_share_zfs(sa_share_t share, char *path, share_t *sh, 1203*da6c28aaSamw void *exportdata, zfs_share_op_t operation) 1204ecd6cf80Smarks { 1205ecd6cf80Smarks libzfs_handle_t *libhandle; 1206ecd6cf80Smarks sa_group_t group; 1207ecd6cf80Smarks sa_handle_t sahandle; 1208ecd6cf80Smarks char *dataset; 1209ecd6cf80Smarks int err = EINVAL; 1210ecd6cf80Smarks int i, j; 12114d79fe3bSmarks char newpath[MAXPATHLEN]; 1212a1ef5d63Smarks char *pathp; 1213ecd6cf80Smarks 1214ecd6cf80Smarks /* 1215ecd6cf80Smarks * First find the dataset name 1216ecd6cf80Smarks */ 1217ecd6cf80Smarks if ((group = sa_get_parent_group(share)) == NULL) { 1218ecd6cf80Smarks return (SA_SYSTEM_ERR); 1219ecd6cf80Smarks } 1220ecd6cf80Smarks if ((sahandle = sa_find_group_handle(group)) == NULL) { 1221ecd6cf80Smarks return (SA_SYSTEM_ERR); 1222ecd6cf80Smarks } 1223ecd6cf80Smarks 12244d79fe3bSmarks /* 12254d79fe3bSmarks * If get_zfs_dataset fails, see if it is a subdirectory 12264d79fe3bSmarks */ 1227a1ef5d63Smarks 1228a1ef5d63Smarks pathp = path; 1229a1ef5d63Smarks while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 12304d79fe3bSmarks char *p; 12314d79fe3bSmarks 1232a1ef5d63Smarks if (pathp == path) { 1233a1ef5d63Smarks (void) strlcpy(newpath, path, sizeof (newpath)); 1234a1ef5d63Smarks pathp = newpath; 1235a1ef5d63Smarks } 1236a1ef5d63Smarks 1237a1ef5d63Smarks /* 1238a1ef5d63Smarks * chop off part of path, but if we are at root then 1239a1ef5d63Smarks * make sure path is a / 1240a1ef5d63Smarks */ 1241a1ef5d63Smarks if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1242a1ef5d63Smarks if (pathp == p) { 1243a1ef5d63Smarks *(p + 1) = '\0'; /* skip over /, root case */ 1244a1ef5d63Smarks } else { 1245a1ef5d63Smarks *p = '\0'; 1246a1ef5d63Smarks } 1247a1ef5d63Smarks } else { 12484d79fe3bSmarks return (SA_SYSTEM_ERR); 1249a1ef5d63Smarks } 1250ecd6cf80Smarks } 1251ecd6cf80Smarks 1252ecd6cf80Smarks libhandle = libzfs_init(); 1253ecd6cf80Smarks if (libhandle != NULL) { 1254ecd6cf80Smarks 1255ecd6cf80Smarks i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1256ecd6cf80Smarks sh->sh_size = i; 1257ecd6cf80Smarks 1258ecd6cf80Smarks j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1259ecd6cf80Smarks sh->sh_size += j; 1260ecd6cf80Smarks SMAX(i, j); 1261ecd6cf80Smarks 1262ecd6cf80Smarks j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1263ecd6cf80Smarks sh->sh_size += j; 1264ecd6cf80Smarks SMAX(i, j); 1265ecd6cf80Smarks 1266ecd6cf80Smarks j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1267ecd6cf80Smarks sh->sh_size += j; 1268ecd6cf80Smarks SMAX(i, j); 1269ecd6cf80Smarks 1270ecd6cf80Smarks j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1271ecd6cf80Smarks sh->sh_size += j; 1272ecd6cf80Smarks SMAX(i, j); 1273ecd6cf80Smarks err = zfs_deleg_share_nfs(libhandle, dataset, path, 1274*da6c28aaSamw exportdata, sh, i, operation); 1275ecd6cf80Smarks libzfs_fini(libhandle); 1276ecd6cf80Smarks } 1277ecd6cf80Smarks free(dataset); 1278ecd6cf80Smarks return (err); 1279ecd6cf80Smarks } 1280