16185db85Sdougm /* 26185db85Sdougm * CDDL HEADER START 36185db85Sdougm * 46185db85Sdougm * The contents of this file are subject to the terms of the 56185db85Sdougm * Common Development and Distribution License (the "License"). 66185db85Sdougm * You may not use this file except in compliance with the License. 76185db85Sdougm * 86185db85Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96185db85Sdougm * or http://www.opensolaris.org/os/licensing. 106185db85Sdougm * See the License for the specific language governing permissions 116185db85Sdougm * and limitations under the License. 126185db85Sdougm * 136185db85Sdougm * When distributing Covered Code, include this CDDL HEADER in each 146185db85Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156185db85Sdougm * If applicable, add the following below this CDDL HEADER, with the 166185db85Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 176185db85Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 186185db85Sdougm * 196185db85Sdougm * CDDL HEADER END 206185db85Sdougm */ 216185db85Sdougm 226185db85Sdougm /* 23148c5f43SAlan Wright * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 246185db85Sdougm */ 25*c3f7431dSDan Kruchinin /* 26*c3f7431dSDan Kruchinin * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 27*c3f7431dSDan Kruchinin */ 286185db85Sdougm 29a1ef5d63Smarks #include <stdio.h> 306185db85Sdougm #include <libzfs.h> 316185db85Sdougm #include <string.h> 32a3351425Sdougm #include <strings.h> 33a63214d6SBill Krier #include <errno.h> 346185db85Sdougm #include <libshare.h> 356185db85Sdougm #include "libshare_impl.h" 361cea05afSdougm #include <libintl.h> 37a1ef5d63Smarks #include <sys/mnttab.h> 38a1ef5d63Smarks #include <sys/mntent.h> 396185db85Sdougm 40da6c28aaSamw extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 416185db85Sdougm extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 426185db85Sdougm extern char *sa_fstype(char *); 436185db85Sdougm extern void set_node_attr(void *, char *, char *); 446185db85Sdougm extern int sa_is_share(void *); 455b6e0c46Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 461cea05afSdougm 471cea05afSdougm /* 481cea05afSdougm * File system specific code for ZFS. The original code was stolen 491cea05afSdougm * from the "zfs" command and modified to better suit this library's 501cea05afSdougm * usage. 511cea05afSdougm */ 521cea05afSdougm 531cea05afSdougm typedef struct get_all_cbdata { 541cea05afSdougm zfs_handle_t **cb_handles; 551cea05afSdougm size_t cb_alloc; 561cea05afSdougm size_t cb_used; 57a3351425Sdougm uint_t cb_types; 581cea05afSdougm } get_all_cbdata_t; 591cea05afSdougm 601cea05afSdougm /* 61549ec3ffSdougm * sa_zfs_init(impl_handle) 621cea05afSdougm * 63549ec3ffSdougm * Initialize an access handle into libzfs. The handle needs to stay 64549ec3ffSdougm * around until sa_zfs_fini() in order to maintain the cache of 65549ec3ffSdougm * mounts. 661cea05afSdougm */ 671cea05afSdougm 6857b448deSdougm int 69549ec3ffSdougm sa_zfs_init(sa_handle_impl_t impl_handle) 701cea05afSdougm { 71549ec3ffSdougm impl_handle->zfs_libhandle = libzfs_init(); 7257b448deSdougm if (impl_handle->zfs_libhandle != NULL) { 7357b448deSdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 7457b448deSdougm return (B_TRUE); 7557b448deSdougm } 7657b448deSdougm return (B_FALSE); 771cea05afSdougm } 781cea05afSdougm 791cea05afSdougm /* 80549ec3ffSdougm * sa_zfs_fini(impl_handle) 811cea05afSdougm * 821cea05afSdougm * cleanup data structures and the libzfs handle used for accessing 831cea05afSdougm * zfs file share info. 841cea05afSdougm */ 851cea05afSdougm 861cea05afSdougm void 87549ec3ffSdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 881cea05afSdougm { 89549ec3ffSdougm if (impl_handle->zfs_libhandle != NULL) { 9057b448deSdougm if (impl_handle->zfs_list != NULL) { 91a3351425Sdougm zfs_handle_t **zhp = impl_handle->zfs_list; 92a3351425Sdougm size_t i; 93a3351425Sdougm 9457b448deSdougm /* 95a3351425Sdougm * Contents of zfs_list need to be freed so we 96a3351425Sdougm * don't lose ZFS handles. 9757b448deSdougm */ 98a3351425Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) { 99a3351425Sdougm zfs_close(zhp[i]); 100a3351425Sdougm } 10157b448deSdougm free(impl_handle->zfs_list); 10257b448deSdougm impl_handle->zfs_list = NULL; 10357b448deSdougm impl_handle->zfs_list_count = 0; 10457b448deSdougm } 105a3351425Sdougm 106a3351425Sdougm libzfs_fini(impl_handle->zfs_libhandle); 107a3351425Sdougm impl_handle->zfs_libhandle = NULL; 1081cea05afSdougm } 1091cea05afSdougm } 1101cea05afSdougm 1111cea05afSdougm /* 1121cea05afSdougm * get_one_filesystem(zfs_handle_t, data) 1131cea05afSdougm * 114da6c28aaSamw * an iterator function called while iterating through the ZFS 1151cea05afSdougm * root. It accumulates into an array of file system handles that can 1161cea05afSdougm * be used to derive info about those file systems. 117a3351425Sdougm * 118a3351425Sdougm * Note that as this function is called, we close all zhp handles that 119a3351425Sdougm * are not going to be places into the cp_handles list. We don't want 120a3351425Sdougm * to close the ones we are keeping, but all others would be leaked if 121a3351425Sdougm * not closed here. 1221cea05afSdougm */ 1231cea05afSdougm 1241cea05afSdougm static int 1251cea05afSdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1261cea05afSdougm { 1271cea05afSdougm get_all_cbdata_t *cbp = data; 128a3351425Sdougm zfs_type_t type = zfs_get_type(zhp); 1291cea05afSdougm 1301cea05afSdougm /* 131a3351425Sdougm * Interate over any nested datasets. 1321cea05afSdougm */ 133a3351425Sdougm if (type == ZFS_TYPE_FILESYSTEM && 134a3351425Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 135a3351425Sdougm zfs_close(zhp); 136a3351425Sdougm return (1); 137a3351425Sdougm } 138a3351425Sdougm 139a3351425Sdougm /* 140a3351425Sdougm * Skip any datasets whose type does not match. 141a3351425Sdougm */ 142a3351425Sdougm if ((type & cbp->cb_types) == 0) { 1431cea05afSdougm zfs_close(zhp); 1441cea05afSdougm return (0); 1451cea05afSdougm } 1461cea05afSdougm 1471cea05afSdougm if (cbp->cb_alloc == cbp->cb_used) { 1481cea05afSdougm zfs_handle_t **handles; 1491cea05afSdougm 1501cea05afSdougm if (cbp->cb_alloc == 0) 1511cea05afSdougm cbp->cb_alloc = 64; 1521cea05afSdougm else 1531cea05afSdougm cbp->cb_alloc *= 2; 1541cea05afSdougm 155a3351425Sdougm handles = (zfs_handle_t **)calloc(1, 156a3351425Sdougm cbp->cb_alloc * sizeof (void *)); 157a3351425Sdougm 1581cea05afSdougm if (handles == NULL) { 159a3351425Sdougm zfs_close(zhp); 16057b448deSdougm return (0); 1611cea05afSdougm } 1621cea05afSdougm if (cbp->cb_handles) { 163a3351425Sdougm bcopy(cbp->cb_handles, handles, 1641cea05afSdougm cbp->cb_used * sizeof (void *)); 1651cea05afSdougm free(cbp->cb_handles); 1661cea05afSdougm } 1671cea05afSdougm 1681cea05afSdougm cbp->cb_handles = handles; 1691cea05afSdougm } 1701cea05afSdougm 1711cea05afSdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1721cea05afSdougm 173a3351425Sdougm return (0); 1741cea05afSdougm } 1751cea05afSdougm 1761cea05afSdougm /* 1771cea05afSdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1781cea05afSdougm * 1791cea05afSdougm * iterate through all ZFS file systems starting at the root. Returns 1801cea05afSdougm * a count and an array of handle pointers. Allocating is only done 1811cea05afSdougm * once. The caller does not need to free since it will be done at 1821cea05afSdougm * sa_zfs_fini() time. 1831cea05afSdougm */ 1841cea05afSdougm 1851cea05afSdougm static void 186549ec3ffSdougm get_all_filesystems(sa_handle_impl_t impl_handle, 187549ec3ffSdougm zfs_handle_t ***fslist, size_t *count) 1881cea05afSdougm { 1891cea05afSdougm get_all_cbdata_t cb = { 0 }; 190a3351425Sdougm cb.cb_types = ZFS_TYPE_FILESYSTEM; 1911cea05afSdougm 192549ec3ffSdougm if (impl_handle->zfs_list != NULL) { 19357b448deSdougm *fslist = impl_handle->zfs_list; 19457b448deSdougm *count = impl_handle->zfs_list_count; 19557b448deSdougm return; 1961cea05afSdougm } 1971cea05afSdougm 198549ec3ffSdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 19957b448deSdougm get_one_filesystem, &cb); 2001cea05afSdougm 201549ec3ffSdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 202549ec3ffSdougm impl_handle->zfs_list_count = *count = cb.cb_used; 2031cea05afSdougm } 2041cea05afSdougm 2056185db85Sdougm /* 2061cea05afSdougm * mountpoint_compare(a, b) 2071cea05afSdougm * 2081cea05afSdougm * compares the mountpoint on two zfs file systems handles. 2091cea05afSdougm * returns values following strcmp() model. 2106185db85Sdougm */ 2116185db85Sdougm 2121cea05afSdougm static int 2131cea05afSdougm mountpoint_compare(const void *a, const void *b) 2141cea05afSdougm { 2151cea05afSdougm zfs_handle_t **za = (zfs_handle_t **)a; 2161cea05afSdougm zfs_handle_t **zb = (zfs_handle_t **)b; 2171cea05afSdougm char mounta[MAXPATHLEN]; 2181cea05afSdougm char mountb[MAXPATHLEN]; 2191cea05afSdougm 2201cea05afSdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2211cea05afSdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2221cea05afSdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2231cea05afSdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2241cea05afSdougm 2251cea05afSdougm return (strcmp(mounta, mountb)); 2261cea05afSdougm } 2271cea05afSdougm 228a1ef5d63Smarks /* 229743a77edSAlan Wright * return legacy mountpoint. Caller provides space for mountpoint and 230743a77edSAlan Wright * dataset. 231a1ef5d63Smarks */ 232a1ef5d63Smarks int 233743a77edSAlan Wright get_legacy_mountpoint(char *path, char *dataset, size_t dlen, 234743a77edSAlan Wright char *mountpoint, size_t mlen) 235a1ef5d63Smarks { 236a1ef5d63Smarks FILE *fp; 237a1ef5d63Smarks struct mnttab entry; 238a1ef5d63Smarks 239a1ef5d63Smarks if ((fp = fopen(MNTTAB, "r")) == NULL) { 240a1ef5d63Smarks return (1); 241a1ef5d63Smarks } 242a1ef5d63Smarks 243a1ef5d63Smarks while (getmntent(fp, &entry) == 0) { 244a1ef5d63Smarks 245a1ef5d63Smarks if (entry.mnt_fstype == NULL || 246a1ef5d63Smarks strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 247a1ef5d63Smarks continue; 248a1ef5d63Smarks 249a1ef5d63Smarks if (strcmp(entry.mnt_mountp, path) == 0) { 250743a77edSAlan Wright if (mlen > 0) 251743a77edSAlan Wright (void) strlcpy(mountpoint, entry.mnt_mountp, 252743a77edSAlan Wright mlen); 253743a77edSAlan Wright if (dlen > 0) 254743a77edSAlan Wright (void) strlcpy(dataset, entry.mnt_special, 255743a77edSAlan Wright dlen); 256743a77edSAlan Wright break; 257a1ef5d63Smarks } 258a1ef5d63Smarks } 259a1ef5d63Smarks (void) fclose(fp); 260a1ef5d63Smarks return (1); 261a1ef5d63Smarks } 262a1ef5d63Smarks 2636185db85Sdougm /* 264549ec3ffSdougm * get_zfs_dataset(impl_handle, path) 2656185db85Sdougm * 2666185db85Sdougm * get the name of the ZFS dataset the path is equivalent to. The 2676185db85Sdougm * dataset name is used for get/set of ZFS properties since libzfs 2686185db85Sdougm * requires a dataset to do a zfs_open(). 2696185db85Sdougm */ 2706185db85Sdougm 2716185db85Sdougm static char * 272a1ef5d63Smarks get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 273a1ef5d63Smarks boolean_t search_mnttab) 2746185db85Sdougm { 2751cea05afSdougm size_t i, count = 0; 2766185db85Sdougm char *dataset = NULL; 2771cea05afSdougm zfs_handle_t **zlist; 2781cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 27967331909Sdougm char canmount[ZFS_MAXPROPLEN]; 2806185db85Sdougm 281549ec3ffSdougm get_all_filesystems(impl_handle, &zlist, &count); 2821cea05afSdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2831cea05afSdougm for (i = 0; i < count; i++) { 28457b448deSdougm /* must have a mountpoint */ 28557b448deSdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 28657b448deSdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 28757b448deSdougm /* no mountpoint */ 28857b448deSdougm continue; 28957b448deSdougm } 29057b448deSdougm 29157b448deSdougm /* mountpoint must be a path */ 29257b448deSdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 293a1ef5d63Smarks strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 294a1ef5d63Smarks /* 295743a77edSAlan Wright * Search mmttab for mountpoint and get dataset. 296a1ef5d63Smarks */ 297a1ef5d63Smarks 298a1ef5d63Smarks if (search_mnttab == B_TRUE && 299a1ef5d63Smarks get_legacy_mountpoint(path, mountpoint, 300743a77edSAlan Wright sizeof (mountpoint), NULL, 0) == 0) { 301a1ef5d63Smarks dataset = mountpoint; 302a1ef5d63Smarks break; 303a1ef5d63Smarks } 30457b448deSdougm continue; 305a1ef5d63Smarks } 30657b448deSdougm 30757b448deSdougm /* canmount must be set */ 30857b448deSdougm canmount[0] = '\0'; 309ecd6cf80Smarks if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 31067331909Sdougm sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 31157b448deSdougm strcmp(canmount, "off") == 0) 31257b448deSdougm continue; 3131cea05afSdougm 31457b448deSdougm /* 31557b448deSdougm * have a mountable handle but want to skip those marked none 31657b448deSdougm * and legacy 31757b448deSdougm */ 31857b448deSdougm if (strcmp(mountpoint, path) == 0) { 31957b448deSdougm dataset = (char *)zfs_get_name(zlist[i]); 32057b448deSdougm break; 32157b448deSdougm } 3221cea05afSdougm 3236185db85Sdougm } 3241cea05afSdougm 32557b448deSdougm if (dataset != NULL) 32657b448deSdougm dataset = strdup(dataset); 32757b448deSdougm 3286185db85Sdougm return (dataset); 3296185db85Sdougm } 3306185db85Sdougm 3316185db85Sdougm /* 3326185db85Sdougm * get_zfs_property(dataset, property) 3336185db85Sdougm * 3346185db85Sdougm * Get the file system property specified from the ZFS dataset. 3356185db85Sdougm */ 3366185db85Sdougm 3376185db85Sdougm static char * 3386185db85Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 3396185db85Sdougm { 3406185db85Sdougm zfs_handle_t *handle = NULL; 3416185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3426185db85Sdougm libzfs_handle_t *libhandle; 3436185db85Sdougm 3446185db85Sdougm libhandle = libzfs_init(); 3456185db85Sdougm if (libhandle != NULL) { 34657b448deSdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 34757b448deSdougm if (handle != NULL) { 34857b448deSdougm if (zfs_prop_get(handle, property, shareopts, 34957b448deSdougm sizeof (shareopts), NULL, NULL, 0, 35057b448deSdougm B_FALSE) == 0) { 35157b448deSdougm zfs_close(handle); 35257b448deSdougm libzfs_fini(libhandle); 35357b448deSdougm return (strdup(shareopts)); 35457b448deSdougm } 35557b448deSdougm zfs_close(handle); 3566185db85Sdougm } 35757b448deSdougm libzfs_fini(libhandle); 3586185db85Sdougm } 3596185db85Sdougm return (NULL); 3606185db85Sdougm } 3616185db85Sdougm 3626185db85Sdougm /* 363549ec3ffSdougm * sa_zfs_is_shared(handle, path) 3646185db85Sdougm * 3656185db85Sdougm * Check to see if the ZFS path provided has the sharenfs option set 3666185db85Sdougm * or not. 3676185db85Sdougm */ 3686185db85Sdougm 3696185db85Sdougm int 370549ec3ffSdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 3716185db85Sdougm { 3726185db85Sdougm int ret = 0; 3736185db85Sdougm char *dataset; 3746185db85Sdougm zfs_handle_t *handle = NULL; 3756185db85Sdougm char shareopts[ZFS_MAXPROPLEN]; 3766185db85Sdougm libzfs_handle_t *libhandle; 3776185db85Sdougm 378a1ef5d63Smarks dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 3796185db85Sdougm if (dataset != NULL) { 38057b448deSdougm libhandle = libzfs_init(); 38157b448deSdougm if (libhandle != NULL) { 38257b448deSdougm handle = zfs_open(libhandle, dataset, 38357b448deSdougm ZFS_TYPE_FILESYSTEM); 38457b448deSdougm if (handle != NULL) { 38557b448deSdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 38657b448deSdougm shareopts, sizeof (shareopts), NULL, NULL, 38757b448deSdougm 0, B_FALSE) == 0 && 38857b448deSdougm strcmp(shareopts, "off") != 0) { 38957b448deSdougm ret = 1; /* it is shared */ 39057b448deSdougm } 39157b448deSdougm zfs_close(handle); 39257b448deSdougm } 39357b448deSdougm libzfs_fini(libhandle); 3946185db85Sdougm } 39557b448deSdougm free(dataset); 3966185db85Sdougm } 3976185db85Sdougm return (ret); 3986185db85Sdougm } 3996185db85Sdougm 4006185db85Sdougm /* 401da6c28aaSamw * find_or_create_group(handle, groupname, proto, *err) 4026185db85Sdougm * 4036185db85Sdougm * While walking the ZFS tree, we need to add shares to a defined 4046185db85Sdougm * group. If the group doesn't exist, create it first, making sure it 4056185db85Sdougm * is marked as a ZFS group. 4066185db85Sdougm * 40793a6f655Sdougm * Note that all ZFS shares are in a subgroup of the top level group 40893a6f655Sdougm * called "zfs". 4096185db85Sdougm */ 4106185db85Sdougm 4116185db85Sdougm static sa_group_t 412549ec3ffSdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 4136185db85Sdougm { 4146185db85Sdougm sa_group_t group; 4156185db85Sdougm sa_optionset_t optionset; 4166185db85Sdougm int ret = SA_OK; 4176185db85Sdougm 4186185db85Sdougm /* 4196185db85Sdougm * we check to see if the "zfs" group exists. Since this 4206185db85Sdougm * should be the top level group, we don't want the 4216185db85Sdougm * parent. This is to make sure the zfs group has been created 4226185db85Sdougm * and to created if it hasn't been. 4236185db85Sdougm */ 424549ec3ffSdougm group = sa_get_group(handle, groupname); 4256185db85Sdougm if (group == NULL) { 42657b448deSdougm group = sa_create_group(handle, groupname, &ret); 42793a6f655Sdougm 42857b448deSdougm /* make sure this is flagged as a ZFS group */ 42957b448deSdougm if (group != NULL) 43057b448deSdougm ret = sa_set_group_attr(group, "zfs", "true"); 4316185db85Sdougm } 4326185db85Sdougm if (group != NULL) { 43357b448deSdougm if (proto != NULL) { 43457b448deSdougm optionset = sa_get_optionset(group, proto); 435da6c28aaSamw if (optionset == NULL) 43657b448deSdougm optionset = sa_create_optionset(group, proto); 4376185db85Sdougm } 4386185db85Sdougm } 4396185db85Sdougm if (err != NULL) 44057b448deSdougm *err = ret; 4416185db85Sdougm return (group); 4426185db85Sdougm } 4436185db85Sdougm 44493a6f655Sdougm /* 44593a6f655Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 44693a6f655Sdougm * 44793a6f655Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 44893a6f655Sdougm * function looks to see if the groupname exists and returns it if it 44993a6f655Sdougm * does or else creates a new one with the specified name and returns 45093a6f655Sdougm * that. The "zfs" group will exist before we get here, but we make 45193a6f655Sdougm * sure just in case. 45293a6f655Sdougm * 45393a6f655Sdougm * err must be a valid pointer. 45493a6f655Sdougm */ 45593a6f655Sdougm 45693a6f655Sdougm static sa_group_t 457da6c28aaSamw find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 458da6c28aaSamw char *optstring, int *err) 45993a6f655Sdougm { 46093a6f655Sdougm sa_group_t group = NULL; 46193a6f655Sdougm sa_group_t zfs; 46293a6f655Sdougm char *name; 46393a6f655Sdougm char *options; 46493a6f655Sdougm 46593a6f655Sdougm /* start with the top-level "zfs" group */ 466549ec3ffSdougm zfs = sa_get_group(handle, "zfs"); 46793a6f655Sdougm *err = SA_OK; 46893a6f655Sdougm if (zfs != NULL) { 46957b448deSdougm for (group = sa_get_sub_group(zfs); group != NULL; 47057b448deSdougm group = sa_get_next_group(group)) { 47157b448deSdougm name = sa_get_group_attr(group, "name"); 47257b448deSdougm if (name != NULL && strcmp(name, groupname) == 0) { 47357b448deSdougm /* have the group so break out of here */ 47457b448deSdougm sa_free_attr_string(name); 47557b448deSdougm break; 47657b448deSdougm } 47757b448deSdougm if (name != NULL) 47857b448deSdougm sa_free_attr_string(name); 47993a6f655Sdougm } 48057b448deSdougm 48157b448deSdougm if (group == NULL) { 48257b448deSdougm /* 4833c484793Sdougm * Need to create the sub-group since it doesn't exist 48457b448deSdougm */ 48557b448deSdougm group = _sa_create_zfs_group(zfs, groupname); 4863c484793Sdougm if (group == NULL) { 4873c484793Sdougm *err = SA_NO_MEMORY; 4883c484793Sdougm return (NULL); 48957b448deSdougm } 4903c484793Sdougm set_node_attr(group, "zfs", "true"); 4913c484793Sdougm } 4923c484793Sdougm if (strcmp(optstring, "on") == 0) 4933c484793Sdougm optstring = "rw"; 4943c484793Sdougm options = strdup(optstring); 4953c484793Sdougm if (options != NULL) { 4963c484793Sdougm *err = sa_parse_legacy_options(group, options, 4973c484793Sdougm proto); 4983c484793Sdougm /* If no optionset, add one. */ 4993c484793Sdougm if (sa_get_optionset(group, proto) == NULL) 5003c484793Sdougm (void) sa_create_optionset(group, proto); 501*c3f7431dSDan Kruchinin 502*c3f7431dSDan Kruchinin /* 503*c3f7431dSDan Kruchinin * Do not forget to update an optionset of 504*c3f7431dSDan Kruchinin * the parent group so that it contains 505*c3f7431dSDan Kruchinin * all protocols its subgroups have. 506*c3f7431dSDan Kruchinin */ 507*c3f7431dSDan Kruchinin if (sa_get_optionset(zfs, proto) == NULL) 508*c3f7431dSDan Kruchinin (void) sa_create_optionset(zfs, proto); 509*c3f7431dSDan Kruchinin 5103c484793Sdougm free(options); 5113c484793Sdougm } else { 5123c484793Sdougm *err = SA_NO_MEMORY; 51393a6f655Sdougm } 51493a6f655Sdougm } 51593a6f655Sdougm return (group); 51693a6f655Sdougm } 51793a6f655Sdougm 518da6c28aaSamw /* 519da6c28aaSamw * zfs_construct_resource(share, name, base, dataset) 520da6c28aaSamw * 521da6c28aaSamw * Add a resource to the share using name as a template. If name == 522da6c28aaSamw * NULL, then construct a name based on the dataset value. 523da6c28aaSamw * name. 524da6c28aaSamw */ 525da6c28aaSamw static void 526da6c28aaSamw zfs_construct_resource(sa_share_t share, char *dataset) 527da6c28aaSamw { 528da6c28aaSamw char buff[SA_MAX_RESOURCE_NAME + 1]; 529da6c28aaSamw int ret = SA_OK; 530da6c28aaSamw 531da6c28aaSamw (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset); 532da6c28aaSamw sa_fix_resource_name(buff); 533da6c28aaSamw (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret); 534da6c28aaSamw } 535da6c28aaSamw 53657b448deSdougm /* 53757b448deSdougm * zfs_inherited(handle, source, sourcestr) 53857b448deSdougm * 539da6c28aaSamw * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares 54057b448deSdougm * for readability. 54157b448deSdougm */ 54257b448deSdougm static int 54357b448deSdougm zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 544da6c28aaSamw char *shareopts, char *mountpoint, char *proto, char *dataset) 54557b448deSdougm { 54657b448deSdougm int doshopt = 0; 54757b448deSdougm int err = SA_OK; 54857b448deSdougm sa_group_t group; 549da6c28aaSamw sa_resource_t resource; 550da6c28aaSamw uint64_t features; 55157b448deSdougm 55257b448deSdougm /* 55357b448deSdougm * Need to find the "real" parent sub-group. It may not be 55457b448deSdougm * mounted, but it was identified in the "sourcestr" 55557b448deSdougm * variable. The real parent not mounted can occur if 55657b448deSdougm * "canmount=off and sharenfs=on". 55757b448deSdougm */ 558da6c28aaSamw group = find_or_create_zfs_subgroup(handle, sourcestr, proto, 559da6c28aaSamw shareopts, &doshopt); 56057b448deSdougm if (group != NULL) { 561da6c28aaSamw /* 562da6c28aaSamw * We may need the first share for resource 563da6c28aaSamw * prototype. We only care about it if it has a 564da6c28aaSamw * resource that sets a prefix value. 565da6c28aaSamw */ 566da6c28aaSamw if (share == NULL) 567da6c28aaSamw share = _sa_add_share(group, mountpoint, 568da6c28aaSamw SA_SHARE_TRANSIENT, &err, 569da6c28aaSamw (uint64_t)SA_FEATURE_NONE); 57057b448deSdougm /* 57157b448deSdougm * some options may only be on shares. If the opt 57257b448deSdougm * string contains one of those, we put it just on the 57357b448deSdougm * share. 57457b448deSdougm */ 57557b448deSdougm if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 57657b448deSdougm char *options; 57757b448deSdougm options = strdup(shareopts); 57857b448deSdougm if (options != NULL) { 579da6c28aaSamw set_node_attr(share, "dataset", dataset); 58057b448deSdougm err = sa_parse_legacy_options(share, options, 581da6c28aaSamw proto); 582da6c28aaSamw set_node_attr(share, "dataset", NULL); 58357b448deSdougm free(options); 58457b448deSdougm } 585da6c28aaSamw if (sa_get_optionset(group, proto) == NULL) 586da6c28aaSamw (void) sa_create_optionset(group, proto); 587da6c28aaSamw } 588da6c28aaSamw features = sa_proto_get_featureset(proto); 589da6c28aaSamw if (share != NULL && features & SA_FEATURE_RESOURCE) { 590da6c28aaSamw /* 591da6c28aaSamw * We have a share and the protocol requires 592da6c28aaSamw * that at least one resource exist (probably 593da6c28aaSamw * SMB). We need to make sure that there is at 594da6c28aaSamw * least one. 595da6c28aaSamw */ 596da6c28aaSamw resource = sa_get_share_resource(share, NULL); 597da6c28aaSamw if (resource == NULL) { 598da6c28aaSamw zfs_construct_resource(share, dataset); 599da6c28aaSamw } 60057b448deSdougm } 60157b448deSdougm } else { 60257b448deSdougm err = SA_NO_MEMORY; 60357b448deSdougm } 60457b448deSdougm return (err); 60557b448deSdougm } 60657b448deSdougm 60757b448deSdougm /* 60897df5ac9Sdougm * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset, 60997df5ac9Sdougm * grouperr) 61057b448deSdougm * 61157b448deSdougm * handle case where this is the top of a sub-group in ZFS. Pulled out 61297df5ac9Sdougm * of sa_get_zfs_shares for readability. We need the grouperr from the 61397df5ac9Sdougm * creation of the subgroup to know whether to add the public 61497df5ac9Sdougm * property, etc. to the specific share. 61557b448deSdougm */ 61657b448deSdougm static int 617da6c28aaSamw zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 61897df5ac9Sdougm char *shareopts, char *proto, char *dataset, int grouperr) 61957b448deSdougm { 62057b448deSdougm int err = SA_OK; 621da6c28aaSamw sa_resource_t resource; 622da6c28aaSamw uint64_t features; 62357b448deSdougm 62457b448deSdougm set_node_attr(group, "zfs", "true"); 625da6c28aaSamw if (share == NULL) 626da6c28aaSamw share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 627da6c28aaSamw &err, (uint64_t)SA_FEATURE_NONE); 6283c484793Sdougm 6293c484793Sdougm if (err != SA_OK) 6303c484793Sdougm return (err); 6313c484793Sdougm 6323c484793Sdougm if (strcmp(shareopts, "on") == 0) 6333c484793Sdougm shareopts = ""; 6343c484793Sdougm if (shareopts != NULL) { 6353c484793Sdougm char *options; 6363c484793Sdougm if (grouperr == SA_PROP_SHARE_ONLY) { 637da6c28aaSamw /* 6383c484793Sdougm * Some properties may only be on shares, but 6393c484793Sdougm * due to the ZFS sub-groups being artificial, 6403c484793Sdougm * we sometimes get this and have to deal with 6413c484793Sdougm * it. We do it by attempting to put it on the 6423c484793Sdougm * share. 643da6c28aaSamw */ 6443c484793Sdougm options = strdup(shareopts); 6453c484793Sdougm if (options != NULL) { 6463c484793Sdougm err = sa_parse_legacy_options(share, 6473c484793Sdougm options, proto); 6483c484793Sdougm free(options); 649da6c28aaSamw } 65057b448deSdougm } 6513c484793Sdougm /* Unmark the share's changed state */ 6523c484793Sdougm set_node_attr(share, "changed", NULL); 6533c484793Sdougm } 6543c484793Sdougm features = sa_proto_get_featureset(proto); 6553c484793Sdougm if (share != NULL && features & SA_FEATURE_RESOURCE) { 6563c484793Sdougm /* 6573c484793Sdougm * We have a share and the protocol requires that at 6583c484793Sdougm * least one resource exist (probably SMB). We need to 6593c484793Sdougm * make sure that there is at least one. 6603c484793Sdougm */ 6613c484793Sdougm resource = sa_get_share_resource(share, NULL); 6623c484793Sdougm if (resource == NULL) { 6633c484793Sdougm zfs_construct_resource(share, dataset); 6643c484793Sdougm } 66557b448deSdougm } 66657b448deSdougm return (err); 66757b448deSdougm } 66857b448deSdougm 66957b448deSdougm /* 67057b448deSdougm * zfs_grp_error(err) 67157b448deSdougm * 67257b448deSdougm * Print group create error, but only once. If err is 0 do the 67357b448deSdougm * print else don't. 67457b448deSdougm */ 67557b448deSdougm 67657b448deSdougm static void 67757b448deSdougm zfs_grp_error(int err) 67857b448deSdougm { 67957b448deSdougm if (err == 0) { 68057b448deSdougm /* only print error once */ 68157b448deSdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 68257b448deSdougm "Cannot create ZFS subgroup during initialization:" 68357b448deSdougm " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 68457b448deSdougm } 68557b448deSdougm } 68657b448deSdougm 687da6c28aaSamw /* 688da6c28aaSamw * zfs_process_share(handle, share, mountpoint, proto, source, 689da6c28aaSamw * shareopts, sourcestr) 690da6c28aaSamw * 6915b6e0c46Sdougm * Creates the subgroup, if necessary and adds shares, resources 692da6c28aaSamw * and properties. 693da6c28aaSamw */ 6945b6e0c46Sdougm int 6955b6e0c46Sdougm sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 696da6c28aaSamw char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 697da6c28aaSamw char *sourcestr, char *dataset) 698da6c28aaSamw { 699da6c28aaSamw int err = SA_OK; 700da6c28aaSamw 701da6c28aaSamw if (source & ZPROP_SRC_INHERITED) { 702da6c28aaSamw err = zfs_inherited(handle, share, sourcestr, shareopts, 703da6c28aaSamw mountpoint, proto, dataset); 704da6c28aaSamw } else { 705da6c28aaSamw group = find_or_create_zfs_subgroup(handle, dataset, proto, 706da6c28aaSamw shareopts, &err); 707da6c28aaSamw if (group == NULL) { 70897df5ac9Sdougm static boolean_t reported_error = B_FALSE; 709da6c28aaSamw /* 71097df5ac9Sdougm * There is a problem, but we can't do 711da6c28aaSamw * anything about it at this point so we issue 71297df5ac9Sdougm * a warning and move on. 713da6c28aaSamw */ 71497df5ac9Sdougm zfs_grp_error(reported_error); 71597df5ac9Sdougm reported_error = B_TRUE; 716da6c28aaSamw } 717da6c28aaSamw set_node_attr(group, "zfs", "true"); 718da6c28aaSamw /* 719da6c28aaSamw * Add share with local opts via zfs_notinherited. 720da6c28aaSamw */ 721da6c28aaSamw err = zfs_notinherited(group, share, mountpoint, shareopts, 72297df5ac9Sdougm proto, dataset, err); 723da6c28aaSamw } 724da6c28aaSamw return (err); 725da6c28aaSamw } 726da6c28aaSamw 7276185db85Sdougm /* 728549ec3ffSdougm * sa_get_zfs_shares(handle, groupname) 7296185db85Sdougm * 7306185db85Sdougm * Walk the mnttab for all zfs mounts and determine which are 7316185db85Sdougm * shared. Find or create the appropriate group/sub-group to contain 7326185db85Sdougm * the shares. 7336185db85Sdougm * 7346185db85Sdougm * All shares are in a sub-group that will hold the properties. This 7356185db85Sdougm * allows representing the inherited property model. 7363c484793Sdougm * 7373c484793Sdougm * One area of complication is if "sharenfs" is set at one level of 7383c484793Sdougm * the directory tree and "sharesmb" is set at a different level, the 7393c484793Sdougm * a sub-group must be formed at the lower level for both 7403c484793Sdougm * protocols. That is the nature of the problem in CR 6667349. 7416185db85Sdougm */ 7426185db85Sdougm 7436185db85Sdougm int 744549ec3ffSdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 7456185db85Sdougm { 7466185db85Sdougm sa_group_t zfsgroup; 7473c484793Sdougm boolean_t nfs; 7483c484793Sdougm boolean_t nfs_inherited; 7493c484793Sdougm boolean_t smb; 7503c484793Sdougm boolean_t smb_inherited; 7511cea05afSdougm zfs_handle_t **zlist; 7523c484793Sdougm char nfsshareopts[ZFS_MAXPROPLEN]; 7533c484793Sdougm char smbshareopts[ZFS_MAXPROPLEN]; 7546185db85Sdougm sa_share_t share; 755990b4856Slling zprop_source_t source; 7563c484793Sdougm char nfssourcestr[ZFS_MAXPROPLEN]; 7573c484793Sdougm char smbsourcestr[ZFS_MAXPROPLEN]; 7581cea05afSdougm char mountpoint[ZFS_MAXPROPLEN]; 7591cea05afSdougm size_t count = 0, i; 760549ec3ffSdougm libzfs_handle_t *zfs_libhandle; 7613c484793Sdougm int err = SA_OK; 7626185db85Sdougm 7636185db85Sdougm /* 764549ec3ffSdougm * If we can't access libzfs, don't bother doing anything. 7656185db85Sdougm */ 766549ec3ffSdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 7671cea05afSdougm if (zfs_libhandle == NULL) 76857b448deSdougm return (SA_SYSTEM_ERR); 7696185db85Sdougm 770da6c28aaSamw zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 7713c484793Sdougm /* Not an error, this could be a legacy condition */ 772546405c3Sdougm if (zfsgroup == NULL) 7733c484793Sdougm return (SA_OK); 774546405c3Sdougm 775546405c3Sdougm /* 776546405c3Sdougm * need to walk the mounted ZFS pools and datasets to 777546405c3Sdougm * find shares that are possible. 778546405c3Sdougm */ 779546405c3Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 780546405c3Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 781546405c3Sdougm 782546405c3Sdougm for (i = 0; i < count; i++) { 783546405c3Sdougm char *dataset; 784546405c3Sdougm 785990b4856Slling source = ZPROP_SRC_ALL; 786546405c3Sdougm /* If no mountpoint, skip. */ 787546405c3Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 788546405c3Sdougm mountpoint, sizeof (mountpoint), NULL, NULL, 0, 789546405c3Sdougm B_FALSE) != 0) 790546405c3Sdougm continue; 791546405c3Sdougm 7926185db85Sdougm /* 793546405c3Sdougm * zfs_get_name value must not be freed. It is just a 794546405c3Sdougm * pointer to a value in the handle. 7956185db85Sdougm */ 796546405c3Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 797546405c3Sdougm continue; 7981cea05afSdougm 799546405c3Sdougm /* 800546405c3Sdougm * only deal with "mounted" file systems since 801546405c3Sdougm * unmounted file systems can't actually be shared. 802546405c3Sdougm */ 80357b448deSdougm 804546405c3Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 805546405c3Sdougm continue; 80657b448deSdougm 8073c484793Sdougm nfs = nfs_inherited = B_FALSE; 8083c484793Sdougm 8093c484793Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts, 8103c484793Sdougm sizeof (nfsshareopts), &source, nfssourcestr, 811546405c3Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 8123c484793Sdougm strcmp(nfsshareopts, "off") != 0) { 8133c484793Sdougm if (source & ZPROP_SRC_INHERITED) 8143c484793Sdougm nfs_inherited = B_TRUE; 8153c484793Sdougm else 8163c484793Sdougm nfs = B_TRUE; 817da6c28aaSamw } 8183c484793Sdougm 8193c484793Sdougm smb = smb_inherited = B_FALSE; 8203c484793Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts, 8213c484793Sdougm sizeof (smbshareopts), &source, smbsourcestr, 822da6c28aaSamw ZFS_MAXPROPLEN, B_FALSE) == 0 && 8233c484793Sdougm strcmp(smbshareopts, "off") != 0) { 8243c484793Sdougm if (source & ZPROP_SRC_INHERITED) 8253c484793Sdougm smb_inherited = B_TRUE; 8263c484793Sdougm else 8273c484793Sdougm smb = B_TRUE; 8283c484793Sdougm } 8293c484793Sdougm 8303c484793Sdougm /* 8313c484793Sdougm * If the mountpoint is already shared, it must be a 8323c484793Sdougm * non-ZFS share. We want to remove the share from its 8333c484793Sdougm * parent group and reshare it under ZFS. 8343c484793Sdougm */ 8353c484793Sdougm share = sa_find_share(handle, mountpoint); 8363c484793Sdougm if (share != NULL && 8373c484793Sdougm (nfs || smb || nfs_inherited || smb_inherited)) { 8383c484793Sdougm err = sa_remove_share(share); 8393c484793Sdougm share = NULL; 8403c484793Sdougm } 8413c484793Sdougm 8423c484793Sdougm /* 8433c484793Sdougm * At this point, we have the information needed to 8443c484793Sdougm * determine what to do with the share. 8453c484793Sdougm * 8463c484793Sdougm * If smb or nfs is set, we have a new sub-group. 8473c484793Sdougm * If smb_inherit and/or nfs_inherit is set, then 8483c484793Sdougm * place on an existing sub-group. If both are set, 8493c484793Sdougm * the existing sub-group is the closest up the tree. 8503c484793Sdougm */ 8513c484793Sdougm if (nfs || smb) { 8523c484793Sdougm /* 8533c484793Sdougm * Non-inherited is the straightforward 8543c484793Sdougm * case. sa_zfs_process_share handles it 8553c484793Sdougm * directly. Make sure that if the "other" 8563c484793Sdougm * protocol is inherited, that we treat it as 8573c484793Sdougm * non-inherited as well. 8583c484793Sdougm */ 8593c484793Sdougm if (nfs || nfs_inherited) { 8603c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8613c484793Sdougm share, mountpoint, "nfs", 8623c484793Sdougm 0, nfsshareopts, 8633c484793Sdougm nfssourcestr, dataset); 8643c484793Sdougm share = sa_find_share(handle, mountpoint); 865da6c28aaSamw } 8663c484793Sdougm if (smb || smb_inherited) { 8673c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8683c484793Sdougm share, mountpoint, "smb", 8693c484793Sdougm 0, smbshareopts, 8703c484793Sdougm smbsourcestr, dataset); 8713c484793Sdougm } 8723c484793Sdougm } else if (nfs_inherited || smb_inherited) { 8733c484793Sdougm char *grpdataset; 8743c484793Sdougm /* 8753c484793Sdougm * If we only have inherited groups, it is 8763c484793Sdougm * important to find the closer of the two if 8773c484793Sdougm * the protocols are set at different 8783c484793Sdougm * levels. The closest sub-group is the one we 8793c484793Sdougm * want to work with. 8803c484793Sdougm */ 8813c484793Sdougm if (nfs_inherited && smb_inherited) { 8823c484793Sdougm if (strcmp(nfssourcestr, smbsourcestr) <= 0) 8833c484793Sdougm grpdataset = nfssourcestr; 8843c484793Sdougm else 8853c484793Sdougm grpdataset = smbsourcestr; 8863c484793Sdougm } else if (nfs_inherited) { 8873c484793Sdougm grpdataset = nfssourcestr; 8883c484793Sdougm } else if (smb_inherited) { 8893c484793Sdougm grpdataset = smbsourcestr; 8903c484793Sdougm } 8913c484793Sdougm if (nfs_inherited) { 8923c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8933c484793Sdougm share, mountpoint, "nfs", 8943c484793Sdougm ZPROP_SRC_INHERITED, nfsshareopts, 8953c484793Sdougm grpdataset, dataset); 8963c484793Sdougm share = sa_find_share(handle, mountpoint); 8973c484793Sdougm } 8983c484793Sdougm if (smb_inherited) { 8993c484793Sdougm err = sa_zfs_process_share(handle, zfsgroup, 9003c484793Sdougm share, mountpoint, "smb", 9013c484793Sdougm ZPROP_SRC_INHERITED, smbshareopts, 9023c484793Sdougm grpdataset, dataset); 9036185db85Sdougm } 9046185db85Sdougm } 9056185db85Sdougm } 9061cea05afSdougm /* 9071cea05afSdougm * Don't need to free the "zlist" variable since it is only a 9081cea05afSdougm * pointer to a cached value that will be freed when 9091cea05afSdougm * sa_fini() is called. 9101cea05afSdougm */ 9113c484793Sdougm return (err); 9126185db85Sdougm } 9136185db85Sdougm 9146185db85Sdougm #define COMMAND "/usr/sbin/zfs" 9156185db85Sdougm 9166185db85Sdougm /* 9176185db85Sdougm * sa_zfs_set_sharenfs(group, path, on) 9186185db85Sdougm * 9196185db85Sdougm * Update the "sharenfs" property on the path. If on is true, then set 9206185db85Sdougm * to the properties on the group or "on" if no properties are 9216185db85Sdougm * defined. Set to "off" if on is false. 9226185db85Sdougm */ 9236185db85Sdougm 9246185db85Sdougm int 9256185db85Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 9266185db85Sdougm { 9276185db85Sdougm int ret = SA_NOT_IMPLEMENTED; 9286185db85Sdougm char *command; 9296185db85Sdougm 9306185db85Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 9316185db85Sdougm if (command != NULL) { 93257b448deSdougm char *opts = NULL; 93357b448deSdougm char *dataset = NULL; 93457b448deSdougm FILE *pfile; 93557b448deSdougm sa_handle_impl_t impl_handle; 93657b448deSdougm /* for now, NFS is always available for "zfs" */ 93757b448deSdougm if (on) { 93857b448deSdougm opts = sa_proto_legacy_format("nfs", group, 1); 93957b448deSdougm if (opts != NULL && strlen(opts) == 0) { 94057b448deSdougm free(opts); 94157b448deSdougm opts = strdup("on"); 94257b448deSdougm } 9436185db85Sdougm } 94457b448deSdougm 94557b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 94657b448deSdougm assert(impl_handle != NULL); 94757b448deSdougm if (impl_handle != NULL) 948a1ef5d63Smarks dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 94957b448deSdougm else 9506185db85Sdougm ret = SA_SYSTEM_ERR; 95157b448deSdougm 95257b448deSdougm if (dataset != NULL) { 95357b448deSdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 95457b448deSdougm "%s set sharenfs=\"%s\" %s", COMMAND, 95557b448deSdougm opts != NULL ? opts : "off", dataset); 95657b448deSdougm pfile = popen(command, "r"); 95757b448deSdougm if (pfile != NULL) { 95857b448deSdougm ret = pclose(pfile); 95957b448deSdougm if (ret != 0) 96057b448deSdougm ret = SA_SYSTEM_ERR; 96157b448deSdougm } 9626185db85Sdougm } 96357b448deSdougm if (opts != NULL) 96457b448deSdougm free(opts); 96557b448deSdougm if (dataset != NULL) 96657b448deSdougm free(dataset); 96757b448deSdougm free(command); 9686185db85Sdougm } 9696185db85Sdougm return (ret); 9706185db85Sdougm } 9716185db85Sdougm 972da6c28aaSamw /* 973da6c28aaSamw * add_resources(share, opt) 974da6c28aaSamw * 975da6c28aaSamw * Add resource properties to those in "opt". Resources are prefixed 976da6c28aaSamw * with name=resourcename. 977da6c28aaSamw */ 978da6c28aaSamw static char * 979da6c28aaSamw add_resources(sa_share_t share, char *opt) 980da6c28aaSamw { 981da6c28aaSamw char *newopt = NULL; 982da6c28aaSamw char *propstr; 983da6c28aaSamw sa_resource_t resource; 984da6c28aaSamw 985da6c28aaSamw newopt = strdup(opt); 986da6c28aaSamw if (newopt == NULL) 987da6c28aaSamw return (newopt); 988da6c28aaSamw 989da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 990da6c28aaSamw resource != NULL; 991da6c28aaSamw resource = sa_get_next_resource(resource)) { 992da6c28aaSamw char *name; 993da6c28aaSamw size_t size; 994da6c28aaSamw 995da6c28aaSamw name = sa_get_resource_attr(resource, "name"); 996da6c28aaSamw if (name == NULL) { 997da6c28aaSamw free(newopt); 998da6c28aaSamw return (NULL); 999da6c28aaSamw } 1000da6c28aaSamw size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 1001da6c28aaSamw newopt = calloc(1, size); 1002da6c28aaSamw if (newopt != NULL) 1003da6c28aaSamw (void) snprintf(newopt, size, "%s,name=%s", opt, name); 1004fe1c642dSBill Krier sa_free_attr_string(name); 1005da6c28aaSamw free(opt); 1006da6c28aaSamw opt = newopt; 1007da6c28aaSamw propstr = sa_proto_legacy_format("smb", resource, 0); 1008da6c28aaSamw if (propstr == NULL) { 1009da6c28aaSamw free(opt); 1010da6c28aaSamw return (NULL); 1011da6c28aaSamw } 1012da6c28aaSamw size = strlen(propstr) + strlen(opt) + 2; 1013da6c28aaSamw newopt = calloc(1, size); 1014da6c28aaSamw if (newopt != NULL) 1015da6c28aaSamw (void) snprintf(newopt, size, "%s,%s", opt, propstr); 1016da6c28aaSamw free(opt); 1017da6c28aaSamw opt = newopt; 1018da6c28aaSamw } 1019da6c28aaSamw return (opt); 1020da6c28aaSamw } 1021da6c28aaSamw 1022da6c28aaSamw /* 1023da6c28aaSamw * sa_zfs_set_sharesmb(group, path, on) 1024da6c28aaSamw * 1025da6c28aaSamw * Update the "sharesmb" property on the path. If on is true, then set 1026da6c28aaSamw * to the properties on the group or "on" if no properties are 1027da6c28aaSamw * defined. Set to "off" if on is false. 1028da6c28aaSamw */ 1029da6c28aaSamw 1030da6c28aaSamw int 1031da6c28aaSamw sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 1032da6c28aaSamw { 1033da6c28aaSamw int ret = SA_NOT_IMPLEMENTED; 1034da6c28aaSamw char *command; 1035da6c28aaSamw sa_share_t share; 1036da6c28aaSamw 1037da6c28aaSamw /* In case SMB not enabled */ 1038da6c28aaSamw if (sa_get_optionset(group, "smb") == NULL) 1039da6c28aaSamw return (SA_NOT_SUPPORTED); 1040da6c28aaSamw 1041da6c28aaSamw command = malloc(ZFS_MAXPROPLEN * 2); 1042da6c28aaSamw if (command != NULL) { 1043da6c28aaSamw char *opts = NULL; 1044da6c28aaSamw char *dataset = NULL; 1045da6c28aaSamw FILE *pfile; 1046da6c28aaSamw sa_handle_impl_t impl_handle; 1047da6c28aaSamw 1048da6c28aaSamw if (on) { 1049da6c28aaSamw char *newopt; 1050da6c28aaSamw 1051da6c28aaSamw share = sa_get_share(group, NULL); 1052da6c28aaSamw opts = sa_proto_legacy_format("smb", share, 1); 1053da6c28aaSamw if (opts != NULL && strlen(opts) == 0) { 1054da6c28aaSamw free(opts); 1055da6c28aaSamw opts = strdup("on"); 1056da6c28aaSamw } 1057da6c28aaSamw newopt = add_resources(opts, share); 1058da6c28aaSamw free(opts); 1059da6c28aaSamw opts = newopt; 1060da6c28aaSamw } 1061da6c28aaSamw 1062da6c28aaSamw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1063da6c28aaSamw assert(impl_handle != NULL); 1064da6c28aaSamw if (impl_handle != NULL) 1065da6c28aaSamw dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1066da6c28aaSamw else 1067da6c28aaSamw ret = SA_SYSTEM_ERR; 1068da6c28aaSamw 1069da6c28aaSamw if (dataset != NULL) { 1070da6c28aaSamw (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1071da6c28aaSamw "echo %s set sharesmb=\"%s\" %s", COMMAND, 1072da6c28aaSamw opts != NULL ? opts : "off", dataset); 1073da6c28aaSamw pfile = popen(command, "r"); 1074da6c28aaSamw if (pfile != NULL) { 1075da6c28aaSamw ret = pclose(pfile); 1076da6c28aaSamw if (ret != 0) 1077da6c28aaSamw ret = SA_SYSTEM_ERR; 1078da6c28aaSamw } 1079da6c28aaSamw } 1080da6c28aaSamw if (opts != NULL) 1081da6c28aaSamw free(opts); 1082da6c28aaSamw if (dataset != NULL) 1083da6c28aaSamw free(dataset); 1084da6c28aaSamw free(command); 1085da6c28aaSamw } 1086da6c28aaSamw return (ret); 1087da6c28aaSamw } 1088da6c28aaSamw 10896185db85Sdougm /* 10906185db85Sdougm * sa_zfs_update(group) 10916185db85Sdougm * 10926185db85Sdougm * call back to ZFS to update the share if necessary. 10936185db85Sdougm * Don't do it if it isn't a real change. 10946185db85Sdougm */ 10956185db85Sdougm int 10966185db85Sdougm sa_zfs_update(sa_group_t group) 10976185db85Sdougm { 10986185db85Sdougm sa_optionset_t protopt; 10996185db85Sdougm sa_group_t parent; 11006185db85Sdougm char *command; 11016185db85Sdougm char *optstring; 11026185db85Sdougm int ret = SA_OK; 11036185db85Sdougm int doupdate = 0; 11046185db85Sdougm FILE *pfile; 11056185db85Sdougm 11066185db85Sdougm if (sa_is_share(group)) 110757b448deSdougm parent = sa_get_parent_group(group); 11086185db85Sdougm else 110957b448deSdougm parent = group; 11106185db85Sdougm 11116185db85Sdougm if (parent != NULL) { 111257b448deSdougm command = malloc(ZFS_MAXPROPLEN * 2); 111357b448deSdougm if (command == NULL) 111457b448deSdougm return (SA_NO_MEMORY); 111557b448deSdougm 111657b448deSdougm *command = '\0'; 111757b448deSdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 111857b448deSdougm protopt = sa_get_next_optionset(protopt)) { 111957b448deSdougm 112057b448deSdougm char *proto = sa_get_optionset_attr(protopt, "type"); 112157b448deSdougm char *path; 112257b448deSdougm char *dataset = NULL; 112357b448deSdougm char *zfsopts = NULL; 112457b448deSdougm 112557b448deSdougm if (sa_is_share(group)) { 112657b448deSdougm path = sa_get_share_attr((sa_share_t)group, 112757b448deSdougm "path"); 112857b448deSdougm if (path != NULL) { 112957b448deSdougm sa_handle_impl_t impl_handle; 113057b448deSdougm 113157b448deSdougm impl_handle = sa_find_group_handle( 113257b448deSdougm group); 113357b448deSdougm if (impl_handle != NULL) 113457b448deSdougm dataset = get_zfs_dataset( 1135a1ef5d63Smarks impl_handle, path, B_FALSE); 113657b448deSdougm else 113757b448deSdougm ret = SA_SYSTEM_ERR; 113857b448deSdougm 113957b448deSdougm sa_free_attr_string(path); 114057b448deSdougm } 11416185db85Sdougm } else { 114257b448deSdougm dataset = sa_get_group_attr(group, "name"); 11436185db85Sdougm } 114457b448deSdougm /* update only when there is an optstring found */ 114557b448deSdougm doupdate = 0; 114657b448deSdougm if (proto != NULL && dataset != NULL) { 114757b448deSdougm optstring = sa_proto_legacy_format(proto, 114857b448deSdougm group, 1); 114957b448deSdougm zfsopts = get_zfs_property(dataset, 115057b448deSdougm ZFS_PROP_SHARENFS); 115157b448deSdougm 115257b448deSdougm if (optstring != NULL && zfsopts != NULL) { 115357b448deSdougm if (strcmp(optstring, zfsopts) != 0) 115457b448deSdougm doupdate++; 115557b448deSdougm } 115657b448deSdougm if (doupdate) { 115757b448deSdougm if (optstring != NULL && 115857b448deSdougm strlen(optstring) > 0) { 115957b448deSdougm (void) snprintf(command, 116057b448deSdougm ZFS_MAXPROPLEN * 2, 11611f713840SDoug McCallum "%s set share%s=%s %s", 11621f713840SDoug McCallum COMMAND, proto, 116357b448deSdougm optstring, dataset); 116457b448deSdougm } else { 116557b448deSdougm (void) snprintf(command, 116657b448deSdougm ZFS_MAXPROPLEN * 2, 11671f713840SDoug McCallum "%s set share%s=on %s", 11681f713840SDoug McCallum COMMAND, proto, 116957b448deSdougm dataset); 117057b448deSdougm } 117157b448deSdougm pfile = popen(command, "r"); 117257b448deSdougm if (pfile != NULL) 117357b448deSdougm ret = pclose(pfile); 117457b448deSdougm switch (ret) { 117557b448deSdougm default: 117657b448deSdougm case 1: 117757b448deSdougm ret = SA_SYSTEM_ERR; 117857b448deSdougm break; 117957b448deSdougm case 2: 118057b448deSdougm ret = SA_SYNTAX_ERR; 118157b448deSdougm break; 118257b448deSdougm case 0: 118357b448deSdougm break; 118457b448deSdougm } 118557b448deSdougm } 118657b448deSdougm if (optstring != NULL) 118757b448deSdougm free(optstring); 118857b448deSdougm if (zfsopts != NULL) 118957b448deSdougm free(zfsopts); 11906185db85Sdougm } 119157b448deSdougm if (proto != NULL) 119257b448deSdougm sa_free_attr_string(proto); 119357b448deSdougm if (dataset != NULL) 119457b448deSdougm free(dataset); 11956185db85Sdougm } 119657b448deSdougm free(command); 11976185db85Sdougm } 11986185db85Sdougm return (ret); 11996185db85Sdougm } 12006185db85Sdougm 12016185db85Sdougm /* 12026185db85Sdougm * sa_group_is_zfs(group) 12036185db85Sdougm * 12046185db85Sdougm * Given the group, determine if the zfs attribute is set. 12056185db85Sdougm */ 12066185db85Sdougm 12076185db85Sdougm int 12086185db85Sdougm sa_group_is_zfs(sa_group_t group) 12096185db85Sdougm { 12106185db85Sdougm char *zfs; 12116185db85Sdougm int ret = 0; 12126185db85Sdougm 12136185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 12146185db85Sdougm if (zfs != NULL) { 121557b448deSdougm ret = 1; 121657b448deSdougm sa_free_attr_string(zfs); 12176185db85Sdougm } 12186185db85Sdougm return (ret); 12196185db85Sdougm } 12206185db85Sdougm 12216185db85Sdougm /* 12226185db85Sdougm * sa_path_is_zfs(path) 12236185db85Sdougm * 12246185db85Sdougm * Check to see if the file system path represents is of type "zfs". 12256185db85Sdougm */ 12266185db85Sdougm 12276185db85Sdougm int 12286185db85Sdougm sa_path_is_zfs(char *path) 12296185db85Sdougm { 12306185db85Sdougm char *fstype; 12316185db85Sdougm int ret = 0; 12326185db85Sdougm 12336185db85Sdougm fstype = sa_fstype(path); 123457b448deSdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) 123557b448deSdougm ret = 1; 12366185db85Sdougm if (fstype != NULL) 123757b448deSdougm sa_free_fstype(fstype); 12386185db85Sdougm return (ret); 12396185db85Sdougm } 1240ecd6cf80Smarks 1241ecd6cf80Smarks int 1242ecd6cf80Smarks sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1243ecd6cf80Smarks { 1244ecd6cf80Smarks char *path; 1245ecd6cf80Smarks 1246ed78bdc4Smarks /* Make sure path is valid */ 1247ed78bdc4Smarks 1248ecd6cf80Smarks path = sa_get_share_attr(share, "path"); 1249ecd6cf80Smarks if (path != NULL) { 1250ecd6cf80Smarks (void) memset(sh, 0, sizeof (sh)); 1251ecd6cf80Smarks (void) sa_fillshare(share, proto, sh); 1252ed78bdc4Smarks sa_free_attr_string(path); 1253ecd6cf80Smarks return (0); 1254ecd6cf80Smarks } else 1255ecd6cf80Smarks return (1); 1256ecd6cf80Smarks } 1257ecd6cf80Smarks 1258ecd6cf80Smarks #define SMAX(i, j) \ 1259ecd6cf80Smarks if ((j) > (i)) { \ 1260ecd6cf80Smarks (i) = (j); \ 1261ecd6cf80Smarks } 1262ecd6cf80Smarks 1263ecd6cf80Smarks int 1264743a77edSAlan Wright sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh, 1265da6c28aaSamw void *exportdata, zfs_share_op_t operation) 1266ecd6cf80Smarks { 1267ecd6cf80Smarks libzfs_handle_t *libhandle; 1268ecd6cf80Smarks sa_group_t group; 1269ecd6cf80Smarks sa_handle_t sahandle; 1270ecd6cf80Smarks char *dataset; 1271ecd6cf80Smarks int err = EINVAL; 1272ecd6cf80Smarks int i, j; 12734d79fe3bSmarks char newpath[MAXPATHLEN]; 1274a1ef5d63Smarks char *pathp; 1275ecd6cf80Smarks 1276ecd6cf80Smarks /* 1277ecd6cf80Smarks * First find the dataset name 1278ecd6cf80Smarks */ 1279ecd6cf80Smarks if ((group = sa_get_parent_group(share)) == NULL) { 1280a63214d6SBill Krier return (EINVAL); 1281ecd6cf80Smarks } 1282ecd6cf80Smarks if ((sahandle = sa_find_group_handle(group)) == NULL) { 1283a63214d6SBill Krier return (EINVAL); 1284ecd6cf80Smarks } 1285ecd6cf80Smarks 12864d79fe3bSmarks /* 12874d79fe3bSmarks * If get_zfs_dataset fails, see if it is a subdirectory 12884d79fe3bSmarks */ 1289a1ef5d63Smarks 1290a1ef5d63Smarks pathp = path; 1291a1ef5d63Smarks while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 12924d79fe3bSmarks char *p; 12934d79fe3bSmarks 1294a1ef5d63Smarks if (pathp == path) { 1295a1ef5d63Smarks (void) strlcpy(newpath, path, sizeof (newpath)); 1296a1ef5d63Smarks pathp = newpath; 1297a1ef5d63Smarks } 1298a1ef5d63Smarks 1299d34e4517SDoug McCallum /* 1300d34e4517SDoug McCallum * Make sure only one leading '/' This condition came 1301d34e4517SDoug McCallum * about when using HAStoragePlus which insisted on 1302d34e4517SDoug McCallum * putting an extra leading '/' in the ZFS path 1303d34e4517SDoug McCallum * name. The problem is fixed in other areas, but this 1304d34e4517SDoug McCallum * will catch any other ways that a double slash might 1305d34e4517SDoug McCallum * get introduced. 1306d34e4517SDoug McCallum */ 1307d34e4517SDoug McCallum while (*pathp == '/' && *(pathp + 1) == '/') 1308d34e4517SDoug McCallum pathp++; 1309d34e4517SDoug McCallum 1310a1ef5d63Smarks /* 1311a1ef5d63Smarks * chop off part of path, but if we are at root then 1312a1ef5d63Smarks * make sure path is a / 1313a1ef5d63Smarks */ 1314a1ef5d63Smarks if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1315a1ef5d63Smarks if (pathp == p) { 1316a1ef5d63Smarks *(p + 1) = '\0'; /* skip over /, root case */ 1317a1ef5d63Smarks } else { 1318a1ef5d63Smarks *p = '\0'; 1319a1ef5d63Smarks } 1320a1ef5d63Smarks } else { 1321a63214d6SBill Krier return (EINVAL); 1322a1ef5d63Smarks } 1323ecd6cf80Smarks } 1324ecd6cf80Smarks 1325ecd6cf80Smarks libhandle = libzfs_init(); 1326ecd6cf80Smarks if (libhandle != NULL) { 1327743a77edSAlan Wright char *resource_name; 1328ecd6cf80Smarks 1329ecd6cf80Smarks i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1330ecd6cf80Smarks sh->sh_size = i; 1331ecd6cf80Smarks 1332ecd6cf80Smarks j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1333ecd6cf80Smarks sh->sh_size += j; 1334ecd6cf80Smarks SMAX(i, j); 1335ecd6cf80Smarks 1336ecd6cf80Smarks j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1337ecd6cf80Smarks sh->sh_size += j; 1338ecd6cf80Smarks SMAX(i, j); 1339ecd6cf80Smarks 1340ecd6cf80Smarks j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1341ecd6cf80Smarks sh->sh_size += j; 1342ecd6cf80Smarks SMAX(i, j); 1343ecd6cf80Smarks 1344ecd6cf80Smarks j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1345ecd6cf80Smarks sh->sh_size += j; 1346ecd6cf80Smarks SMAX(i, j); 1347743a77edSAlan Wright 1348743a77edSAlan Wright resource_name = sa_get_resource_attr(resource, "name"); 1349743a77edSAlan Wright 1350ecd6cf80Smarks err = zfs_deleg_share_nfs(libhandle, dataset, path, 1351743a77edSAlan Wright resource_name, exportdata, sh, i, operation); 13525b6e0c46Sdougm if (err == SA_OK) 13535b6e0c46Sdougm sa_update_sharetab_ts(sahandle); 1354a63214d6SBill Krier else 1355a63214d6SBill Krier err = errno; 1356743a77edSAlan Wright if (resource_name) 1357743a77edSAlan Wright sa_free_attr_string(resource_name); 1358743a77edSAlan Wright 1359ecd6cf80Smarks libzfs_fini(libhandle); 1360ecd6cf80Smarks } 1361ecd6cf80Smarks free(dataset); 1362ecd6cf80Smarks return (err); 1363ecd6cf80Smarks } 13645b6e0c46Sdougm 13655b6e0c46Sdougm /* 13665b6e0c46Sdougm * sa_get_zfs_handle(handle) 13675b6e0c46Sdougm * 13685b6e0c46Sdougm * Given an sa_handle_t, return the libzfs_handle_t *. This is only 13695b6e0c46Sdougm * used internally by libzfs. Needed in order to avoid including 13705b6e0c46Sdougm * libshare_impl.h in libzfs. 13715b6e0c46Sdougm */ 13725b6e0c46Sdougm 13735b6e0c46Sdougm libzfs_handle_t * 13745b6e0c46Sdougm sa_get_zfs_handle(sa_handle_t handle) 13755b6e0c46Sdougm { 13765b6e0c46Sdougm sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 13775b6e0c46Sdougm 13785b6e0c46Sdougm return (implhandle->zfs_libhandle); 13795b6e0c46Sdougm } 1380743a77edSAlan Wright 1381743a77edSAlan Wright /* 1382743a77edSAlan Wright * sa_get_zfs_info(libzfs, path, mountpoint, dataset) 1383743a77edSAlan Wright * 1384743a77edSAlan Wright * Find the ZFS dataset and mountpoint for a given path 1385743a77edSAlan Wright */ 1386743a77edSAlan Wright int 1387743a77edSAlan Wright sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp, 1388743a77edSAlan Wright char *datasetp) 1389743a77edSAlan Wright { 1390743a77edSAlan Wright get_all_cbdata_t cb = { 0 }; 1391743a77edSAlan Wright int i; 1392743a77edSAlan Wright char mountpoint[ZFS_MAXPROPLEN]; 1393743a77edSAlan Wright char dataset[ZFS_MAXPROPLEN]; 1394743a77edSAlan Wright char canmount[ZFS_MAXPROPLEN]; 1395743a77edSAlan Wright char *dp; 1396743a77edSAlan Wright int count; 1397743a77edSAlan Wright int ret = 0; 1398743a77edSAlan Wright 1399743a77edSAlan Wright cb.cb_types = ZFS_TYPE_FILESYSTEM; 1400743a77edSAlan Wright 1401743a77edSAlan Wright if (libzfs == NULL) 1402743a77edSAlan Wright return (0); 1403743a77edSAlan Wright 1404743a77edSAlan Wright (void) zfs_iter_root(libzfs, get_one_filesystem, &cb); 1405743a77edSAlan Wright count = cb.cb_used; 1406743a77edSAlan Wright 1407743a77edSAlan Wright qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare); 1408743a77edSAlan Wright for (i = 0; i < count; i++) { 1409743a77edSAlan Wright /* must have a mountpoint */ 1410743a77edSAlan Wright if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT, 1411743a77edSAlan Wright mountpoint, sizeof (mountpoint), 1412743a77edSAlan Wright NULL, NULL, 0, B_FALSE) != 0) { 1413743a77edSAlan Wright /* no mountpoint */ 1414743a77edSAlan Wright continue; 1415743a77edSAlan Wright } 1416743a77edSAlan Wright 1417743a77edSAlan Wright /* mountpoint must be a path */ 1418743a77edSAlan Wright if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 1419743a77edSAlan Wright strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 1420743a77edSAlan Wright /* 1421743a77edSAlan Wright * Search mmttab for mountpoint 1422743a77edSAlan Wright */ 1423743a77edSAlan Wright 1424743a77edSAlan Wright if (get_legacy_mountpoint(path, dataset, 1425743a77edSAlan Wright ZFS_MAXPROPLEN, mountpoint, 1426743a77edSAlan Wright ZFS_MAXPROPLEN) == 0) { 1427743a77edSAlan Wright ret = 1; 1428743a77edSAlan Wright break; 1429743a77edSAlan Wright } 1430743a77edSAlan Wright continue; 1431743a77edSAlan Wright } 1432743a77edSAlan Wright 1433743a77edSAlan Wright /* canmount must be set */ 1434743a77edSAlan Wright canmount[0] = '\0'; 1435743a77edSAlan Wright if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount, 1436743a77edSAlan Wright sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 1437743a77edSAlan Wright strcmp(canmount, "off") == 0) 1438743a77edSAlan Wright continue; 1439743a77edSAlan Wright 1440743a77edSAlan Wright /* 1441743a77edSAlan Wright * have a mountable handle but want to skip those marked none 1442743a77edSAlan Wright * and legacy 1443743a77edSAlan Wright */ 1444743a77edSAlan Wright if (strcmp(mountpoint, path) == 0) { 1445743a77edSAlan Wright dp = (char *)zfs_get_name(cb.cb_handles[i]); 1446743a77edSAlan Wright if (dp != NULL) { 1447743a77edSAlan Wright if (datasetp != NULL) 1448743a77edSAlan Wright (void) strcpy(datasetp, dp); 1449743a77edSAlan Wright if (mountpointp != NULL) 1450743a77edSAlan Wright (void) strcpy(mountpointp, mountpoint); 1451743a77edSAlan Wright ret = 1; 1452743a77edSAlan Wright } 1453743a77edSAlan Wright break; 1454743a77edSAlan Wright } 1455743a77edSAlan Wright 1456743a77edSAlan Wright } 1457743a77edSAlan Wright 1458743a77edSAlan Wright return (ret); 1459743a77edSAlan Wright } 1460148c5f43SAlan Wright 1461148c5f43SAlan Wright /* 1462148c5f43SAlan Wright * This method builds values for "sharesmb" property from the 1463148c5f43SAlan Wright * nvlist argument. The values are returned in sharesmb_val variable. 1464148c5f43SAlan Wright */ 1465148c5f43SAlan Wright static int 1466148c5f43SAlan Wright sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val) 1467148c5f43SAlan Wright { 1468148c5f43SAlan Wright char cur_val[MAXPATHLEN]; 1469148c5f43SAlan Wright char *name, *val; 1470148c5f43SAlan Wright nvpair_t *cur; 1471148c5f43SAlan Wright int err = 0; 1472148c5f43SAlan Wright 1473148c5f43SAlan Wright cur = nvlist_next_nvpair(nvl, NULL); 1474148c5f43SAlan Wright while (cur != NULL) { 1475148c5f43SAlan Wright name = nvpair_name(cur); 1476148c5f43SAlan Wright err = nvpair_value_string(cur, &val); 1477148c5f43SAlan Wright if ((err != 0) || (name == NULL) || (val == NULL)) 1478148c5f43SAlan Wright return (-1); 1479148c5f43SAlan Wright 1480148c5f43SAlan Wright (void) snprintf(cur_val, MAXPATHLEN, "%s=%s,", name, val); 1481148c5f43SAlan Wright (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1482148c5f43SAlan Wright 1483148c5f43SAlan Wright cur = nvlist_next_nvpair(nvl, cur); 1484148c5f43SAlan Wright } 1485148c5f43SAlan Wright 1486148c5f43SAlan Wright return (0); 1487148c5f43SAlan Wright } 1488148c5f43SAlan Wright 1489148c5f43SAlan Wright /* 1490148c5f43SAlan Wright * This method builds values for "sharesmb" property from values 1491148c5f43SAlan Wright * already existing on the share. The properties set via sa_zfs_sprint_new_prop 1492148c5f43SAlan Wright * method are passed in sharesmb_val. If a existing property is already 1493148c5f43SAlan Wright * set via sa_zfs_sprint_new_prop method, then they are not appended 1494148c5f43SAlan Wright * to the sharesmb_val string. The returned sharesmb_val string is a combination 1495148c5f43SAlan Wright * of new and existing values for 'sharesmb' property. 1496148c5f43SAlan Wright */ 1497148c5f43SAlan Wright static int 1498148c5f43SAlan Wright sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val) 1499148c5f43SAlan Wright { 1500148c5f43SAlan Wright char shareopts[ZFS_MAXPROPLEN], cur_val[MAXPATHLEN]; 1501148c5f43SAlan Wright char *token, *last, *value; 1502148c5f43SAlan Wright 1503148c5f43SAlan Wright if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts, 1504148c5f43SAlan Wright sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0) 1505148c5f43SAlan Wright return (-1); 1506148c5f43SAlan Wright 1507148c5f43SAlan Wright if (strstr(shareopts, "=") == NULL) 1508148c5f43SAlan Wright return (0); 1509148c5f43SAlan Wright 1510148c5f43SAlan Wright for (token = strtok_r(shareopts, ",", &last); token != NULL; 1511148c5f43SAlan Wright token = strtok_r(NULL, ",", &last)) { 1512148c5f43SAlan Wright value = strchr(token, '='); 1513148c5f43SAlan Wright if (value == NULL) 1514148c5f43SAlan Wright return (-1); 1515148c5f43SAlan Wright *value++ = '\0'; 1516148c5f43SAlan Wright 1517148c5f43SAlan Wright (void) snprintf(cur_val, MAXPATHLEN, "%s=", token); 1518148c5f43SAlan Wright if (strstr(sharesmb_val, cur_val) == NULL) { 1519148c5f43SAlan Wright (void) strlcat(cur_val, value, MAXPATHLEN); 1520148c5f43SAlan Wright (void) strlcat(cur_val, ",", MAXPATHLEN); 1521148c5f43SAlan Wright (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1522148c5f43SAlan Wright } 1523148c5f43SAlan Wright } 1524148c5f43SAlan Wright 1525148c5f43SAlan Wright return (0); 1526148c5f43SAlan Wright } 1527148c5f43SAlan Wright 1528148c5f43SAlan Wright /* 1529148c5f43SAlan Wright * Sets the share properties on a ZFS share. For now, this method sets only 1530148c5f43SAlan Wright * the "sharesmb" property. 1531148c5f43SAlan Wright * 1532148c5f43SAlan Wright * This method includes building a comma seperated name-value string to be 1533148c5f43SAlan Wright * set on the "sharesmb" property of a ZFS share. This name-value string is 1534148c5f43SAlan Wright * build in 2 steps: 1535148c5f43SAlan Wright * - New property values given as name-value pair are set first. 1536148c5f43SAlan Wright * - Existing optionset properties, which are not part of the new properties 1537148c5f43SAlan Wright * passed in step 1, are appended to the newly set properties. 1538148c5f43SAlan Wright */ 1539148c5f43SAlan Wright int 1540148c5f43SAlan Wright sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl) 1541148c5f43SAlan Wright { 1542148c5f43SAlan Wright zfs_handle_t *z_fs; 1543148c5f43SAlan Wright libzfs_handle_t *z_lib; 1544148c5f43SAlan Wright char sharesmb_val[MAXPATHLEN]; 1545148c5f43SAlan Wright char *dataset, *lastcomma; 1546148c5f43SAlan Wright 1547148c5f43SAlan Wright if (nvlist_empty(nvl)) 1548148c5f43SAlan Wright return (0); 1549148c5f43SAlan Wright 1550148c5f43SAlan Wright if ((handle == NULL) || (path == NULL)) 1551148c5f43SAlan Wright return (-1); 1552148c5f43SAlan Wright 1553148c5f43SAlan Wright if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL) 1554148c5f43SAlan Wright return (-1); 1555148c5f43SAlan Wright 1556148c5f43SAlan Wright if ((z_lib = libzfs_init()) == NULL) { 1557148c5f43SAlan Wright free(dataset); 1558148c5f43SAlan Wright return (-1); 1559148c5f43SAlan Wright } 1560148c5f43SAlan Wright 1561148c5f43SAlan Wright z_fs = zfs_open(z_lib, dataset, ZFS_TYPE_DATASET); 1562148c5f43SAlan Wright if (z_fs == NULL) { 1563148c5f43SAlan Wright free(dataset); 1564148c5f43SAlan Wright libzfs_fini(z_lib); 1565148c5f43SAlan Wright return (-1); 1566148c5f43SAlan Wright } 1567148c5f43SAlan Wright 1568148c5f43SAlan Wright bzero(sharesmb_val, MAXPATHLEN); 1569148c5f43SAlan Wright if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) { 1570148c5f43SAlan Wright free(dataset); 1571148c5f43SAlan Wright zfs_close(z_fs); 1572148c5f43SAlan Wright libzfs_fini(z_lib); 1573148c5f43SAlan Wright return (-1); 1574148c5f43SAlan Wright } 1575148c5f43SAlan Wright 1576148c5f43SAlan Wright if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) { 1577148c5f43SAlan Wright free(dataset); 1578148c5f43SAlan Wright zfs_close(z_fs); 1579148c5f43SAlan Wright libzfs_fini(z_lib); 1580148c5f43SAlan Wright return (-1); 1581148c5f43SAlan Wright } 1582148c5f43SAlan Wright 1583148c5f43SAlan Wright lastcomma = strrchr(sharesmb_val, ','); 1584148c5f43SAlan Wright if ((lastcomma != NULL) && (lastcomma[1] == '\0')) 1585148c5f43SAlan Wright *lastcomma = '\0'; 1586148c5f43SAlan Wright 1587148c5f43SAlan Wright (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB), 1588148c5f43SAlan Wright sharesmb_val); 1589148c5f43SAlan Wright free(dataset); 1590148c5f43SAlan Wright zfs_close(z_fs); 1591148c5f43SAlan Wright libzfs_fini(z_lib); 1592148c5f43SAlan Wright 1593148c5f43SAlan Wright return (0); 1594148c5f43SAlan Wright } 1595