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> 31*4345Sdougm #include <strings.h> 323034Sdougm #include <libshare.h> 333034Sdougm #include "libshare_impl.h" 343218Sdougm #include <libintl.h> 353034Sdougm 363034Sdougm extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *); 373034Sdougm extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 383034Sdougm extern char *sa_fstype(char *); 393034Sdougm extern void set_node_attr(void *, char *, char *); 403034Sdougm extern int sa_is_share(void *); 413218Sdougm 423034Sdougm /* 433218Sdougm * File system specific code for ZFS. The original code was stolen 443218Sdougm * from the "zfs" command and modified to better suit this library's 453218Sdougm * usage. 463218Sdougm */ 473218Sdougm 483218Sdougm typedef struct get_all_cbdata { 493218Sdougm zfs_handle_t **cb_handles; 503218Sdougm size_t cb_alloc; 513218Sdougm size_t cb_used; 52*4345Sdougm uint_t cb_types; 533218Sdougm } get_all_cbdata_t; 543218Sdougm 553218Sdougm /* 563910Sdougm * sa_zfs_init(impl_handle) 573218Sdougm * 583910Sdougm * Initialize an access handle into libzfs. The handle needs to stay 593910Sdougm * around until sa_zfs_fini() in order to maintain the cache of 603910Sdougm * mounts. 613218Sdougm */ 623218Sdougm 634327Sdougm int 643910Sdougm sa_zfs_init(sa_handle_impl_t impl_handle) 653218Sdougm { 663910Sdougm impl_handle->zfs_libhandle = libzfs_init(); 674327Sdougm if (impl_handle->zfs_libhandle != NULL) { 684327Sdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 694327Sdougm return (B_TRUE); 704327Sdougm } 714327Sdougm return (B_FALSE); 723218Sdougm } 733218Sdougm 743218Sdougm /* 753910Sdougm * sa_zfs_fini(impl_handle) 763218Sdougm * 773218Sdougm * cleanup data structures and the libzfs handle used for accessing 783218Sdougm * zfs file share info. 793218Sdougm */ 803218Sdougm 813218Sdougm void 823910Sdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 833218Sdougm { 843910Sdougm if (impl_handle->zfs_libhandle != NULL) { 854327Sdougm if (impl_handle->zfs_list != NULL) { 86*4345Sdougm zfs_handle_t **zhp = impl_handle->zfs_list; 87*4345Sdougm size_t i; 88*4345Sdougm 894327Sdougm /* 90*4345Sdougm * Contents of zfs_list need to be freed so we 91*4345Sdougm * don't lose ZFS handles. 924327Sdougm */ 93*4345Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) { 94*4345Sdougm zfs_close(zhp[i]); 95*4345Sdougm } 964327Sdougm free(impl_handle->zfs_list); 974327Sdougm impl_handle->zfs_list = NULL; 984327Sdougm impl_handle->zfs_list_count = 0; 994327Sdougm } 100*4345Sdougm 101*4345Sdougm libzfs_fini(impl_handle->zfs_libhandle); 102*4345Sdougm impl_handle->zfs_libhandle = NULL; 1033218Sdougm } 1043218Sdougm } 1053218Sdougm 1063218Sdougm /* 1073218Sdougm * get_one_filesystem(zfs_handle_t, data) 1083218Sdougm * 1093218Sdougm * an interator function called while iterating through the ZFS 1103218Sdougm * root. It accumulates into an array of file system handles that can 1113218Sdougm * be used to derive info about those file systems. 112*4345Sdougm * 113*4345Sdougm * Note that as this function is called, we close all zhp handles that 114*4345Sdougm * are not going to be places into the cp_handles list. We don't want 115*4345Sdougm * to close the ones we are keeping, but all others would be leaked if 116*4345Sdougm * not closed here. 1173034Sdougm */ 1183034Sdougm 1193218Sdougm static int 1203218Sdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1213218Sdougm { 1223218Sdougm get_all_cbdata_t *cbp = data; 123*4345Sdougm zfs_type_t type = zfs_get_type(zhp); 1243218Sdougm 1253218Sdougm /* 126*4345Sdougm * Interate over any nested datasets. 1273218Sdougm */ 128*4345Sdougm if (type == ZFS_TYPE_FILESYSTEM && 129*4345Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 130*4345Sdougm zfs_close(zhp); 131*4345Sdougm return (1); 132*4345Sdougm } 133*4345Sdougm 134*4345Sdougm /* 135*4345Sdougm * Skip any datasets whose type does not match. 136*4345Sdougm */ 137*4345Sdougm if ((type & cbp->cb_types) == 0) { 1383218Sdougm zfs_close(zhp); 1393218Sdougm return (0); 1403218Sdougm } 1413218Sdougm 1423218Sdougm if (cbp->cb_alloc == cbp->cb_used) { 1433218Sdougm zfs_handle_t **handles; 1443218Sdougm 1453218Sdougm if (cbp->cb_alloc == 0) 1463218Sdougm cbp->cb_alloc = 64; 1473218Sdougm else 1483218Sdougm cbp->cb_alloc *= 2; 1493218Sdougm 150*4345Sdougm handles = (zfs_handle_t **)calloc(1, 151*4345Sdougm cbp->cb_alloc * sizeof (void *)); 152*4345Sdougm 1533218Sdougm if (handles == NULL) { 154*4345Sdougm zfs_close(zhp); 1554327Sdougm return (0); 1563218Sdougm } 1573218Sdougm if (cbp->cb_handles) { 158*4345Sdougm bcopy(cbp->cb_handles, handles, 1593218Sdougm cbp->cb_used * sizeof (void *)); 1603218Sdougm free(cbp->cb_handles); 1613218Sdougm } 1623218Sdougm 1633218Sdougm cbp->cb_handles = handles; 1643218Sdougm } 1653218Sdougm 1663218Sdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1673218Sdougm 168*4345Sdougm return (0); 1693218Sdougm } 1703218Sdougm 1713218Sdougm /* 1723218Sdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1733218Sdougm * 1743218Sdougm * iterate through all ZFS file systems starting at the root. Returns 1753218Sdougm * a count and an array of handle pointers. Allocating is only done 1763218Sdougm * once. The caller does not need to free since it will be done at 1773218Sdougm * sa_zfs_fini() time. 1783218Sdougm */ 1793218Sdougm 1803218Sdougm static void 1813910Sdougm get_all_filesystems(sa_handle_impl_t impl_handle, 1823910Sdougm zfs_handle_t ***fslist, size_t *count) 1833218Sdougm { 1843218Sdougm get_all_cbdata_t cb = { 0 }; 185*4345Sdougm cb.cb_types = ZFS_TYPE_FILESYSTEM; 1863218Sdougm 1873910Sdougm if (impl_handle->zfs_list != NULL) { 1884327Sdougm *fslist = impl_handle->zfs_list; 1894327Sdougm *count = impl_handle->zfs_list_count; 1904327Sdougm return; 1913218Sdougm } 1923218Sdougm 1933910Sdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 1944327Sdougm get_one_filesystem, &cb); 1953218Sdougm 1963910Sdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 1973910Sdougm impl_handle->zfs_list_count = *count = cb.cb_used; 1983218Sdougm } 1993218Sdougm 2003218Sdougm /* 2013218Sdougm * mountpoint_compare(a, b) 2023218Sdougm * 2033218Sdougm * compares the mountpoint on two zfs file systems handles. 2043218Sdougm * returns values following strcmp() model. 2053218Sdougm */ 2063218Sdougm 2073218Sdougm static int 2083218Sdougm mountpoint_compare(const void *a, const void *b) 2093218Sdougm { 2103218Sdougm zfs_handle_t **za = (zfs_handle_t **)a; 2113218Sdougm zfs_handle_t **zb = (zfs_handle_t **)b; 2123218Sdougm char mounta[MAXPATHLEN]; 2133218Sdougm char mountb[MAXPATHLEN]; 2143218Sdougm 2153218Sdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2163218Sdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2173218Sdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2183218Sdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2193218Sdougm 2203218Sdougm return (strcmp(mounta, mountb)); 2213218Sdougm } 2223218Sdougm 2233034Sdougm /* 2243910Sdougm * get_zfs_dataset(impl_handle, path) 2253034Sdougm * 2263034Sdougm * get the name of the ZFS dataset the path is equivalent to. The 2273034Sdougm * dataset name is used for get/set of ZFS properties since libzfs 2283034Sdougm * requires a dataset to do a zfs_open(). 2293034Sdougm */ 2303034Sdougm 2313034Sdougm static char * 2323910Sdougm get_zfs_dataset(sa_handle_impl_t impl_handle, char *path) 2333034Sdougm { 2343218Sdougm size_t i, count = 0; 2353034Sdougm char *dataset = NULL; 2363218Sdougm zfs_handle_t **zlist; 2373218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 2384180Sdougm char canmount[ZFS_MAXPROPLEN]; 2393218Sdougm 2403910Sdougm get_all_filesystems(impl_handle, &zlist, &count); 2413218Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2423218Sdougm for (i = 0; i < count; i++) { 2434327Sdougm /* must have a mountpoint */ 2444327Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 2454327Sdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 2464327Sdougm /* no mountpoint */ 2474327Sdougm continue; 2484327Sdougm } 2493034Sdougm 2504327Sdougm /* mountpoint must be a path */ 2514327Sdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 2524327Sdougm strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 2534327Sdougm continue; 2543218Sdougm 2554327Sdougm /* canmount must be set */ 2564327Sdougm canmount[0] = '\0'; 2574327Sdougm if (!zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 2584180Sdougm sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 2594327Sdougm strcmp(canmount, "off") == 0) 2604327Sdougm continue; 2613218Sdougm 2624327Sdougm /* 2634327Sdougm * have a mountable handle but want to skip those marked none 2644327Sdougm * and legacy 2654327Sdougm */ 2664327Sdougm if (strcmp(mountpoint, path) == 0) { 2674327Sdougm dataset = (char *)zfs_get_name(zlist[i]); 2684327Sdougm break; 2694327Sdougm } 2703218Sdougm 2713034Sdougm } 2723218Sdougm 2734327Sdougm if (dataset != NULL) 2744327Sdougm dataset = strdup(dataset); 2754327Sdougm 2763034Sdougm return (dataset); 2773034Sdougm } 2783034Sdougm 2793034Sdougm /* 2803034Sdougm * get_zfs_property(dataset, property) 2813034Sdougm * 2823034Sdougm * Get the file system property specified from the ZFS dataset. 2833034Sdougm */ 2843034Sdougm 2853034Sdougm static char * 2863034Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 2873034Sdougm { 2883034Sdougm zfs_handle_t *handle = NULL; 2893034Sdougm char shareopts[ZFS_MAXPROPLEN]; 2903034Sdougm libzfs_handle_t *libhandle; 2913034Sdougm 2923034Sdougm libhandle = libzfs_init(); 2933034Sdougm if (libhandle != NULL) { 2944327Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 2954327Sdougm if (handle != NULL) { 2964327Sdougm if (zfs_prop_get(handle, property, shareopts, 2974327Sdougm sizeof (shareopts), NULL, NULL, 0, 2984327Sdougm B_FALSE) == 0) { 2994327Sdougm zfs_close(handle); 3004327Sdougm libzfs_fini(libhandle); 3014327Sdougm return (strdup(shareopts)); 3024327Sdougm } 3034327Sdougm zfs_close(handle); 3043034Sdougm } 3054327Sdougm libzfs_fini(libhandle); 3063034Sdougm } 3073034Sdougm return (NULL); 3083034Sdougm } 3093034Sdougm 3103034Sdougm /* 3113910Sdougm * sa_zfs_is_shared(handle, path) 3123034Sdougm * 3133034Sdougm * Check to see if the ZFS path provided has the sharenfs option set 3143034Sdougm * or not. 3153034Sdougm */ 3163034Sdougm 3173034Sdougm int 3183910Sdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 3193034Sdougm { 3203034Sdougm int ret = 0; 3213034Sdougm char *dataset; 3223034Sdougm zfs_handle_t *handle = NULL; 3233034Sdougm char shareopts[ZFS_MAXPROPLEN]; 3243034Sdougm libzfs_handle_t *libhandle; 3253034Sdougm 3263910Sdougm dataset = get_zfs_dataset((sa_handle_t)sahandle, path); 3273034Sdougm if (dataset != NULL) { 3284327Sdougm libhandle = libzfs_init(); 3294327Sdougm if (libhandle != NULL) { 3304327Sdougm handle = zfs_open(libhandle, dataset, 3314327Sdougm ZFS_TYPE_FILESYSTEM); 3324327Sdougm if (handle != NULL) { 3334327Sdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 3344327Sdougm shareopts, sizeof (shareopts), NULL, NULL, 3354327Sdougm 0, B_FALSE) == 0 && 3364327Sdougm strcmp(shareopts, "off") != 0) { 3374327Sdougm ret = 1; /* it is shared */ 3384327Sdougm } 3394327Sdougm zfs_close(handle); 3404327Sdougm } 3414327Sdougm libzfs_fini(libhandle); 3423034Sdougm } 3434327Sdougm free(dataset); 3443034Sdougm } 3453034Sdougm return (ret); 3463034Sdougm } 3473034Sdougm 3483034Sdougm /* 3493034Sdougm * find_or_create_group(groupname, proto, *err) 3503034Sdougm * 3513034Sdougm * While walking the ZFS tree, we need to add shares to a defined 3523034Sdougm * group. If the group doesn't exist, create it first, making sure it 3533034Sdougm * is marked as a ZFS group. 3543034Sdougm * 3553108Sdougm * Note that all ZFS shares are in a subgroup of the top level group 3563108Sdougm * called "zfs". 3573034Sdougm */ 3583034Sdougm 3593034Sdougm static sa_group_t 3603910Sdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 3613034Sdougm { 3623034Sdougm sa_group_t group; 3633034Sdougm sa_optionset_t optionset; 3643034Sdougm int ret = SA_OK; 3653034Sdougm 3663034Sdougm /* 3673034Sdougm * we check to see if the "zfs" group exists. Since this 3683034Sdougm * should be the top level group, we don't want the 3693034Sdougm * parent. This is to make sure the zfs group has been created 3703034Sdougm * and to created if it hasn't been. 3713034Sdougm */ 3723910Sdougm group = sa_get_group(handle, groupname); 3733034Sdougm if (group == NULL) { 3744327Sdougm group = sa_create_group(handle, groupname, &ret); 3753108Sdougm 3764327Sdougm /* make sure this is flagged as a ZFS group */ 3774327Sdougm if (group != NULL) 3784327Sdougm ret = sa_set_group_attr(group, "zfs", "true"); 3793034Sdougm } 3803034Sdougm if (group != NULL) { 3814327Sdougm if (proto != NULL) { 3824327Sdougm optionset = sa_get_optionset(group, proto); 3834327Sdougm if (optionset == NULL) { 3844327Sdougm optionset = sa_create_optionset(group, proto); 3854327Sdougm } else { 3864327Sdougm char **protolist; 3874327Sdougm int numprotos, i; 3884327Sdougm numprotos = sa_get_protocols(&protolist); 3894327Sdougm for (i = 0; i < numprotos; i++) { 3904327Sdougm optionset = sa_create_optionset(group, 3914327Sdougm protolist[i]); 3924327Sdougm } 3934327Sdougm if (protolist != NULL) 3944327Sdougm free(protolist); 3954327Sdougm } 3963034Sdougm } 3973034Sdougm } 3983034Sdougm if (err != NULL) 3994327Sdougm *err = ret; 4003034Sdougm return (group); 4013034Sdougm } 4023034Sdougm 4033034Sdougm /* 4043108Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 4053108Sdougm * 4063108Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 4073108Sdougm * function looks to see if the groupname exists and returns it if it 4083108Sdougm * does or else creates a new one with the specified name and returns 4093108Sdougm * that. The "zfs" group will exist before we get here, but we make 4103108Sdougm * sure just in case. 4113108Sdougm * 4123108Sdougm * err must be a valid pointer. 4133108Sdougm */ 4143108Sdougm 4153108Sdougm static sa_group_t 4163910Sdougm find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, 4173910Sdougm char *optstring, int *err) 4183108Sdougm { 4193108Sdougm sa_group_t group = NULL; 4203108Sdougm sa_group_t zfs; 4213108Sdougm char *name; 4223108Sdougm char *options; 4233108Sdougm 4243108Sdougm /* start with the top-level "zfs" group */ 4253910Sdougm zfs = sa_get_group(handle, "zfs"); 4263108Sdougm *err = SA_OK; 4273108Sdougm if (zfs != NULL) { 4284327Sdougm for (group = sa_get_sub_group(zfs); group != NULL; 4294327Sdougm group = sa_get_next_group(group)) { 4304327Sdougm name = sa_get_group_attr(group, "name"); 4314327Sdougm if (name != NULL && strcmp(name, groupname) == 0) { 4324327Sdougm /* have the group so break out of here */ 4334327Sdougm sa_free_attr_string(name); 4344327Sdougm break; 4354327Sdougm } 4364327Sdougm if (name != NULL) 4374327Sdougm sa_free_attr_string(name); 4383108Sdougm } 4393108Sdougm 4404327Sdougm if (group == NULL) { 4414327Sdougm /* 4424327Sdougm * need to create the sub-group since it doesn't exist 4434327Sdougm */ 4444327Sdougm group = _sa_create_zfs_group(zfs, groupname); 4454327Sdougm if (group != NULL) 4464327Sdougm set_node_attr(group, "zfs", "true"); 4474327Sdougm if (strcmp(optstring, "on") == 0) 4484327Sdougm optstring = "rw"; 4494327Sdougm if (group != NULL) { 4504327Sdougm options = strdup(optstring); 4514327Sdougm if (options != NULL) { 4524327Sdougm *err = sa_parse_legacy_options(group, 4534327Sdougm options, "nfs"); 4544327Sdougm free(options); 4554327Sdougm } else { 4564327Sdougm *err = SA_NO_MEMORY; 4574327Sdougm } 4584327Sdougm } 4593108Sdougm } 4603108Sdougm } 4613108Sdougm return (group); 4623108Sdougm } 4633108Sdougm 4643108Sdougm /* 4654327Sdougm * zfs_inherited(handle, source, sourcestr) 4664327Sdougm * 4674327Sdougm * handle case of inherited sharenfs. Pulled out of sa_get_zfs_shares 4684327Sdougm * for readability. 4694327Sdougm */ 4704327Sdougm static int 4714327Sdougm zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 4724327Sdougm char *shareopts, char *mountpoint) 4734327Sdougm { 4744327Sdougm int doshopt = 0; 4754327Sdougm int err = SA_OK; 4764327Sdougm sa_group_t group; 4774327Sdougm 4784327Sdougm /* 4794327Sdougm * Need to find the "real" parent sub-group. It may not be 4804327Sdougm * mounted, but it was identified in the "sourcestr" 4814327Sdougm * variable. The real parent not mounted can occur if 4824327Sdougm * "canmount=off and sharenfs=on". 4834327Sdougm */ 4844327Sdougm group = find_or_create_zfs_subgroup(handle, sourcestr, shareopts, 4854327Sdougm &doshopt); 4864327Sdougm if (group != NULL) { 4874327Sdougm share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 4884327Sdougm &err); 4894327Sdougm /* 4904327Sdougm * some options may only be on shares. If the opt 4914327Sdougm * string contains one of those, we put it just on the 4924327Sdougm * share. 4934327Sdougm */ 4944327Sdougm if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 4954327Sdougm char *options; 4964327Sdougm options = strdup(shareopts); 4974327Sdougm if (options != NULL) { 4984327Sdougm err = sa_parse_legacy_options(share, options, 4994327Sdougm "nfs"); 5004327Sdougm free(options); 5014327Sdougm } 5024327Sdougm } 5034327Sdougm } else { 5044327Sdougm err = SA_NO_MEMORY; 5054327Sdougm } 5064327Sdougm return (err); 5074327Sdougm } 5084327Sdougm 5094327Sdougm /* 5104327Sdougm * zfs_notinherited() 5114327Sdougm * 5124327Sdougm * handle case where this is the top of a sub-group in ZFS. Pulled out 5134327Sdougm * of sa_get_zfs_shares for readability. 5144327Sdougm */ 5154327Sdougm static int 5164327Sdougm zfs_notinherited(sa_group_t group, char *mountpoint, char *shareopts) 5174327Sdougm { 5184327Sdougm int err = SA_OK; 5194327Sdougm sa_share_t share; 5204327Sdougm 5214327Sdougm set_node_attr(group, "zfs", "true"); 5224327Sdougm share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, &err); 5234327Sdougm if (err == SA_OK) { 5244327Sdougm if (strcmp(shareopts, "on") != 0) { 5254327Sdougm char *options; 5264327Sdougm options = strdup(shareopts); 5274327Sdougm if (options != NULL) { 5284327Sdougm err = sa_parse_legacy_options(group, options, 5294327Sdougm "nfs"); 5304327Sdougm free(options); 5314327Sdougm } 5324327Sdougm if (err == SA_PROP_SHARE_ONLY) { 5334327Sdougm /* 5344327Sdougm * Same as above, some properties may 5354327Sdougm * only be on shares, but due to the 5364327Sdougm * ZFS sub-groups being artificial, we 5374327Sdougm * sometimes get this and have to deal 5384327Sdougm * with it. We do it by attempting to 5394327Sdougm * put it on the share. 5404327Sdougm */ 5414327Sdougm options = strdup(shareopts); 542*4345Sdougm if (options != NULL) { 5434327Sdougm err = sa_parse_legacy_options(share, 5444327Sdougm options, "nfs"); 5454327Sdougm free(options); 546*4345Sdougm } 5474327Sdougm } 5484327Sdougm /* unmark the share's changed state */ 5494327Sdougm set_node_attr(share, "changed", NULL); 5504327Sdougm } 5514327Sdougm } 5524327Sdougm return (err); 5534327Sdougm } 5544327Sdougm 5554327Sdougm /* 5564327Sdougm * zfs_grp_error(err) 5574327Sdougm * 5584327Sdougm * Print group create error, but only once. If err is 0 do the 5594327Sdougm * print else don't. 5604327Sdougm */ 5614327Sdougm 5624327Sdougm static void 5634327Sdougm zfs_grp_error(int err) 5644327Sdougm { 5654327Sdougm if (err == 0) { 5664327Sdougm /* only print error once */ 5674327Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 5684327Sdougm "Cannot create ZFS subgroup during initialization:" 5694327Sdougm " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 5704327Sdougm } 5714327Sdougm } 5724327Sdougm 5734327Sdougm /* 5743910Sdougm * sa_get_zfs_shares(handle, groupname) 5753034Sdougm * 5763034Sdougm * Walk the mnttab for all zfs mounts and determine which are 5773034Sdougm * shared. Find or create the appropriate group/sub-group to contain 5783034Sdougm * the shares. 5793034Sdougm * 5803034Sdougm * All shares are in a sub-group that will hold the properties. This 5813034Sdougm * allows representing the inherited property model. 5823034Sdougm */ 5833034Sdougm 5843034Sdougm int 5853910Sdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 5863034Sdougm { 5873034Sdougm sa_group_t group; 5883034Sdougm sa_group_t zfsgroup; 5893034Sdougm int legacy = 0; 5903034Sdougm int err; 5913218Sdougm zfs_handle_t **zlist; 5923034Sdougm char shareopts[ZFS_MAXPROPLEN]; 5933034Sdougm sa_share_t share; 5943034Sdougm zfs_source_t source; 5953034Sdougm char sourcestr[ZFS_MAXPROPLEN]; 5963218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 5973218Sdougm size_t count = 0, i; 5983910Sdougm libzfs_handle_t *zfs_libhandle; 5993034Sdougm 6003034Sdougm /* 6013910Sdougm * If we can't access libzfs, don't bother doing anything. 6023034Sdougm */ 6033910Sdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 6043218Sdougm if (zfs_libhandle == NULL) 6054327Sdougm return (SA_SYSTEM_ERR); 6063034Sdougm 6073910Sdougm zfsgroup = find_or_create_group(handle, groupname, "nfs", &err); 6083034Sdougm if (zfsgroup != NULL) { 6093034Sdougm /* 6103034Sdougm * need to walk the mounted ZFS pools and datasets to 6113034Sdougm * find shares that are possible. 6123034Sdougm */ 6134327Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 6144327Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 6153218Sdougm 6164327Sdougm group = zfsgroup; 6174327Sdougm for (i = 0; i < count; i++) { 6184327Sdougm char *dataset; 6193218Sdougm 6204327Sdougm source = ZFS_SRC_ALL; 6214327Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 6224327Sdougm mountpoint, sizeof (mountpoint), NULL, NULL, 0, 6234327Sdougm B_FALSE) != 0) { 6244327Sdougm /* no mountpoint */ 6254327Sdougm continue; 6264327Sdougm } 6274327Sdougm 6283218Sdougm /* 6294327Sdougm * zfs_get_name value must not be freed. It is just a 6304327Sdougm * pointer to a value in the handle. 6313218Sdougm */ 6324327Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 6334327Sdougm continue; 6344327Sdougm 6353218Sdougm /* 6364327Sdougm * only deal with "mounted" file systems since 6374327Sdougm * unmounted file systems can't actually be shared. 6383218Sdougm */ 6394327Sdougm 6404327Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 6414327Sdougm continue; 6424327Sdougm 6434327Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 6444327Sdougm sizeof (shareopts), &source, sourcestr, 6454327Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 6464327Sdougm strcmp(shareopts, "off") != 0) { 6474327Sdougm /* it is shared so add to list */ 6484327Sdougm share = sa_find_share(handle, mountpoint); 6494327Sdougm err = SA_OK; 6504327Sdougm if (share != NULL) { 6514327Sdougm /* 6524327Sdougm * A zfs file system had been shared 6534327Sdougm * through traditional methods 6544327Sdougm * (share/dfstab or added to a non-zfs 6554327Sdougm * group. Now it has been added to a 6564327Sdougm * ZFS group via the zfs 6574327Sdougm * command. Remove from previous 6584327Sdougm * config and setup with current 6594327Sdougm * options. 6604327Sdougm */ 6614327Sdougm err = sa_remove_share(share); 6624327Sdougm share = NULL; 6633108Sdougm } 6644327Sdougm if (err == SA_OK) { 6654327Sdougm if (source & ZFS_SRC_INHERITED) { 6664327Sdougm err = zfs_inherited(handle, 6674327Sdougm share, sourcestr, 6684327Sdougm shareopts, mountpoint); 6694327Sdougm } else { 6704327Sdougm group = _sa_create_zfs_group( 6714327Sdougm zfsgroup, dataset); 6724327Sdougm if (group == NULL) { 6734327Sdougm static int err = 0; 674*4345Sdougm /* 675*4345Sdougm * there is a problem, 676*4345Sdougm * but we can't do 677*4345Sdougm * anything about it 678*4345Sdougm * at this point so we 679*4345Sdougm * issue a warning an 680*4345Sdougm * move on. 681*4345Sdougm */ 6824327Sdougm zfs_grp_error(err); 6834327Sdougm err = 1; 6844327Sdougm continue; 6854327Sdougm } 6864327Sdougm set_node_attr(group, "zfs", 6874327Sdougm "true"); 6884327Sdougm share = _sa_add_share(group, 6894327Sdougm mountpoint, 6904327Sdougm SA_SHARE_TRANSIENT, &err); 6914327Sdougm err = zfs_notinherited(group, 6924327Sdougm mountpoint, shareopts); 6934327Sdougm } 6943218Sdougm } 6953034Sdougm } 6963034Sdougm } 6973034Sdougm } 6983218Sdougm /* 6993218Sdougm * Don't need to free the "zlist" variable since it is only a 7003218Sdougm * pointer to a cached value that will be freed when 7013218Sdougm * sa_fini() is called. 7023218Sdougm */ 7033034Sdougm return (legacy); 7043034Sdougm } 7053034Sdougm 7063034Sdougm #define COMMAND "/usr/sbin/zfs" 7073034Sdougm 7083034Sdougm /* 7093034Sdougm * sa_zfs_set_sharenfs(group, path, on) 7103034Sdougm * 7113034Sdougm * Update the "sharenfs" property on the path. If on is true, then set 7123034Sdougm * to the properties on the group or "on" if no properties are 7133034Sdougm * defined. Set to "off" if on is false. 7143034Sdougm */ 7153034Sdougm 7163034Sdougm int 7173034Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 7183034Sdougm { 7193034Sdougm int ret = SA_NOT_IMPLEMENTED; 7203034Sdougm char *command; 7213034Sdougm 7223034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 7233034Sdougm if (command != NULL) { 7244327Sdougm char *opts = NULL; 7254327Sdougm char *dataset = NULL; 7264327Sdougm FILE *pfile; 7274327Sdougm sa_handle_impl_t impl_handle; 7284327Sdougm /* for now, NFS is always available for "zfs" */ 7294327Sdougm if (on) { 7304327Sdougm opts = sa_proto_legacy_format("nfs", group, 1); 7314327Sdougm if (opts != NULL && strlen(opts) == 0) { 7324327Sdougm free(opts); 7334327Sdougm opts = strdup("on"); 7344327Sdougm } 7353034Sdougm } 7363910Sdougm 7374327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 7384327Sdougm assert(impl_handle != NULL); 7394327Sdougm if (impl_handle != NULL) 7404327Sdougm dataset = get_zfs_dataset(impl_handle, path); 7414327Sdougm else 7424327Sdougm ret = SA_SYSTEM_ERR; 7433910Sdougm 7444327Sdougm if (dataset != NULL) { 7454327Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 7464327Sdougm "%s set sharenfs=\"%s\" %s", COMMAND, 7474327Sdougm opts != NULL ? opts : "off", dataset); 7484327Sdougm pfile = popen(command, "r"); 7494327Sdougm if (pfile != NULL) { 7504327Sdougm ret = pclose(pfile); 7514327Sdougm if (ret != 0) 7524327Sdougm ret = SA_SYSTEM_ERR; 7534327Sdougm } 7543034Sdougm } 7554327Sdougm if (opts != NULL) 7564327Sdougm free(opts); 7574327Sdougm if (dataset != NULL) 7584327Sdougm free(dataset); 7594327Sdougm free(command); 7603034Sdougm } 7613034Sdougm return (ret); 7623034Sdougm } 7633034Sdougm 7643034Sdougm /* 7653034Sdougm * sa_zfs_update(group) 7663034Sdougm * 7673034Sdougm * call back to ZFS to update the share if necessary. 7683034Sdougm * Don't do it if it isn't a real change. 7693034Sdougm */ 7703034Sdougm int 7713034Sdougm sa_zfs_update(sa_group_t group) 7723034Sdougm { 7733034Sdougm sa_optionset_t protopt; 7743034Sdougm sa_group_t parent; 7753034Sdougm char *command; 7763034Sdougm char *optstring; 7773034Sdougm int ret = SA_OK; 7783034Sdougm int doupdate = 0; 7793034Sdougm FILE *pfile; 7803034Sdougm 7813034Sdougm if (sa_is_share(group)) 7824327Sdougm parent = sa_get_parent_group(group); 7833034Sdougm else 7844327Sdougm parent = group; 7853034Sdougm 7863034Sdougm if (parent != NULL) { 7874327Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 7884327Sdougm if (command == NULL) 7894327Sdougm return (SA_NO_MEMORY); 7904327Sdougm 7914327Sdougm *command = '\0'; 7924327Sdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 7934327Sdougm protopt = sa_get_next_optionset(protopt)) { 7943034Sdougm 7954327Sdougm char *proto = sa_get_optionset_attr(protopt, "type"); 7964327Sdougm char *path; 7974327Sdougm char *dataset = NULL; 7984327Sdougm char *zfsopts = NULL; 7993034Sdougm 8004327Sdougm if (sa_is_share(group)) { 8014327Sdougm path = sa_get_share_attr((sa_share_t)group, 8024327Sdougm "path"); 8034327Sdougm if (path != NULL) { 8044327Sdougm sa_handle_impl_t impl_handle; 8053034Sdougm 8064327Sdougm impl_handle = sa_find_group_handle( 8074327Sdougm group); 8084327Sdougm if (impl_handle != NULL) 8094327Sdougm dataset = get_zfs_dataset( 8104327Sdougm impl_handle, path); 8114327Sdougm else 8124327Sdougm ret = SA_SYSTEM_ERR; 8133910Sdougm 8144327Sdougm sa_free_attr_string(path); 8154327Sdougm } 8164327Sdougm } else { 8174327Sdougm dataset = sa_get_group_attr(group, "name"); 8184327Sdougm } 8194327Sdougm /* update only when there is an optstring found */ 8204327Sdougm doupdate = 0; 8214327Sdougm if (proto != NULL && dataset != NULL) { 8224327Sdougm optstring = sa_proto_legacy_format(proto, 8234327Sdougm group, 1); 8244327Sdougm zfsopts = get_zfs_property(dataset, 8254327Sdougm ZFS_PROP_SHARENFS); 8263034Sdougm 8274327Sdougm if (optstring != NULL && zfsopts != NULL) { 8284327Sdougm if (strcmp(optstring, zfsopts) != 0) 8294327Sdougm doupdate++; 8304327Sdougm } 8313034Sdougm 8324327Sdougm if (doupdate) { 8334327Sdougm if (optstring != NULL && 8344327Sdougm strlen(optstring) > 0) { 8354327Sdougm (void) snprintf(command, 8364327Sdougm ZFS_MAXPROPLEN * 2, 8374327Sdougm "%s set sharenfs=%s %s" 8384327Sdougm COMMAND, 8394327Sdougm optstring, dataset); 8404327Sdougm } else { 8414327Sdougm (void) snprintf(command, 8424327Sdougm ZFS_MAXPROPLEN * 2, 8434327Sdougm "%s set sharenfs=on %s", 8444327Sdougm COMMAND, 8454327Sdougm dataset); 8464327Sdougm } 8474327Sdougm pfile = popen(command, "r"); 8484327Sdougm if (pfile != NULL) 8494327Sdougm ret = pclose(pfile); 8504327Sdougm switch (ret) { 8514327Sdougm default: 8524327Sdougm case 1: 8534327Sdougm ret = SA_SYSTEM_ERR; 8544327Sdougm break; 8554327Sdougm case 2: 8564327Sdougm ret = SA_SYNTAX_ERR; 8574327Sdougm break; 8584327Sdougm case 0: 8594327Sdougm break; 8604327Sdougm } 8614327Sdougm } 8624327Sdougm if (optstring != NULL) 8634327Sdougm free(optstring); 8644327Sdougm if (zfsopts != NULL) 8654327Sdougm free(zfsopts); 8663034Sdougm } 8674327Sdougm if (proto != NULL) 8684327Sdougm sa_free_attr_string(proto); 8694327Sdougm if (dataset != NULL) 8704327Sdougm free(dataset); 8713034Sdougm } 8724327Sdougm free(command); 8733034Sdougm } 8743034Sdougm return (ret); 8753034Sdougm } 8763034Sdougm 8773034Sdougm /* 8783034Sdougm * sa_group_is_zfs(group) 8793034Sdougm * 8803034Sdougm * Given the group, determine if the zfs attribute is set. 8813034Sdougm */ 8823034Sdougm 8833034Sdougm int 8843034Sdougm sa_group_is_zfs(sa_group_t group) 8853034Sdougm { 8863034Sdougm char *zfs; 8873034Sdougm int ret = 0; 8883034Sdougm 8893034Sdougm zfs = sa_get_group_attr(group, "zfs"); 8903034Sdougm if (zfs != NULL) { 8914327Sdougm ret = 1; 8924327Sdougm sa_free_attr_string(zfs); 8933034Sdougm } 8943034Sdougm return (ret); 8953034Sdougm } 8963034Sdougm 8973034Sdougm /* 8983034Sdougm * sa_path_is_zfs(path) 8993034Sdougm * 9003034Sdougm * Check to see if the file system path represents is of type "zfs". 9013034Sdougm */ 9023034Sdougm 9033034Sdougm int 9043034Sdougm sa_path_is_zfs(char *path) 9053034Sdougm { 9063034Sdougm char *fstype; 9073034Sdougm int ret = 0; 9083034Sdougm 9093034Sdougm fstype = sa_fstype(path); 9104327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) 9114327Sdougm ret = 1; 9123034Sdougm if (fstype != NULL) 9134327Sdougm sa_free_fstype(fstype); 9143034Sdougm return (ret); 9153034Sdougm } 916