13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 235951Sdougm * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 294592Smarks #include <stdio.h> 303034Sdougm #include <libzfs.h> 313034Sdougm #include <string.h> 324345Sdougm #include <strings.h> 333034Sdougm #include <libshare.h> 343034Sdougm #include "libshare_impl.h" 353218Sdougm #include <libintl.h> 364592Smarks #include <sys/mnttab.h> 374592Smarks #include <sys/mntent.h> 383034Sdougm 395331Samw extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 403034Sdougm extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 413034Sdougm extern char *sa_fstype(char *); 423034Sdougm extern void set_node_attr(void *, char *, char *); 433034Sdougm extern int sa_is_share(void *); 445951Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 453218Sdougm 463034Sdougm /* 473218Sdougm * File system specific code for ZFS. The original code was stolen 483218Sdougm * from the "zfs" command and modified to better suit this library's 493218Sdougm * usage. 503218Sdougm */ 513218Sdougm 523218Sdougm typedef struct get_all_cbdata { 533218Sdougm zfs_handle_t **cb_handles; 543218Sdougm size_t cb_alloc; 553218Sdougm size_t cb_used; 564345Sdougm uint_t cb_types; 573218Sdougm } get_all_cbdata_t; 583218Sdougm 593218Sdougm /* 603910Sdougm * sa_zfs_init(impl_handle) 613218Sdougm * 623910Sdougm * Initialize an access handle into libzfs. The handle needs to stay 633910Sdougm * around until sa_zfs_fini() in order to maintain the cache of 643910Sdougm * mounts. 653218Sdougm */ 663218Sdougm 674327Sdougm int 683910Sdougm sa_zfs_init(sa_handle_impl_t impl_handle) 693218Sdougm { 703910Sdougm impl_handle->zfs_libhandle = libzfs_init(); 714327Sdougm if (impl_handle->zfs_libhandle != NULL) { 724327Sdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 734327Sdougm return (B_TRUE); 744327Sdougm } 754327Sdougm return (B_FALSE); 763218Sdougm } 773218Sdougm 783218Sdougm /* 793910Sdougm * sa_zfs_fini(impl_handle) 803218Sdougm * 813218Sdougm * cleanup data structures and the libzfs handle used for accessing 823218Sdougm * zfs file share info. 833218Sdougm */ 843218Sdougm 853218Sdougm void 863910Sdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 873218Sdougm { 883910Sdougm if (impl_handle->zfs_libhandle != NULL) { 894327Sdougm if (impl_handle->zfs_list != NULL) { 904345Sdougm zfs_handle_t **zhp = impl_handle->zfs_list; 914345Sdougm size_t i; 924345Sdougm 934327Sdougm /* 944345Sdougm * Contents of zfs_list need to be freed so we 954345Sdougm * don't lose ZFS handles. 964327Sdougm */ 974345Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) { 984345Sdougm zfs_close(zhp[i]); 994345Sdougm } 1004327Sdougm free(impl_handle->zfs_list); 1014327Sdougm impl_handle->zfs_list = NULL; 1024327Sdougm impl_handle->zfs_list_count = 0; 1034327Sdougm } 1044345Sdougm 1054345Sdougm libzfs_fini(impl_handle->zfs_libhandle); 1064345Sdougm impl_handle->zfs_libhandle = NULL; 1073218Sdougm } 1083218Sdougm } 1093218Sdougm 1103218Sdougm /* 1113218Sdougm * get_one_filesystem(zfs_handle_t, data) 1123218Sdougm * 1135331Samw * an iterator function called while iterating through the ZFS 1143218Sdougm * root. It accumulates into an array of file system handles that can 1153218Sdougm * be used to derive info about those file systems. 1164345Sdougm * 1174345Sdougm * Note that as this function is called, we close all zhp handles that 1184345Sdougm * are not going to be places into the cp_handles list. We don't want 1194345Sdougm * to close the ones we are keeping, but all others would be leaked if 1204345Sdougm * not closed here. 1213034Sdougm */ 1223034Sdougm 1233218Sdougm static int 1243218Sdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1253218Sdougm { 1263218Sdougm get_all_cbdata_t *cbp = data; 1274345Sdougm zfs_type_t type = zfs_get_type(zhp); 1283218Sdougm 1293218Sdougm /* 1304345Sdougm * Interate over any nested datasets. 1313218Sdougm */ 1324345Sdougm if (type == ZFS_TYPE_FILESYSTEM && 1334345Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 1344345Sdougm zfs_close(zhp); 1354345Sdougm return (1); 1364345Sdougm } 1374345Sdougm 1384345Sdougm /* 1394345Sdougm * Skip any datasets whose type does not match. 1404345Sdougm */ 1414345Sdougm if ((type & cbp->cb_types) == 0) { 1423218Sdougm zfs_close(zhp); 1433218Sdougm return (0); 1443218Sdougm } 1453218Sdougm 1463218Sdougm if (cbp->cb_alloc == cbp->cb_used) { 1473218Sdougm zfs_handle_t **handles; 1483218Sdougm 1493218Sdougm if (cbp->cb_alloc == 0) 1503218Sdougm cbp->cb_alloc = 64; 1513218Sdougm else 1523218Sdougm cbp->cb_alloc *= 2; 1533218Sdougm 1544345Sdougm handles = (zfs_handle_t **)calloc(1, 1554345Sdougm cbp->cb_alloc * sizeof (void *)); 1564345Sdougm 1573218Sdougm if (handles == NULL) { 1584345Sdougm zfs_close(zhp); 1594327Sdougm return (0); 1603218Sdougm } 1613218Sdougm if (cbp->cb_handles) { 1624345Sdougm bcopy(cbp->cb_handles, handles, 1633218Sdougm cbp->cb_used * sizeof (void *)); 1643218Sdougm free(cbp->cb_handles); 1653218Sdougm } 1663218Sdougm 1673218Sdougm cbp->cb_handles = handles; 1683218Sdougm } 1693218Sdougm 1703218Sdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1713218Sdougm 1724345Sdougm return (0); 1733218Sdougm } 1743218Sdougm 1753218Sdougm /* 1763218Sdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1773218Sdougm * 1783218Sdougm * iterate through all ZFS file systems starting at the root. Returns 1793218Sdougm * a count and an array of handle pointers. Allocating is only done 1803218Sdougm * once. The caller does not need to free since it will be done at 1813218Sdougm * sa_zfs_fini() time. 1823218Sdougm */ 1833218Sdougm 1843218Sdougm static void 1853910Sdougm get_all_filesystems(sa_handle_impl_t impl_handle, 1863910Sdougm zfs_handle_t ***fslist, size_t *count) 1873218Sdougm { 1883218Sdougm get_all_cbdata_t cb = { 0 }; 1894345Sdougm cb.cb_types = ZFS_TYPE_FILESYSTEM; 1903218Sdougm 1913910Sdougm if (impl_handle->zfs_list != NULL) { 1924327Sdougm *fslist = impl_handle->zfs_list; 1934327Sdougm *count = impl_handle->zfs_list_count; 1944327Sdougm return; 1953218Sdougm } 1963218Sdougm 1973910Sdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 1984327Sdougm get_one_filesystem, &cb); 1993218Sdougm 2003910Sdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 2013910Sdougm impl_handle->zfs_list_count = *count = cb.cb_used; 2023218Sdougm } 2033218Sdougm 2043218Sdougm /* 2053218Sdougm * mountpoint_compare(a, b) 2063218Sdougm * 2073218Sdougm * compares the mountpoint on two zfs file systems handles. 2083218Sdougm * returns values following strcmp() model. 2093218Sdougm */ 2103218Sdougm 2113218Sdougm static int 2123218Sdougm mountpoint_compare(const void *a, const void *b) 2133218Sdougm { 2143218Sdougm zfs_handle_t **za = (zfs_handle_t **)a; 2153218Sdougm zfs_handle_t **zb = (zfs_handle_t **)b; 2163218Sdougm char mounta[MAXPATHLEN]; 2173218Sdougm char mountb[MAXPATHLEN]; 2183218Sdougm 2193218Sdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2203218Sdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2213218Sdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2223218Sdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2233218Sdougm 2243218Sdougm return (strcmp(mounta, mountb)); 2253218Sdougm } 2263218Sdougm 2273034Sdougm /* 2284592Smarks * return legacy mountpoint. Caller provides space for mountpoint. 2294592Smarks */ 2304592Smarks int 2314592Smarks get_legacy_mountpoint(char *path, char *mountpoint, size_t len) 2324592Smarks { 2334592Smarks FILE *fp; 2344592Smarks struct mnttab entry; 2354592Smarks 2364592Smarks if ((fp = fopen(MNTTAB, "r")) == NULL) { 2374592Smarks return (1); 2384592Smarks } 2394592Smarks 2404592Smarks while (getmntent(fp, &entry) == 0) { 2414592Smarks 2424592Smarks if (entry.mnt_fstype == NULL || 2434592Smarks strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 2444592Smarks continue; 2454592Smarks 2464592Smarks if (strcmp(entry.mnt_mountp, path) == 0) { 2474592Smarks (void) strlcpy(mountpoint, entry.mnt_special, len); 2484592Smarks (void) fclose(fp); 2494592Smarks return (0); 2504592Smarks } 2514592Smarks } 2524592Smarks (void) fclose(fp); 2534592Smarks return (1); 2544592Smarks } 2554592Smarks 2564592Smarks /* 2573910Sdougm * get_zfs_dataset(impl_handle, path) 2583034Sdougm * 2593034Sdougm * get the name of the ZFS dataset the path is equivalent to. The 2603034Sdougm * dataset name is used for get/set of ZFS properties since libzfs 2613034Sdougm * requires a dataset to do a zfs_open(). 2623034Sdougm */ 2633034Sdougm 2643034Sdougm static char * 2654592Smarks get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 2664592Smarks boolean_t search_mnttab) 2673034Sdougm { 2683218Sdougm size_t i, count = 0; 2693034Sdougm char *dataset = NULL; 2703218Sdougm zfs_handle_t **zlist; 2713218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 2724180Sdougm char canmount[ZFS_MAXPROPLEN]; 2733218Sdougm 2743910Sdougm get_all_filesystems(impl_handle, &zlist, &count); 2753218Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2763218Sdougm for (i = 0; i < count; i++) { 2774327Sdougm /* must have a mountpoint */ 2784327Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 2794327Sdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 2804327Sdougm /* no mountpoint */ 2814327Sdougm continue; 2824327Sdougm } 2833034Sdougm 2844327Sdougm /* mountpoint must be a path */ 2854327Sdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 2864592Smarks strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 2874592Smarks /* 2884592Smarks * Search mmttab for mountpoint 2894592Smarks */ 2904592Smarks 2914592Smarks if (search_mnttab == B_TRUE && 2924592Smarks get_legacy_mountpoint(path, mountpoint, 2934592Smarks sizeof (mountpoint)) == 0) { 2944592Smarks dataset = mountpoint; 2954592Smarks break; 2964592Smarks } 2974327Sdougm continue; 2984592Smarks } 2993218Sdougm 3004327Sdougm /* canmount must be set */ 3014327Sdougm canmount[0] = '\0'; 3024543Smarks if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 3034180Sdougm sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 3044327Sdougm strcmp(canmount, "off") == 0) 3054327Sdougm continue; 3063218Sdougm 3074327Sdougm /* 3084327Sdougm * have a mountable handle but want to skip those marked none 3094327Sdougm * and legacy 3104327Sdougm */ 3114327Sdougm if (strcmp(mountpoint, path) == 0) { 3124327Sdougm dataset = (char *)zfs_get_name(zlist[i]); 3134327Sdougm break; 3144327Sdougm } 3153218Sdougm 3163034Sdougm } 3173218Sdougm 3184327Sdougm if (dataset != NULL) 3194327Sdougm dataset = strdup(dataset); 3204327Sdougm 3213034Sdougm return (dataset); 3223034Sdougm } 3233034Sdougm 3243034Sdougm /* 3253034Sdougm * get_zfs_property(dataset, property) 3263034Sdougm * 3273034Sdougm * Get the file system property specified from the ZFS dataset. 3283034Sdougm */ 3293034Sdougm 3303034Sdougm static char * 3313034Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 3323034Sdougm { 3333034Sdougm zfs_handle_t *handle = NULL; 3343034Sdougm char shareopts[ZFS_MAXPROPLEN]; 3353034Sdougm libzfs_handle_t *libhandle; 3363034Sdougm 3373034Sdougm libhandle = libzfs_init(); 3383034Sdougm if (libhandle != NULL) { 3394327Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 3404327Sdougm if (handle != NULL) { 3414327Sdougm if (zfs_prop_get(handle, property, shareopts, 3424327Sdougm sizeof (shareopts), NULL, NULL, 0, 3434327Sdougm B_FALSE) == 0) { 3444327Sdougm zfs_close(handle); 3454327Sdougm libzfs_fini(libhandle); 3464327Sdougm return (strdup(shareopts)); 3474327Sdougm } 3484327Sdougm zfs_close(handle); 3493034Sdougm } 3504327Sdougm libzfs_fini(libhandle); 3513034Sdougm } 3523034Sdougm return (NULL); 3533034Sdougm } 3543034Sdougm 3553034Sdougm /* 3563910Sdougm * sa_zfs_is_shared(handle, path) 3573034Sdougm * 3583034Sdougm * Check to see if the ZFS path provided has the sharenfs option set 3593034Sdougm * or not. 3603034Sdougm */ 3613034Sdougm 3623034Sdougm int 3633910Sdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 3643034Sdougm { 3653034Sdougm int ret = 0; 3663034Sdougm char *dataset; 3673034Sdougm zfs_handle_t *handle = NULL; 3683034Sdougm char shareopts[ZFS_MAXPROPLEN]; 3693034Sdougm libzfs_handle_t *libhandle; 3703034Sdougm 3714592Smarks dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 3723034Sdougm if (dataset != NULL) { 3734327Sdougm libhandle = libzfs_init(); 3744327Sdougm if (libhandle != NULL) { 3754327Sdougm handle = zfs_open(libhandle, dataset, 3764327Sdougm ZFS_TYPE_FILESYSTEM); 3774327Sdougm if (handle != NULL) { 3784327Sdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 3794327Sdougm shareopts, sizeof (shareopts), NULL, NULL, 3804327Sdougm 0, B_FALSE) == 0 && 3814327Sdougm strcmp(shareopts, "off") != 0) { 3824327Sdougm ret = 1; /* it is shared */ 3834327Sdougm } 3844327Sdougm zfs_close(handle); 3854327Sdougm } 3864327Sdougm libzfs_fini(libhandle); 3873034Sdougm } 3884327Sdougm free(dataset); 3893034Sdougm } 3903034Sdougm return (ret); 3913034Sdougm } 3923034Sdougm 3933034Sdougm /* 3945331Samw * find_or_create_group(handle, groupname, proto, *err) 3953034Sdougm * 3963034Sdougm * While walking the ZFS tree, we need to add shares to a defined 3973034Sdougm * group. If the group doesn't exist, create it first, making sure it 3983034Sdougm * is marked as a ZFS group. 3993034Sdougm * 4003108Sdougm * Note that all ZFS shares are in a subgroup of the top level group 4013108Sdougm * called "zfs". 4023034Sdougm */ 4033034Sdougm 4043034Sdougm static sa_group_t 4053910Sdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 4063034Sdougm { 4073034Sdougm sa_group_t group; 4083034Sdougm sa_optionset_t optionset; 4093034Sdougm int ret = SA_OK; 4103034Sdougm 4113034Sdougm /* 4123034Sdougm * we check to see if the "zfs" group exists. Since this 4133034Sdougm * should be the top level group, we don't want the 4143034Sdougm * parent. This is to make sure the zfs group has been created 4153034Sdougm * and to created if it hasn't been. 4163034Sdougm */ 4173910Sdougm group = sa_get_group(handle, groupname); 4183034Sdougm if (group == NULL) { 4194327Sdougm group = sa_create_group(handle, groupname, &ret); 4203108Sdougm 4214327Sdougm /* make sure this is flagged as a ZFS group */ 4224327Sdougm if (group != NULL) 4234327Sdougm ret = sa_set_group_attr(group, "zfs", "true"); 4243034Sdougm } 4253034Sdougm if (group != NULL) { 4264327Sdougm if (proto != NULL) { 4274327Sdougm optionset = sa_get_optionset(group, proto); 4285331Samw if (optionset == NULL) 4294327Sdougm optionset = sa_create_optionset(group, proto); 4303034Sdougm } 4313034Sdougm } 4323034Sdougm if (err != NULL) 4334327Sdougm *err = ret; 4343034Sdougm return (group); 4353034Sdougm } 4363034Sdougm 4373034Sdougm /* 4383108Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 4393108Sdougm * 4403108Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 4413108Sdougm * function looks to see if the groupname exists and returns it if it 4423108Sdougm * does or else creates a new one with the specified name and returns 4433108Sdougm * that. The "zfs" group will exist before we get here, but we make 4443108Sdougm * sure just in case. 4453108Sdougm * 4463108Sdougm * err must be a valid pointer. 4473108Sdougm */ 4483108Sdougm 4493108Sdougm static sa_group_t 4505331Samw find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 4515331Samw char *optstring, int *err) 4523108Sdougm { 4533108Sdougm sa_group_t group = NULL; 4543108Sdougm sa_group_t zfs; 4553108Sdougm char *name; 4563108Sdougm char *options; 4573108Sdougm 4583108Sdougm /* start with the top-level "zfs" group */ 4593910Sdougm zfs = sa_get_group(handle, "zfs"); 4603108Sdougm *err = SA_OK; 4613108Sdougm if (zfs != NULL) { 4624327Sdougm for (group = sa_get_sub_group(zfs); group != NULL; 4634327Sdougm group = sa_get_next_group(group)) { 4644327Sdougm name = sa_get_group_attr(group, "name"); 4654327Sdougm if (name != NULL && strcmp(name, groupname) == 0) { 4664327Sdougm /* have the group so break out of here */ 4674327Sdougm sa_free_attr_string(name); 4684327Sdougm break; 4694327Sdougm } 4704327Sdougm if (name != NULL) 4714327Sdougm sa_free_attr_string(name); 4723108Sdougm } 4733108Sdougm 4744327Sdougm if (group == NULL) { 4754327Sdougm /* 476*6149Sdougm * Need to create the sub-group since it doesn't exist 4774327Sdougm */ 4784327Sdougm group = _sa_create_zfs_group(zfs, groupname); 479*6149Sdougm if (group == NULL) { 480*6149Sdougm *err = SA_NO_MEMORY; 481*6149Sdougm return (NULL); 4824327Sdougm } 483*6149Sdougm set_node_attr(group, "zfs", "true"); 484*6149Sdougm } 485*6149Sdougm if (strcmp(optstring, "on") == 0) 486*6149Sdougm optstring = "rw"; 487*6149Sdougm options = strdup(optstring); 488*6149Sdougm if (options != NULL) { 489*6149Sdougm *err = sa_parse_legacy_options(group, options, 490*6149Sdougm proto); 491*6149Sdougm /* If no optionset, add one. */ 492*6149Sdougm if (sa_get_optionset(group, proto) == NULL) 493*6149Sdougm (void) sa_create_optionset(group, proto); 494*6149Sdougm free(options); 495*6149Sdougm } else { 496*6149Sdougm *err = SA_NO_MEMORY; 4973108Sdougm } 4983108Sdougm } 4993108Sdougm return (group); 5003108Sdougm } 5013108Sdougm 5023108Sdougm /* 5035331Samw * zfs_construct_resource(share, name, base, dataset) 5045331Samw * 5055331Samw * Add a resource to the share using name as a template. If name == 5065331Samw * NULL, then construct a name based on the dataset value. 5075331Samw * name. 5085331Samw */ 5095331Samw static void 5105331Samw zfs_construct_resource(sa_share_t share, char *dataset) 5115331Samw { 5125331Samw char buff[SA_MAX_RESOURCE_NAME + 1]; 5135331Samw int ret = SA_OK; 5145331Samw 5155331Samw (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset); 5165331Samw sa_fix_resource_name(buff); 5175331Samw (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret); 5185331Samw } 5195331Samw 5205331Samw /* 5214327Sdougm * zfs_inherited(handle, source, sourcestr) 5224327Sdougm * 5235331Samw * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares 5244327Sdougm * for readability. 5254327Sdougm */ 5264327Sdougm static int 5274327Sdougm zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 5285331Samw char *shareopts, char *mountpoint, char *proto, char *dataset) 5294327Sdougm { 5304327Sdougm int doshopt = 0; 5314327Sdougm int err = SA_OK; 5324327Sdougm sa_group_t group; 5335331Samw sa_resource_t resource; 5345331Samw uint64_t features; 5354327Sdougm 5364327Sdougm /* 5374327Sdougm * Need to find the "real" parent sub-group. It may not be 5384327Sdougm * mounted, but it was identified in the "sourcestr" 5394327Sdougm * variable. The real parent not mounted can occur if 5404327Sdougm * "canmount=off and sharenfs=on". 5414327Sdougm */ 5425331Samw group = find_or_create_zfs_subgroup(handle, sourcestr, proto, 5435331Samw shareopts, &doshopt); 5444327Sdougm if (group != NULL) { 5455331Samw /* 5465331Samw * We may need the first share for resource 5475331Samw * prototype. We only care about it if it has a 5485331Samw * resource that sets a prefix value. 5495331Samw */ 5505331Samw if (share == NULL) 5515331Samw share = _sa_add_share(group, mountpoint, 5525331Samw SA_SHARE_TRANSIENT, &err, 5535331Samw (uint64_t)SA_FEATURE_NONE); 5544327Sdougm /* 5554327Sdougm * some options may only be on shares. If the opt 5564327Sdougm * string contains one of those, we put it just on the 5574327Sdougm * share. 5584327Sdougm */ 5594327Sdougm if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 5604327Sdougm char *options; 5614327Sdougm options = strdup(shareopts); 5624327Sdougm if (options != NULL) { 5635331Samw set_node_attr(share, "dataset", dataset); 5644327Sdougm err = sa_parse_legacy_options(share, options, 5655331Samw proto); 5665331Samw set_node_attr(share, "dataset", NULL); 5674327Sdougm free(options); 5684327Sdougm } 5695331Samw if (sa_get_optionset(group, proto) == NULL) 5705331Samw (void) sa_create_optionset(group, proto); 5715331Samw } 5725331Samw features = sa_proto_get_featureset(proto); 5735331Samw if (share != NULL && features & SA_FEATURE_RESOURCE) { 5745331Samw /* 5755331Samw * We have a share and the protocol requires 5765331Samw * that at least one resource exist (probably 5775331Samw * SMB). We need to make sure that there is at 5785331Samw * least one. 5795331Samw */ 5805331Samw resource = sa_get_share_resource(share, NULL); 5815331Samw if (resource == NULL) { 5825331Samw zfs_construct_resource(share, dataset); 5835331Samw } 5844327Sdougm } 5854327Sdougm } else { 5864327Sdougm err = SA_NO_MEMORY; 5874327Sdougm } 5884327Sdougm return (err); 5894327Sdougm } 5904327Sdougm 5914327Sdougm /* 5925454Sdougm * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset, 5935454Sdougm * grouperr) 5944327Sdougm * 5954327Sdougm * handle case where this is the top of a sub-group in ZFS. Pulled out 5965454Sdougm * of sa_get_zfs_shares for readability. We need the grouperr from the 5975454Sdougm * creation of the subgroup to know whether to add the public 5985454Sdougm * property, etc. to the specific share. 5994327Sdougm */ 6004327Sdougm static int 6015331Samw zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 6025454Sdougm char *shareopts, char *proto, char *dataset, int grouperr) 6034327Sdougm { 6044327Sdougm int err = SA_OK; 6055331Samw sa_resource_t resource; 6065331Samw uint64_t features; 6074327Sdougm 6084327Sdougm set_node_attr(group, "zfs", "true"); 6095331Samw if (share == NULL) 6105331Samw share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 6115331Samw &err, (uint64_t)SA_FEATURE_NONE); 612*6149Sdougm 613*6149Sdougm if (err != SA_OK) 614*6149Sdougm return (err); 615*6149Sdougm 616*6149Sdougm if (strcmp(shareopts, "on") == 0) 617*6149Sdougm shareopts = ""; 618*6149Sdougm if (shareopts != NULL) { 619*6149Sdougm char *options; 620*6149Sdougm if (grouperr == SA_PROP_SHARE_ONLY) { 621*6149Sdougm /* 622*6149Sdougm * Some properties may only be on shares, but 623*6149Sdougm * due to the ZFS sub-groups being artificial, 624*6149Sdougm * we sometimes get this and have to deal with 625*6149Sdougm * it. We do it by attempting to put it on the 626*6149Sdougm * share. 627*6149Sdougm */ 628*6149Sdougm options = strdup(shareopts); 629*6149Sdougm if (options != NULL) { 630*6149Sdougm err = sa_parse_legacy_options(share, 631*6149Sdougm options, proto); 632*6149Sdougm free(options); 6335331Samw } 6345331Samw } 635*6149Sdougm /* Unmark the share's changed state */ 636*6149Sdougm set_node_attr(share, "changed", NULL); 637*6149Sdougm } 638*6149Sdougm features = sa_proto_get_featureset(proto); 639*6149Sdougm if (share != NULL && features & SA_FEATURE_RESOURCE) { 640*6149Sdougm /* 641*6149Sdougm * We have a share and the protocol requires that at 642*6149Sdougm * least one resource exist (probably SMB). We need to 643*6149Sdougm * make sure that there is at least one. 644*6149Sdougm */ 645*6149Sdougm resource = sa_get_share_resource(share, NULL); 646*6149Sdougm if (resource == NULL) { 647*6149Sdougm zfs_construct_resource(share, dataset); 6484327Sdougm } 6494327Sdougm } 6504327Sdougm return (err); 6514327Sdougm } 6524327Sdougm 6534327Sdougm /* 6544327Sdougm * zfs_grp_error(err) 6554327Sdougm * 6564327Sdougm * Print group create error, but only once. If err is 0 do the 6574327Sdougm * print else don't. 6584327Sdougm */ 6594327Sdougm 6604327Sdougm static void 6614327Sdougm zfs_grp_error(int err) 6624327Sdougm { 6634327Sdougm if (err == 0) { 6644327Sdougm /* only print error once */ 6654327Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 6664327Sdougm "Cannot create ZFS subgroup during initialization:" 6674327Sdougm " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 6684327Sdougm } 6694327Sdougm } 6704327Sdougm 6714327Sdougm /* 6725331Samw * zfs_process_share(handle, share, mountpoint, proto, source, 6735331Samw * shareopts, sourcestr) 6745331Samw * 6755951Sdougm * Creates the subgroup, if necessary and adds shares, resources 6765331Samw * and properties. 6775331Samw */ 6785951Sdougm int 6795951Sdougm sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 6805331Samw char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 6815331Samw char *sourcestr, char *dataset) 6825331Samw { 6835331Samw int err = SA_OK; 6845331Samw 6855331Samw if (source & ZPROP_SRC_INHERITED) { 6865331Samw err = zfs_inherited(handle, share, sourcestr, shareopts, 6875331Samw mountpoint, proto, dataset); 6885331Samw } else { 6895331Samw group = find_or_create_zfs_subgroup(handle, dataset, proto, 6905331Samw shareopts, &err); 6915331Samw if (group == NULL) { 6925454Sdougm static boolean_t reported_error = B_FALSE; 6935331Samw /* 6945454Sdougm * There is a problem, but we can't do 6955331Samw * anything about it at this point so we issue 6965454Sdougm * a warning and move on. 6975331Samw */ 6985454Sdougm zfs_grp_error(reported_error); 6995454Sdougm reported_error = B_TRUE; 7005331Samw } 7015331Samw set_node_attr(group, "zfs", "true"); 7025331Samw /* 7035331Samw * Add share with local opts via zfs_notinherited. 7045331Samw */ 7055331Samw err = zfs_notinherited(group, share, mountpoint, shareopts, 7065454Sdougm proto, dataset, err); 7075331Samw } 7085331Samw return (err); 7095331Samw } 7105331Samw 7115331Samw /* 7123910Sdougm * sa_get_zfs_shares(handle, groupname) 7133034Sdougm * 7143034Sdougm * Walk the mnttab for all zfs mounts and determine which are 7153034Sdougm * shared. Find or create the appropriate group/sub-group to contain 7163034Sdougm * the shares. 7173034Sdougm * 7183034Sdougm * All shares are in a sub-group that will hold the properties. This 7193034Sdougm * allows representing the inherited property model. 720*6149Sdougm * 721*6149Sdougm * One area of complication is if "sharenfs" is set at one level of 722*6149Sdougm * the directory tree and "sharesmb" is set at a different level, the 723*6149Sdougm * a sub-group must be formed at the lower level for both 724*6149Sdougm * protocols. That is the nature of the problem in CR 6667349. 7253034Sdougm */ 7263034Sdougm 7273034Sdougm int 7283910Sdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 7293034Sdougm { 7303034Sdougm sa_group_t zfsgroup; 731*6149Sdougm boolean_t nfs; 732*6149Sdougm boolean_t nfs_inherited; 733*6149Sdougm boolean_t smb; 734*6149Sdougm boolean_t smb_inherited; 7353218Sdougm zfs_handle_t **zlist; 736*6149Sdougm char nfsshareopts[ZFS_MAXPROPLEN]; 737*6149Sdougm char smbshareopts[ZFS_MAXPROPLEN]; 7383034Sdougm sa_share_t share; 7395094Slling zprop_source_t source; 740*6149Sdougm char nfssourcestr[ZFS_MAXPROPLEN]; 741*6149Sdougm char smbsourcestr[ZFS_MAXPROPLEN]; 7423218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 7433218Sdougm size_t count = 0, i; 7443910Sdougm libzfs_handle_t *zfs_libhandle; 745*6149Sdougm int err = SA_OK; 7463034Sdougm 7473034Sdougm /* 7483910Sdougm * If we can't access libzfs, don't bother doing anything. 7493034Sdougm */ 7503910Sdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 7513218Sdougm if (zfs_libhandle == NULL) 7524327Sdougm return (SA_SYSTEM_ERR); 7533034Sdougm 7545331Samw zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 755*6149Sdougm /* Not an error, this could be a legacy condition */ 7564524Sdougm if (zfsgroup == NULL) 757*6149Sdougm return (SA_OK); 7583218Sdougm 7594524Sdougm /* 7604524Sdougm * need to walk the mounted ZFS pools and datasets to 7614524Sdougm * find shares that are possible. 7624524Sdougm */ 7634524Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 7644524Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 7654524Sdougm 7664524Sdougm for (i = 0; i < count; i++) { 7674524Sdougm char *dataset; 7683218Sdougm 7695094Slling source = ZPROP_SRC_ALL; 7704524Sdougm /* If no mountpoint, skip. */ 7714524Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 7724524Sdougm mountpoint, sizeof (mountpoint), NULL, NULL, 0, 7734524Sdougm B_FALSE) != 0) 7744524Sdougm continue; 7754327Sdougm 7764524Sdougm /* 7774524Sdougm * zfs_get_name value must not be freed. It is just a 7784524Sdougm * pointer to a value in the handle. 7794524Sdougm */ 7804524Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 7814524Sdougm continue; 7824327Sdougm 7834524Sdougm /* 7844524Sdougm * only deal with "mounted" file systems since 7854524Sdougm * unmounted file systems can't actually be shared. 7864524Sdougm */ 7874327Sdougm 7884524Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 7894524Sdougm continue; 7904327Sdougm 791*6149Sdougm nfs = nfs_inherited = B_FALSE; 792*6149Sdougm 793*6149Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts, 794*6149Sdougm sizeof (nfsshareopts), &source, nfssourcestr, 795*6149Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 796*6149Sdougm strcmp(nfsshareopts, "off") != 0) { 797*6149Sdougm if (source & ZPROP_SRC_INHERITED) 798*6149Sdougm nfs_inherited = B_TRUE; 799*6149Sdougm else 800*6149Sdougm nfs = B_TRUE; 801*6149Sdougm } 802*6149Sdougm 803*6149Sdougm smb = smb_inherited = B_FALSE; 804*6149Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts, 805*6149Sdougm sizeof (smbshareopts), &source, smbsourcestr, 8064524Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 807*6149Sdougm strcmp(smbshareopts, "off") != 0) { 808*6149Sdougm if (source & ZPROP_SRC_INHERITED) 809*6149Sdougm smb_inherited = B_TRUE; 810*6149Sdougm else 811*6149Sdougm smb = B_TRUE; 812*6149Sdougm } 813*6149Sdougm 814*6149Sdougm /* 815*6149Sdougm * If the mountpoint is already shared, it must be a 816*6149Sdougm * non-ZFS share. We want to remove the share from its 817*6149Sdougm * parent group and reshare it under ZFS. 818*6149Sdougm */ 819*6149Sdougm share = sa_find_share(handle, mountpoint); 820*6149Sdougm if (share != NULL && 821*6149Sdougm (nfs || smb || nfs_inherited || smb_inherited)) { 822*6149Sdougm err = sa_remove_share(share); 823*6149Sdougm share = NULL; 824*6149Sdougm } 825*6149Sdougm 826*6149Sdougm /* 827*6149Sdougm * At this point, we have the information needed to 828*6149Sdougm * determine what to do with the share. 829*6149Sdougm * 830*6149Sdougm * If smb or nfs is set, we have a new sub-group. 831*6149Sdougm * If smb_inherit and/or nfs_inherit is set, then 832*6149Sdougm * place on an existing sub-group. If both are set, 833*6149Sdougm * the existing sub-group is the closest up the tree. 834*6149Sdougm */ 835*6149Sdougm if (nfs || smb) { 836*6149Sdougm /* 837*6149Sdougm * Non-inherited is the straightforward 838*6149Sdougm * case. sa_zfs_process_share handles it 839*6149Sdougm * directly. Make sure that if the "other" 840*6149Sdougm * protocol is inherited, that we treat it as 841*6149Sdougm * non-inherited as well. 842*6149Sdougm */ 843*6149Sdougm if (nfs || nfs_inherited) { 844*6149Sdougm err = sa_zfs_process_share(handle, zfsgroup, 845*6149Sdougm share, mountpoint, "nfs", 846*6149Sdougm 0, nfsshareopts, 847*6149Sdougm nfssourcestr, dataset); 848*6149Sdougm share = sa_find_share(handle, mountpoint); 8495331Samw } 850*6149Sdougm if (smb || smb_inherited) { 851*6149Sdougm err = sa_zfs_process_share(handle, zfsgroup, 852*6149Sdougm share, mountpoint, "smb", 853*6149Sdougm 0, smbshareopts, 854*6149Sdougm smbsourcestr, dataset); 8555331Samw } 856*6149Sdougm } else if (nfs_inherited || smb_inherited) { 857*6149Sdougm char *grpdataset; 858*6149Sdougm /* 859*6149Sdougm * If we only have inherited groups, it is 860*6149Sdougm * important to find the closer of the two if 861*6149Sdougm * the protocols are set at different 862*6149Sdougm * levels. The closest sub-group is the one we 863*6149Sdougm * want to work with. 864*6149Sdougm */ 865*6149Sdougm if (nfs_inherited && smb_inherited) { 866*6149Sdougm if (strcmp(nfssourcestr, smbsourcestr) <= 0) 867*6149Sdougm grpdataset = nfssourcestr; 868*6149Sdougm else 869*6149Sdougm grpdataset = smbsourcestr; 870*6149Sdougm } else if (nfs_inherited) { 871*6149Sdougm grpdataset = nfssourcestr; 872*6149Sdougm } else if (smb_inherited) { 873*6149Sdougm grpdataset = smbsourcestr; 874*6149Sdougm } 875*6149Sdougm if (nfs_inherited) { 876*6149Sdougm err = sa_zfs_process_share(handle, zfsgroup, 877*6149Sdougm share, mountpoint, "nfs", 878*6149Sdougm ZPROP_SRC_INHERITED, nfsshareopts, 879*6149Sdougm grpdataset, dataset); 880*6149Sdougm share = sa_find_share(handle, mountpoint); 881*6149Sdougm } 882*6149Sdougm if (smb_inherited) { 883*6149Sdougm err = sa_zfs_process_share(handle, zfsgroup, 884*6149Sdougm share, mountpoint, "smb", 885*6149Sdougm ZPROP_SRC_INHERITED, smbshareopts, 886*6149Sdougm grpdataset, dataset); 8873034Sdougm } 8883034Sdougm } 8893034Sdougm } 8903218Sdougm /* 8913218Sdougm * Don't need to free the "zlist" variable since it is only a 8923218Sdougm * pointer to a cached value that will be freed when 8933218Sdougm * sa_fini() is called. 8943218Sdougm */ 895*6149Sdougm return (err); 8963034Sdougm } 8973034Sdougm 8983034Sdougm #define COMMAND "/usr/sbin/zfs" 8993034Sdougm 9003034Sdougm /* 9013034Sdougm * sa_zfs_set_sharenfs(group, path, on) 9023034Sdougm * 9033034Sdougm * Update the "sharenfs" property on the path. If on is true, then set 9043034Sdougm * to the properties on the group or "on" if no properties are 9053034Sdougm * defined. Set to "off" if on is false. 9063034Sdougm */ 9073034Sdougm 9083034Sdougm int 9093034Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 9103034Sdougm { 9113034Sdougm int ret = SA_NOT_IMPLEMENTED; 9123034Sdougm char *command; 9133034Sdougm 9143034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 9153034Sdougm if (command != NULL) { 9164327Sdougm char *opts = NULL; 9174327Sdougm char *dataset = NULL; 9184327Sdougm FILE *pfile; 9194327Sdougm sa_handle_impl_t impl_handle; 9204327Sdougm /* for now, NFS is always available for "zfs" */ 9214327Sdougm if (on) { 9224327Sdougm opts = sa_proto_legacy_format("nfs", group, 1); 9234327Sdougm if (opts != NULL && strlen(opts) == 0) { 9244327Sdougm free(opts); 9254327Sdougm opts = strdup("on"); 9264327Sdougm } 9273034Sdougm } 9283910Sdougm 9294327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 9304327Sdougm assert(impl_handle != NULL); 9314327Sdougm if (impl_handle != NULL) 9324592Smarks dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 9334327Sdougm else 9344327Sdougm ret = SA_SYSTEM_ERR; 9353910Sdougm 9364327Sdougm if (dataset != NULL) { 9374327Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 9384327Sdougm "%s set sharenfs=\"%s\" %s", COMMAND, 9394327Sdougm opts != NULL ? opts : "off", dataset); 9404327Sdougm pfile = popen(command, "r"); 9414327Sdougm if (pfile != NULL) { 9424327Sdougm ret = pclose(pfile); 9434327Sdougm if (ret != 0) 9444327Sdougm ret = SA_SYSTEM_ERR; 9454327Sdougm } 9463034Sdougm } 9474327Sdougm if (opts != NULL) 9484327Sdougm free(opts); 9494327Sdougm if (dataset != NULL) 9504327Sdougm free(dataset); 9514327Sdougm free(command); 9523034Sdougm } 9533034Sdougm return (ret); 9543034Sdougm } 9553034Sdougm 9563034Sdougm /* 9575331Samw * add_resources(share, opt) 9585331Samw * 9595331Samw * Add resource properties to those in "opt". Resources are prefixed 9605331Samw * with name=resourcename. 9615331Samw */ 9625331Samw static char * 9635331Samw add_resources(sa_share_t share, char *opt) 9645331Samw { 9655331Samw char *newopt = NULL; 9665331Samw char *propstr; 9675331Samw sa_resource_t resource; 9685331Samw 9695331Samw newopt = strdup(opt); 9705331Samw if (newopt == NULL) 9715331Samw return (newopt); 9725331Samw 9735331Samw for (resource = sa_get_share_resource(share, NULL); 9745331Samw resource != NULL; 9755331Samw resource = sa_get_next_resource(resource)) { 9765331Samw char *name; 9775331Samw size_t size; 9785331Samw 9795331Samw name = sa_get_resource_attr(resource, "name"); 9805331Samw if (name == NULL) { 9815331Samw free(newopt); 9825331Samw return (NULL); 9835331Samw } 9845331Samw size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 9855331Samw newopt = calloc(1, size); 9865331Samw if (newopt != NULL) 9875331Samw (void) snprintf(newopt, size, "%s,name=%s", opt, name); 9885331Samw free(opt); 9895331Samw opt = newopt; 9905331Samw propstr = sa_proto_legacy_format("smb", resource, 0); 9915331Samw if (propstr == NULL) { 9925331Samw free(opt); 9935331Samw return (NULL); 9945331Samw } 9955331Samw size = strlen(propstr) + strlen(opt) + 2; 9965331Samw newopt = calloc(1, size); 9975331Samw if (newopt != NULL) 9985331Samw (void) snprintf(newopt, size, "%s,%s", opt, propstr); 9995331Samw free(opt); 10005331Samw opt = newopt; 10015331Samw } 10025331Samw return (opt); 10035331Samw } 10045331Samw 10055331Samw /* 10065331Samw * sa_zfs_set_sharesmb(group, path, on) 10075331Samw * 10085331Samw * Update the "sharesmb" property on the path. If on is true, then set 10095331Samw * to the properties on the group or "on" if no properties are 10105331Samw * defined. Set to "off" if on is false. 10115331Samw */ 10125331Samw 10135331Samw int 10145331Samw sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 10155331Samw { 10165331Samw int ret = SA_NOT_IMPLEMENTED; 10175331Samw char *command; 10185331Samw sa_share_t share; 10195331Samw 10205331Samw /* In case SMB not enabled */ 10215331Samw if (sa_get_optionset(group, "smb") == NULL) 10225331Samw return (SA_NOT_SUPPORTED); 10235331Samw 10245331Samw command = malloc(ZFS_MAXPROPLEN * 2); 10255331Samw if (command != NULL) { 10265331Samw char *opts = NULL; 10275331Samw char *dataset = NULL; 10285331Samw FILE *pfile; 10295331Samw sa_handle_impl_t impl_handle; 10305331Samw 10315331Samw if (on) { 10325331Samw char *newopt; 10335331Samw 10345331Samw share = sa_get_share(group, NULL); 10355331Samw opts = sa_proto_legacy_format("smb", share, 1); 10365331Samw if (opts != NULL && strlen(opts) == 0) { 10375331Samw free(opts); 10385331Samw opts = strdup("on"); 10395331Samw } 10405331Samw newopt = add_resources(opts, share); 10415331Samw free(opts); 10425331Samw opts = newopt; 10435331Samw } 10445331Samw 10455331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 10465331Samw assert(impl_handle != NULL); 10475331Samw if (impl_handle != NULL) 10485331Samw dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 10495331Samw else 10505331Samw ret = SA_SYSTEM_ERR; 10515331Samw 10525331Samw if (dataset != NULL) { 10535331Samw (void) snprintf(command, ZFS_MAXPROPLEN * 2, 10545331Samw "echo %s set sharesmb=\"%s\" %s", COMMAND, 10555331Samw opts != NULL ? opts : "off", dataset); 10565331Samw pfile = popen(command, "r"); 10575331Samw if (pfile != NULL) { 10585331Samw ret = pclose(pfile); 10595331Samw if (ret != 0) 10605331Samw ret = SA_SYSTEM_ERR; 10615331Samw } 10625331Samw } 10635331Samw if (opts != NULL) 10645331Samw free(opts); 10655331Samw if (dataset != NULL) 10665331Samw free(dataset); 10675331Samw free(command); 10685331Samw } 10695331Samw return (ret); 10705331Samw } 10715331Samw 10725331Samw /* 10733034Sdougm * sa_zfs_update(group) 10743034Sdougm * 10753034Sdougm * call back to ZFS to update the share if necessary. 10763034Sdougm * Don't do it if it isn't a real change. 10773034Sdougm */ 10783034Sdougm int 10793034Sdougm sa_zfs_update(sa_group_t group) 10803034Sdougm { 10813034Sdougm sa_optionset_t protopt; 10823034Sdougm sa_group_t parent; 10833034Sdougm char *command; 10843034Sdougm char *optstring; 10853034Sdougm int ret = SA_OK; 10863034Sdougm int doupdate = 0; 10873034Sdougm FILE *pfile; 10883034Sdougm 10893034Sdougm if (sa_is_share(group)) 10904327Sdougm parent = sa_get_parent_group(group); 10913034Sdougm else 10924327Sdougm parent = group; 10933034Sdougm 10943034Sdougm if (parent != NULL) { 10954327Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 10964327Sdougm if (command == NULL) 10974327Sdougm return (SA_NO_MEMORY); 10984327Sdougm 10994327Sdougm *command = '\0'; 11004327Sdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 11014327Sdougm protopt = sa_get_next_optionset(protopt)) { 11023034Sdougm 11034327Sdougm char *proto = sa_get_optionset_attr(protopt, "type"); 11044327Sdougm char *path; 11054327Sdougm char *dataset = NULL; 11064327Sdougm char *zfsopts = NULL; 11073034Sdougm 11084327Sdougm if (sa_is_share(group)) { 11094327Sdougm path = sa_get_share_attr((sa_share_t)group, 11104327Sdougm "path"); 11114327Sdougm if (path != NULL) { 11124327Sdougm sa_handle_impl_t impl_handle; 11133034Sdougm 11144327Sdougm impl_handle = sa_find_group_handle( 11154327Sdougm group); 11164327Sdougm if (impl_handle != NULL) 11174327Sdougm dataset = get_zfs_dataset( 11184592Smarks impl_handle, path, B_FALSE); 11194327Sdougm else 11204327Sdougm ret = SA_SYSTEM_ERR; 11213910Sdougm 11224327Sdougm sa_free_attr_string(path); 11234327Sdougm } 11244327Sdougm } else { 11254327Sdougm dataset = sa_get_group_attr(group, "name"); 11264327Sdougm } 11274327Sdougm /* update only when there is an optstring found */ 11284327Sdougm doupdate = 0; 11294327Sdougm if (proto != NULL && dataset != NULL) { 11304327Sdougm optstring = sa_proto_legacy_format(proto, 11314327Sdougm group, 1); 11324327Sdougm zfsopts = get_zfs_property(dataset, 11334327Sdougm ZFS_PROP_SHARENFS); 11343034Sdougm 11354327Sdougm if (optstring != NULL && zfsopts != NULL) { 11364327Sdougm if (strcmp(optstring, zfsopts) != 0) 11374327Sdougm doupdate++; 11384327Sdougm } 11394327Sdougm if (doupdate) { 11404327Sdougm if (optstring != NULL && 11414327Sdougm strlen(optstring) > 0) { 11424327Sdougm (void) snprintf(command, 11434327Sdougm ZFS_MAXPROPLEN * 2, 11444942Sdougm "%s set sharenfs=%s %s", 11454327Sdougm COMMAND, 11464327Sdougm optstring, dataset); 11474327Sdougm } else { 11484327Sdougm (void) snprintf(command, 11494327Sdougm ZFS_MAXPROPLEN * 2, 11504327Sdougm "%s set sharenfs=on %s", 11514327Sdougm COMMAND, 11524327Sdougm dataset); 11534327Sdougm } 11544327Sdougm pfile = popen(command, "r"); 11554327Sdougm if (pfile != NULL) 11564327Sdougm ret = pclose(pfile); 11574327Sdougm switch (ret) { 11584327Sdougm default: 11594327Sdougm case 1: 11604327Sdougm ret = SA_SYSTEM_ERR; 11614327Sdougm break; 11624327Sdougm case 2: 11634327Sdougm ret = SA_SYNTAX_ERR; 11644327Sdougm break; 11654327Sdougm case 0: 11664327Sdougm break; 11674327Sdougm } 11684327Sdougm } 11694327Sdougm if (optstring != NULL) 11704327Sdougm free(optstring); 11714327Sdougm if (zfsopts != NULL) 11724327Sdougm free(zfsopts); 11733034Sdougm } 11744327Sdougm if (proto != NULL) 11754327Sdougm sa_free_attr_string(proto); 11764327Sdougm if (dataset != NULL) 11774327Sdougm free(dataset); 11783034Sdougm } 11794327Sdougm free(command); 11803034Sdougm } 11813034Sdougm return (ret); 11823034Sdougm } 11833034Sdougm 11843034Sdougm /* 11853034Sdougm * sa_group_is_zfs(group) 11863034Sdougm * 11873034Sdougm * Given the group, determine if the zfs attribute is set. 11883034Sdougm */ 11893034Sdougm 11903034Sdougm int 11913034Sdougm sa_group_is_zfs(sa_group_t group) 11923034Sdougm { 11933034Sdougm char *zfs; 11943034Sdougm int ret = 0; 11953034Sdougm 11963034Sdougm zfs = sa_get_group_attr(group, "zfs"); 11973034Sdougm if (zfs != NULL) { 11984327Sdougm ret = 1; 11994327Sdougm sa_free_attr_string(zfs); 12003034Sdougm } 12013034Sdougm return (ret); 12023034Sdougm } 12033034Sdougm 12043034Sdougm /* 12053034Sdougm * sa_path_is_zfs(path) 12063034Sdougm * 12073034Sdougm * Check to see if the file system path represents is of type "zfs". 12083034Sdougm */ 12093034Sdougm 12103034Sdougm int 12113034Sdougm sa_path_is_zfs(char *path) 12123034Sdougm { 12133034Sdougm char *fstype; 12143034Sdougm int ret = 0; 12153034Sdougm 12163034Sdougm fstype = sa_fstype(path); 12174327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) 12184327Sdougm ret = 1; 12193034Sdougm if (fstype != NULL) 12204327Sdougm sa_free_fstype(fstype); 12213034Sdougm return (ret); 12223034Sdougm } 12234543Smarks 12244543Smarks int 12254543Smarks sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 12264543Smarks { 12274543Smarks char *path; 12284543Smarks 12294713Smarks /* Make sure path is valid */ 12304713Smarks 12314543Smarks path = sa_get_share_attr(share, "path"); 12324543Smarks if (path != NULL) { 12334543Smarks (void) memset(sh, 0, sizeof (sh)); 12344543Smarks (void) sa_fillshare(share, proto, sh); 12354713Smarks sa_free_attr_string(path); 12364543Smarks return (0); 12374543Smarks } else 12384543Smarks return (1); 12394543Smarks } 12404543Smarks 12414543Smarks #define SMAX(i, j) \ 12424543Smarks if ((j) > (i)) { \ 12434543Smarks (i) = (j); \ 12444543Smarks } 12454543Smarks 12464543Smarks int 12474543Smarks sa_share_zfs(sa_share_t share, char *path, share_t *sh, 12485331Samw void *exportdata, zfs_share_op_t operation) 12494543Smarks { 12504543Smarks libzfs_handle_t *libhandle; 12514543Smarks sa_group_t group; 12524543Smarks sa_handle_t sahandle; 12534543Smarks char *dataset; 12544543Smarks int err = EINVAL; 12554543Smarks int i, j; 12564566Smarks char newpath[MAXPATHLEN]; 12574592Smarks char *pathp; 12584543Smarks 12594543Smarks /* 12604543Smarks * First find the dataset name 12614543Smarks */ 12624543Smarks if ((group = sa_get_parent_group(share)) == NULL) { 12634543Smarks return (SA_SYSTEM_ERR); 12644543Smarks } 12654543Smarks if ((sahandle = sa_find_group_handle(group)) == NULL) { 12664543Smarks return (SA_SYSTEM_ERR); 12674543Smarks } 12684543Smarks 12694566Smarks /* 12704566Smarks * If get_zfs_dataset fails, see if it is a subdirectory 12714566Smarks */ 12724592Smarks 12734592Smarks pathp = path; 12744592Smarks while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 12754566Smarks char *p; 12764566Smarks 12774592Smarks if (pathp == path) { 12784592Smarks (void) strlcpy(newpath, path, sizeof (newpath)); 12794592Smarks pathp = newpath; 12804592Smarks } 12814592Smarks 12824592Smarks /* 12834592Smarks * chop off part of path, but if we are at root then 12844592Smarks * make sure path is a / 12854592Smarks */ 12864592Smarks if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 12874592Smarks if (pathp == p) { 12884592Smarks *(p + 1) = '\0'; /* skip over /, root case */ 12894592Smarks } else { 12904592Smarks *p = '\0'; 12914592Smarks } 12924592Smarks } else { 12934566Smarks return (SA_SYSTEM_ERR); 12944592Smarks } 12954543Smarks } 12964543Smarks 12974543Smarks libhandle = libzfs_init(); 12984543Smarks if (libhandle != NULL) { 12994543Smarks 13004543Smarks i = (sh->sh_path ? strlen(sh->sh_path) : 0); 13014543Smarks sh->sh_size = i; 13024543Smarks 13034543Smarks j = (sh->sh_res ? strlen(sh->sh_res) : 0); 13044543Smarks sh->sh_size += j; 13054543Smarks SMAX(i, j); 13064543Smarks 13074543Smarks j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 13084543Smarks sh->sh_size += j; 13094543Smarks SMAX(i, j); 13104543Smarks 13114543Smarks j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 13124543Smarks sh->sh_size += j; 13134543Smarks SMAX(i, j); 13144543Smarks 13154543Smarks j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 13164543Smarks sh->sh_size += j; 13174543Smarks SMAX(i, j); 13184543Smarks err = zfs_deleg_share_nfs(libhandle, dataset, path, 13195331Samw exportdata, sh, i, operation); 13205951Sdougm if (err == SA_OK) 13215951Sdougm sa_update_sharetab_ts(sahandle); 13224543Smarks libzfs_fini(libhandle); 13234543Smarks } 13244543Smarks free(dataset); 13254543Smarks return (err); 13264543Smarks } 13275951Sdougm 13285951Sdougm /* 13295951Sdougm * sa_get_zfs_handle(handle) 13305951Sdougm * 13315951Sdougm * Given an sa_handle_t, return the libzfs_handle_t *. This is only 13325951Sdougm * used internally by libzfs. Needed in order to avoid including 13335951Sdougm * libshare_impl.h in libzfs. 13345951Sdougm */ 13355951Sdougm 13365951Sdougm libzfs_handle_t * 13375951Sdougm sa_get_zfs_handle(sa_handle_t handle) 13385951Sdougm { 13395951Sdougm sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 13405951Sdougm 13415951Sdougm return (implhandle->zfs_libhandle); 13425951Sdougm } 1343