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 /* 23*3407Sdougm * 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 static libzfs_handle_t *zfs_libhandle = NULL; 543218Sdougm static zfs_handle_t **zfs_list = NULL; 553218Sdougm static size_t zfs_list_count = 0; 563218Sdougm 573218Sdougm /* 583218Sdougm * sa_zfs_init() 593218Sdougm * 603218Sdougm * initialize an access handle into libzfs 613218Sdougm */ 623218Sdougm 633218Sdougm void 643218Sdougm sa_zfs_init() 653218Sdougm { 663218Sdougm zfs_libhandle = libzfs_init(); 673218Sdougm libzfs_print_on_error(zfs_libhandle, B_TRUE); 683218Sdougm } 693218Sdougm 703218Sdougm /* 713218Sdougm * sa_zfs_fini() 723218Sdougm * 733218Sdougm * cleanup data structures and the libzfs handle used for accessing 743218Sdougm * zfs file share info. 753218Sdougm */ 763218Sdougm 773218Sdougm void 783218Sdougm sa_zfs_fini() 793218Sdougm { 803218Sdougm if (zfs_libhandle != NULL) { 813218Sdougm libzfs_fini(zfs_libhandle); 823218Sdougm zfs_libhandle = NULL; 833218Sdougm if (zfs_list != NULL) { 843218Sdougm /* 853218Sdougm * contents of zfs_list were already freed by the call to 863218Sdougm * libzfs_fini(). 873218Sdougm */ 883218Sdougm free(zfs_list); 893218Sdougm zfs_list = NULL; 903218Sdougm } 913218Sdougm } 923218Sdougm } 933218Sdougm 943218Sdougm /* 953218Sdougm * get_one_filesystem(zfs_handle_t, data) 963218Sdougm * 973218Sdougm * an interator function called while iterating through the ZFS 983218Sdougm * root. It accumulates into an array of file system handles that can 993218Sdougm * be used to derive info about those file systems. 1003034Sdougm */ 1013034Sdougm 1023218Sdougm static int 1033218Sdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1043218Sdougm { 1053218Sdougm get_all_cbdata_t *cbp = data; 1063218Sdougm 1073218Sdougm /* 1083218Sdougm * Skip any zvols 1093218Sdougm */ 1103218Sdougm if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1113218Sdougm zfs_close(zhp); 1123218Sdougm return (0); 1133218Sdougm } 1143218Sdougm 1153218Sdougm if (cbp->cb_alloc == cbp->cb_used) { 1163218Sdougm zfs_handle_t **handles; 1173218Sdougm 1183218Sdougm if (cbp->cb_alloc == 0) 1193218Sdougm cbp->cb_alloc = 64; 1203218Sdougm else 1213218Sdougm cbp->cb_alloc *= 2; 1223218Sdougm 1233218Sdougm handles = calloc(1, cbp->cb_alloc * sizeof (void *)); 1243218Sdougm if (handles == NULL) { 1253218Sdougm return (0); 1263218Sdougm } 1273218Sdougm 1283218Sdougm if (cbp->cb_handles) { 1293218Sdougm (void) memcpy(handles, cbp->cb_handles, 1303218Sdougm cbp->cb_used * sizeof (void *)); 1313218Sdougm free(cbp->cb_handles); 1323218Sdougm } 1333218Sdougm 1343218Sdougm cbp->cb_handles = handles; 1353218Sdougm } 1363218Sdougm 1373218Sdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1383218Sdougm 1393218Sdougm return (zfs_iter_filesystems(zhp, get_one_filesystem, data)); 1403218Sdougm } 1413218Sdougm 1423218Sdougm /* 1433218Sdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1443218Sdougm * 1453218Sdougm * iterate through all ZFS file systems starting at the root. Returns 1463218Sdougm * a count and an array of handle pointers. Allocating is only done 1473218Sdougm * once. The caller does not need to free since it will be done at 1483218Sdougm * sa_zfs_fini() time. 1493218Sdougm */ 1503218Sdougm 1513218Sdougm static void 1523218Sdougm get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1533218Sdougm { 1543218Sdougm get_all_cbdata_t cb = { 0 }; 1553218Sdougm 1563218Sdougm if (zfs_list != NULL) { 1573218Sdougm *fslist = zfs_list; 1583218Sdougm *count = zfs_list_count; 1593218Sdougm return; 1603218Sdougm } 1613218Sdougm 1623218Sdougm (void) zfs_iter_root(zfs_libhandle, get_one_filesystem, &cb); 1633218Sdougm 1643218Sdougm zfs_list = *fslist = cb.cb_handles; 1653218Sdougm zfs_list_count = *count = cb.cb_used; 1663218Sdougm } 1673218Sdougm 1683218Sdougm /* 1693218Sdougm * mountpoint_compare(a, b) 1703218Sdougm * 1713218Sdougm * compares the mountpoint on two zfs file systems handles. 1723218Sdougm * returns values following strcmp() model. 1733218Sdougm */ 1743218Sdougm 1753218Sdougm static int 1763218Sdougm mountpoint_compare(const void *a, const void *b) 1773218Sdougm { 1783218Sdougm zfs_handle_t **za = (zfs_handle_t **)a; 1793218Sdougm zfs_handle_t **zb = (zfs_handle_t **)b; 1803218Sdougm char mounta[MAXPATHLEN]; 1813218Sdougm char mountb[MAXPATHLEN]; 1823218Sdougm 1833218Sdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 1843218Sdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 1853218Sdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 1863218Sdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 1873218Sdougm 1883218Sdougm return (strcmp(mounta, mountb)); 1893218Sdougm } 1903218Sdougm 1913034Sdougm /* 1923034Sdougm * get_zfs_dataset(path) 1933034Sdougm * 1943034Sdougm * get the name of the ZFS dataset the path is equivalent to. The 1953034Sdougm * dataset name is used for get/set of ZFS properties since libzfs 1963034Sdougm * requires a dataset to do a zfs_open(). 1973034Sdougm */ 1983034Sdougm 1993034Sdougm static char * 2003034Sdougm get_zfs_dataset(char *path) 2013034Sdougm { 2023218Sdougm size_t i, count = 0; 2033034Sdougm char *dataset = NULL; 2043218Sdougm zfs_handle_t **zlist; 2053218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 2063218Sdougm 2073218Sdougm get_all_filesystems(&zlist, &count); 2083218Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2093218Sdougm for (i = 0; i < count; i++) { 2103218Sdougm /* must have a mountpoint */ 2113218Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 2123218Sdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 2133218Sdougm /* no mountpoint */ 2143218Sdougm continue; 2153218Sdougm } 2163034Sdougm 2173218Sdougm /* mountpoint must be a path */ 2183218Sdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 2193218Sdougm strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 2203218Sdougm continue; 2213218Sdougm 2223218Sdougm /* canmount must be set */ 2233218Sdougm if (!zfs_prop_get_int(zlist[i], ZFS_PROP_CANMOUNT)) 2243218Sdougm continue; 2253218Sdougm 2263218Sdougm /* 2273218Sdougm * have a mountable handle but want to skip those marked none 2283218Sdougm * and legacy 2293218Sdougm */ 2303218Sdougm if (strcmp(mountpoint, path) == 0) { 2313218Sdougm dataset = (char *)zfs_get_name(zlist[i]); 2323218Sdougm break; 2333034Sdougm } 2343218Sdougm 2353034Sdougm } 2363218Sdougm 2373034Sdougm if (dataset != NULL) { 2383034Sdougm dataset = strdup(dataset); 2393034Sdougm } 2403034Sdougm return (dataset); 2413034Sdougm } 2423034Sdougm 2433034Sdougm /* 2443034Sdougm * get_zfs_property(dataset, property) 2453034Sdougm * 2463034Sdougm * Get the file system property specified from the ZFS dataset. 2473034Sdougm */ 2483034Sdougm 2493034Sdougm static char * 2503034Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 2513034Sdougm { 2523034Sdougm zfs_handle_t *handle = NULL; 2533034Sdougm char shareopts[ZFS_MAXPROPLEN]; 2543034Sdougm libzfs_handle_t *libhandle; 2553034Sdougm 2563034Sdougm libhandle = libzfs_init(); 2573034Sdougm if (libhandle != NULL) { 2583034Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 2593034Sdougm if (handle != NULL) { 2603034Sdougm if (zfs_prop_get(handle, property, shareopts, 2613034Sdougm sizeof (shareopts), NULL, NULL, 0, 2623218Sdougm B_FALSE) == 0) { 2633034Sdougm zfs_close(handle); 2643034Sdougm libzfs_fini(libhandle); 2653034Sdougm return (strdup(shareopts)); 2663034Sdougm } 2673034Sdougm zfs_close(handle); 2683034Sdougm } 2693034Sdougm libzfs_fini(libhandle); 2703034Sdougm } 2713034Sdougm return (NULL); 2723034Sdougm } 2733034Sdougm 2743034Sdougm /* 2753034Sdougm * sa_zfs_is_shared(path) 2763034Sdougm * 2773034Sdougm * Check to see if the ZFS path provided has the sharenfs option set 2783034Sdougm * or not. 2793034Sdougm */ 2803034Sdougm 2813034Sdougm int 2823034Sdougm sa_zfs_is_shared(char *path) 2833034Sdougm { 2843034Sdougm int ret = 0; 2853034Sdougm char *dataset; 2863034Sdougm zfs_handle_t *handle = NULL; 2873034Sdougm char shareopts[ZFS_MAXPROPLEN]; 2883034Sdougm libzfs_handle_t *libhandle; 2893034Sdougm 2903034Sdougm dataset = get_zfs_dataset(path); 2913034Sdougm if (dataset != NULL) { 2923034Sdougm libhandle = libzfs_init(); 2933034Sdougm if (libhandle != NULL) { 2943034Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 2953034Sdougm if (handle != NULL) { 2963034Sdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, shareopts, 2973034Sdougm sizeof (shareopts), NULL, NULL, 0, 2983218Sdougm B_FALSE) == 0 && 2993034Sdougm strcmp(shareopts, "off") != 0) 3003034Sdougm ret = 1; /* it is shared */ 3013034Sdougm zfs_close(handle); 3023034Sdougm } 3033034Sdougm libzfs_fini(libhandle); 3043034Sdougm } 3053034Sdougm free(dataset); 3063034Sdougm } 3073034Sdougm return (ret); 3083034Sdougm } 3093034Sdougm 3103034Sdougm /* 3113034Sdougm * find_or_create_group(groupname, proto, *err) 3123034Sdougm * 3133034Sdougm * While walking the ZFS tree, we need to add shares to a defined 3143034Sdougm * group. If the group doesn't exist, create it first, making sure it 3153034Sdougm * is marked as a ZFS group. 3163034Sdougm * 3173108Sdougm * Note that all ZFS shares are in a subgroup of the top level group 3183108Sdougm * called "zfs". 3193034Sdougm */ 3203034Sdougm 3213034Sdougm static sa_group_t 3223034Sdougm find_or_create_group(char *groupname, char *proto, int *err) 3233034Sdougm { 3243034Sdougm sa_group_t group; 3253034Sdougm sa_optionset_t optionset; 3263034Sdougm int ret = SA_OK; 3273034Sdougm 3283034Sdougm /* 3293034Sdougm * we check to see if the "zfs" group exists. Since this 3303034Sdougm * should be the top level group, we don't want the 3313034Sdougm * parent. This is to make sure the zfs group has been created 3323034Sdougm * and to created if it hasn't been. 3333034Sdougm */ 3343034Sdougm group = sa_get_group(groupname); 3353034Sdougm if (group == NULL) { 3363034Sdougm group = sa_create_group(groupname, &ret); 3373108Sdougm 3383108Sdougm /* make sure this is flagged as a ZFS group */ 3393034Sdougm if (group != NULL) 3403034Sdougm ret = sa_set_group_attr(group, "zfs", "true"); 3413034Sdougm } 3423034Sdougm if (group != NULL) { 3433034Sdougm if (proto != NULL) { 3443034Sdougm optionset = sa_get_optionset(group, proto); 3453034Sdougm if (optionset == NULL) { 3463034Sdougm optionset = sa_create_optionset(group, proto); 3473034Sdougm } else { 3483034Sdougm char **protolist; 3493034Sdougm int numprotos, i; 3503034Sdougm numprotos = sa_get_protocols(&protolist); 3513034Sdougm for (i = 0; i < numprotos; i++) { 3523034Sdougm optionset = sa_create_optionset(group, protolist[i]); 3533034Sdougm } 3543034Sdougm if (protolist != NULL) 3553034Sdougm free(protolist); 3563034Sdougm } 3573034Sdougm } 3583034Sdougm } 3593034Sdougm if (err != NULL) 3603034Sdougm *err = ret; 3613034Sdougm return (group); 3623034Sdougm } 3633034Sdougm 3643034Sdougm /* 3653108Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 3663108Sdougm * 3673108Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 3683108Sdougm * function looks to see if the groupname exists and returns it if it 3693108Sdougm * does or else creates a new one with the specified name and returns 3703108Sdougm * that. The "zfs" group will exist before we get here, but we make 3713108Sdougm * sure just in case. 3723108Sdougm * 3733108Sdougm * err must be a valid pointer. 3743108Sdougm */ 3753108Sdougm 3763108Sdougm static sa_group_t 3773108Sdougm find_or_create_zfs_subgroup(char *groupname, char *optstring, int *err) 3783108Sdougm { 3793108Sdougm sa_group_t group = NULL; 3803108Sdougm sa_group_t zfs; 3813108Sdougm char *name; 3823108Sdougm char *options; 3833108Sdougm 3843108Sdougm /* start with the top-level "zfs" group */ 3853108Sdougm zfs = sa_get_group("zfs"); 3863108Sdougm *err = SA_OK; 3873108Sdougm if (zfs != NULL) { 3883108Sdougm for (group = sa_get_sub_group(zfs); group != NULL; 3893108Sdougm group = sa_get_next_group(group)) { 3903108Sdougm name = sa_get_group_attr(group, "name"); 3913108Sdougm if (name != NULL && strcmp(name, groupname) == 0) { 3923108Sdougm /* have the group so break out of here */ 3933108Sdougm sa_free_attr_string(name); 3943108Sdougm break; 3953108Sdougm } 3963108Sdougm if (name != NULL) 3973108Sdougm sa_free_attr_string(name); 3983108Sdougm } 3993108Sdougm 4003108Sdougm if (group == NULL) { 4013108Sdougm /* need to create the sub-group since it doesn't exist */ 4023108Sdougm group = _sa_create_zfs_group(zfs, groupname); 4033108Sdougm if (group != NULL) { 4043108Sdougm set_node_attr(group, "zfs", "true"); 4053108Sdougm } 4063108Sdougm if (strcmp(optstring, "on") == 0) 4073108Sdougm optstring = "rw"; 4083108Sdougm if (group != NULL) { 4093108Sdougm options = strdup(optstring); 4103108Sdougm if (options != NULL) { 4113108Sdougm *err = sa_parse_legacy_options(group, options, "nfs"); 4123108Sdougm free(options); 4133108Sdougm } else { 4143108Sdougm *err = SA_NO_MEMORY; 4153108Sdougm } 4163108Sdougm } 4173108Sdougm } 4183108Sdougm } 4193108Sdougm return (group); 4203108Sdougm } 4213108Sdougm 4223108Sdougm /* 4233034Sdougm * sa_get_zfs_shares(groupname) 4243034Sdougm * 4253034Sdougm * Walk the mnttab for all zfs mounts and determine which are 4263034Sdougm * shared. Find or create the appropriate group/sub-group to contain 4273034Sdougm * the shares. 4283034Sdougm * 4293034Sdougm * All shares are in a sub-group that will hold the properties. This 4303034Sdougm * allows representing the inherited property model. 4313034Sdougm */ 4323034Sdougm 4333034Sdougm int 4343034Sdougm sa_get_zfs_shares(char *groupname) 4353034Sdougm { 4363034Sdougm sa_group_t group; 4373034Sdougm sa_group_t zfsgroup; 4383034Sdougm int legacy = 0; 4393034Sdougm int err; 4403218Sdougm zfs_handle_t **zlist; 4413034Sdougm char shareopts[ZFS_MAXPROPLEN]; 4423034Sdougm sa_share_t share; 4433034Sdougm zfs_source_t source; 4443034Sdougm char sourcestr[ZFS_MAXPROPLEN]; 4453218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 4463108Sdougm char *options; 4473218Sdougm size_t count = 0, i; 4483034Sdougm 4493034Sdougm /* 4503034Sdougm * if we can't access libzfs, don't bother doing anything. 4513034Sdougm */ 4523218Sdougm if (zfs_libhandle == NULL) 4533034Sdougm return (SA_SYSTEM_ERR); 4543034Sdougm 4553034Sdougm zfsgroup = find_or_create_group(groupname, "nfs", &err); 4563034Sdougm if (zfsgroup != NULL) { 4573034Sdougm /* 4583034Sdougm * need to walk the mounted ZFS pools and datasets to 4593034Sdougm * find shares that are possible. 4603034Sdougm */ 4613218Sdougm get_all_filesystems(&zlist, &count); 4623218Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 4633218Sdougm 4643034Sdougm group = zfsgroup; 4653218Sdougm for (i = 0; i < count; i++) { 4663218Sdougm char *dataset; 4673218Sdougm 4683218Sdougm source = ZFS_SRC_ALL; 4693218Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 4703218Sdougm sizeof (mountpoint), NULL, NULL, 0, 4713218Sdougm B_FALSE) != 0) { 4723218Sdougm /* no mountpoint */ 4733218Sdougm continue; 4743218Sdougm } 4753218Sdougm 4763218Sdougm /* 4773218Sdougm * zfs_get_name value must not be freed. It is just a 4783218Sdougm * pointer to a value in the handle. 4793218Sdougm */ 4803218Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 4813218Sdougm continue; 4823218Sdougm 4833218Sdougm /* 4843218Sdougm * only deal with "mounted" file systems since 4853218Sdougm * unmounted file systems can't actually be shared. 4863218Sdougm */ 4873218Sdougm 4883218Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 4893218Sdougm continue; 4903218Sdougm 4913218Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 4923034Sdougm sizeof (shareopts), &source, sourcestr, 4933034Sdougm ZFS_MAXPROPLEN, 4943218Sdougm B_FALSE) == 0 && 4953034Sdougm strcmp(shareopts, "off") != 0) { 4963218Sdougm /* it is shared so add to list */ 4973218Sdougm share = sa_find_share(mountpoint); 4983218Sdougm err = SA_OK; 4993218Sdougm if (share != NULL) { 5003218Sdougm /* 5013218Sdougm * A zfs file system had been shared 5023218Sdougm * through traditional methods 5033218Sdougm * (share/dfstab or added to a non-zfs 5043218Sdougm * group. Now it has been added to a 5053218Sdougm * ZFS group via the zfs 5063218Sdougm * command. Remove from previous 5073218Sdougm * config and setup with current 5083218Sdougm * options. 5093218Sdougm */ 5103218Sdougm err = sa_remove_share(share); 5113218Sdougm share = NULL; 5123218Sdougm } 5133218Sdougm if (err == SA_OK) { 5143218Sdougm if (source & ZFS_SRC_INHERITED) { 5153218Sdougm int doshopt = 0; 5163218Sdougm /* 5173218Sdougm * Need to find the "real" parent 5183218Sdougm * sub-group. It may not be mounted, but it 5193218Sdougm * was identified in the "sourcestr" 5203218Sdougm * variable. The real parent not mounted can 5213218Sdougm * occur if "canmount=off and sharenfs=on". 5223218Sdougm */ 5233218Sdougm group = find_or_create_zfs_subgroup(sourcestr, 5243218Sdougm shareopts, &doshopt); 5253218Sdougm if (group != NULL) { 5263218Sdougm share = _sa_add_share(group, mountpoint, 5273034Sdougm SA_SHARE_TRANSIENT, 5283034Sdougm &err); 5293218Sdougm /* 5303218Sdougm * some options may only be on 5313218Sdougm * shares. If the opt string 5323218Sdougm * contains one of those, we 5333218Sdougm * put it just on the share. 5343218Sdougm */ 5353218Sdougm if (share != NULL && 5363218Sdougm doshopt == SA_PROP_SHARE_ONLY) { 5373218Sdougm options = strdup(shareopts); 5383218Sdougm if (options != NULL) { 5393218Sdougm err = sa_parse_legacy_options(share, 5403108Sdougm options, "nfs"); 5413218Sdougm free(options); 5423108Sdougm } 5433108Sdougm } 5443034Sdougm } else { 5453218Sdougm err = SA_NO_MEMORY; 5463218Sdougm } 5473218Sdougm } else { 5483218Sdougm group = _sa_create_zfs_group(zfsgroup, dataset); 5493218Sdougm if (group == NULL) { 5503218Sdougm static int err = 0; 5513108Sdougm /* 5523218Sdougm * there is a problem, but we can't do 5533218Sdougm * anything about it at this point so 5543218Sdougm * we issue a warning an move on. 5553108Sdougm */ 5563218Sdougm if (err == 0) { 5573218Sdougm /* only print error once */ 5583218Sdougm (void) fprintf(stderr, 559*3407Sdougm dgettext(TEXT_DOMAIN, 560*3407Sdougm "Cannot create ZFS subgroup " 5613218Sdougm "during initialization:" 5623218Sdougm " %s\n"), 5633218Sdougm sa_errorstr(SA_SYSTEM_ERR)); 5643218Sdougm err = 1; 5653218Sdougm } 5663218Sdougm continue; 5673218Sdougm } 5683218Sdougm set_node_attr(group, "zfs", "true"); 5693218Sdougm share = _sa_add_share(group, mountpoint, 5703218Sdougm SA_SHARE_TRANSIENT, &err); 5713218Sdougm if (err == SA_OK) { 5723218Sdougm if (strcmp(shareopts, "on") != 0) { 5733218Sdougm options = strdup(shareopts); 5743218Sdougm if (options != NULL) { 5753218Sdougm err = sa_parse_legacy_options(group, 5763034Sdougm options, 5773034Sdougm "nfs"); 5783218Sdougm free(options); 5793218Sdougm } 5803218Sdougm if (err == SA_PROP_SHARE_ONLY) { 5813108Sdougm /* 5823108Sdougm * Same as above, some 5833108Sdougm * properties may only be on 5843108Sdougm * shares, but due to the ZFS 5853108Sdougm * sub-groups being 5863108Sdougm * artificial, we sometimes 5873108Sdougm * get this and have to deal 5883108Sdougm * with it. We do it by 5893108Sdougm * attempting to put it on the 5903108Sdougm * share. 5913108Sdougm */ 5923218Sdougm options = strdup(shareopts); 5933218Sdougm if (options != NULL) 5943218Sdougm err = sa_parse_legacy_options( 5953108Sdougm share, 5963108Sdougm options, 5973108Sdougm "nfs"); 5983108Sdougm free(options); 5993108Sdougm } 6003218Sdougm /* unmark the share's changed state */ 6013218Sdougm set_node_attr(share, "changed", NULL); 6023034Sdougm } 6033034Sdougm } 6043034Sdougm } 6053034Sdougm } 6063034Sdougm } 6073034Sdougm } 6083034Sdougm } 6093218Sdougm /* 6103218Sdougm * Don't need to free the "zlist" variable since it is only a 6113218Sdougm * pointer to a cached value that will be freed when 6123218Sdougm * sa_fini() is called. 6133218Sdougm */ 6143034Sdougm return (legacy); 6153034Sdougm } 6163034Sdougm 6173034Sdougm #define COMMAND "/usr/sbin/zfs" 6183034Sdougm 6193034Sdougm /* 6203034Sdougm * sa_zfs_set_sharenfs(group, path, on) 6213034Sdougm * 6223034Sdougm * Update the "sharenfs" property on the path. If on is true, then set 6233034Sdougm * to the properties on the group or "on" if no properties are 6243034Sdougm * defined. Set to "off" if on is false. 6253034Sdougm */ 6263034Sdougm 6273034Sdougm int 6283034Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 6293034Sdougm { 6303034Sdougm int ret = SA_NOT_IMPLEMENTED; 6313034Sdougm char *command; 6323034Sdougm 6333034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 6343034Sdougm if (command != NULL) { 6353034Sdougm char *opts = NULL; 6363034Sdougm char *dataset; 6373034Sdougm FILE *pfile; 6383034Sdougm /* for now, NFS is always available for "zfs" */ 6393034Sdougm if (on) { 6403034Sdougm opts = sa_proto_legacy_format("nfs", group, 1); 6413034Sdougm if (opts != NULL && strlen(opts) == 0) { 6423034Sdougm free(opts); 6433034Sdougm opts = strdup("on"); 6443034Sdougm } 6453034Sdougm } 6463034Sdougm dataset = get_zfs_dataset(path); 6473034Sdougm if (dataset != NULL) { 6483034Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 6493034Sdougm "%s set sharenfs=\"%s\" %s", COMMAND, 6503034Sdougm opts != NULL ? opts : "off", 6513034Sdougm dataset); 6523034Sdougm pfile = popen(command, "r"); 6533034Sdougm if (pfile != NULL) { 6543034Sdougm ret = pclose(pfile); 6553034Sdougm if (ret != 0) 6563034Sdougm ret = SA_SYSTEM_ERR; 6573034Sdougm } 6583034Sdougm } 6593034Sdougm if (opts != NULL) 6603034Sdougm free(opts); 6613034Sdougm if (dataset != NULL) 6623034Sdougm free(dataset); 6633034Sdougm free(command); 6643034Sdougm } 6653034Sdougm return (ret); 6663034Sdougm } 6673034Sdougm 6683034Sdougm /* 6693034Sdougm * sa_zfs_update(group) 6703034Sdougm * 6713034Sdougm * call back to ZFS to update the share if necessary. 6723034Sdougm * Don't do it if it isn't a real change. 6733034Sdougm */ 6743034Sdougm int 6753034Sdougm sa_zfs_update(sa_group_t group) 6763034Sdougm { 6773034Sdougm sa_optionset_t protopt; 6783034Sdougm sa_group_t parent; 6793034Sdougm char *command; 6803034Sdougm char *optstring; 6813034Sdougm int ret = SA_OK; 6823034Sdougm int doupdate = 0; 6833034Sdougm FILE *pfile; 6843034Sdougm 6853034Sdougm if (sa_is_share(group)) 6863034Sdougm parent = sa_get_parent_group(group); 6873034Sdougm else 6883034Sdougm parent = group; 6893034Sdougm 6903034Sdougm if (parent != NULL) { 6913034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 6923034Sdougm if (command == NULL) 6933034Sdougm return (SA_NO_MEMORY); 6943034Sdougm 6953034Sdougm *command = '\0'; 6963034Sdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 6973034Sdougm protopt = sa_get_next_optionset(protopt)) { 6983034Sdougm 6993034Sdougm char *proto = sa_get_optionset_attr(protopt, "type"); 7003034Sdougm char *path; 7013034Sdougm char *dataset = NULL; 7023034Sdougm char *zfsopts = NULL; 7033034Sdougm 7043034Sdougm if (sa_is_share(group)) { 7053034Sdougm path = sa_get_share_attr((sa_share_t)group, "path"); 7063034Sdougm if (path != NULL) { 7073034Sdougm dataset = get_zfs_dataset(path); 7083034Sdougm sa_free_attr_string(path); 7093034Sdougm } 7103034Sdougm } else { 7113034Sdougm dataset = sa_get_group_attr(group, "name"); 7123034Sdougm } 7133034Sdougm /* update only when there is an optstring found */ 7143034Sdougm doupdate = 0; 7153034Sdougm if (proto != NULL && dataset != NULL) { 7163034Sdougm optstring = sa_proto_legacy_format(proto, group, 1); 7173034Sdougm zfsopts = get_zfs_property(dataset, ZFS_PROP_SHARENFS); 7183034Sdougm 7193034Sdougm if (optstring != NULL && zfsopts != NULL) { 7203034Sdougm if (strcmp(optstring, zfsopts) != 0) 7213034Sdougm doupdate++; 7223034Sdougm } 7233034Sdougm 7243034Sdougm if (doupdate) { 7253034Sdougm if (optstring != NULL && strlen(optstring) > 0) { 7263034Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 7273034Sdougm "%s set sharenfs=%s %s", COMMAND, 7283034Sdougm optstring, dataset); 7293034Sdougm } else { 7303034Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 7313034Sdougm "%s set sharenfs=on %s", COMMAND, 7323034Sdougm dataset); 7333034Sdougm } 7343034Sdougm pfile = popen(command, "r"); 7353034Sdougm if (pfile != NULL) 7363034Sdougm ret = pclose(pfile); 7373034Sdougm switch (ret) { 7383034Sdougm default: 7393034Sdougm case 1: 7403034Sdougm ret = SA_SYSTEM_ERR; 7413034Sdougm break; 7423034Sdougm case 2: 7433034Sdougm ret = SA_SYNTAX_ERR; 7443034Sdougm break; 7453034Sdougm case 0: 7463034Sdougm break; 7473034Sdougm } 7483034Sdougm } 7493034Sdougm if (optstring != NULL) { 7503034Sdougm free(optstring); 7513034Sdougm } 7523034Sdougm if (zfsopts != NULL) 7533034Sdougm free(zfsopts); 7543034Sdougm } 7553034Sdougm if (proto != NULL) 7563034Sdougm sa_free_attr_string(proto); 7573034Sdougm if (dataset != NULL) 7583034Sdougm free(dataset); 7593034Sdougm } 7603034Sdougm free(command); 7613034Sdougm } 7623034Sdougm return (ret); 7633034Sdougm } 7643034Sdougm 7653034Sdougm /* 7663034Sdougm * sa_group_is_zfs(group) 7673034Sdougm * 7683034Sdougm * Given the group, determine if the zfs attribute is set. 7693034Sdougm */ 7703034Sdougm 7713034Sdougm int 7723034Sdougm sa_group_is_zfs(sa_group_t group) 7733034Sdougm { 7743034Sdougm char *zfs; 7753034Sdougm int ret = 0; 7763034Sdougm 7773034Sdougm zfs = sa_get_group_attr(group, "zfs"); 7783034Sdougm if (zfs != NULL) { 7793034Sdougm ret = 1; 7803034Sdougm sa_free_attr_string(zfs); 7813034Sdougm } 7823034Sdougm return (ret); 7833034Sdougm } 7843034Sdougm 7853034Sdougm /* 7863034Sdougm * sa_path_is_zfs(path) 7873034Sdougm * 7883034Sdougm * Check to see if the file system path represents is of type "zfs". 7893034Sdougm */ 7903034Sdougm 7913034Sdougm int 7923034Sdougm sa_path_is_zfs(char *path) 7933034Sdougm { 7943034Sdougm char *fstype; 7953034Sdougm int ret = 0; 7963034Sdougm 7973034Sdougm fstype = sa_fstype(path); 7983034Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 7993034Sdougm ret = 1; 8003034Sdougm } 8013034Sdougm if (fstype != NULL) 8023034Sdougm sa_free_fstype(fstype); 8033034Sdougm return (ret); 8043034Sdougm } 805