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 /* 543910Sdougm * sa_zfs_init(impl_handle) 553218Sdougm * 563910Sdougm * Initialize an access handle into libzfs. The handle needs to stay 573910Sdougm * around until sa_zfs_fini() in order to maintain the cache of 583910Sdougm * mounts. 593218Sdougm */ 603218Sdougm 613218Sdougm void 623910Sdougm sa_zfs_init(sa_handle_impl_t impl_handle) 633218Sdougm { 643910Sdougm impl_handle->zfs_libhandle = libzfs_init(); 653910Sdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 663218Sdougm } 673218Sdougm 683218Sdougm /* 693910Sdougm * 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 763910Sdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 773218Sdougm { 783910Sdougm if (impl_handle->zfs_libhandle != NULL) { 793910Sdougm libzfs_fini(impl_handle->zfs_libhandle); 803910Sdougm impl_handle->zfs_libhandle = NULL; 813910Sdougm if (impl_handle->zfs_list != NULL) { 823218Sdougm /* 833218Sdougm * contents of zfs_list were already freed by the call to 843218Sdougm * libzfs_fini(). 853218Sdougm */ 863910Sdougm free(impl_handle->zfs_list); 873910Sdougm impl_handle->zfs_list = NULL; 883910Sdougm 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 1513910Sdougm get_all_filesystems(sa_handle_impl_t impl_handle, 1523910Sdougm zfs_handle_t ***fslist, size_t *count) 1533218Sdougm { 1543218Sdougm get_all_cbdata_t cb = { 0 }; 1553218Sdougm 1563910Sdougm if (impl_handle->zfs_list != NULL) { 1573910Sdougm *fslist = impl_handle->zfs_list; 1583910Sdougm *count = impl_handle->zfs_list_count; 1593218Sdougm return; 1603218Sdougm } 1613218Sdougm 1623910Sdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 1633910Sdougm get_one_filesystem, &cb); 1643218Sdougm 1653910Sdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 1663910Sdougm 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 /* 1933910Sdougm * 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 * 2013910Sdougm 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]; 207*4180Sdougm char canmount[ZFS_MAXPROPLEN]; 2083218Sdougm 2093910Sdougm get_all_filesystems(impl_handle, &zlist, &count); 2103218Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2113218Sdougm for (i = 0; i < count; i++) { 2123218Sdougm /* must have a mountpoint */ 2133218Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 2143218Sdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 2153218Sdougm /* no mountpoint */ 2163218Sdougm continue; 2173218Sdougm } 2183034Sdougm 2193218Sdougm /* mountpoint must be a path */ 2203218Sdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 2213218Sdougm strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 2223218Sdougm continue; 2233218Sdougm 2243218Sdougm /* canmount must be set */ 225*4180Sdougm canmount[0] = '\0'; 226*4180Sdougm if (!zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 227*4180Sdougm sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 228*4180Sdougm strcmp(canmount, "off") == 0) 2293218Sdougm continue; 2303218Sdougm 2313218Sdougm /* 2323218Sdougm * have a mountable handle but want to skip those marked none 2333218Sdougm * and legacy 2343218Sdougm */ 2353218Sdougm if (strcmp(mountpoint, path) == 0) { 2363218Sdougm dataset = (char *)zfs_get_name(zlist[i]); 2373218Sdougm break; 2383034Sdougm } 2393218Sdougm 2403034Sdougm } 2413218Sdougm 2423034Sdougm if (dataset != NULL) { 2433034Sdougm dataset = strdup(dataset); 2443034Sdougm } 2453034Sdougm return (dataset); 2463034Sdougm } 2473034Sdougm 2483034Sdougm /* 2493034Sdougm * get_zfs_property(dataset, property) 2503034Sdougm * 2513034Sdougm * Get the file system property specified from the ZFS dataset. 2523034Sdougm */ 2533034Sdougm 2543034Sdougm static char * 2553034Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 2563034Sdougm { 2573034Sdougm zfs_handle_t *handle = NULL; 2583034Sdougm char shareopts[ZFS_MAXPROPLEN]; 2593034Sdougm libzfs_handle_t *libhandle; 2603034Sdougm 2613034Sdougm libhandle = libzfs_init(); 2623034Sdougm if (libhandle != NULL) { 2633034Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 2643034Sdougm if (handle != NULL) { 2653034Sdougm if (zfs_prop_get(handle, property, shareopts, 2663034Sdougm sizeof (shareopts), NULL, NULL, 0, 2673218Sdougm B_FALSE) == 0) { 2683034Sdougm zfs_close(handle); 2693034Sdougm libzfs_fini(libhandle); 2703034Sdougm return (strdup(shareopts)); 2713034Sdougm } 2723034Sdougm zfs_close(handle); 2733034Sdougm } 2743034Sdougm libzfs_fini(libhandle); 2753034Sdougm } 2763034Sdougm return (NULL); 2773034Sdougm } 2783034Sdougm 2793034Sdougm /* 2803910Sdougm * sa_zfs_is_shared(handle, path) 2813034Sdougm * 2823034Sdougm * Check to see if the ZFS path provided has the sharenfs option set 2833034Sdougm * or not. 2843034Sdougm */ 2853034Sdougm 2863034Sdougm int 2873910Sdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 2883034Sdougm { 2893034Sdougm int ret = 0; 2903034Sdougm char *dataset; 2913034Sdougm zfs_handle_t *handle = NULL; 2923034Sdougm char shareopts[ZFS_MAXPROPLEN]; 2933034Sdougm libzfs_handle_t *libhandle; 2943034Sdougm 2953910Sdougm dataset = get_zfs_dataset((sa_handle_t)sahandle, path); 2963034Sdougm if (dataset != NULL) { 2973034Sdougm libhandle = libzfs_init(); 2983034Sdougm if (libhandle != NULL) { 2993034Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 3003034Sdougm if (handle != NULL) { 3013034Sdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, shareopts, 3023034Sdougm sizeof (shareopts), NULL, NULL, 0, 3033218Sdougm B_FALSE) == 0 && 3043034Sdougm strcmp(shareopts, "off") != 0) 3053034Sdougm ret = 1; /* it is shared */ 3063034Sdougm zfs_close(handle); 3073034Sdougm } 3083034Sdougm libzfs_fini(libhandle); 3093034Sdougm } 3103034Sdougm free(dataset); 3113034Sdougm } 3123034Sdougm return (ret); 3133034Sdougm } 3143034Sdougm 3153034Sdougm /* 3163034Sdougm * find_or_create_group(groupname, proto, *err) 3173034Sdougm * 3183034Sdougm * While walking the ZFS tree, we need to add shares to a defined 3193034Sdougm * group. If the group doesn't exist, create it first, making sure it 3203034Sdougm * is marked as a ZFS group. 3213034Sdougm * 3223108Sdougm * Note that all ZFS shares are in a subgroup of the top level group 3233108Sdougm * called "zfs". 3243034Sdougm */ 3253034Sdougm 3263034Sdougm static sa_group_t 3273910Sdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 3283034Sdougm { 3293034Sdougm sa_group_t group; 3303034Sdougm sa_optionset_t optionset; 3313034Sdougm int ret = SA_OK; 3323034Sdougm 3333034Sdougm /* 3343034Sdougm * we check to see if the "zfs" group exists. Since this 3353034Sdougm * should be the top level group, we don't want the 3363034Sdougm * parent. This is to make sure the zfs group has been created 3373034Sdougm * and to created if it hasn't been. 3383034Sdougm */ 3393910Sdougm group = sa_get_group(handle, groupname); 3403034Sdougm if (group == NULL) { 3413910Sdougm group = sa_create_group(handle, groupname, &ret); 3423108Sdougm 3433108Sdougm /* make sure this is flagged as a ZFS group */ 3443034Sdougm if (group != NULL) 3453034Sdougm ret = sa_set_group_attr(group, "zfs", "true"); 3463034Sdougm } 3473034Sdougm if (group != NULL) { 3483034Sdougm if (proto != NULL) { 3493034Sdougm optionset = sa_get_optionset(group, proto); 3503034Sdougm if (optionset == NULL) { 3513034Sdougm optionset = sa_create_optionset(group, proto); 3523034Sdougm } else { 3533034Sdougm char **protolist; 3543034Sdougm int numprotos, i; 3553034Sdougm numprotos = sa_get_protocols(&protolist); 3563034Sdougm for (i = 0; i < numprotos; i++) { 3573034Sdougm optionset = sa_create_optionset(group, protolist[i]); 3583034Sdougm } 3593034Sdougm if (protolist != NULL) 3603034Sdougm free(protolist); 3613034Sdougm } 3623034Sdougm } 3633034Sdougm } 3643034Sdougm if (err != NULL) 3653034Sdougm *err = ret; 3663034Sdougm return (group); 3673034Sdougm } 3683034Sdougm 3693034Sdougm /* 3703108Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 3713108Sdougm * 3723108Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 3733108Sdougm * function looks to see if the groupname exists and returns it if it 3743108Sdougm * does or else creates a new one with the specified name and returns 3753108Sdougm * that. The "zfs" group will exist before we get here, but we make 3763108Sdougm * sure just in case. 3773108Sdougm * 3783108Sdougm * err must be a valid pointer. 3793108Sdougm */ 3803108Sdougm 3813108Sdougm static sa_group_t 3823910Sdougm find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, 3833910Sdougm char *optstring, int *err) 3843108Sdougm { 3853108Sdougm sa_group_t group = NULL; 3863108Sdougm sa_group_t zfs; 3873108Sdougm char *name; 3883108Sdougm char *options; 3893108Sdougm 3903108Sdougm /* start with the top-level "zfs" group */ 3913910Sdougm zfs = sa_get_group(handle, "zfs"); 3923108Sdougm *err = SA_OK; 3933108Sdougm if (zfs != NULL) { 3943108Sdougm for (group = sa_get_sub_group(zfs); group != NULL; 3953108Sdougm group = sa_get_next_group(group)) { 3963108Sdougm name = sa_get_group_attr(group, "name"); 3973108Sdougm if (name != NULL && strcmp(name, groupname) == 0) { 3983108Sdougm /* have the group so break out of here */ 3993108Sdougm sa_free_attr_string(name); 4003108Sdougm break; 4013108Sdougm } 4023108Sdougm if (name != NULL) 4033108Sdougm sa_free_attr_string(name); 4043108Sdougm } 4053108Sdougm 4063108Sdougm if (group == NULL) { 4073108Sdougm /* need to create the sub-group since it doesn't exist */ 4083108Sdougm group = _sa_create_zfs_group(zfs, groupname); 4093108Sdougm if (group != NULL) { 4103108Sdougm set_node_attr(group, "zfs", "true"); 4113108Sdougm } 4123108Sdougm if (strcmp(optstring, "on") == 0) 4133108Sdougm optstring = "rw"; 4143108Sdougm if (group != NULL) { 4153108Sdougm options = strdup(optstring); 4163108Sdougm if (options != NULL) { 4173108Sdougm *err = sa_parse_legacy_options(group, options, "nfs"); 4183108Sdougm free(options); 4193108Sdougm } else { 4203108Sdougm *err = SA_NO_MEMORY; 4213108Sdougm } 4223108Sdougm } 4233108Sdougm } 4243108Sdougm } 4253108Sdougm return (group); 4263108Sdougm } 4273108Sdougm 4283108Sdougm /* 4293910Sdougm * sa_get_zfs_shares(handle, groupname) 4303034Sdougm * 4313034Sdougm * Walk the mnttab for all zfs mounts and determine which are 4323034Sdougm * shared. Find or create the appropriate group/sub-group to contain 4333034Sdougm * the shares. 4343034Sdougm * 4353034Sdougm * All shares are in a sub-group that will hold the properties. This 4363034Sdougm * allows representing the inherited property model. 4373034Sdougm */ 4383034Sdougm 4393034Sdougm int 4403910Sdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 4413034Sdougm { 4423034Sdougm sa_group_t group; 4433034Sdougm sa_group_t zfsgroup; 4443034Sdougm int legacy = 0; 4453034Sdougm int err; 4463218Sdougm zfs_handle_t **zlist; 4473034Sdougm char shareopts[ZFS_MAXPROPLEN]; 4483034Sdougm sa_share_t share; 4493034Sdougm zfs_source_t source; 4503034Sdougm char sourcestr[ZFS_MAXPROPLEN]; 4513218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 4523108Sdougm char *options; 4533218Sdougm size_t count = 0, i; 4543910Sdougm libzfs_handle_t *zfs_libhandle; 4553034Sdougm 4563034Sdougm /* 4573910Sdougm * If we can't access libzfs, don't bother doing anything. 4583034Sdougm */ 4593910Sdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 4603218Sdougm if (zfs_libhandle == NULL) 4613034Sdougm return (SA_SYSTEM_ERR); 4623034Sdougm 4633910Sdougm zfsgroup = find_or_create_group(handle, groupname, "nfs", &err); 4643034Sdougm if (zfsgroup != NULL) { 4653034Sdougm /* 4663034Sdougm * need to walk the mounted ZFS pools and datasets to 4673034Sdougm * find shares that are possible. 4683034Sdougm */ 4693910Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 4703218Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 4713218Sdougm 4723034Sdougm group = zfsgroup; 4733218Sdougm for (i = 0; i < count; i++) { 4743218Sdougm char *dataset; 4753218Sdougm 4763218Sdougm source = ZFS_SRC_ALL; 4773218Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 4783218Sdougm sizeof (mountpoint), NULL, NULL, 0, 4793218Sdougm B_FALSE) != 0) { 4803218Sdougm /* no mountpoint */ 4813218Sdougm continue; 4823218Sdougm } 4833218Sdougm 4843218Sdougm /* 4853218Sdougm * zfs_get_name value must not be freed. It is just a 4863218Sdougm * pointer to a value in the handle. 4873218Sdougm */ 4883218Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 4893218Sdougm continue; 4903218Sdougm 4913218Sdougm /* 4923218Sdougm * only deal with "mounted" file systems since 4933218Sdougm * unmounted file systems can't actually be shared. 4943218Sdougm */ 4953218Sdougm 4963218Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 4973218Sdougm continue; 4983218Sdougm 4993218Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 5003034Sdougm sizeof (shareopts), &source, sourcestr, 5013034Sdougm ZFS_MAXPROPLEN, 5023218Sdougm B_FALSE) == 0 && 5033034Sdougm strcmp(shareopts, "off") != 0) { 5043218Sdougm /* it is shared so add to list */ 5053910Sdougm share = sa_find_share(handle, mountpoint); 5063218Sdougm err = SA_OK; 5073218Sdougm if (share != NULL) { 5083218Sdougm /* 5093218Sdougm * A zfs file system had been shared 5103218Sdougm * through traditional methods 5113218Sdougm * (share/dfstab or added to a non-zfs 5123218Sdougm * group. Now it has been added to a 5133218Sdougm * ZFS group via the zfs 5143218Sdougm * command. Remove from previous 5153218Sdougm * config and setup with current 5163218Sdougm * options. 5173218Sdougm */ 5183218Sdougm err = sa_remove_share(share); 5193218Sdougm share = NULL; 5203218Sdougm } 5213218Sdougm if (err == SA_OK) { 5223218Sdougm if (source & ZFS_SRC_INHERITED) { 5233218Sdougm int doshopt = 0; 5243218Sdougm /* 5253218Sdougm * Need to find the "real" parent 5263218Sdougm * sub-group. It may not be mounted, but it 5273218Sdougm * was identified in the "sourcestr" 5283218Sdougm * variable. The real parent not mounted can 5293218Sdougm * occur if "canmount=off and sharenfs=on". 5303218Sdougm */ 5313910Sdougm group = find_or_create_zfs_subgroup(handle, 5323910Sdougm sourcestr, 5333218Sdougm shareopts, &doshopt); 5343218Sdougm if (group != NULL) { 5353218Sdougm share = _sa_add_share(group, mountpoint, 5363034Sdougm SA_SHARE_TRANSIENT, 5373034Sdougm &err); 5383218Sdougm /* 5393218Sdougm * some options may only be on 5403218Sdougm * shares. If the opt string 5413218Sdougm * contains one of those, we 5423218Sdougm * put it just on the share. 5433218Sdougm */ 5443218Sdougm if (share != NULL && 5453218Sdougm doshopt == SA_PROP_SHARE_ONLY) { 5463218Sdougm options = strdup(shareopts); 5473218Sdougm if (options != NULL) { 5483218Sdougm err = sa_parse_legacy_options(share, 5493108Sdougm options, "nfs"); 5503218Sdougm free(options); 5513108Sdougm } 5523108Sdougm } 5533034Sdougm } else { 5543218Sdougm err = SA_NO_MEMORY; 5553218Sdougm } 5563218Sdougm } else { 5573218Sdougm group = _sa_create_zfs_group(zfsgroup, dataset); 5583218Sdougm if (group == NULL) { 5593218Sdougm static int err = 0; 5603108Sdougm /* 5613218Sdougm * there is a problem, but we can't do 5623218Sdougm * anything about it at this point so 5633218Sdougm * we issue a warning an move on. 5643108Sdougm */ 5653218Sdougm if (err == 0) { 5663218Sdougm /* only print error once */ 5673218Sdougm (void) fprintf(stderr, 5683407Sdougm dgettext(TEXT_DOMAIN, 5693407Sdougm "Cannot create ZFS subgroup " 5703218Sdougm "during initialization:" 5713218Sdougm " %s\n"), 5723218Sdougm sa_errorstr(SA_SYSTEM_ERR)); 5733218Sdougm err = 1; 5743218Sdougm } 5753218Sdougm continue; 5763218Sdougm } 5773218Sdougm set_node_attr(group, "zfs", "true"); 5783218Sdougm share = _sa_add_share(group, mountpoint, 5793218Sdougm SA_SHARE_TRANSIENT, &err); 5803218Sdougm if (err == SA_OK) { 5813218Sdougm if (strcmp(shareopts, "on") != 0) { 5823218Sdougm options = strdup(shareopts); 5833218Sdougm if (options != NULL) { 5843218Sdougm err = sa_parse_legacy_options(group, 5853034Sdougm options, 5863034Sdougm "nfs"); 5873218Sdougm free(options); 5883218Sdougm } 5893218Sdougm if (err == SA_PROP_SHARE_ONLY) { 5903108Sdougm /* 5913108Sdougm * Same as above, some 5923108Sdougm * properties may only be on 5933108Sdougm * shares, but due to the ZFS 5943108Sdougm * sub-groups being 5953108Sdougm * artificial, we sometimes 5963108Sdougm * get this and have to deal 5973108Sdougm * with it. We do it by 5983108Sdougm * attempting to put it on the 5993108Sdougm * share. 6003108Sdougm */ 6013218Sdougm options = strdup(shareopts); 6023218Sdougm if (options != NULL) 6033218Sdougm err = sa_parse_legacy_options( 6043108Sdougm share, 6053108Sdougm options, 6063108Sdougm "nfs"); 6073108Sdougm free(options); 6083108Sdougm } 6093218Sdougm /* unmark the share's changed state */ 6103218Sdougm set_node_attr(share, "changed", NULL); 6113034Sdougm } 6123034Sdougm } 6133034Sdougm } 6143034Sdougm } 6153034Sdougm } 6163034Sdougm } 6173034Sdougm } 6183218Sdougm /* 6193218Sdougm * Don't need to free the "zlist" variable since it is only a 6203218Sdougm * pointer to a cached value that will be freed when 6213218Sdougm * sa_fini() is called. 6223218Sdougm */ 6233034Sdougm return (legacy); 6243034Sdougm } 6253034Sdougm 6263034Sdougm #define COMMAND "/usr/sbin/zfs" 6273034Sdougm 6283034Sdougm /* 6293034Sdougm * sa_zfs_set_sharenfs(group, path, on) 6303034Sdougm * 6313034Sdougm * Update the "sharenfs" property on the path. If on is true, then set 6323034Sdougm * to the properties on the group or "on" if no properties are 6333034Sdougm * defined. Set to "off" if on is false. 6343034Sdougm */ 6353034Sdougm 6363034Sdougm int 6373034Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 6383034Sdougm { 6393034Sdougm int ret = SA_NOT_IMPLEMENTED; 6403034Sdougm char *command; 6413034Sdougm 6423034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 6433034Sdougm if (command != NULL) { 6443034Sdougm char *opts = NULL; 6453910Sdougm char *dataset = NULL; 6463034Sdougm FILE *pfile; 6473910Sdougm sa_handle_impl_t impl_handle; 6483034Sdougm /* for now, NFS is always available for "zfs" */ 6493034Sdougm if (on) { 6503034Sdougm opts = sa_proto_legacy_format("nfs", group, 1); 6513034Sdougm if (opts != NULL && strlen(opts) == 0) { 6523034Sdougm free(opts); 6533034Sdougm opts = strdup("on"); 6543034Sdougm } 6553034Sdougm } 6563910Sdougm 6573910Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 658*4180Sdougm assert(impl_handle != NULL); 6593910Sdougm if (impl_handle != NULL) 6603910Sdougm dataset = get_zfs_dataset(impl_handle, path); 6613910Sdougm else 6623910Sdougm ret = SA_SYSTEM_ERR; 6633910Sdougm 6643034Sdougm if (dataset != NULL) { 6653034Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 6663034Sdougm "%s set sharenfs=\"%s\" %s", COMMAND, 6673034Sdougm opts != NULL ? opts : "off", 6683034Sdougm dataset); 6693034Sdougm pfile = popen(command, "r"); 6703034Sdougm if (pfile != NULL) { 6713034Sdougm ret = pclose(pfile); 6723034Sdougm if (ret != 0) 6733034Sdougm ret = SA_SYSTEM_ERR; 6743034Sdougm } 6753034Sdougm } 6763034Sdougm if (opts != NULL) 6773034Sdougm free(opts); 6783034Sdougm if (dataset != NULL) 6793034Sdougm free(dataset); 6803034Sdougm free(command); 6813034Sdougm } 6823034Sdougm return (ret); 6833034Sdougm } 6843034Sdougm 6853034Sdougm /* 6863034Sdougm * sa_zfs_update(group) 6873034Sdougm * 6883034Sdougm * call back to ZFS to update the share if necessary. 6893034Sdougm * Don't do it if it isn't a real change. 6903034Sdougm */ 6913034Sdougm int 6923034Sdougm sa_zfs_update(sa_group_t group) 6933034Sdougm { 6943034Sdougm sa_optionset_t protopt; 6953034Sdougm sa_group_t parent; 6963034Sdougm char *command; 6973034Sdougm char *optstring; 6983034Sdougm int ret = SA_OK; 6993034Sdougm int doupdate = 0; 7003034Sdougm FILE *pfile; 7013034Sdougm 7023034Sdougm if (sa_is_share(group)) 7033034Sdougm parent = sa_get_parent_group(group); 7043034Sdougm else 7053034Sdougm parent = group; 7063034Sdougm 7073034Sdougm if (parent != NULL) { 7083034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 7093034Sdougm if (command == NULL) 7103034Sdougm return (SA_NO_MEMORY); 7113034Sdougm 7123034Sdougm *command = '\0'; 7133034Sdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 7143034Sdougm protopt = sa_get_next_optionset(protopt)) { 7153034Sdougm 7163034Sdougm char *proto = sa_get_optionset_attr(protopt, "type"); 7173034Sdougm char *path; 7183034Sdougm char *dataset = NULL; 7193034Sdougm char *zfsopts = NULL; 7203034Sdougm 7213034Sdougm if (sa_is_share(group)) { 7223034Sdougm path = sa_get_share_attr((sa_share_t)group, "path"); 7233034Sdougm if (path != NULL) { 7243910Sdougm sa_handle_impl_t impl_handle; 7253910Sdougm 7263910Sdougm impl_handle = sa_find_group_handle(group); 7273910Sdougm if (impl_handle != NULL) 7283910Sdougm dataset = get_zfs_dataset(impl_handle, path); 7293910Sdougm else 7303910Sdougm ret = SA_SYSTEM_ERR; 7313910Sdougm 7323034Sdougm sa_free_attr_string(path); 7333034Sdougm } 7343034Sdougm } else { 7353034Sdougm dataset = sa_get_group_attr(group, "name"); 7363034Sdougm } 7373034Sdougm /* update only when there is an optstring found */ 7383034Sdougm doupdate = 0; 7393034Sdougm if (proto != NULL && dataset != NULL) { 7403034Sdougm optstring = sa_proto_legacy_format(proto, group, 1); 7413034Sdougm zfsopts = get_zfs_property(dataset, ZFS_PROP_SHARENFS); 7423034Sdougm 7433034Sdougm if (optstring != NULL && zfsopts != NULL) { 7443034Sdougm if (strcmp(optstring, zfsopts) != 0) 7453034Sdougm doupdate++; 7463034Sdougm } 7473034Sdougm 7483034Sdougm if (doupdate) { 7493034Sdougm if (optstring != NULL && strlen(optstring) > 0) { 7503034Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 7513034Sdougm "%s set sharenfs=%s %s", COMMAND, 7523034Sdougm optstring, dataset); 7533034Sdougm } else { 7543034Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 7553034Sdougm "%s set sharenfs=on %s", COMMAND, 7563034Sdougm dataset); 7573034Sdougm } 7583034Sdougm pfile = popen(command, "r"); 7593034Sdougm if (pfile != NULL) 7603034Sdougm ret = pclose(pfile); 7613034Sdougm switch (ret) { 7623034Sdougm default: 7633034Sdougm case 1: 7643034Sdougm ret = SA_SYSTEM_ERR; 7653034Sdougm break; 7663034Sdougm case 2: 7673034Sdougm ret = SA_SYNTAX_ERR; 7683034Sdougm break; 7693034Sdougm case 0: 7703034Sdougm break; 7713034Sdougm } 7723034Sdougm } 7733034Sdougm if (optstring != NULL) { 7743034Sdougm free(optstring); 7753034Sdougm } 7763034Sdougm if (zfsopts != NULL) 7773034Sdougm free(zfsopts); 7783034Sdougm } 7793034Sdougm if (proto != NULL) 7803034Sdougm sa_free_attr_string(proto); 7813034Sdougm if (dataset != NULL) 7823034Sdougm free(dataset); 7833034Sdougm } 7843034Sdougm free(command); 7853034Sdougm } 7863034Sdougm return (ret); 7873034Sdougm } 7883034Sdougm 7893034Sdougm /* 7903034Sdougm * sa_group_is_zfs(group) 7913034Sdougm * 7923034Sdougm * Given the group, determine if the zfs attribute is set. 7933034Sdougm */ 7943034Sdougm 7953034Sdougm int 7963034Sdougm sa_group_is_zfs(sa_group_t group) 7973034Sdougm { 7983034Sdougm char *zfs; 7993034Sdougm int ret = 0; 8003034Sdougm 8013034Sdougm zfs = sa_get_group_attr(group, "zfs"); 8023034Sdougm if (zfs != NULL) { 8033034Sdougm ret = 1; 8043034Sdougm sa_free_attr_string(zfs); 8053034Sdougm } 8063034Sdougm return (ret); 8073034Sdougm } 8083034Sdougm 8093034Sdougm /* 8103034Sdougm * sa_path_is_zfs(path) 8113034Sdougm * 8123034Sdougm * Check to see if the file system path represents is of type "zfs". 8133034Sdougm */ 8143034Sdougm 8153034Sdougm int 8163034Sdougm sa_path_is_zfs(char *path) 8173034Sdougm { 8183034Sdougm char *fstype; 8193034Sdougm int ret = 0; 8203034Sdougm 8213034Sdougm fstype = sa_fstype(path); 8223034Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 8233034Sdougm ret = 1; 8243034Sdougm } 8253034Sdougm if (fstype != NULL) 8263034Sdougm sa_free_fstype(fstype); 8273034Sdougm return (ret); 8283034Sdougm } 829