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 /* 233407Sdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm #include <libzfs.h> 303034Sdougm #include <string.h> 313034Sdougm #include <libshare.h> 323034Sdougm #include "libshare_impl.h" 333218Sdougm #include <libintl.h> 343034Sdougm 353034Sdougm extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *); 363034Sdougm extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 373034Sdougm extern char *sa_fstype(char *); 383034Sdougm extern void set_node_attr(void *, char *, char *); 393034Sdougm extern int sa_is_share(void *); 403218Sdougm 413034Sdougm /* 423218Sdougm * File system specific code for ZFS. The original code was stolen 433218Sdougm * from the "zfs" command and modified to better suit this library's 443218Sdougm * usage. 453218Sdougm */ 463218Sdougm 473218Sdougm typedef struct get_all_cbdata { 483218Sdougm zfs_handle_t **cb_handles; 493218Sdougm size_t cb_alloc; 503218Sdougm size_t cb_used; 513218Sdougm } get_all_cbdata_t; 523218Sdougm 533218Sdougm /* 54*3910Sdougm * sa_zfs_init(impl_handle) 553218Sdougm * 56*3910Sdougm * Initialize an access handle into libzfs. The handle needs to stay 57*3910Sdougm * around until sa_zfs_fini() in order to maintain the cache of 58*3910Sdougm * mounts. 593218Sdougm */ 603218Sdougm 613218Sdougm void 62*3910Sdougm sa_zfs_init(sa_handle_impl_t impl_handle) 633218Sdougm { 64*3910Sdougm impl_handle->zfs_libhandle = libzfs_init(); 65*3910Sdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 663218Sdougm } 673218Sdougm 683218Sdougm /* 69*3910Sdougm * sa_zfs_fini(impl_handle) 703218Sdougm * 713218Sdougm * cleanup data structures and the libzfs handle used for accessing 723218Sdougm * zfs file share info. 733218Sdougm */ 743218Sdougm 753218Sdougm void 76*3910Sdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 773218Sdougm { 78*3910Sdougm if (impl_handle->zfs_libhandle != NULL) { 79*3910Sdougm libzfs_fini(impl_handle->zfs_libhandle); 80*3910Sdougm impl_handle->zfs_libhandle = NULL; 81*3910Sdougm if (impl_handle->zfs_list != NULL) { 823218Sdougm /* 833218Sdougm * contents of zfs_list were already freed by the call to 843218Sdougm * libzfs_fini(). 853218Sdougm */ 86*3910Sdougm free(impl_handle->zfs_list); 87*3910Sdougm impl_handle->zfs_list = NULL; 88*3910Sdougm impl_handle->zfs_list_count = 0; 893218Sdougm } 903218Sdougm } 913218Sdougm } 923218Sdougm 933218Sdougm /* 943218Sdougm * get_one_filesystem(zfs_handle_t, data) 953218Sdougm * 963218Sdougm * an interator function called while iterating through the ZFS 973218Sdougm * root. It accumulates into an array of file system handles that can 983218Sdougm * be used to derive info about those file systems. 993034Sdougm */ 1003034Sdougm 1013218Sdougm static int 1023218Sdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1033218Sdougm { 1043218Sdougm get_all_cbdata_t *cbp = data; 1053218Sdougm 1063218Sdougm /* 1073218Sdougm * Skip any zvols 1083218Sdougm */ 1093218Sdougm if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1103218Sdougm zfs_close(zhp); 1113218Sdougm return (0); 1123218Sdougm } 1133218Sdougm 1143218Sdougm if (cbp->cb_alloc == cbp->cb_used) { 1153218Sdougm zfs_handle_t **handles; 1163218Sdougm 1173218Sdougm if (cbp->cb_alloc == 0) 1183218Sdougm cbp->cb_alloc = 64; 1193218Sdougm else 1203218Sdougm cbp->cb_alloc *= 2; 1213218Sdougm 1223218Sdougm handles = calloc(1, cbp->cb_alloc * sizeof (void *)); 1233218Sdougm if (handles == NULL) { 1243218Sdougm return (0); 1253218Sdougm } 1263218Sdougm 1273218Sdougm if (cbp->cb_handles) { 1283218Sdougm (void) memcpy(handles, cbp->cb_handles, 1293218Sdougm cbp->cb_used * sizeof (void *)); 1303218Sdougm free(cbp->cb_handles); 1313218Sdougm } 1323218Sdougm 1333218Sdougm cbp->cb_handles = handles; 1343218Sdougm } 1353218Sdougm 1363218Sdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1373218Sdougm 1383218Sdougm return (zfs_iter_filesystems(zhp, get_one_filesystem, data)); 1393218Sdougm } 1403218Sdougm 1413218Sdougm /* 1423218Sdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1433218Sdougm * 1443218Sdougm * iterate through all ZFS file systems starting at the root. Returns 1453218Sdougm * a count and an array of handle pointers. Allocating is only done 1463218Sdougm * once. The caller does not need to free since it will be done at 1473218Sdougm * sa_zfs_fini() time. 1483218Sdougm */ 1493218Sdougm 1503218Sdougm static void 151*3910Sdougm get_all_filesystems(sa_handle_impl_t impl_handle, 152*3910Sdougm zfs_handle_t ***fslist, size_t *count) 1533218Sdougm { 1543218Sdougm get_all_cbdata_t cb = { 0 }; 1553218Sdougm 156*3910Sdougm if (impl_handle->zfs_list != NULL) { 157*3910Sdougm *fslist = impl_handle->zfs_list; 158*3910Sdougm *count = impl_handle->zfs_list_count; 1593218Sdougm return; 1603218Sdougm } 1613218Sdougm 162*3910Sdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 163*3910Sdougm get_one_filesystem, &cb); 1643218Sdougm 165*3910Sdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 166*3910Sdougm impl_handle->zfs_list_count = *count = cb.cb_used; 1673218Sdougm } 1683218Sdougm 1693218Sdougm /* 1703218Sdougm * mountpoint_compare(a, b) 1713218Sdougm * 1723218Sdougm * compares the mountpoint on two zfs file systems handles. 1733218Sdougm * returns values following strcmp() model. 1743218Sdougm */ 1753218Sdougm 1763218Sdougm static int 1773218Sdougm mountpoint_compare(const void *a, const void *b) 1783218Sdougm { 1793218Sdougm zfs_handle_t **za = (zfs_handle_t **)a; 1803218Sdougm zfs_handle_t **zb = (zfs_handle_t **)b; 1813218Sdougm char mounta[MAXPATHLEN]; 1823218Sdougm char mountb[MAXPATHLEN]; 1833218Sdougm 1843218Sdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 1853218Sdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 1863218Sdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 1873218Sdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 1883218Sdougm 1893218Sdougm return (strcmp(mounta, mountb)); 1903218Sdougm } 1913218Sdougm 1923034Sdougm /* 193*3910Sdougm * get_zfs_dataset(impl_handle, path) 1943034Sdougm * 1953034Sdougm * get the name of the ZFS dataset the path is equivalent to. The 1963034Sdougm * dataset name is used for get/set of ZFS properties since libzfs 1973034Sdougm * requires a dataset to do a zfs_open(). 1983034Sdougm */ 1993034Sdougm 2003034Sdougm static char * 201*3910Sdougm get_zfs_dataset(sa_handle_impl_t impl_handle, char *path) 2023034Sdougm { 2033218Sdougm size_t i, count = 0; 2043034Sdougm char *dataset = NULL; 2053218Sdougm zfs_handle_t **zlist; 2063218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 2073218Sdougm 208*3910Sdougm get_all_filesystems(impl_handle, &zlist, &count); 2093218Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2103218Sdougm for (i = 0; i < count; i++) { 2113218Sdougm /* must have a mountpoint */ 2123218Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 2133218Sdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 2143218Sdougm /* no mountpoint */ 2153218Sdougm continue; 2163218Sdougm } 2173034Sdougm 2183218Sdougm /* mountpoint must be a path */ 2193218Sdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 2203218Sdougm strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 2213218Sdougm continue; 2223218Sdougm 2233218Sdougm /* canmount must be set */ 2243218Sdougm if (!zfs_prop_get_int(zlist[i], ZFS_PROP_CANMOUNT)) 2253218Sdougm continue; 2263218Sdougm 2273218Sdougm /* 2283218Sdougm * have a mountable handle but want to skip those marked none 2293218Sdougm * and legacy 2303218Sdougm */ 2313218Sdougm if (strcmp(mountpoint, path) == 0) { 2323218Sdougm dataset = (char *)zfs_get_name(zlist[i]); 2333218Sdougm break; 2343034Sdougm } 2353218Sdougm 2363034Sdougm } 2373218Sdougm 2383034Sdougm if (dataset != NULL) { 2393034Sdougm dataset = strdup(dataset); 2403034Sdougm } 2413034Sdougm return (dataset); 2423034Sdougm } 2433034Sdougm 2443034Sdougm /* 2453034Sdougm * get_zfs_property(dataset, property) 2463034Sdougm * 2473034Sdougm * Get the file system property specified from the ZFS dataset. 2483034Sdougm */ 2493034Sdougm 2503034Sdougm static char * 2513034Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 2523034Sdougm { 2533034Sdougm zfs_handle_t *handle = NULL; 2543034Sdougm char shareopts[ZFS_MAXPROPLEN]; 2553034Sdougm libzfs_handle_t *libhandle; 2563034Sdougm 2573034Sdougm libhandle = libzfs_init(); 2583034Sdougm if (libhandle != NULL) { 2593034Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 2603034Sdougm if (handle != NULL) { 2613034Sdougm if (zfs_prop_get(handle, property, shareopts, 2623034Sdougm sizeof (shareopts), NULL, NULL, 0, 2633218Sdougm B_FALSE) == 0) { 2643034Sdougm zfs_close(handle); 2653034Sdougm libzfs_fini(libhandle); 2663034Sdougm return (strdup(shareopts)); 2673034Sdougm } 2683034Sdougm zfs_close(handle); 2693034Sdougm } 2703034Sdougm libzfs_fini(libhandle); 2713034Sdougm } 2723034Sdougm return (NULL); 2733034Sdougm } 2743034Sdougm 2753034Sdougm /* 276*3910Sdougm * sa_zfs_is_shared(handle, path) 2773034Sdougm * 2783034Sdougm * Check to see if the ZFS path provided has the sharenfs option set 2793034Sdougm * or not. 2803034Sdougm */ 2813034Sdougm 2823034Sdougm int 283*3910Sdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 2843034Sdougm { 2853034Sdougm int ret = 0; 2863034Sdougm char *dataset; 2873034Sdougm zfs_handle_t *handle = NULL; 2883034Sdougm char shareopts[ZFS_MAXPROPLEN]; 2893034Sdougm libzfs_handle_t *libhandle; 2903034Sdougm 291*3910Sdougm dataset = get_zfs_dataset((sa_handle_t)sahandle, path); 2923034Sdougm if (dataset != NULL) { 2933034Sdougm libhandle = libzfs_init(); 2943034Sdougm if (libhandle != NULL) { 2953034Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 2963034Sdougm if (handle != NULL) { 2973034Sdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, shareopts, 2983034Sdougm sizeof (shareopts), NULL, NULL, 0, 2993218Sdougm B_FALSE) == 0 && 3003034Sdougm strcmp(shareopts, "off") != 0) 3013034Sdougm ret = 1; /* it is shared */ 3023034Sdougm zfs_close(handle); 3033034Sdougm } 3043034Sdougm libzfs_fini(libhandle); 3053034Sdougm } 3063034Sdougm free(dataset); 3073034Sdougm } 3083034Sdougm return (ret); 3093034Sdougm } 3103034Sdougm 3113034Sdougm /* 3123034Sdougm * find_or_create_group(groupname, proto, *err) 3133034Sdougm * 3143034Sdougm * While walking the ZFS tree, we need to add shares to a defined 3153034Sdougm * group. If the group doesn't exist, create it first, making sure it 3163034Sdougm * is marked as a ZFS group. 3173034Sdougm * 3183108Sdougm * Note that all ZFS shares are in a subgroup of the top level group 3193108Sdougm * called "zfs". 3203034Sdougm */ 3213034Sdougm 3223034Sdougm static sa_group_t 323*3910Sdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 3243034Sdougm { 3253034Sdougm sa_group_t group; 3263034Sdougm sa_optionset_t optionset; 3273034Sdougm int ret = SA_OK; 3283034Sdougm 3293034Sdougm /* 3303034Sdougm * we check to see if the "zfs" group exists. Since this 3313034Sdougm * should be the top level group, we don't want the 3323034Sdougm * parent. This is to make sure the zfs group has been created 3333034Sdougm * and to created if it hasn't been. 3343034Sdougm */ 335*3910Sdougm group = sa_get_group(handle, groupname); 3363034Sdougm if (group == NULL) { 337*3910Sdougm group = sa_create_group(handle, groupname, &ret); 3383108Sdougm 3393108Sdougm /* make sure this is flagged as a ZFS group */ 3403034Sdougm if (group != NULL) 3413034Sdougm ret = sa_set_group_attr(group, "zfs", "true"); 3423034Sdougm } 3433034Sdougm if (group != NULL) { 3443034Sdougm if (proto != NULL) { 3453034Sdougm optionset = sa_get_optionset(group, proto); 3463034Sdougm if (optionset == NULL) { 3473034Sdougm optionset = sa_create_optionset(group, proto); 3483034Sdougm } else { 3493034Sdougm char **protolist; 3503034Sdougm int numprotos, i; 3513034Sdougm numprotos = sa_get_protocols(&protolist); 3523034Sdougm for (i = 0; i < numprotos; i++) { 3533034Sdougm optionset = sa_create_optionset(group, protolist[i]); 3543034Sdougm } 3553034Sdougm if (protolist != NULL) 3563034Sdougm free(protolist); 3573034Sdougm } 3583034Sdougm } 3593034Sdougm } 3603034Sdougm if (err != NULL) 3613034Sdougm *err = ret; 3623034Sdougm return (group); 3633034Sdougm } 3643034Sdougm 3653034Sdougm /* 3663108Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 3673108Sdougm * 3683108Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 3693108Sdougm * function looks to see if the groupname exists and returns it if it 3703108Sdougm * does or else creates a new one with the specified name and returns 3713108Sdougm * that. The "zfs" group will exist before we get here, but we make 3723108Sdougm * sure just in case. 3733108Sdougm * 3743108Sdougm * err must be a valid pointer. 3753108Sdougm */ 3763108Sdougm 3773108Sdougm static sa_group_t 378*3910Sdougm find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, 379*3910Sdougm char *optstring, int *err) 3803108Sdougm { 3813108Sdougm sa_group_t group = NULL; 3823108Sdougm sa_group_t zfs; 3833108Sdougm char *name; 3843108Sdougm char *options; 3853108Sdougm 3863108Sdougm /* start with the top-level "zfs" group */ 387*3910Sdougm zfs = sa_get_group(handle, "zfs"); 3883108Sdougm *err = SA_OK; 3893108Sdougm if (zfs != NULL) { 3903108Sdougm for (group = sa_get_sub_group(zfs); group != NULL; 3913108Sdougm group = sa_get_next_group(group)) { 3923108Sdougm name = sa_get_group_attr(group, "name"); 3933108Sdougm if (name != NULL && strcmp(name, groupname) == 0) { 3943108Sdougm /* have the group so break out of here */ 3953108Sdougm sa_free_attr_string(name); 3963108Sdougm break; 3973108Sdougm } 3983108Sdougm if (name != NULL) 3993108Sdougm sa_free_attr_string(name); 4003108Sdougm } 4013108Sdougm 4023108Sdougm if (group == NULL) { 4033108Sdougm /* need to create the sub-group since it doesn't exist */ 4043108Sdougm group = _sa_create_zfs_group(zfs, groupname); 4053108Sdougm if (group != NULL) { 4063108Sdougm set_node_attr(group, "zfs", "true"); 4073108Sdougm } 4083108Sdougm if (strcmp(optstring, "on") == 0) 4093108Sdougm optstring = "rw"; 4103108Sdougm if (group != NULL) { 4113108Sdougm options = strdup(optstring); 4123108Sdougm if (options != NULL) { 4133108Sdougm *err = sa_parse_legacy_options(group, options, "nfs"); 4143108Sdougm free(options); 4153108Sdougm } else { 4163108Sdougm *err = SA_NO_MEMORY; 4173108Sdougm } 4183108Sdougm } 4193108Sdougm } 4203108Sdougm } 4213108Sdougm return (group); 4223108Sdougm } 4233108Sdougm 4243108Sdougm /* 425*3910Sdougm * sa_get_zfs_shares(handle, groupname) 4263034Sdougm * 4273034Sdougm * Walk the mnttab for all zfs mounts and determine which are 4283034Sdougm * shared. Find or create the appropriate group/sub-group to contain 4293034Sdougm * the shares. 4303034Sdougm * 4313034Sdougm * All shares are in a sub-group that will hold the properties. This 4323034Sdougm * allows representing the inherited property model. 4333034Sdougm */ 4343034Sdougm 4353034Sdougm int 436*3910Sdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 4373034Sdougm { 4383034Sdougm sa_group_t group; 4393034Sdougm sa_group_t zfsgroup; 4403034Sdougm int legacy = 0; 4413034Sdougm int err; 4423218Sdougm zfs_handle_t **zlist; 4433034Sdougm char shareopts[ZFS_MAXPROPLEN]; 4443034Sdougm sa_share_t share; 4453034Sdougm zfs_source_t source; 4463034Sdougm char sourcestr[ZFS_MAXPROPLEN]; 4473218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 4483108Sdougm char *options; 4493218Sdougm size_t count = 0, i; 450*3910Sdougm libzfs_handle_t *zfs_libhandle; 4513034Sdougm 4523034Sdougm /* 453*3910Sdougm * If we can't access libzfs, don't bother doing anything. 4543034Sdougm */ 455*3910Sdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 4563218Sdougm if (zfs_libhandle == NULL) 4573034Sdougm return (SA_SYSTEM_ERR); 4583034Sdougm 459*3910Sdougm zfsgroup = find_or_create_group(handle, groupname, "nfs", &err); 4603034Sdougm if (zfsgroup != NULL) { 4613034Sdougm /* 4623034Sdougm * need to walk the mounted ZFS pools and datasets to 4633034Sdougm * find shares that are possible. 4643034Sdougm */ 465*3910Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 4663218Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 4673218Sdougm 4683034Sdougm group = zfsgroup; 4693218Sdougm for (i = 0; i < count; i++) { 4703218Sdougm char *dataset; 4713218Sdougm 4723218Sdougm source = ZFS_SRC_ALL; 4733218Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 4743218Sdougm sizeof (mountpoint), NULL, NULL, 0, 4753218Sdougm B_FALSE) != 0) { 4763218Sdougm /* no mountpoint */ 4773218Sdougm continue; 4783218Sdougm } 4793218Sdougm 4803218Sdougm /* 4813218Sdougm * zfs_get_name value must not be freed. It is just a 4823218Sdougm * pointer to a value in the handle. 4833218Sdougm */ 4843218Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 4853218Sdougm continue; 4863218Sdougm 4873218Sdougm /* 4883218Sdougm * only deal with "mounted" file systems since 4893218Sdougm * unmounted file systems can't actually be shared. 4903218Sdougm */ 4913218Sdougm 4923218Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 4933218Sdougm continue; 4943218Sdougm 4953218Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 4963034Sdougm sizeof (shareopts), &source, sourcestr, 4973034Sdougm ZFS_MAXPROPLEN, 4983218Sdougm B_FALSE) == 0 && 4993034Sdougm strcmp(shareopts, "off") != 0) { 5003218Sdougm /* it is shared so add to list */ 501*3910Sdougm share = sa_find_share(handle, mountpoint); 5023218Sdougm err = SA_OK; 5033218Sdougm if (share != NULL) { 5043218Sdougm /* 5053218Sdougm * A zfs file system had been shared 5063218Sdougm * through traditional methods 5073218Sdougm * (share/dfstab or added to a non-zfs 5083218Sdougm * group. Now it has been added to a 5093218Sdougm * ZFS group via the zfs 5103218Sdougm * command. Remove from previous 5113218Sdougm * config and setup with current 5123218Sdougm * options. 5133218Sdougm */ 5143218Sdougm err = sa_remove_share(share); 5153218Sdougm share = NULL; 5163218Sdougm } 5173218Sdougm if (err == SA_OK) { 5183218Sdougm if (source & ZFS_SRC_INHERITED) { 5193218Sdougm int doshopt = 0; 5203218Sdougm /* 5213218Sdougm * Need to find the "real" parent 5223218Sdougm * sub-group. It may not be mounted, but it 5233218Sdougm * was identified in the "sourcestr" 5243218Sdougm * variable. The real parent not mounted can 5253218Sdougm * occur if "canmount=off and sharenfs=on". 5263218Sdougm */ 527*3910Sdougm group = find_or_create_zfs_subgroup(handle, 528*3910Sdougm sourcestr, 5293218Sdougm shareopts, &doshopt); 5303218Sdougm if (group != NULL) { 5313218Sdougm share = _sa_add_share(group, mountpoint, 5323034Sdougm SA_SHARE_TRANSIENT, 5333034Sdougm &err); 5343218Sdougm /* 5353218Sdougm * some options may only be on 5363218Sdougm * shares. If the opt string 5373218Sdougm * contains one of those, we 5383218Sdougm * put it just on the share. 5393218Sdougm */ 5403218Sdougm if (share != NULL && 5413218Sdougm doshopt == SA_PROP_SHARE_ONLY) { 5423218Sdougm options = strdup(shareopts); 5433218Sdougm if (options != NULL) { 5443218Sdougm err = sa_parse_legacy_options(share, 5453108Sdougm options, "nfs"); 5463218Sdougm free(options); 5473108Sdougm } 5483108Sdougm } 5493034Sdougm } else { 5503218Sdougm err = SA_NO_MEMORY; 5513218Sdougm } 5523218Sdougm } else { 5533218Sdougm group = _sa_create_zfs_group(zfsgroup, dataset); 5543218Sdougm if (group == NULL) { 5553218Sdougm static int err = 0; 5563108Sdougm /* 5573218Sdougm * there is a problem, but we can't do 5583218Sdougm * anything about it at this point so 5593218Sdougm * we issue a warning an move on. 5603108Sdougm */ 5613218Sdougm if (err == 0) { 5623218Sdougm /* only print error once */ 5633218Sdougm (void) fprintf(stderr, 5643407Sdougm dgettext(TEXT_DOMAIN, 5653407Sdougm "Cannot create ZFS subgroup " 5663218Sdougm "during initialization:" 5673218Sdougm " %s\n"), 5683218Sdougm sa_errorstr(SA_SYSTEM_ERR)); 5693218Sdougm err = 1; 5703218Sdougm } 5713218Sdougm continue; 5723218Sdougm } 5733218Sdougm set_node_attr(group, "zfs", "true"); 5743218Sdougm share = _sa_add_share(group, mountpoint, 5753218Sdougm SA_SHARE_TRANSIENT, &err); 5763218Sdougm if (err == SA_OK) { 5773218Sdougm if (strcmp(shareopts, "on") != 0) { 5783218Sdougm options = strdup(shareopts); 5793218Sdougm if (options != NULL) { 5803218Sdougm err = sa_parse_legacy_options(group, 5813034Sdougm options, 5823034Sdougm "nfs"); 5833218Sdougm free(options); 5843218Sdougm } 5853218Sdougm if (err == SA_PROP_SHARE_ONLY) { 5863108Sdougm /* 5873108Sdougm * Same as above, some 5883108Sdougm * properties may only be on 5893108Sdougm * shares, but due to the ZFS 5903108Sdougm * sub-groups being 5913108Sdougm * artificial, we sometimes 5923108Sdougm * get this and have to deal 5933108Sdougm * with it. We do it by 5943108Sdougm * attempting to put it on the 5953108Sdougm * share. 5963108Sdougm */ 5973218Sdougm options = strdup(shareopts); 5983218Sdougm if (options != NULL) 5993218Sdougm err = sa_parse_legacy_options( 6003108Sdougm share, 6013108Sdougm options, 6023108Sdougm "nfs"); 6033108Sdougm free(options); 6043108Sdougm } 6053218Sdougm /* unmark the share's changed state */ 6063218Sdougm set_node_attr(share, "changed", NULL); 6073034Sdougm } 6083034Sdougm } 6093034Sdougm } 6103034Sdougm } 6113034Sdougm } 6123034Sdougm } 6133034Sdougm } 6143218Sdougm /* 6153218Sdougm * Don't need to free the "zlist" variable since it is only a 6163218Sdougm * pointer to a cached value that will be freed when 6173218Sdougm * sa_fini() is called. 6183218Sdougm */ 6193034Sdougm return (legacy); 6203034Sdougm } 6213034Sdougm 6223034Sdougm #define COMMAND "/usr/sbin/zfs" 6233034Sdougm 6243034Sdougm /* 6253034Sdougm * sa_zfs_set_sharenfs(group, path, on) 6263034Sdougm * 6273034Sdougm * Update the "sharenfs" property on the path. If on is true, then set 6283034Sdougm * to the properties on the group or "on" if no properties are 6293034Sdougm * defined. Set to "off" if on is false. 6303034Sdougm */ 6313034Sdougm 6323034Sdougm int 6333034Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 6343034Sdougm { 6353034Sdougm int ret = SA_NOT_IMPLEMENTED; 6363034Sdougm char *command; 6373034Sdougm 6383034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 6393034Sdougm if (command != NULL) { 6403034Sdougm char *opts = NULL; 641*3910Sdougm char *dataset = NULL; 6423034Sdougm FILE *pfile; 643*3910Sdougm sa_handle_impl_t impl_handle; 6443034Sdougm /* for now, NFS is always available for "zfs" */ 6453034Sdougm if (on) { 6463034Sdougm opts = sa_proto_legacy_format("nfs", group, 1); 6473034Sdougm if (opts != NULL && strlen(opts) == 0) { 6483034Sdougm free(opts); 6493034Sdougm opts = strdup("on"); 6503034Sdougm } 6513034Sdougm } 652*3910Sdougm 653*3910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 654*3910Sdougm if (impl_handle != NULL) 655*3910Sdougm dataset = get_zfs_dataset(impl_handle, path); 656*3910Sdougm else 657*3910Sdougm ret = SA_SYSTEM_ERR; 658*3910Sdougm 6593034Sdougm if (dataset != NULL) { 6603034Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 6613034Sdougm "%s set sharenfs=\"%s\" %s", COMMAND, 6623034Sdougm opts != NULL ? opts : "off", 6633034Sdougm dataset); 6643034Sdougm pfile = popen(command, "r"); 6653034Sdougm if (pfile != NULL) { 6663034Sdougm ret = pclose(pfile); 6673034Sdougm if (ret != 0) 6683034Sdougm ret = SA_SYSTEM_ERR; 6693034Sdougm } 6703034Sdougm } 6713034Sdougm if (opts != NULL) 6723034Sdougm free(opts); 6733034Sdougm if (dataset != NULL) 6743034Sdougm free(dataset); 6753034Sdougm free(command); 6763034Sdougm } 6773034Sdougm return (ret); 6783034Sdougm } 6793034Sdougm 6803034Sdougm /* 6813034Sdougm * sa_zfs_update(group) 6823034Sdougm * 6833034Sdougm * call back to ZFS to update the share if necessary. 6843034Sdougm * Don't do it if it isn't a real change. 6853034Sdougm */ 6863034Sdougm int 6873034Sdougm sa_zfs_update(sa_group_t group) 6883034Sdougm { 6893034Sdougm sa_optionset_t protopt; 6903034Sdougm sa_group_t parent; 6913034Sdougm char *command; 6923034Sdougm char *optstring; 6933034Sdougm int ret = SA_OK; 6943034Sdougm int doupdate = 0; 6953034Sdougm FILE *pfile; 6963034Sdougm 6973034Sdougm if (sa_is_share(group)) 6983034Sdougm parent = sa_get_parent_group(group); 6993034Sdougm else 7003034Sdougm parent = group; 7013034Sdougm 7023034Sdougm if (parent != NULL) { 7033034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 7043034Sdougm if (command == NULL) 7053034Sdougm return (SA_NO_MEMORY); 7063034Sdougm 7073034Sdougm *command = '\0'; 7083034Sdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 7093034Sdougm protopt = sa_get_next_optionset(protopt)) { 7103034Sdougm 7113034Sdougm char *proto = sa_get_optionset_attr(protopt, "type"); 7123034Sdougm char *path; 7133034Sdougm char *dataset = NULL; 7143034Sdougm char *zfsopts = NULL; 7153034Sdougm 7163034Sdougm if (sa_is_share(group)) { 7173034Sdougm path = sa_get_share_attr((sa_share_t)group, "path"); 7183034Sdougm if (path != NULL) { 719*3910Sdougm sa_handle_impl_t impl_handle; 720*3910Sdougm 721*3910Sdougm impl_handle = sa_find_group_handle(group); 722*3910Sdougm if (impl_handle != NULL) 723*3910Sdougm dataset = get_zfs_dataset(impl_handle, path); 724*3910Sdougm else 725*3910Sdougm ret = SA_SYSTEM_ERR; 726*3910Sdougm 7273034Sdougm sa_free_attr_string(path); 7283034Sdougm } 7293034Sdougm } else { 7303034Sdougm dataset = sa_get_group_attr(group, "name"); 7313034Sdougm } 7323034Sdougm /* update only when there is an optstring found */ 7333034Sdougm doupdate = 0; 7343034Sdougm if (proto != NULL && dataset != NULL) { 7353034Sdougm optstring = sa_proto_legacy_format(proto, group, 1); 7363034Sdougm zfsopts = get_zfs_property(dataset, ZFS_PROP_SHARENFS); 7373034Sdougm 7383034Sdougm if (optstring != NULL && zfsopts != NULL) { 7393034Sdougm if (strcmp(optstring, zfsopts) != 0) 7403034Sdougm doupdate++; 7413034Sdougm } 7423034Sdougm 7433034Sdougm if (doupdate) { 7443034Sdougm if (optstring != NULL && strlen(optstring) > 0) { 7453034Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 7463034Sdougm "%s set sharenfs=%s %s", COMMAND, 7473034Sdougm optstring, dataset); 7483034Sdougm } else { 7493034Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 7503034Sdougm "%s set sharenfs=on %s", COMMAND, 7513034Sdougm dataset); 7523034Sdougm } 7533034Sdougm pfile = popen(command, "r"); 7543034Sdougm if (pfile != NULL) 7553034Sdougm ret = pclose(pfile); 7563034Sdougm switch (ret) { 7573034Sdougm default: 7583034Sdougm case 1: 7593034Sdougm ret = SA_SYSTEM_ERR; 7603034Sdougm break; 7613034Sdougm case 2: 7623034Sdougm ret = SA_SYNTAX_ERR; 7633034Sdougm break; 7643034Sdougm case 0: 7653034Sdougm break; 7663034Sdougm } 7673034Sdougm } 7683034Sdougm if (optstring != NULL) { 7693034Sdougm free(optstring); 7703034Sdougm } 7713034Sdougm if (zfsopts != NULL) 7723034Sdougm free(zfsopts); 7733034Sdougm } 7743034Sdougm if (proto != NULL) 7753034Sdougm sa_free_attr_string(proto); 7763034Sdougm if (dataset != NULL) 7773034Sdougm free(dataset); 7783034Sdougm } 7793034Sdougm free(command); 7803034Sdougm } 7813034Sdougm return (ret); 7823034Sdougm } 7833034Sdougm 7843034Sdougm /* 7853034Sdougm * sa_group_is_zfs(group) 7863034Sdougm * 7873034Sdougm * Given the group, determine if the zfs attribute is set. 7883034Sdougm */ 7893034Sdougm 7903034Sdougm int 7913034Sdougm sa_group_is_zfs(sa_group_t group) 7923034Sdougm { 7933034Sdougm char *zfs; 7943034Sdougm int ret = 0; 7953034Sdougm 7963034Sdougm zfs = sa_get_group_attr(group, "zfs"); 7973034Sdougm if (zfs != NULL) { 7983034Sdougm ret = 1; 7993034Sdougm sa_free_attr_string(zfs); 8003034Sdougm } 8013034Sdougm return (ret); 8023034Sdougm } 8033034Sdougm 8043034Sdougm /* 8053034Sdougm * sa_path_is_zfs(path) 8063034Sdougm * 8073034Sdougm * Check to see if the file system path represents is of type "zfs". 8083034Sdougm */ 8093034Sdougm 8103034Sdougm int 8113034Sdougm sa_path_is_zfs(char *path) 8123034Sdougm { 8133034Sdougm char *fstype; 8143034Sdougm int ret = 0; 8153034Sdougm 8163034Sdougm fstype = sa_fstype(path); 8173034Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 8183034Sdougm ret = 1; 8193034Sdougm } 8203034Sdougm if (fstype != NULL) 8213034Sdougm sa_free_fstype(fstype); 8223034Sdougm return (ret); 8233034Sdougm } 824