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> 314345Sdougm #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; 524345Sdougm 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) { 864345Sdougm zfs_handle_t **zhp = impl_handle->zfs_list; 874345Sdougm size_t i; 884345Sdougm 894327Sdougm /* 904345Sdougm * Contents of zfs_list need to be freed so we 914345Sdougm * don't lose ZFS handles. 924327Sdougm */ 934345Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) { 944345Sdougm zfs_close(zhp[i]); 954345Sdougm } 964327Sdougm free(impl_handle->zfs_list); 974327Sdougm impl_handle->zfs_list = NULL; 984327Sdougm impl_handle->zfs_list_count = 0; 994327Sdougm } 1004345Sdougm 1014345Sdougm libzfs_fini(impl_handle->zfs_libhandle); 1024345Sdougm 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. 1124345Sdougm * 1134345Sdougm * Note that as this function is called, we close all zhp handles that 1144345Sdougm * are not going to be places into the cp_handles list. We don't want 1154345Sdougm * to close the ones we are keeping, but all others would be leaked if 1164345Sdougm * 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; 1234345Sdougm zfs_type_t type = zfs_get_type(zhp); 1243218Sdougm 1253218Sdougm /* 1264345Sdougm * Interate over any nested datasets. 1273218Sdougm */ 1284345Sdougm if (type == ZFS_TYPE_FILESYSTEM && 1294345Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 1304345Sdougm zfs_close(zhp); 1314345Sdougm return (1); 1324345Sdougm } 1334345Sdougm 1344345Sdougm /* 1354345Sdougm * Skip any datasets whose type does not match. 1364345Sdougm */ 1374345Sdougm 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 1504345Sdougm handles = (zfs_handle_t **)calloc(1, 1514345Sdougm cbp->cb_alloc * sizeof (void *)); 1524345Sdougm 1533218Sdougm if (handles == NULL) { 1544345Sdougm zfs_close(zhp); 1554327Sdougm return (0); 1563218Sdougm } 1573218Sdougm if (cbp->cb_handles) { 1584345Sdougm 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 1684345Sdougm 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 }; 1854345Sdougm 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); 5424345Sdougm if (options != NULL) { 5434327Sdougm err = sa_parse_legacy_options(share, 5444327Sdougm options, "nfs"); 5454327Sdougm free(options); 5464345Sdougm } 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); 608*4524Sdougm if (zfsgroup == NULL) 609*4524Sdougm return (legacy); 6103218Sdougm 611*4524Sdougm /* 612*4524Sdougm * need to walk the mounted ZFS pools and datasets to 613*4524Sdougm * find shares that are possible. 614*4524Sdougm */ 615*4524Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 616*4524Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 617*4524Sdougm 618*4524Sdougm group = zfsgroup; 619*4524Sdougm for (i = 0; i < count; i++) { 620*4524Sdougm char *dataset; 6213218Sdougm 622*4524Sdougm source = ZFS_SRC_ALL; 623*4524Sdougm /* If no mountpoint, skip. */ 624*4524Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 625*4524Sdougm mountpoint, sizeof (mountpoint), NULL, NULL, 0, 626*4524Sdougm B_FALSE) != 0) 627*4524Sdougm continue; 6284327Sdougm 629*4524Sdougm /* 630*4524Sdougm * zfs_get_name value must not be freed. It is just a 631*4524Sdougm * pointer to a value in the handle. 632*4524Sdougm */ 633*4524Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 634*4524Sdougm continue; 6354327Sdougm 636*4524Sdougm /* 637*4524Sdougm * only deal with "mounted" file systems since 638*4524Sdougm * unmounted file systems can't actually be shared. 639*4524Sdougm */ 6404327Sdougm 641*4524Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 642*4524Sdougm continue; 6434327Sdougm 644*4524Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 645*4524Sdougm sizeof (shareopts), &source, sourcestr, 646*4524Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 647*4524Sdougm strcmp(shareopts, "off") != 0) { 648*4524Sdougm /* it is shared so add to list */ 649*4524Sdougm share = sa_find_share(handle, mountpoint); 650*4524Sdougm err = SA_OK; 651*4524Sdougm if (share != NULL) { 652*4524Sdougm /* 653*4524Sdougm * A zfs file system had been shared 654*4524Sdougm * through traditional methods 655*4524Sdougm * (share/dfstab or added to a non-zfs 656*4524Sdougm * group. Now it has been added to a 657*4524Sdougm * ZFS group via the zfs 658*4524Sdougm * command. Remove from previous 659*4524Sdougm * config and setup with current 660*4524Sdougm * options. 661*4524Sdougm */ 662*4524Sdougm err = sa_remove_share(share); 663*4524Sdougm share = NULL; 664*4524Sdougm } 665*4524Sdougm if (err == SA_OK) { 666*4524Sdougm if (source & ZFS_SRC_INHERITED) { 667*4524Sdougm err = zfs_inherited(handle, 668*4524Sdougm share, sourcestr, 669*4524Sdougm shareopts, mountpoint); 670*4524Sdougm } else { 671*4524Sdougm group = _sa_create_zfs_group( 672*4524Sdougm zfsgroup, dataset); 673*4524Sdougm if (group == NULL) { 674*4524Sdougm static int err = 0; 6754345Sdougm /* 6764345Sdougm * there is a problem, 6774345Sdougm * but we can't do 6784345Sdougm * anything about it 6794345Sdougm * at this point so we 6804345Sdougm * issue a warning an 6814345Sdougm * move on. 6824345Sdougm */ 683*4524Sdougm zfs_grp_error(err); 684*4524Sdougm err = 1; 685*4524Sdougm continue; 6864327Sdougm } 687*4524Sdougm set_node_attr(group, "zfs", 688*4524Sdougm "true"); 689*4524Sdougm /* 690*4524Sdougm * Add share with local opts via 691*4524Sdougm * zfs_notinherited. 692*4524Sdougm */ 693*4524Sdougm err = zfs_notinherited(group, 694*4524Sdougm mountpoint, shareopts); 6953218Sdougm } 6963034Sdougm } 6973034Sdougm } 6983034Sdougm } 6993218Sdougm /* 7003218Sdougm * Don't need to free the "zlist" variable since it is only a 7013218Sdougm * pointer to a cached value that will be freed when 7023218Sdougm * sa_fini() is called. 7033218Sdougm */ 7043034Sdougm return (legacy); 7053034Sdougm } 7063034Sdougm 7073034Sdougm #define COMMAND "/usr/sbin/zfs" 7083034Sdougm 7093034Sdougm /* 7103034Sdougm * sa_zfs_set_sharenfs(group, path, on) 7113034Sdougm * 7123034Sdougm * Update the "sharenfs" property on the path. If on is true, then set 7133034Sdougm * to the properties on the group or "on" if no properties are 7143034Sdougm * defined. Set to "off" if on is false. 7153034Sdougm */ 7163034Sdougm 7173034Sdougm int 7183034Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 7193034Sdougm { 7203034Sdougm int ret = SA_NOT_IMPLEMENTED; 7213034Sdougm char *command; 7223034Sdougm 7233034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 7243034Sdougm if (command != NULL) { 7254327Sdougm char *opts = NULL; 7264327Sdougm char *dataset = NULL; 7274327Sdougm FILE *pfile; 7284327Sdougm sa_handle_impl_t impl_handle; 7294327Sdougm /* for now, NFS is always available for "zfs" */ 7304327Sdougm if (on) { 7314327Sdougm opts = sa_proto_legacy_format("nfs", group, 1); 7324327Sdougm if (opts != NULL && strlen(opts) == 0) { 7334327Sdougm free(opts); 7344327Sdougm opts = strdup("on"); 7354327Sdougm } 7363034Sdougm } 7373910Sdougm 7384327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 7394327Sdougm assert(impl_handle != NULL); 7404327Sdougm if (impl_handle != NULL) 7414327Sdougm dataset = get_zfs_dataset(impl_handle, path); 7424327Sdougm else 7434327Sdougm ret = SA_SYSTEM_ERR; 7443910Sdougm 7454327Sdougm if (dataset != NULL) { 7464327Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 7474327Sdougm "%s set sharenfs=\"%s\" %s", COMMAND, 7484327Sdougm opts != NULL ? opts : "off", dataset); 7494327Sdougm pfile = popen(command, "r"); 7504327Sdougm if (pfile != NULL) { 7514327Sdougm ret = pclose(pfile); 7524327Sdougm if (ret != 0) 7534327Sdougm ret = SA_SYSTEM_ERR; 7544327Sdougm } 7553034Sdougm } 7564327Sdougm if (opts != NULL) 7574327Sdougm free(opts); 7584327Sdougm if (dataset != NULL) 7594327Sdougm free(dataset); 7604327Sdougm free(command); 7613034Sdougm } 7623034Sdougm return (ret); 7633034Sdougm } 7643034Sdougm 7653034Sdougm /* 7663034Sdougm * sa_zfs_update(group) 7673034Sdougm * 7683034Sdougm * call back to ZFS to update the share if necessary. 7693034Sdougm * Don't do it if it isn't a real change. 7703034Sdougm */ 7713034Sdougm int 7723034Sdougm sa_zfs_update(sa_group_t group) 7733034Sdougm { 7743034Sdougm sa_optionset_t protopt; 7753034Sdougm sa_group_t parent; 7763034Sdougm char *command; 7773034Sdougm char *optstring; 7783034Sdougm int ret = SA_OK; 7793034Sdougm int doupdate = 0; 7803034Sdougm FILE *pfile; 7813034Sdougm 7823034Sdougm if (sa_is_share(group)) 7834327Sdougm parent = sa_get_parent_group(group); 7843034Sdougm else 7854327Sdougm parent = group; 7863034Sdougm 7873034Sdougm if (parent != NULL) { 7884327Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 7894327Sdougm if (command == NULL) 7904327Sdougm return (SA_NO_MEMORY); 7914327Sdougm 7924327Sdougm *command = '\0'; 7934327Sdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 7944327Sdougm protopt = sa_get_next_optionset(protopt)) { 7953034Sdougm 7964327Sdougm char *proto = sa_get_optionset_attr(protopt, "type"); 7974327Sdougm char *path; 7984327Sdougm char *dataset = NULL; 7994327Sdougm char *zfsopts = NULL; 8003034Sdougm 8014327Sdougm if (sa_is_share(group)) { 8024327Sdougm path = sa_get_share_attr((sa_share_t)group, 8034327Sdougm "path"); 8044327Sdougm if (path != NULL) { 8054327Sdougm sa_handle_impl_t impl_handle; 8063034Sdougm 8074327Sdougm impl_handle = sa_find_group_handle( 8084327Sdougm group); 8094327Sdougm if (impl_handle != NULL) 8104327Sdougm dataset = get_zfs_dataset( 8114327Sdougm impl_handle, path); 8124327Sdougm else 8134327Sdougm ret = SA_SYSTEM_ERR; 8143910Sdougm 8154327Sdougm sa_free_attr_string(path); 8164327Sdougm } 8174327Sdougm } else { 8184327Sdougm dataset = sa_get_group_attr(group, "name"); 8194327Sdougm } 8204327Sdougm /* update only when there is an optstring found */ 8214327Sdougm doupdate = 0; 8224327Sdougm if (proto != NULL && dataset != NULL) { 8234327Sdougm optstring = sa_proto_legacy_format(proto, 8244327Sdougm group, 1); 8254327Sdougm zfsopts = get_zfs_property(dataset, 8264327Sdougm ZFS_PROP_SHARENFS); 8273034Sdougm 8284327Sdougm if (optstring != NULL && zfsopts != NULL) { 8294327Sdougm if (strcmp(optstring, zfsopts) != 0) 8304327Sdougm doupdate++; 8314327Sdougm } 8323034Sdougm 8334327Sdougm if (doupdate) { 8344327Sdougm if (optstring != NULL && 8354327Sdougm strlen(optstring) > 0) { 8364327Sdougm (void) snprintf(command, 8374327Sdougm ZFS_MAXPROPLEN * 2, 8384327Sdougm "%s set sharenfs=%s %s" 8394327Sdougm COMMAND, 8404327Sdougm optstring, dataset); 8414327Sdougm } else { 8424327Sdougm (void) snprintf(command, 8434327Sdougm ZFS_MAXPROPLEN * 2, 8444327Sdougm "%s set sharenfs=on %s", 8454327Sdougm COMMAND, 8464327Sdougm dataset); 8474327Sdougm } 8484327Sdougm pfile = popen(command, "r"); 8494327Sdougm if (pfile != NULL) 8504327Sdougm ret = pclose(pfile); 8514327Sdougm switch (ret) { 8524327Sdougm default: 8534327Sdougm case 1: 8544327Sdougm ret = SA_SYSTEM_ERR; 8554327Sdougm break; 8564327Sdougm case 2: 8574327Sdougm ret = SA_SYNTAX_ERR; 8584327Sdougm break; 8594327Sdougm case 0: 8604327Sdougm break; 8614327Sdougm } 8624327Sdougm } 8634327Sdougm if (optstring != NULL) 8644327Sdougm free(optstring); 8654327Sdougm if (zfsopts != NULL) 8664327Sdougm free(zfsopts); 8673034Sdougm } 8684327Sdougm if (proto != NULL) 8694327Sdougm sa_free_attr_string(proto); 8704327Sdougm if (dataset != NULL) 8714327Sdougm free(dataset); 8723034Sdougm } 8734327Sdougm free(command); 8743034Sdougm } 8753034Sdougm return (ret); 8763034Sdougm } 8773034Sdougm 8783034Sdougm /* 8793034Sdougm * sa_group_is_zfs(group) 8803034Sdougm * 8813034Sdougm * Given the group, determine if the zfs attribute is set. 8823034Sdougm */ 8833034Sdougm 8843034Sdougm int 8853034Sdougm sa_group_is_zfs(sa_group_t group) 8863034Sdougm { 8873034Sdougm char *zfs; 8883034Sdougm int ret = 0; 8893034Sdougm 8903034Sdougm zfs = sa_get_group_attr(group, "zfs"); 8913034Sdougm if (zfs != NULL) { 8924327Sdougm ret = 1; 8934327Sdougm sa_free_attr_string(zfs); 8943034Sdougm } 8953034Sdougm return (ret); 8963034Sdougm } 8973034Sdougm 8983034Sdougm /* 8993034Sdougm * sa_path_is_zfs(path) 9003034Sdougm * 9013034Sdougm * Check to see if the file system path represents is of type "zfs". 9023034Sdougm */ 9033034Sdougm 9043034Sdougm int 9053034Sdougm sa_path_is_zfs(char *path) 9063034Sdougm { 9073034Sdougm char *fstype; 9083034Sdougm int ret = 0; 9093034Sdougm 9103034Sdougm fstype = sa_fstype(path); 9114327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) 9124327Sdougm ret = 1; 9133034Sdougm if (fstype != NULL) 9144327Sdougm sa_free_fstype(fstype); 9153034Sdougm return (ret); 9163034Sdougm } 917