16185db85Sdougm /* 26185db85Sdougm * CDDL HEADER START 36185db85Sdougm * 46185db85Sdougm * The contents of this file are subject to the terms of the 56185db85Sdougm * Common Development and Distribution License (the "License"). 66185db85Sdougm * You may not use this file except in compliance with the License. 76185db85Sdougm * 86185db85Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96185db85Sdougm * or http://www.opensolaris.org/os/licensing. 106185db85Sdougm * See the License for the specific language governing permissions 116185db85Sdougm * and limitations under the License. 126185db85Sdougm * 136185db85Sdougm * When distributing Covered Code, include this CDDL HEADER in each 146185db85Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156185db85Sdougm * If applicable, add the following below this CDDL HEADER, with the 166185db85Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 176185db85Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 186185db85Sdougm * 196185db85Sdougm * CDDL HEADER END 206185db85Sdougm */ 216185db85Sdougm 226185db85Sdougm /* 23*5b6e0c46Sdougm * Copyright 2008 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 39da6c28aaSamw 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 *); 44*5b6e0c46Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 451cea05afSdougm 461cea05afSdougm /* 471cea05afSdougm * File system specific code for ZFS. The original code was stolen 481cea05afSdougm * from the "zfs" command and modified to better suit this library's 491cea05afSdougm * usage. 501cea05afSdougm */ 511cea05afSdougm 521cea05afSdougm typedef struct get_all_cbdata { 531cea05afSdougm zfs_handle_t **cb_handles; 541cea05afSdougm size_t cb_alloc; 551cea05afSdougm size_t cb_used; 56a3351425Sdougm uint_t cb_types; 571cea05afSdougm } get_all_cbdata_t; 581cea05afSdougm 591cea05afSdougm /* 60549ec3ffSdougm * sa_zfs_init(impl_handle) 611cea05afSdougm * 62549ec3ffSdougm * Initialize an access handle into libzfs. The handle needs to stay 63549ec3ffSdougm * around until sa_zfs_fini() in order to maintain the cache of 64549ec3ffSdougm * mounts. 651cea05afSdougm */ 661cea05afSdougm 6757b448deSdougm int 68549ec3ffSdougm sa_zfs_init(sa_handle_impl_t impl_handle) 691cea05afSdougm { 70549ec3ffSdougm impl_handle->zfs_libhandle = libzfs_init(); 7157b448deSdougm if (impl_handle->zfs_libhandle != NULL) { 7257b448deSdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 7357b448deSdougm return (B_TRUE); 7457b448deSdougm } 7557b448deSdougm return (B_FALSE); 761cea05afSdougm } 771cea05afSdougm 781cea05afSdougm /* 79549ec3ffSdougm * sa_zfs_fini(impl_handle) 801cea05afSdougm * 811cea05afSdougm * cleanup data structures and the libzfs handle used for accessing 821cea05afSdougm * zfs file share info. 831cea05afSdougm */ 841cea05afSdougm 851cea05afSdougm void 86549ec3ffSdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 871cea05afSdougm { 88549ec3ffSdougm if (impl_handle->zfs_libhandle != NULL) { 8957b448deSdougm if (impl_handle->zfs_list != NULL) { 90a3351425Sdougm zfs_handle_t **zhp = impl_handle->zfs_list; 91a3351425Sdougm size_t i; 92a3351425Sdougm 9357b448deSdougm /* 94a3351425Sdougm * Contents of zfs_list need to be freed so we 95a3351425Sdougm * don't lose ZFS handles. 9657b448deSdougm */ 97a3351425Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) { 98a3351425Sdougm zfs_close(zhp[i]); 99a3351425Sdougm } 10057b448deSdougm free(impl_handle->zfs_list); 10157b448deSdougm impl_handle->zfs_list = NULL; 10257b448deSdougm impl_handle->zfs_list_count = 0; 10357b448deSdougm } 104a3351425Sdougm 105a3351425Sdougm libzfs_fini(impl_handle->zfs_libhandle); 106a3351425Sdougm impl_handle->zfs_libhandle = NULL; 1071cea05afSdougm } 1081cea05afSdougm } 1091cea05afSdougm 1101cea05afSdougm /* 1111cea05afSdougm * get_one_filesystem(zfs_handle_t, data) 1121cea05afSdougm * 113da6c28aaSamw * an iterator function called while iterating through the ZFS 1141cea05afSdougm * root. It accumulates into an array of file system handles that can 1151cea05afSdougm * be used to derive info about those file systems. 116a3351425Sdougm * 117a3351425Sdougm * Note that as this function is called, we close all zhp handles that 118a3351425Sdougm * are not going to be places into the cp_handles list. We don't want 119a3351425Sdougm * to close the ones we are keeping, but all others would be leaked if 120a3351425Sdougm * not closed here. 1211cea05afSdougm */ 1221cea05afSdougm 1231cea05afSdougm static int 1241cea05afSdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1251cea05afSdougm { 1261cea05afSdougm get_all_cbdata_t *cbp = data; 127a3351425Sdougm zfs_type_t type = zfs_get_type(zhp); 1281cea05afSdougm 1291cea05afSdougm /* 130a3351425Sdougm * Interate over any nested datasets. 1311cea05afSdougm */ 132a3351425Sdougm if (type == ZFS_TYPE_FILESYSTEM && 133a3351425Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 134a3351425Sdougm zfs_close(zhp); 135a3351425Sdougm return (1); 136a3351425Sdougm } 137a3351425Sdougm 138a3351425Sdougm /* 139a3351425Sdougm * Skip any datasets whose type does not match. 140a3351425Sdougm */ 141a3351425Sdougm if ((type & cbp->cb_types) == 0) { 1421cea05afSdougm zfs_close(zhp); 1431cea05afSdougm return (0); 1441cea05afSdougm } 1451cea05afSdougm 1461cea05afSdougm if (cbp->cb_alloc == cbp->cb_used) { 1471cea05afSdougm zfs_handle_t **handles; 1481cea05afSdougm 1491cea05afSdougm if (cbp->cb_alloc == 0) 1501cea05afSdougm cbp->cb_alloc = 64; 1511cea05afSdougm else 1521cea05afSdougm cbp->cb_alloc *= 2; 1531cea05afSdougm 154a3351425Sdougm handles = (zfs_handle_t **)calloc(1, 155a3351425Sdougm cbp->cb_alloc * sizeof (void *)); 156a3351425Sdougm 1571cea05afSdougm if (handles == NULL) { 158a3351425Sdougm zfs_close(zhp); 15957b448deSdougm return (0); 1601cea05afSdougm } 1611cea05afSdougm if (cbp->cb_handles) { 162a3351425Sdougm bcopy(cbp->cb_handles, handles, 1631cea05afSdougm cbp->cb_used * sizeof (void *)); 1641cea05afSdougm free(cbp->cb_handles); 1651cea05afSdougm } 1661cea05afSdougm 1671cea05afSdougm cbp->cb_handles = handles; 1681cea05afSdougm } 1691cea05afSdougm 1701cea05afSdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1711cea05afSdougm 172a3351425Sdougm return (0); 1731cea05afSdougm } 1741cea05afSdougm 1751cea05afSdougm /* 1761cea05afSdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1771cea05afSdougm * 1781cea05afSdougm * iterate through all ZFS file systems starting at the root. Returns 1791cea05afSdougm * a count and an array of handle pointers. Allocating is only done 1801cea05afSdougm * once. The caller does not need to free since it will be done at 1811cea05afSdougm * sa_zfs_fini() time. 1821cea05afSdougm */ 1831cea05afSdougm 1841cea05afSdougm static void 185549ec3ffSdougm get_all_filesystems(sa_handle_impl_t impl_handle, 186549ec3ffSdougm zfs_handle_t ***fslist, size_t *count) 1871cea05afSdougm { 1881cea05afSdougm get_all_cbdata_t cb = { 0 }; 189a3351425Sdougm cb.cb_types = ZFS_TYPE_FILESYSTEM; 1901cea05afSdougm 191549ec3ffSdougm if (impl_handle->zfs_list != NULL) { 19257b448deSdougm *fslist = impl_handle->zfs_list; 19357b448deSdougm *count = impl_handle->zfs_list_count; 19457b448deSdougm return; 1951cea05afSdougm } 1961cea05afSdougm 197549ec3ffSdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 19857b448deSdougm get_one_filesystem, &cb); 1991cea05afSdougm 200549ec3ffSdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 201549ec3ffSdougm impl_handle->zfs_list_count = *count = cb.cb_used; 2021cea05afSdougm } 2031cea05afSdougm 2046185db85Sdougm /* 2051cea05afSdougm * mountpoint_compare(a, b) 2061cea05afSdougm * 2071cea05afSdougm * compares the mountpoint on two zfs file systems handles. 2081cea05afSdougm * returns values following strcmp() model. 2096185db85Sdougm */ 2106185db85Sdougm 2111cea05afSdougm static int 2121cea05afSdougm mountpoint_compare(const void *a, const void *b) 2131cea05afSdougm { 2141cea05afSdougm zfs_handle_t **za = (zfs_handle_t **)a; 2151cea05afSdougm zfs_handle_t **zb = (zfs_handle_t **)b; 2161cea05afSdougm char mounta[MAXPATHLEN]; 2171cea05afSdougm char mountb[MAXPATHLEN]; 2181cea05afSdougm 2191cea05afSdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2201cea05afSdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2211cea05afSdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2221cea05afSdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2231cea05afSdougm 2241cea05afSdougm return (strcmp(mounta, mountb)); 2251cea05afSdougm } 2261cea05afSdougm 227a1ef5d63Smarks /* 228a1ef5d63Smarks * return legacy mountpoint. Caller provides space for mountpoint. 229a1ef5d63Smarks */ 230a1ef5d63Smarks int 231a1ef5d63Smarks get_legacy_mountpoint(char *path, char *mountpoint, size_t len) 232a1ef5d63Smarks { 233a1ef5d63Smarks FILE *fp; 234a1ef5d63Smarks struct mnttab entry; 235a1ef5d63Smarks 236a1ef5d63Smarks if ((fp = fopen(MNTTAB, "r")) == NULL) { 237a1ef5d63Smarks return (1); 238a1ef5d63Smarks } 239a1ef5d63Smarks 240a1ef5d63Smarks while (getmntent(fp, &entry) == 0) { 241a1ef5d63Smarks 242a1ef5d63Smarks if (entry.mnt_fstype == NULL || 243a1ef5d63Smarks strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 244a1ef5d63Smarks continue; 245a1ef5d63Smarks 246a1ef5d63Smarks if (strcmp(entry.mnt_mountp, path) == 0) { 247a1ef5d63Smarks (void) strlcpy(mountpoint, entry.mnt_special, len); 248a1ef5d63Smarks (void) fclose(fp); 249a1ef5d63Smarks return (0); 250a1ef5d63Smarks } 251a1ef5d63Smarks } 252a1ef5d63Smarks (void) fclose(fp); 253a1ef5d63Smarks return (1); 254a1ef5d63Smarks } 255a1ef5d63Smarks 2566185db85Sdougm /* 257549ec3ffSdougm * get_zfs_dataset(impl_handle, path) 2586185db85Sdougm * 2596185db85Sdougm * get the name of the ZFS dataset the path is equivalent to. The 2606185db85Sdougm * dataset name is used for get/set of ZFS properties since libzfs 2616185db85Sdougm * requires a dataset to do a zfs_open(). 2626185db85Sdougm */ 2636185db85Sdougm 2646185db85Sdougm static char * 265a1ef5d63Smarks get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 266a1ef5d63Smarks boolean_t search_mnttab) 2676185db85Sdougm { 2681cea05afSdougm size_t i, count = 0; 2696185db85Sdougm char *dataset = NULL; 2701cea05afSdougm zfs_handle_t **zlist; 2711cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 27267331909Sdougm char canmount[ZFS_MAXPROPLEN]; 2736185db85Sdougm 274549ec3ffSdougm get_all_filesystems(impl_handle, &zlist, &count); 2751cea05afSdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2761cea05afSdougm for (i = 0; i < count; i++) { 27757b448deSdougm /* must have a mountpoint */ 27857b448deSdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 27957b448deSdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 28057b448deSdougm /* no mountpoint */ 28157b448deSdougm continue; 28257b448deSdougm } 28357b448deSdougm 28457b448deSdougm /* mountpoint must be a path */ 28557b448deSdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 286a1ef5d63Smarks strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 287a1ef5d63Smarks /* 288a1ef5d63Smarks * Search mmttab for mountpoint 289a1ef5d63Smarks */ 290a1ef5d63Smarks 291a1ef5d63Smarks if (search_mnttab == B_TRUE && 292a1ef5d63Smarks get_legacy_mountpoint(path, mountpoint, 293a1ef5d63Smarks sizeof (mountpoint)) == 0) { 294a1ef5d63Smarks dataset = mountpoint; 295a1ef5d63Smarks break; 296a1ef5d63Smarks } 29757b448deSdougm continue; 298a1ef5d63Smarks } 29957b448deSdougm 30057b448deSdougm /* canmount must be set */ 30157b448deSdougm canmount[0] = '\0'; 302ecd6cf80Smarks if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 30367331909Sdougm sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 30457b448deSdougm strcmp(canmount, "off") == 0) 30557b448deSdougm continue; 3061cea05afSdougm 30757b448deSdougm /* 30857b448deSdougm * have a mountable handle but want to skip those marked none 30957b448deSdougm * and legacy 31057b448deSdougm */ 31157b448deSdougm if (strcmp(mountpoint, path) == 0) { 31257b448deSdougm dataset = (char *)zfs_get_name(zlist[i]); 31357b448deSdougm break; 31457b448deSdougm } 3151cea05afSdougm 3166185db85Sdougm } 3171cea05afSdougm 31857b448deSdougm if (dataset != NULL) 31957b448deSdougm dataset = strdup(dataset); 32057b448deSdougm 3216185db85Sdougm return (dataset); 3226185db85Sdougm } 3236185db85Sdougm 3246185db85Sdougm /* 3256185db85Sdougm * get_zfs_property(dataset, property) 3266185db85Sdougm * 3276185db85Sdougm * Get the file system property specified from the ZFS dataset. 3286185db85Sdougm */ 3296185db85Sdougm 3306185db85Sdougm static char * 3316185db85Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 3326185db85Sdougm { 3336185db85Sdougm zfs_handle_t *handle = NULL; 3346185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3356185db85Sdougm libzfs_handle_t *libhandle; 3366185db85Sdougm 3376185db85Sdougm libhandle = libzfs_init(); 3386185db85Sdougm if (libhandle != NULL) { 33957b448deSdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 34057b448deSdougm if (handle != NULL) { 34157b448deSdougm if (zfs_prop_get(handle, property, shareopts, 34257b448deSdougm sizeof (shareopts), NULL, NULL, 0, 34357b448deSdougm B_FALSE) == 0) { 34457b448deSdougm zfs_close(handle); 34557b448deSdougm libzfs_fini(libhandle); 34657b448deSdougm return (strdup(shareopts)); 34757b448deSdougm } 34857b448deSdougm zfs_close(handle); 3496185db85Sdougm } 35057b448deSdougm libzfs_fini(libhandle); 3516185db85Sdougm } 3526185db85Sdougm return (NULL); 3536185db85Sdougm } 3546185db85Sdougm 3556185db85Sdougm /* 356549ec3ffSdougm * sa_zfs_is_shared(handle, path) 3576185db85Sdougm * 3586185db85Sdougm * Check to see if the ZFS path provided has the sharenfs option set 3596185db85Sdougm * or not. 3606185db85Sdougm */ 3616185db85Sdougm 3626185db85Sdougm int 363549ec3ffSdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 3646185db85Sdougm { 3656185db85Sdougm int ret = 0; 3666185db85Sdougm char *dataset; 3676185db85Sdougm zfs_handle_t *handle = NULL; 3686185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3696185db85Sdougm libzfs_handle_t *libhandle; 3706185db85Sdougm 371a1ef5d63Smarks dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 3726185db85Sdougm if (dataset != NULL) { 37357b448deSdougm libhandle = libzfs_init(); 37457b448deSdougm if (libhandle != NULL) { 37557b448deSdougm handle = zfs_open(libhandle, dataset, 37657b448deSdougm ZFS_TYPE_FILESYSTEM); 37757b448deSdougm if (handle != NULL) { 37857b448deSdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 37957b448deSdougm shareopts, sizeof (shareopts), NULL, NULL, 38057b448deSdougm 0, B_FALSE) == 0 && 38157b448deSdougm strcmp(shareopts, "off") != 0) { 38257b448deSdougm ret = 1; /* it is shared */ 38357b448deSdougm } 38457b448deSdougm zfs_close(handle); 38557b448deSdougm } 38657b448deSdougm libzfs_fini(libhandle); 3876185db85Sdougm } 38857b448deSdougm free(dataset); 3896185db85Sdougm } 3906185db85Sdougm return (ret); 3916185db85Sdougm } 3926185db85Sdougm 3936185db85Sdougm /* 394da6c28aaSamw * find_or_create_group(handle, groupname, proto, *err) 3956185db85Sdougm * 3966185db85Sdougm * While walking the ZFS tree, we need to add shares to a defined 3976185db85Sdougm * group. If the group doesn't exist, create it first, making sure it 3986185db85Sdougm * is marked as a ZFS group. 3996185db85Sdougm * 40093a6f655Sdougm * Note that all ZFS shares are in a subgroup of the top level group 40193a6f655Sdougm * called "zfs". 4026185db85Sdougm */ 4036185db85Sdougm 4046185db85Sdougm static sa_group_t 405549ec3ffSdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 4066185db85Sdougm { 4076185db85Sdougm sa_group_t group; 4086185db85Sdougm sa_optionset_t optionset; 4096185db85Sdougm int ret = SA_OK; 4106185db85Sdougm 4116185db85Sdougm /* 4126185db85Sdougm * we check to see if the "zfs" group exists. Since this 4136185db85Sdougm * should be the top level group, we don't want the 4146185db85Sdougm * parent. This is to make sure the zfs group has been created 4156185db85Sdougm * and to created if it hasn't been. 4166185db85Sdougm */ 417549ec3ffSdougm group = sa_get_group(handle, groupname); 4186185db85Sdougm if (group == NULL) { 41957b448deSdougm group = sa_create_group(handle, groupname, &ret); 42093a6f655Sdougm 42157b448deSdougm /* make sure this is flagged as a ZFS group */ 42257b448deSdougm if (group != NULL) 42357b448deSdougm ret = sa_set_group_attr(group, "zfs", "true"); 4246185db85Sdougm } 4256185db85Sdougm if (group != NULL) { 42657b448deSdougm if (proto != NULL) { 42757b448deSdougm optionset = sa_get_optionset(group, proto); 428da6c28aaSamw if (optionset == NULL) 42957b448deSdougm optionset = sa_create_optionset(group, proto); 4306185db85Sdougm } 4316185db85Sdougm } 4326185db85Sdougm if (err != NULL) 43357b448deSdougm *err = ret; 4346185db85Sdougm return (group); 4356185db85Sdougm } 4366185db85Sdougm 43793a6f655Sdougm /* 43893a6f655Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 43993a6f655Sdougm * 44093a6f655Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 44193a6f655Sdougm * function looks to see if the groupname exists and returns it if it 44293a6f655Sdougm * does or else creates a new one with the specified name and returns 44393a6f655Sdougm * that. The "zfs" group will exist before we get here, but we make 44493a6f655Sdougm * sure just in case. 44593a6f655Sdougm * 44693a6f655Sdougm * err must be a valid pointer. 44793a6f655Sdougm */ 44893a6f655Sdougm 44993a6f655Sdougm static sa_group_t 450da6c28aaSamw find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 451da6c28aaSamw char *optstring, int *err) 45293a6f655Sdougm { 45393a6f655Sdougm sa_group_t group = NULL; 45493a6f655Sdougm sa_group_t zfs; 45593a6f655Sdougm char *name; 45693a6f655Sdougm char *options; 45793a6f655Sdougm 45893a6f655Sdougm /* start with the top-level "zfs" group */ 459549ec3ffSdougm zfs = sa_get_group(handle, "zfs"); 46093a6f655Sdougm *err = SA_OK; 46193a6f655Sdougm if (zfs != NULL) { 46257b448deSdougm for (group = sa_get_sub_group(zfs); group != NULL; 46357b448deSdougm group = sa_get_next_group(group)) { 46457b448deSdougm name = sa_get_group_attr(group, "name"); 46557b448deSdougm if (name != NULL && strcmp(name, groupname) == 0) { 46657b448deSdougm /* have the group so break out of here */ 46757b448deSdougm sa_free_attr_string(name); 46857b448deSdougm break; 46957b448deSdougm } 47057b448deSdougm if (name != NULL) 47157b448deSdougm sa_free_attr_string(name); 47293a6f655Sdougm } 47357b448deSdougm 47457b448deSdougm if (group == NULL) { 47557b448deSdougm /* 47657b448deSdougm * need to create the sub-group since it doesn't exist 47757b448deSdougm */ 47857b448deSdougm group = _sa_create_zfs_group(zfs, groupname); 47957b448deSdougm if (group != NULL) 48057b448deSdougm set_node_attr(group, "zfs", "true"); 48157b448deSdougm if (strcmp(optstring, "on") == 0) 48257b448deSdougm optstring = "rw"; 48357b448deSdougm if (group != NULL) { 48457b448deSdougm options = strdup(optstring); 48557b448deSdougm if (options != NULL) { 48657b448deSdougm *err = sa_parse_legacy_options(group, 487da6c28aaSamw options, proto); 488da6c28aaSamw 489da6c28aaSamw /* If no optionset, add one */ 490da6c28aaSamw if (sa_get_optionset(group, proto) == 491da6c28aaSamw NULL) 492da6c28aaSamw (void) sa_create_optionset( 493da6c28aaSamw group, proto); 49457b448deSdougm free(options); 49557b448deSdougm } else { 49657b448deSdougm *err = SA_NO_MEMORY; 49757b448deSdougm } 49857b448deSdougm } 499da6c28aaSamw } else if (proto != NULL && strcmp(proto, "smb") == 0) { 500da6c28aaSamw *err = SA_PROP_SHARE_ONLY; 50193a6f655Sdougm } 50293a6f655Sdougm } 50393a6f655Sdougm return (group); 50493a6f655Sdougm } 50593a6f655Sdougm 506da6c28aaSamw /* 507da6c28aaSamw * zfs_construct_resource(share, name, base, dataset) 508da6c28aaSamw * 509da6c28aaSamw * Add a resource to the share using name as a template. If name == 510da6c28aaSamw * NULL, then construct a name based on the dataset value. 511da6c28aaSamw * name. 512da6c28aaSamw */ 513da6c28aaSamw static void 514da6c28aaSamw zfs_construct_resource(sa_share_t share, char *dataset) 515da6c28aaSamw { 516da6c28aaSamw char buff[SA_MAX_RESOURCE_NAME + 1]; 517da6c28aaSamw int ret = SA_OK; 518da6c28aaSamw 519da6c28aaSamw (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset); 520da6c28aaSamw sa_fix_resource_name(buff); 521da6c28aaSamw (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret); 522da6c28aaSamw } 523da6c28aaSamw 52457b448deSdougm /* 52557b448deSdougm * zfs_inherited(handle, source, sourcestr) 52657b448deSdougm * 527da6c28aaSamw * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares 52857b448deSdougm * for readability. 52957b448deSdougm */ 53057b448deSdougm static int 53157b448deSdougm zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 532da6c28aaSamw char *shareopts, char *mountpoint, char *proto, char *dataset) 53357b448deSdougm { 53457b448deSdougm int doshopt = 0; 53557b448deSdougm int err = SA_OK; 53657b448deSdougm sa_group_t group; 537da6c28aaSamw sa_resource_t resource; 538da6c28aaSamw uint64_t features; 53957b448deSdougm 54057b448deSdougm /* 54157b448deSdougm * Need to find the "real" parent sub-group. It may not be 54257b448deSdougm * mounted, but it was identified in the "sourcestr" 54357b448deSdougm * variable. The real parent not mounted can occur if 54457b448deSdougm * "canmount=off and sharenfs=on". 54557b448deSdougm */ 546da6c28aaSamw group = find_or_create_zfs_subgroup(handle, sourcestr, proto, 547da6c28aaSamw shareopts, &doshopt); 54857b448deSdougm if (group != NULL) { 549da6c28aaSamw /* 550da6c28aaSamw * We may need the first share for resource 551da6c28aaSamw * prototype. We only care about it if it has a 552da6c28aaSamw * resource that sets a prefix value. 553da6c28aaSamw */ 554da6c28aaSamw if (share == NULL) 555da6c28aaSamw share = _sa_add_share(group, mountpoint, 556da6c28aaSamw SA_SHARE_TRANSIENT, &err, 557da6c28aaSamw (uint64_t)SA_FEATURE_NONE); 55857b448deSdougm /* 55957b448deSdougm * some options may only be on shares. If the opt 56057b448deSdougm * string contains one of those, we put it just on the 56157b448deSdougm * share. 56257b448deSdougm */ 56357b448deSdougm if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 56457b448deSdougm char *options; 56557b448deSdougm options = strdup(shareopts); 56657b448deSdougm if (options != NULL) { 567da6c28aaSamw set_node_attr(share, "dataset", dataset); 56857b448deSdougm err = sa_parse_legacy_options(share, options, 569da6c28aaSamw proto); 570da6c28aaSamw set_node_attr(share, "dataset", NULL); 57157b448deSdougm free(options); 57257b448deSdougm } 573da6c28aaSamw if (sa_get_optionset(group, proto) == NULL) 574da6c28aaSamw (void) sa_create_optionset(group, proto); 575da6c28aaSamw } 576da6c28aaSamw features = sa_proto_get_featureset(proto); 577da6c28aaSamw if (share != NULL && features & SA_FEATURE_RESOURCE) { 578da6c28aaSamw /* 579da6c28aaSamw * We have a share and the protocol requires 580da6c28aaSamw * that at least one resource exist (probably 581da6c28aaSamw * SMB). We need to make sure that there is at 582da6c28aaSamw * least one. 583da6c28aaSamw */ 584da6c28aaSamw resource = sa_get_share_resource(share, NULL); 585da6c28aaSamw if (resource == NULL) { 586da6c28aaSamw zfs_construct_resource(share, dataset); 587da6c28aaSamw } 58857b448deSdougm } 58957b448deSdougm } else { 59057b448deSdougm err = SA_NO_MEMORY; 59157b448deSdougm } 59257b448deSdougm return (err); 59357b448deSdougm } 59457b448deSdougm 59557b448deSdougm /* 59697df5ac9Sdougm * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset, 59797df5ac9Sdougm * grouperr) 59857b448deSdougm * 59957b448deSdougm * handle case where this is the top of a sub-group in ZFS. Pulled out 60097df5ac9Sdougm * of sa_get_zfs_shares for readability. We need the grouperr from the 60197df5ac9Sdougm * creation of the subgroup to know whether to add the public 60297df5ac9Sdougm * property, etc. to the specific share. 60357b448deSdougm */ 60457b448deSdougm static int 605da6c28aaSamw zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 60697df5ac9Sdougm char *shareopts, char *proto, char *dataset, int grouperr) 60757b448deSdougm { 60857b448deSdougm int err = SA_OK; 609da6c28aaSamw sa_resource_t resource; 610da6c28aaSamw uint64_t features; 61157b448deSdougm 61257b448deSdougm set_node_attr(group, "zfs", "true"); 613da6c28aaSamw if (share == NULL) 614da6c28aaSamw share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 615da6c28aaSamw &err, (uint64_t)SA_FEATURE_NONE); 61657b448deSdougm if (err == SA_OK) { 617f8825440Sdougm if (strcmp(shareopts, "on") == 0) 618da6c28aaSamw shareopts = ""; 619da6c28aaSamw if (shareopts != NULL) { 620da6c28aaSamw char *options; 62197df5ac9Sdougm if (grouperr == SA_PROP_SHARE_ONLY) { 622da6c28aaSamw /* 62397df5ac9Sdougm * Some properties may only be on 62497df5ac9Sdougm * shares, but due to the ZFS 62597df5ac9Sdougm * sub-groups being artificial, we 626da6c28aaSamw * sometimes get this and have to deal 627da6c28aaSamw * with it. We do it by attempting to 628da6c28aaSamw * put it on the share. 629da6c28aaSamw */ 630da6c28aaSamw options = strdup(shareopts); 631da6c28aaSamw if (options != NULL) { 632da6c28aaSamw err = sa_parse_legacy_options(share, 633da6c28aaSamw options, proto); 634da6c28aaSamw free(options); 635da6c28aaSamw } 636da6c28aaSamw } 637da6c28aaSamw /* unmark the share's changed state */ 638da6c28aaSamw set_node_attr(share, "changed", NULL); 639da6c28aaSamw } 640da6c28aaSamw features = sa_proto_get_featureset(proto); 641da6c28aaSamw if (share != NULL && features & SA_FEATURE_RESOURCE) { 642da6c28aaSamw /* 643da6c28aaSamw * We have a share and the protocol requires 644da6c28aaSamw * that at least one resource exist (probably 645da6c28aaSamw * SMB). We need to make sure that there is at 646da6c28aaSamw * least one. 647da6c28aaSamw */ 648da6c28aaSamw resource = sa_get_share_resource(share, NULL); 649da6c28aaSamw if (resource == NULL) { 650da6c28aaSamw zfs_construct_resource(share, dataset); 651da6c28aaSamw } 65257b448deSdougm } 65357b448deSdougm } 65457b448deSdougm return (err); 65557b448deSdougm } 65657b448deSdougm 65757b448deSdougm /* 65857b448deSdougm * zfs_grp_error(err) 65957b448deSdougm * 66057b448deSdougm * Print group create error, but only once. If err is 0 do the 66157b448deSdougm * print else don't. 66257b448deSdougm */ 66357b448deSdougm 66457b448deSdougm static void 66557b448deSdougm zfs_grp_error(int err) 66657b448deSdougm { 66757b448deSdougm if (err == 0) { 66857b448deSdougm /* only print error once */ 66957b448deSdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 67057b448deSdougm "Cannot create ZFS subgroup during initialization:" 67157b448deSdougm " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 67257b448deSdougm } 67357b448deSdougm } 67457b448deSdougm 675da6c28aaSamw /* 676da6c28aaSamw * zfs_process_share(handle, share, mountpoint, proto, source, 677da6c28aaSamw * shareopts, sourcestr) 678da6c28aaSamw * 679*5b6e0c46Sdougm * Creates the subgroup, if necessary and adds shares, resources 680da6c28aaSamw * and properties. 681da6c28aaSamw */ 682*5b6e0c46Sdougm int 683*5b6e0c46Sdougm sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 684da6c28aaSamw char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 685da6c28aaSamw char *sourcestr, char *dataset) 686da6c28aaSamw { 687da6c28aaSamw int err = SA_OK; 688da6c28aaSamw 689da6c28aaSamw if (source & ZPROP_SRC_INHERITED) { 690da6c28aaSamw err = zfs_inherited(handle, share, sourcestr, shareopts, 691da6c28aaSamw mountpoint, proto, dataset); 692da6c28aaSamw } else { 693da6c28aaSamw group = find_or_create_zfs_subgroup(handle, dataset, proto, 694da6c28aaSamw shareopts, &err); 695da6c28aaSamw if (group == NULL) { 69697df5ac9Sdougm static boolean_t reported_error = B_FALSE; 697da6c28aaSamw /* 69897df5ac9Sdougm * There is a problem, but we can't do 699da6c28aaSamw * anything about it at this point so we issue 70097df5ac9Sdougm * a warning and move on. 701da6c28aaSamw */ 70297df5ac9Sdougm zfs_grp_error(reported_error); 70397df5ac9Sdougm reported_error = B_TRUE; 704da6c28aaSamw } 705da6c28aaSamw set_node_attr(group, "zfs", "true"); 706da6c28aaSamw /* 707da6c28aaSamw * Add share with local opts via zfs_notinherited. 708da6c28aaSamw */ 709da6c28aaSamw err = zfs_notinherited(group, share, mountpoint, shareopts, 71097df5ac9Sdougm proto, dataset, err); 711da6c28aaSamw } 712da6c28aaSamw return (err); 713da6c28aaSamw } 714da6c28aaSamw 7156185db85Sdougm /* 716549ec3ffSdougm * sa_get_zfs_shares(handle, groupname) 7176185db85Sdougm * 7186185db85Sdougm * Walk the mnttab for all zfs mounts and determine which are 7196185db85Sdougm * shared. Find or create the appropriate group/sub-group to contain 7206185db85Sdougm * the shares. 7216185db85Sdougm * 7226185db85Sdougm * All shares are in a sub-group that will hold the properties. This 7236185db85Sdougm * allows representing the inherited property model. 7246185db85Sdougm */ 7256185db85Sdougm 7266185db85Sdougm int 727549ec3ffSdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 7286185db85Sdougm { 7296185db85Sdougm sa_group_t group; 7306185db85Sdougm sa_group_t zfsgroup; 7316185db85Sdougm int legacy = 0; 7326185db85Sdougm int err; 7331cea05afSdougm zfs_handle_t **zlist; 7346185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 7356185db85Sdougm sa_share_t share; 736990b4856Slling zprop_source_t source; 7376185db85Sdougm char sourcestr[ZFS_MAXPROPLEN]; 7381cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 7391cea05afSdougm size_t count = 0, i; 740549ec3ffSdougm libzfs_handle_t *zfs_libhandle; 7416185db85Sdougm 7426185db85Sdougm /* 743549ec3ffSdougm * If we can't access libzfs, don't bother doing anything. 7446185db85Sdougm */ 745549ec3ffSdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 7461cea05afSdougm if (zfs_libhandle == NULL) 74757b448deSdougm return (SA_SYSTEM_ERR); 7486185db85Sdougm 749da6c28aaSamw zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 750546405c3Sdougm if (zfsgroup == NULL) 751546405c3Sdougm return (legacy); 752546405c3Sdougm 753546405c3Sdougm /* 754546405c3Sdougm * need to walk the mounted ZFS pools and datasets to 755546405c3Sdougm * find shares that are possible. 756546405c3Sdougm */ 757546405c3Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 758546405c3Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 759546405c3Sdougm 760546405c3Sdougm group = zfsgroup; 761546405c3Sdougm for (i = 0; i < count; i++) { 762546405c3Sdougm char *dataset; 763da6c28aaSamw int foundnfs = 0; 764546405c3Sdougm 765990b4856Slling source = ZPROP_SRC_ALL; 766546405c3Sdougm /* If no mountpoint, skip. */ 767546405c3Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 768546405c3Sdougm mountpoint, sizeof (mountpoint), NULL, NULL, 0, 769546405c3Sdougm B_FALSE) != 0) 770546405c3Sdougm continue; 771546405c3Sdougm 7726185db85Sdougm /* 773546405c3Sdougm * zfs_get_name value must not be freed. It is just a 774546405c3Sdougm * pointer to a value in the handle. 7756185db85Sdougm */ 776546405c3Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 777546405c3Sdougm continue; 7781cea05afSdougm 779546405c3Sdougm /* 780546405c3Sdougm * only deal with "mounted" file systems since 781546405c3Sdougm * unmounted file systems can't actually be shared. 782546405c3Sdougm */ 78357b448deSdougm 784546405c3Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 785546405c3Sdougm continue; 78657b448deSdougm 787546405c3Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 788546405c3Sdougm sizeof (shareopts), &source, sourcestr, 789546405c3Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 790546405c3Sdougm strcmp(shareopts, "off") != 0) { 791546405c3Sdougm /* it is shared so add to list */ 792546405c3Sdougm err = SA_OK; 793da6c28aaSamw foundnfs = 1; 794da6c28aaSamw share = sa_find_share(handle, mountpoint); 795546405c3Sdougm if (share != NULL) { 796546405c3Sdougm /* 797546405c3Sdougm * A zfs file system had been shared 798546405c3Sdougm * through traditional methods 799546405c3Sdougm * (share/dfstab or added to a non-zfs 800546405c3Sdougm * group. Now it has been added to a 801546405c3Sdougm * ZFS group via the zfs 802546405c3Sdougm * command. Remove from previous 803546405c3Sdougm * config and setup with current 804546405c3Sdougm * options. 805546405c3Sdougm */ 806546405c3Sdougm err = sa_remove_share(share); 807546405c3Sdougm share = NULL; 808546405c3Sdougm } 809546405c3Sdougm if (err == SA_OK) { 810*5b6e0c46Sdougm err = sa_zfs_process_share(handle, group, 811da6c28aaSamw share, mountpoint, "nfs", source, 812da6c28aaSamw shareopts, sourcestr, dataset); 813da6c28aaSamw } 814da6c28aaSamw } 815da6c28aaSamw if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, shareopts, 816da6c28aaSamw sizeof (shareopts), &source, sourcestr, 817da6c28aaSamw ZFS_MAXPROPLEN, B_FALSE) == 0 && 818da6c28aaSamw strcmp(shareopts, "off") != 0) { 819da6c28aaSamw /* it is shared so add to list */ 820da6c28aaSamw err = SA_OK; 821da6c28aaSamw share = sa_find_share(handle, mountpoint); 822da6c28aaSamw if (share != NULL && !foundnfs) { 823da6c28aaSamw /* 824da6c28aaSamw * A zfs file system had been shared 825da6c28aaSamw * through traditional methods 826da6c28aaSamw * (share/dfstab or added to a non-zfs 827da6c28aaSamw * group. Now it has been added to a 828da6c28aaSamw * ZFS group via the zfs 829da6c28aaSamw * command. Remove from previous 830da6c28aaSamw * config and setup with current 831da6c28aaSamw * options. 832da6c28aaSamw */ 833da6c28aaSamw err = sa_remove_share(share); 834da6c28aaSamw share = NULL; 835da6c28aaSamw } 836da6c28aaSamw if (err == SA_OK) { 837*5b6e0c46Sdougm err = sa_zfs_process_share(handle, group, 838da6c28aaSamw share, mountpoint, "smb", source, 839da6c28aaSamw shareopts, sourcestr, dataset); 8406185db85Sdougm } 8416185db85Sdougm } 8426185db85Sdougm } 8431cea05afSdougm /* 8441cea05afSdougm * Don't need to free the "zlist" variable since it is only a 8451cea05afSdougm * pointer to a cached value that will be freed when 8461cea05afSdougm * sa_fini() is called. 8471cea05afSdougm */ 8486185db85Sdougm return (legacy); 8496185db85Sdougm } 8506185db85Sdougm 8516185db85Sdougm #define COMMAND "/usr/sbin/zfs" 8526185db85Sdougm 8536185db85Sdougm /* 8546185db85Sdougm * sa_zfs_set_sharenfs(group, path, on) 8556185db85Sdougm * 8566185db85Sdougm * Update the "sharenfs" property on the path. If on is true, then set 8576185db85Sdougm * to the properties on the group or "on" if no properties are 8586185db85Sdougm * defined. Set to "off" if on is false. 8596185db85Sdougm */ 8606185db85Sdougm 8616185db85Sdougm int 8626185db85Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 8636185db85Sdougm { 8646185db85Sdougm int ret = SA_NOT_IMPLEMENTED; 8656185db85Sdougm char *command; 8666185db85Sdougm 8676185db85Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 8686185db85Sdougm if (command != NULL) { 86957b448deSdougm char *opts = NULL; 87057b448deSdougm char *dataset = NULL; 87157b448deSdougm FILE *pfile; 87257b448deSdougm sa_handle_impl_t impl_handle; 87357b448deSdougm /* for now, NFS is always available for "zfs" */ 87457b448deSdougm if (on) { 87557b448deSdougm opts = sa_proto_legacy_format("nfs", group, 1); 87657b448deSdougm if (opts != NULL && strlen(opts) == 0) { 87757b448deSdougm free(opts); 87857b448deSdougm opts = strdup("on"); 87957b448deSdougm } 8806185db85Sdougm } 88157b448deSdougm 88257b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 88357b448deSdougm assert(impl_handle != NULL); 88457b448deSdougm if (impl_handle != NULL) 885a1ef5d63Smarks dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 88657b448deSdougm else 8876185db85Sdougm ret = SA_SYSTEM_ERR; 88857b448deSdougm 88957b448deSdougm if (dataset != NULL) { 89057b448deSdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 89157b448deSdougm "%s set sharenfs=\"%s\" %s", COMMAND, 89257b448deSdougm opts != NULL ? opts : "off", dataset); 89357b448deSdougm pfile = popen(command, "r"); 89457b448deSdougm if (pfile != NULL) { 89557b448deSdougm ret = pclose(pfile); 89657b448deSdougm if (ret != 0) 89757b448deSdougm ret = SA_SYSTEM_ERR; 89857b448deSdougm } 8996185db85Sdougm } 90057b448deSdougm if (opts != NULL) 90157b448deSdougm free(opts); 90257b448deSdougm if (dataset != NULL) 90357b448deSdougm free(dataset); 90457b448deSdougm free(command); 9056185db85Sdougm } 9066185db85Sdougm return (ret); 9076185db85Sdougm } 9086185db85Sdougm 909da6c28aaSamw /* 910da6c28aaSamw * add_resources(share, opt) 911da6c28aaSamw * 912da6c28aaSamw * Add resource properties to those in "opt". Resources are prefixed 913da6c28aaSamw * with name=resourcename. 914da6c28aaSamw */ 915da6c28aaSamw static char * 916da6c28aaSamw add_resources(sa_share_t share, char *opt) 917da6c28aaSamw { 918da6c28aaSamw char *newopt = NULL; 919da6c28aaSamw char *propstr; 920da6c28aaSamw sa_resource_t resource; 921da6c28aaSamw 922da6c28aaSamw newopt = strdup(opt); 923da6c28aaSamw if (newopt == NULL) 924da6c28aaSamw return (newopt); 925da6c28aaSamw 926da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 927da6c28aaSamw resource != NULL; 928da6c28aaSamw resource = sa_get_next_resource(resource)) { 929da6c28aaSamw char *name; 930da6c28aaSamw size_t size; 931da6c28aaSamw 932da6c28aaSamw name = sa_get_resource_attr(resource, "name"); 933da6c28aaSamw if (name == NULL) { 934da6c28aaSamw free(newopt); 935da6c28aaSamw return (NULL); 936da6c28aaSamw } 937da6c28aaSamw size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 938da6c28aaSamw newopt = calloc(1, size); 939da6c28aaSamw if (newopt != NULL) 940da6c28aaSamw (void) snprintf(newopt, size, "%s,name=%s", opt, name); 941da6c28aaSamw free(opt); 942da6c28aaSamw opt = newopt; 943da6c28aaSamw propstr = sa_proto_legacy_format("smb", resource, 0); 944da6c28aaSamw if (propstr == NULL) { 945da6c28aaSamw free(opt); 946da6c28aaSamw return (NULL); 947da6c28aaSamw } 948da6c28aaSamw size = strlen(propstr) + strlen(opt) + 2; 949da6c28aaSamw newopt = calloc(1, size); 950da6c28aaSamw if (newopt != NULL) 951da6c28aaSamw (void) snprintf(newopt, size, "%s,%s", opt, propstr); 952da6c28aaSamw free(opt); 953da6c28aaSamw opt = newopt; 954da6c28aaSamw } 955da6c28aaSamw return (opt); 956da6c28aaSamw } 957da6c28aaSamw 958da6c28aaSamw /* 959da6c28aaSamw * sa_zfs_set_sharesmb(group, path, on) 960da6c28aaSamw * 961da6c28aaSamw * Update the "sharesmb" property on the path. If on is true, then set 962da6c28aaSamw * to the properties on the group or "on" if no properties are 963da6c28aaSamw * defined. Set to "off" if on is false. 964da6c28aaSamw */ 965da6c28aaSamw 966da6c28aaSamw int 967da6c28aaSamw sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 968da6c28aaSamw { 969da6c28aaSamw int ret = SA_NOT_IMPLEMENTED; 970da6c28aaSamw char *command; 971da6c28aaSamw sa_share_t share; 972da6c28aaSamw 973da6c28aaSamw /* In case SMB not enabled */ 974da6c28aaSamw if (sa_get_optionset(group, "smb") == NULL) 975da6c28aaSamw return (SA_NOT_SUPPORTED); 976da6c28aaSamw 977da6c28aaSamw command = malloc(ZFS_MAXPROPLEN * 2); 978da6c28aaSamw if (command != NULL) { 979da6c28aaSamw char *opts = NULL; 980da6c28aaSamw char *dataset = NULL; 981da6c28aaSamw FILE *pfile; 982da6c28aaSamw sa_handle_impl_t impl_handle; 983da6c28aaSamw 984da6c28aaSamw if (on) { 985da6c28aaSamw char *newopt; 986da6c28aaSamw 987da6c28aaSamw share = sa_get_share(group, NULL); 988da6c28aaSamw opts = sa_proto_legacy_format("smb", share, 1); 989da6c28aaSamw if (opts != NULL && strlen(opts) == 0) { 990da6c28aaSamw free(opts); 991da6c28aaSamw opts = strdup("on"); 992da6c28aaSamw } 993da6c28aaSamw newopt = add_resources(opts, share); 994da6c28aaSamw free(opts); 995da6c28aaSamw opts = newopt; 996da6c28aaSamw } 997da6c28aaSamw 998da6c28aaSamw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 999da6c28aaSamw assert(impl_handle != NULL); 1000da6c28aaSamw if (impl_handle != NULL) 1001da6c28aaSamw dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1002da6c28aaSamw else 1003da6c28aaSamw ret = SA_SYSTEM_ERR; 1004da6c28aaSamw 1005da6c28aaSamw if (dataset != NULL) { 1006da6c28aaSamw (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1007da6c28aaSamw "echo %s set sharesmb=\"%s\" %s", COMMAND, 1008da6c28aaSamw opts != NULL ? opts : "off", dataset); 1009da6c28aaSamw pfile = popen(command, "r"); 1010da6c28aaSamw if (pfile != NULL) { 1011da6c28aaSamw ret = pclose(pfile); 1012da6c28aaSamw if (ret != 0) 1013da6c28aaSamw ret = SA_SYSTEM_ERR; 1014da6c28aaSamw } 1015da6c28aaSamw } 1016da6c28aaSamw if (opts != NULL) 1017da6c28aaSamw free(opts); 1018da6c28aaSamw if (dataset != NULL) 1019da6c28aaSamw free(dataset); 1020da6c28aaSamw free(command); 1021da6c28aaSamw } 1022da6c28aaSamw return (ret); 1023da6c28aaSamw } 1024da6c28aaSamw 10256185db85Sdougm /* 10266185db85Sdougm * sa_zfs_update(group) 10276185db85Sdougm * 10286185db85Sdougm * call back to ZFS to update the share if necessary. 10296185db85Sdougm * Don't do it if it isn't a real change. 10306185db85Sdougm */ 10316185db85Sdougm int 10326185db85Sdougm sa_zfs_update(sa_group_t group) 10336185db85Sdougm { 10346185db85Sdougm sa_optionset_t protopt; 10356185db85Sdougm sa_group_t parent; 10366185db85Sdougm char *command; 10376185db85Sdougm char *optstring; 10386185db85Sdougm int ret = SA_OK; 10396185db85Sdougm int doupdate = 0; 10406185db85Sdougm FILE *pfile; 10416185db85Sdougm 10426185db85Sdougm if (sa_is_share(group)) 104357b448deSdougm parent = sa_get_parent_group(group); 10446185db85Sdougm else 104557b448deSdougm parent = group; 10466185db85Sdougm 10476185db85Sdougm if (parent != NULL) { 104857b448deSdougm command = malloc(ZFS_MAXPROPLEN * 2); 104957b448deSdougm if (command == NULL) 105057b448deSdougm return (SA_NO_MEMORY); 105157b448deSdougm 105257b448deSdougm *command = '\0'; 105357b448deSdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 105457b448deSdougm protopt = sa_get_next_optionset(protopt)) { 105557b448deSdougm 105657b448deSdougm char *proto = sa_get_optionset_attr(protopt, "type"); 105757b448deSdougm char *path; 105857b448deSdougm char *dataset = NULL; 105957b448deSdougm char *zfsopts = NULL; 106057b448deSdougm 106157b448deSdougm if (sa_is_share(group)) { 106257b448deSdougm path = sa_get_share_attr((sa_share_t)group, 106357b448deSdougm "path"); 106457b448deSdougm if (path != NULL) { 106557b448deSdougm sa_handle_impl_t impl_handle; 106657b448deSdougm 106757b448deSdougm impl_handle = sa_find_group_handle( 106857b448deSdougm group); 106957b448deSdougm if (impl_handle != NULL) 107057b448deSdougm dataset = get_zfs_dataset( 1071a1ef5d63Smarks impl_handle, path, B_FALSE); 107257b448deSdougm else 107357b448deSdougm ret = SA_SYSTEM_ERR; 107457b448deSdougm 107557b448deSdougm sa_free_attr_string(path); 107657b448deSdougm } 10776185db85Sdougm } else { 107857b448deSdougm dataset = sa_get_group_attr(group, "name"); 10796185db85Sdougm } 108057b448deSdougm /* update only when there is an optstring found */ 108157b448deSdougm doupdate = 0; 108257b448deSdougm if (proto != NULL && dataset != NULL) { 108357b448deSdougm optstring = sa_proto_legacy_format(proto, 108457b448deSdougm group, 1); 108557b448deSdougm zfsopts = get_zfs_property(dataset, 108657b448deSdougm ZFS_PROP_SHARENFS); 108757b448deSdougm 108857b448deSdougm if (optstring != NULL && zfsopts != NULL) { 108957b448deSdougm if (strcmp(optstring, zfsopts) != 0) 109057b448deSdougm doupdate++; 109157b448deSdougm } 109257b448deSdougm if (doupdate) { 109357b448deSdougm if (optstring != NULL && 109457b448deSdougm strlen(optstring) > 0) { 109557b448deSdougm (void) snprintf(command, 109657b448deSdougm ZFS_MAXPROPLEN * 2, 10972b53ee1cSdougm "%s set sharenfs=%s %s", 109857b448deSdougm COMMAND, 109957b448deSdougm optstring, dataset); 110057b448deSdougm } else { 110157b448deSdougm (void) snprintf(command, 110257b448deSdougm ZFS_MAXPROPLEN * 2, 110357b448deSdougm "%s set sharenfs=on %s", 110457b448deSdougm COMMAND, 110557b448deSdougm dataset); 110657b448deSdougm } 110757b448deSdougm pfile = popen(command, "r"); 110857b448deSdougm if (pfile != NULL) 110957b448deSdougm ret = pclose(pfile); 111057b448deSdougm switch (ret) { 111157b448deSdougm default: 111257b448deSdougm case 1: 111357b448deSdougm ret = SA_SYSTEM_ERR; 111457b448deSdougm break; 111557b448deSdougm case 2: 111657b448deSdougm ret = SA_SYNTAX_ERR; 111757b448deSdougm break; 111857b448deSdougm case 0: 111957b448deSdougm break; 112057b448deSdougm } 112157b448deSdougm } 112257b448deSdougm if (optstring != NULL) 112357b448deSdougm free(optstring); 112457b448deSdougm if (zfsopts != NULL) 112557b448deSdougm free(zfsopts); 11266185db85Sdougm } 112757b448deSdougm if (proto != NULL) 112857b448deSdougm sa_free_attr_string(proto); 112957b448deSdougm if (dataset != NULL) 113057b448deSdougm free(dataset); 11316185db85Sdougm } 113257b448deSdougm free(command); 11336185db85Sdougm } 11346185db85Sdougm return (ret); 11356185db85Sdougm } 11366185db85Sdougm 11376185db85Sdougm /* 11386185db85Sdougm * sa_group_is_zfs(group) 11396185db85Sdougm * 11406185db85Sdougm * Given the group, determine if the zfs attribute is set. 11416185db85Sdougm */ 11426185db85Sdougm 11436185db85Sdougm int 11446185db85Sdougm sa_group_is_zfs(sa_group_t group) 11456185db85Sdougm { 11466185db85Sdougm char *zfs; 11476185db85Sdougm int ret = 0; 11486185db85Sdougm 11496185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 11506185db85Sdougm if (zfs != NULL) { 115157b448deSdougm ret = 1; 115257b448deSdougm sa_free_attr_string(zfs); 11536185db85Sdougm } 11546185db85Sdougm return (ret); 11556185db85Sdougm } 11566185db85Sdougm 11576185db85Sdougm /* 11586185db85Sdougm * sa_path_is_zfs(path) 11596185db85Sdougm * 11606185db85Sdougm * Check to see if the file system path represents is of type "zfs". 11616185db85Sdougm */ 11626185db85Sdougm 11636185db85Sdougm int 11646185db85Sdougm sa_path_is_zfs(char *path) 11656185db85Sdougm { 11666185db85Sdougm char *fstype; 11676185db85Sdougm int ret = 0; 11686185db85Sdougm 11696185db85Sdougm fstype = sa_fstype(path); 117057b448deSdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) 117157b448deSdougm ret = 1; 11726185db85Sdougm if (fstype != NULL) 117357b448deSdougm sa_free_fstype(fstype); 11746185db85Sdougm return (ret); 11756185db85Sdougm } 1176ecd6cf80Smarks 1177ecd6cf80Smarks int 1178ecd6cf80Smarks sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1179ecd6cf80Smarks { 1180ecd6cf80Smarks char *path; 1181ecd6cf80Smarks 1182ed78bdc4Smarks /* Make sure path is valid */ 1183ed78bdc4Smarks 1184ecd6cf80Smarks path = sa_get_share_attr(share, "path"); 1185ecd6cf80Smarks if (path != NULL) { 1186ecd6cf80Smarks (void) memset(sh, 0, sizeof (sh)); 1187ecd6cf80Smarks (void) sa_fillshare(share, proto, sh); 1188ed78bdc4Smarks sa_free_attr_string(path); 1189ecd6cf80Smarks return (0); 1190ecd6cf80Smarks } else 1191ecd6cf80Smarks return (1); 1192ecd6cf80Smarks } 1193ecd6cf80Smarks 1194ecd6cf80Smarks #define SMAX(i, j) \ 1195ecd6cf80Smarks if ((j) > (i)) { \ 1196ecd6cf80Smarks (i) = (j); \ 1197ecd6cf80Smarks } 1198ecd6cf80Smarks 1199ecd6cf80Smarks int 1200ecd6cf80Smarks sa_share_zfs(sa_share_t share, char *path, share_t *sh, 1201da6c28aaSamw void *exportdata, zfs_share_op_t operation) 1202ecd6cf80Smarks { 1203ecd6cf80Smarks libzfs_handle_t *libhandle; 1204ecd6cf80Smarks sa_group_t group; 1205ecd6cf80Smarks sa_handle_t sahandle; 1206ecd6cf80Smarks char *dataset; 1207ecd6cf80Smarks int err = EINVAL; 1208ecd6cf80Smarks int i, j; 12094d79fe3bSmarks char newpath[MAXPATHLEN]; 1210a1ef5d63Smarks char *pathp; 1211ecd6cf80Smarks 1212ecd6cf80Smarks /* 1213ecd6cf80Smarks * First find the dataset name 1214ecd6cf80Smarks */ 1215ecd6cf80Smarks if ((group = sa_get_parent_group(share)) == NULL) { 1216ecd6cf80Smarks return (SA_SYSTEM_ERR); 1217ecd6cf80Smarks } 1218ecd6cf80Smarks if ((sahandle = sa_find_group_handle(group)) == NULL) { 1219ecd6cf80Smarks return (SA_SYSTEM_ERR); 1220ecd6cf80Smarks } 1221ecd6cf80Smarks 12224d79fe3bSmarks /* 12234d79fe3bSmarks * If get_zfs_dataset fails, see if it is a subdirectory 12244d79fe3bSmarks */ 1225a1ef5d63Smarks 1226a1ef5d63Smarks pathp = path; 1227a1ef5d63Smarks while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 12284d79fe3bSmarks char *p; 12294d79fe3bSmarks 1230a1ef5d63Smarks if (pathp == path) { 1231a1ef5d63Smarks (void) strlcpy(newpath, path, sizeof (newpath)); 1232a1ef5d63Smarks pathp = newpath; 1233a1ef5d63Smarks } 1234a1ef5d63Smarks 1235a1ef5d63Smarks /* 1236a1ef5d63Smarks * chop off part of path, but if we are at root then 1237a1ef5d63Smarks * make sure path is a / 1238a1ef5d63Smarks */ 1239a1ef5d63Smarks if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1240a1ef5d63Smarks if (pathp == p) { 1241a1ef5d63Smarks *(p + 1) = '\0'; /* skip over /, root case */ 1242a1ef5d63Smarks } else { 1243a1ef5d63Smarks *p = '\0'; 1244a1ef5d63Smarks } 1245a1ef5d63Smarks } else { 12464d79fe3bSmarks return (SA_SYSTEM_ERR); 1247a1ef5d63Smarks } 1248ecd6cf80Smarks } 1249ecd6cf80Smarks 1250ecd6cf80Smarks libhandle = libzfs_init(); 1251ecd6cf80Smarks if (libhandle != NULL) { 1252ecd6cf80Smarks 1253ecd6cf80Smarks i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1254ecd6cf80Smarks sh->sh_size = i; 1255ecd6cf80Smarks 1256ecd6cf80Smarks j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1257ecd6cf80Smarks sh->sh_size += j; 1258ecd6cf80Smarks SMAX(i, j); 1259ecd6cf80Smarks 1260ecd6cf80Smarks j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1261ecd6cf80Smarks sh->sh_size += j; 1262ecd6cf80Smarks SMAX(i, j); 1263ecd6cf80Smarks 1264ecd6cf80Smarks j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1265ecd6cf80Smarks sh->sh_size += j; 1266ecd6cf80Smarks SMAX(i, j); 1267ecd6cf80Smarks 1268ecd6cf80Smarks j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1269ecd6cf80Smarks sh->sh_size += j; 1270ecd6cf80Smarks SMAX(i, j); 1271ecd6cf80Smarks err = zfs_deleg_share_nfs(libhandle, dataset, path, 1272da6c28aaSamw exportdata, sh, i, operation); 1273*5b6e0c46Sdougm if (err == SA_OK) 1274*5b6e0c46Sdougm sa_update_sharetab_ts(sahandle); 1275ecd6cf80Smarks libzfs_fini(libhandle); 1276ecd6cf80Smarks } 1277ecd6cf80Smarks free(dataset); 1278ecd6cf80Smarks return (err); 1279ecd6cf80Smarks } 1280*5b6e0c46Sdougm 1281*5b6e0c46Sdougm /* 1282*5b6e0c46Sdougm * sa_get_zfs_handle(handle) 1283*5b6e0c46Sdougm * 1284*5b6e0c46Sdougm * Given an sa_handle_t, return the libzfs_handle_t *. This is only 1285*5b6e0c46Sdougm * used internally by libzfs. Needed in order to avoid including 1286*5b6e0c46Sdougm * libshare_impl.h in libzfs. 1287*5b6e0c46Sdougm */ 1288*5b6e0c46Sdougm 1289*5b6e0c46Sdougm libzfs_handle_t * 1290*5b6e0c46Sdougm sa_get_zfs_handle(sa_handle_t handle) 1291*5b6e0c46Sdougm { 1292*5b6e0c46Sdougm sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 1293*5b6e0c46Sdougm 1294*5b6e0c46Sdougm return (implhandle->zfs_libhandle); 1295*5b6e0c46Sdougm } 1296