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 /* 238845Samw@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 274592Smarks #include <stdio.h> 283034Sdougm #include <libzfs.h> 293034Sdougm #include <string.h> 304345Sdougm #include <strings.h> 3110761SWilliam.Krier@Sun.COM #include <errno.h> 323034Sdougm #include <libshare.h> 333034Sdougm #include "libshare_impl.h" 343218Sdougm #include <libintl.h> 354592Smarks #include <sys/mnttab.h> 364592Smarks #include <sys/mntent.h> 373034Sdougm 385331Samw extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 393034Sdougm extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 403034Sdougm extern char *sa_fstype(char *); 413034Sdougm extern void set_node_attr(void *, char *, char *); 423034Sdougm extern int sa_is_share(void *); 435951Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 443218Sdougm 453034Sdougm /* 463218Sdougm * File system specific code for ZFS. The original code was stolen 473218Sdougm * from the "zfs" command and modified to better suit this library's 483218Sdougm * usage. 493218Sdougm */ 503218Sdougm 513218Sdougm typedef struct get_all_cbdata { 523218Sdougm zfs_handle_t **cb_handles; 533218Sdougm size_t cb_alloc; 543218Sdougm size_t cb_used; 554345Sdougm uint_t cb_types; 563218Sdougm } get_all_cbdata_t; 573218Sdougm 583218Sdougm /* 593910Sdougm * sa_zfs_init(impl_handle) 603218Sdougm * 613910Sdougm * Initialize an access handle into libzfs. The handle needs to stay 623910Sdougm * around until sa_zfs_fini() in order to maintain the cache of 633910Sdougm * mounts. 643218Sdougm */ 653218Sdougm 664327Sdougm int 673910Sdougm sa_zfs_init(sa_handle_impl_t impl_handle) 683218Sdougm { 693910Sdougm impl_handle->zfs_libhandle = libzfs_init(); 704327Sdougm if (impl_handle->zfs_libhandle != NULL) { 714327Sdougm libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 724327Sdougm return (B_TRUE); 734327Sdougm } 744327Sdougm return (B_FALSE); 753218Sdougm } 763218Sdougm 773218Sdougm /* 783910Sdougm * sa_zfs_fini(impl_handle) 793218Sdougm * 803218Sdougm * cleanup data structures and the libzfs handle used for accessing 813218Sdougm * zfs file share info. 823218Sdougm */ 833218Sdougm 843218Sdougm void 853910Sdougm sa_zfs_fini(sa_handle_impl_t impl_handle) 863218Sdougm { 873910Sdougm if (impl_handle->zfs_libhandle != NULL) { 884327Sdougm if (impl_handle->zfs_list != NULL) { 894345Sdougm zfs_handle_t **zhp = impl_handle->zfs_list; 904345Sdougm size_t i; 914345Sdougm 924327Sdougm /* 934345Sdougm * Contents of zfs_list need to be freed so we 944345Sdougm * don't lose ZFS handles. 954327Sdougm */ 964345Sdougm for (i = 0; i < impl_handle->zfs_list_count; i++) { 974345Sdougm zfs_close(zhp[i]); 984345Sdougm } 994327Sdougm free(impl_handle->zfs_list); 1004327Sdougm impl_handle->zfs_list = NULL; 1014327Sdougm impl_handle->zfs_list_count = 0; 1024327Sdougm } 1034345Sdougm 1044345Sdougm libzfs_fini(impl_handle->zfs_libhandle); 1054345Sdougm impl_handle->zfs_libhandle = NULL; 1063218Sdougm } 1073218Sdougm } 1083218Sdougm 1093218Sdougm /* 1103218Sdougm * get_one_filesystem(zfs_handle_t, data) 1113218Sdougm * 1125331Samw * an iterator function called while iterating through the ZFS 1133218Sdougm * root. It accumulates into an array of file system handles that can 1143218Sdougm * be used to derive info about those file systems. 1154345Sdougm * 1164345Sdougm * Note that as this function is called, we close all zhp handles that 1174345Sdougm * are not going to be places into the cp_handles list. We don't want 1184345Sdougm * to close the ones we are keeping, but all others would be leaked if 1194345Sdougm * not closed here. 1203034Sdougm */ 1213034Sdougm 1223218Sdougm static int 1233218Sdougm get_one_filesystem(zfs_handle_t *zhp, void *data) 1243218Sdougm { 1253218Sdougm get_all_cbdata_t *cbp = data; 1264345Sdougm zfs_type_t type = zfs_get_type(zhp); 1273218Sdougm 1283218Sdougm /* 1294345Sdougm * Interate over any nested datasets. 1303218Sdougm */ 1314345Sdougm if (type == ZFS_TYPE_FILESYSTEM && 1324345Sdougm zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 1334345Sdougm zfs_close(zhp); 1344345Sdougm return (1); 1354345Sdougm } 1364345Sdougm 1374345Sdougm /* 1384345Sdougm * Skip any datasets whose type does not match. 1394345Sdougm */ 1404345Sdougm if ((type & cbp->cb_types) == 0) { 1413218Sdougm zfs_close(zhp); 1423218Sdougm return (0); 1433218Sdougm } 1443218Sdougm 1453218Sdougm if (cbp->cb_alloc == cbp->cb_used) { 1463218Sdougm zfs_handle_t **handles; 1473218Sdougm 1483218Sdougm if (cbp->cb_alloc == 0) 1493218Sdougm cbp->cb_alloc = 64; 1503218Sdougm else 1513218Sdougm cbp->cb_alloc *= 2; 1523218Sdougm 1534345Sdougm handles = (zfs_handle_t **)calloc(1, 1544345Sdougm cbp->cb_alloc * sizeof (void *)); 1554345Sdougm 1563218Sdougm if (handles == NULL) { 1574345Sdougm zfs_close(zhp); 1584327Sdougm return (0); 1593218Sdougm } 1603218Sdougm if (cbp->cb_handles) { 1614345Sdougm bcopy(cbp->cb_handles, handles, 1623218Sdougm cbp->cb_used * sizeof (void *)); 1633218Sdougm free(cbp->cb_handles); 1643218Sdougm } 1653218Sdougm 1663218Sdougm cbp->cb_handles = handles; 1673218Sdougm } 1683218Sdougm 1693218Sdougm cbp->cb_handles[cbp->cb_used++] = zhp; 1703218Sdougm 1714345Sdougm return (0); 1723218Sdougm } 1733218Sdougm 1743218Sdougm /* 1753218Sdougm * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 1763218Sdougm * 1773218Sdougm * iterate through all ZFS file systems starting at the root. Returns 1783218Sdougm * a count and an array of handle pointers. Allocating is only done 1793218Sdougm * once. The caller does not need to free since it will be done at 1803218Sdougm * sa_zfs_fini() time. 1813218Sdougm */ 1823218Sdougm 1833218Sdougm static void 1843910Sdougm get_all_filesystems(sa_handle_impl_t impl_handle, 1853910Sdougm zfs_handle_t ***fslist, size_t *count) 1863218Sdougm { 1873218Sdougm get_all_cbdata_t cb = { 0 }; 1884345Sdougm cb.cb_types = ZFS_TYPE_FILESYSTEM; 1893218Sdougm 1903910Sdougm if (impl_handle->zfs_list != NULL) { 1914327Sdougm *fslist = impl_handle->zfs_list; 1924327Sdougm *count = impl_handle->zfs_list_count; 1934327Sdougm return; 1943218Sdougm } 1953218Sdougm 1963910Sdougm (void) zfs_iter_root(impl_handle->zfs_libhandle, 1974327Sdougm get_one_filesystem, &cb); 1983218Sdougm 1993910Sdougm impl_handle->zfs_list = *fslist = cb.cb_handles; 2003910Sdougm impl_handle->zfs_list_count = *count = cb.cb_used; 2013218Sdougm } 2023218Sdougm 2033218Sdougm /* 2043218Sdougm * mountpoint_compare(a, b) 2053218Sdougm * 2063218Sdougm * compares the mountpoint on two zfs file systems handles. 2073218Sdougm * returns values following strcmp() model. 2083218Sdougm */ 2093218Sdougm 2103218Sdougm static int 2113218Sdougm mountpoint_compare(const void *a, const void *b) 2123218Sdougm { 2133218Sdougm zfs_handle_t **za = (zfs_handle_t **)a; 2143218Sdougm zfs_handle_t **zb = (zfs_handle_t **)b; 2153218Sdougm char mounta[MAXPATHLEN]; 2163218Sdougm char mountb[MAXPATHLEN]; 2173218Sdougm 2183218Sdougm verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 2193218Sdougm sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 2203218Sdougm verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 2213218Sdougm sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 2223218Sdougm 2233218Sdougm return (strcmp(mounta, mountb)); 2243218Sdougm } 2253218Sdougm 2263034Sdougm /* 2278845Samw@Sun.COM * return legacy mountpoint. Caller provides space for mountpoint and 2288845Samw@Sun.COM * dataset. 2294592Smarks */ 2304592Smarks int 2318845Samw@Sun.COM get_legacy_mountpoint(char *path, char *dataset, size_t dlen, 2328845Samw@Sun.COM char *mountpoint, size_t mlen) 2334592Smarks { 2344592Smarks FILE *fp; 2354592Smarks struct mnttab entry; 2364592Smarks 2374592Smarks if ((fp = fopen(MNTTAB, "r")) == NULL) { 2384592Smarks return (1); 2394592Smarks } 2404592Smarks 2414592Smarks while (getmntent(fp, &entry) == 0) { 2424592Smarks 2434592Smarks if (entry.mnt_fstype == NULL || 2444592Smarks strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 2454592Smarks continue; 2464592Smarks 2474592Smarks if (strcmp(entry.mnt_mountp, path) == 0) { 2488845Samw@Sun.COM if (mlen > 0) 2498845Samw@Sun.COM (void) strlcpy(mountpoint, entry.mnt_mountp, 2508845Samw@Sun.COM mlen); 2518845Samw@Sun.COM if (dlen > 0) 2528845Samw@Sun.COM (void) strlcpy(dataset, entry.mnt_special, 2538845Samw@Sun.COM dlen); 2548845Samw@Sun.COM break; 2554592Smarks } 2564592Smarks } 2574592Smarks (void) fclose(fp); 2584592Smarks return (1); 2594592Smarks } 2604592Smarks 2614592Smarks /* 2623910Sdougm * get_zfs_dataset(impl_handle, path) 2633034Sdougm * 2643034Sdougm * get the name of the ZFS dataset the path is equivalent to. The 2653034Sdougm * dataset name is used for get/set of ZFS properties since libzfs 2663034Sdougm * requires a dataset to do a zfs_open(). 2673034Sdougm */ 2683034Sdougm 2693034Sdougm static char * 2704592Smarks get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 2714592Smarks boolean_t search_mnttab) 2723034Sdougm { 2733218Sdougm size_t i, count = 0; 2743034Sdougm char *dataset = NULL; 2753218Sdougm zfs_handle_t **zlist; 2763218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 2774180Sdougm char canmount[ZFS_MAXPROPLEN]; 2783218Sdougm 2793910Sdougm get_all_filesystems(impl_handle, &zlist, &count); 2803218Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 2813218Sdougm for (i = 0; i < count; i++) { 2824327Sdougm /* must have a mountpoint */ 2834327Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 2844327Sdougm sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 2854327Sdougm /* no mountpoint */ 2864327Sdougm continue; 2874327Sdougm } 2883034Sdougm 2894327Sdougm /* mountpoint must be a path */ 2904327Sdougm if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 2914592Smarks strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 2924592Smarks /* 2938845Samw@Sun.COM * Search mmttab for mountpoint and get dataset. 2944592Smarks */ 2954592Smarks 2964592Smarks if (search_mnttab == B_TRUE && 2974592Smarks get_legacy_mountpoint(path, mountpoint, 2988845Samw@Sun.COM sizeof (mountpoint), NULL, 0) == 0) { 2994592Smarks dataset = mountpoint; 3004592Smarks break; 3014592Smarks } 3024327Sdougm continue; 3034592Smarks } 3043218Sdougm 3054327Sdougm /* canmount must be set */ 3064327Sdougm canmount[0] = '\0'; 3074543Smarks if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 3084180Sdougm sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 3094327Sdougm strcmp(canmount, "off") == 0) 3104327Sdougm continue; 3113218Sdougm 3124327Sdougm /* 3134327Sdougm * have a mountable handle but want to skip those marked none 3144327Sdougm * and legacy 3154327Sdougm */ 3164327Sdougm if (strcmp(mountpoint, path) == 0) { 3174327Sdougm dataset = (char *)zfs_get_name(zlist[i]); 3184327Sdougm break; 3194327Sdougm } 3203218Sdougm 3213034Sdougm } 3223218Sdougm 3234327Sdougm if (dataset != NULL) 3244327Sdougm dataset = strdup(dataset); 3254327Sdougm 3263034Sdougm return (dataset); 3273034Sdougm } 3283034Sdougm 3293034Sdougm /* 3303034Sdougm * get_zfs_property(dataset, property) 3313034Sdougm * 3323034Sdougm * Get the file system property specified from the ZFS dataset. 3333034Sdougm */ 3343034Sdougm 3353034Sdougm static char * 3363034Sdougm get_zfs_property(char *dataset, zfs_prop_t property) 3373034Sdougm { 3383034Sdougm zfs_handle_t *handle = NULL; 3393034Sdougm char shareopts[ZFS_MAXPROPLEN]; 3403034Sdougm libzfs_handle_t *libhandle; 3413034Sdougm 3423034Sdougm libhandle = libzfs_init(); 3433034Sdougm if (libhandle != NULL) { 3444327Sdougm handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 3454327Sdougm if (handle != NULL) { 3464327Sdougm if (zfs_prop_get(handle, property, shareopts, 3474327Sdougm sizeof (shareopts), NULL, NULL, 0, 3484327Sdougm B_FALSE) == 0) { 3494327Sdougm zfs_close(handle); 3504327Sdougm libzfs_fini(libhandle); 3514327Sdougm return (strdup(shareopts)); 3524327Sdougm } 3534327Sdougm zfs_close(handle); 3543034Sdougm } 3554327Sdougm libzfs_fini(libhandle); 3563034Sdougm } 3573034Sdougm return (NULL); 3583034Sdougm } 3593034Sdougm 3603034Sdougm /* 3613910Sdougm * sa_zfs_is_shared(handle, path) 3623034Sdougm * 3633034Sdougm * Check to see if the ZFS path provided has the sharenfs option set 3643034Sdougm * or not. 3653034Sdougm */ 3663034Sdougm 3673034Sdougm int 3683910Sdougm sa_zfs_is_shared(sa_handle_t sahandle, char *path) 3693034Sdougm { 3703034Sdougm int ret = 0; 3713034Sdougm char *dataset; 3723034Sdougm zfs_handle_t *handle = NULL; 3733034Sdougm char shareopts[ZFS_MAXPROPLEN]; 3743034Sdougm libzfs_handle_t *libhandle; 3753034Sdougm 3764592Smarks dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 3773034Sdougm if (dataset != NULL) { 3784327Sdougm libhandle = libzfs_init(); 3794327Sdougm if (libhandle != NULL) { 3804327Sdougm handle = zfs_open(libhandle, dataset, 3814327Sdougm ZFS_TYPE_FILESYSTEM); 3824327Sdougm if (handle != NULL) { 3834327Sdougm if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 3844327Sdougm shareopts, sizeof (shareopts), NULL, NULL, 3854327Sdougm 0, B_FALSE) == 0 && 3864327Sdougm strcmp(shareopts, "off") != 0) { 3874327Sdougm ret = 1; /* it is shared */ 3884327Sdougm } 3894327Sdougm zfs_close(handle); 3904327Sdougm } 3914327Sdougm libzfs_fini(libhandle); 3923034Sdougm } 3934327Sdougm free(dataset); 3943034Sdougm } 3953034Sdougm return (ret); 3963034Sdougm } 3973034Sdougm 3983034Sdougm /* 3995331Samw * find_or_create_group(handle, groupname, proto, *err) 4003034Sdougm * 4013034Sdougm * While walking the ZFS tree, we need to add shares to a defined 4023034Sdougm * group. If the group doesn't exist, create it first, making sure it 4033034Sdougm * is marked as a ZFS group. 4043034Sdougm * 4053108Sdougm * Note that all ZFS shares are in a subgroup of the top level group 4063108Sdougm * called "zfs". 4073034Sdougm */ 4083034Sdougm 4093034Sdougm static sa_group_t 4103910Sdougm find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 4113034Sdougm { 4123034Sdougm sa_group_t group; 4133034Sdougm sa_optionset_t optionset; 4143034Sdougm int ret = SA_OK; 4153034Sdougm 4163034Sdougm /* 4173034Sdougm * we check to see if the "zfs" group exists. Since this 4183034Sdougm * should be the top level group, we don't want the 4193034Sdougm * parent. This is to make sure the zfs group has been created 4203034Sdougm * and to created if it hasn't been. 4213034Sdougm */ 4223910Sdougm group = sa_get_group(handle, groupname); 4233034Sdougm if (group == NULL) { 4244327Sdougm group = sa_create_group(handle, groupname, &ret); 4253108Sdougm 4264327Sdougm /* make sure this is flagged as a ZFS group */ 4274327Sdougm if (group != NULL) 4284327Sdougm ret = sa_set_group_attr(group, "zfs", "true"); 4293034Sdougm } 4303034Sdougm if (group != NULL) { 4314327Sdougm if (proto != NULL) { 4324327Sdougm optionset = sa_get_optionset(group, proto); 4335331Samw if (optionset == NULL) 4344327Sdougm optionset = sa_create_optionset(group, proto); 4353034Sdougm } 4363034Sdougm } 4373034Sdougm if (err != NULL) 4384327Sdougm *err = ret; 4393034Sdougm return (group); 4403034Sdougm } 4413034Sdougm 4423034Sdougm /* 4433108Sdougm * find_or_create_zfs_subgroup(groupname, optstring, *err) 4443108Sdougm * 4453108Sdougm * ZFS shares will be in a subgroup of the "zfs" master group. This 4463108Sdougm * function looks to see if the groupname exists and returns it if it 4473108Sdougm * does or else creates a new one with the specified name and returns 4483108Sdougm * that. The "zfs" group will exist before we get here, but we make 4493108Sdougm * sure just in case. 4503108Sdougm * 4513108Sdougm * err must be a valid pointer. 4523108Sdougm */ 4533108Sdougm 4543108Sdougm static sa_group_t 4555331Samw find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 4565331Samw char *optstring, int *err) 4573108Sdougm { 4583108Sdougm sa_group_t group = NULL; 4593108Sdougm sa_group_t zfs; 4603108Sdougm char *name; 4613108Sdougm char *options; 4623108Sdougm 4633108Sdougm /* start with the top-level "zfs" group */ 4643910Sdougm zfs = sa_get_group(handle, "zfs"); 4653108Sdougm *err = SA_OK; 4663108Sdougm if (zfs != NULL) { 4674327Sdougm for (group = sa_get_sub_group(zfs); group != NULL; 4684327Sdougm group = sa_get_next_group(group)) { 4694327Sdougm name = sa_get_group_attr(group, "name"); 4704327Sdougm if (name != NULL && strcmp(name, groupname) == 0) { 4714327Sdougm /* have the group so break out of here */ 4724327Sdougm sa_free_attr_string(name); 4734327Sdougm break; 4744327Sdougm } 4754327Sdougm if (name != NULL) 4764327Sdougm sa_free_attr_string(name); 4773108Sdougm } 4783108Sdougm 4794327Sdougm if (group == NULL) { 4804327Sdougm /* 4816149Sdougm * Need to create the sub-group since it doesn't exist 4824327Sdougm */ 4834327Sdougm group = _sa_create_zfs_group(zfs, groupname); 4846149Sdougm if (group == NULL) { 4856149Sdougm *err = SA_NO_MEMORY; 4866149Sdougm return (NULL); 4874327Sdougm } 4886149Sdougm set_node_attr(group, "zfs", "true"); 4896149Sdougm } 4906149Sdougm if (strcmp(optstring, "on") == 0) 4916149Sdougm optstring = "rw"; 4926149Sdougm options = strdup(optstring); 4936149Sdougm if (options != NULL) { 4946149Sdougm *err = sa_parse_legacy_options(group, options, 4956149Sdougm proto); 4966149Sdougm /* If no optionset, add one. */ 4976149Sdougm if (sa_get_optionset(group, proto) == NULL) 4986149Sdougm (void) sa_create_optionset(group, proto); 4996149Sdougm free(options); 5006149Sdougm } else { 5016149Sdougm *err = SA_NO_MEMORY; 5023108Sdougm } 5033108Sdougm } 5043108Sdougm return (group); 5053108Sdougm } 5063108Sdougm 5073108Sdougm /* 5085331Samw * zfs_construct_resource(share, name, base, dataset) 5095331Samw * 5105331Samw * Add a resource to the share using name as a template. If name == 5115331Samw * NULL, then construct a name based on the dataset value. 5125331Samw * name. 5135331Samw */ 5145331Samw static void 5155331Samw zfs_construct_resource(sa_share_t share, char *dataset) 5165331Samw { 5175331Samw char buff[SA_MAX_RESOURCE_NAME + 1]; 5185331Samw int ret = SA_OK; 5195331Samw 5205331Samw (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset); 5215331Samw sa_fix_resource_name(buff); 5225331Samw (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret); 5235331Samw } 5245331Samw 5255331Samw /* 5264327Sdougm * zfs_inherited(handle, source, sourcestr) 5274327Sdougm * 5285331Samw * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares 5294327Sdougm * for readability. 5304327Sdougm */ 5314327Sdougm static int 5324327Sdougm zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 5335331Samw char *shareopts, char *mountpoint, char *proto, char *dataset) 5344327Sdougm { 5354327Sdougm int doshopt = 0; 5364327Sdougm int err = SA_OK; 5374327Sdougm sa_group_t group; 5385331Samw sa_resource_t resource; 5395331Samw uint64_t features; 5404327Sdougm 5414327Sdougm /* 5424327Sdougm * Need to find the "real" parent sub-group. It may not be 5434327Sdougm * mounted, but it was identified in the "sourcestr" 5444327Sdougm * variable. The real parent not mounted can occur if 5454327Sdougm * "canmount=off and sharenfs=on". 5464327Sdougm */ 5475331Samw group = find_or_create_zfs_subgroup(handle, sourcestr, proto, 5485331Samw shareopts, &doshopt); 5494327Sdougm if (group != NULL) { 5505331Samw /* 5515331Samw * We may need the first share for resource 5525331Samw * prototype. We only care about it if it has a 5535331Samw * resource that sets a prefix value. 5545331Samw */ 5555331Samw if (share == NULL) 5565331Samw share = _sa_add_share(group, mountpoint, 5575331Samw SA_SHARE_TRANSIENT, &err, 5585331Samw (uint64_t)SA_FEATURE_NONE); 5594327Sdougm /* 5604327Sdougm * some options may only be on shares. If the opt 5614327Sdougm * string contains one of those, we put it just on the 5624327Sdougm * share. 5634327Sdougm */ 5644327Sdougm if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 5654327Sdougm char *options; 5664327Sdougm options = strdup(shareopts); 5674327Sdougm if (options != NULL) { 5685331Samw set_node_attr(share, "dataset", dataset); 5694327Sdougm err = sa_parse_legacy_options(share, options, 5705331Samw proto); 5715331Samw set_node_attr(share, "dataset", NULL); 5724327Sdougm free(options); 5734327Sdougm } 5745331Samw if (sa_get_optionset(group, proto) == NULL) 5755331Samw (void) sa_create_optionset(group, proto); 5765331Samw } 5775331Samw features = sa_proto_get_featureset(proto); 5785331Samw if (share != NULL && features & SA_FEATURE_RESOURCE) { 5795331Samw /* 5805331Samw * We have a share and the protocol requires 5815331Samw * that at least one resource exist (probably 5825331Samw * SMB). We need to make sure that there is at 5835331Samw * least one. 5845331Samw */ 5855331Samw resource = sa_get_share_resource(share, NULL); 5865331Samw if (resource == NULL) { 5875331Samw zfs_construct_resource(share, dataset); 5885331Samw } 5894327Sdougm } 5904327Sdougm } else { 5914327Sdougm err = SA_NO_MEMORY; 5924327Sdougm } 5934327Sdougm return (err); 5944327Sdougm } 5954327Sdougm 5964327Sdougm /* 5975454Sdougm * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset, 5985454Sdougm * grouperr) 5994327Sdougm * 6004327Sdougm * handle case where this is the top of a sub-group in ZFS. Pulled out 6015454Sdougm * of sa_get_zfs_shares for readability. We need the grouperr from the 6025454Sdougm * creation of the subgroup to know whether to add the public 6035454Sdougm * property, etc. to the specific share. 6044327Sdougm */ 6054327Sdougm static int 6065331Samw zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 6075454Sdougm char *shareopts, char *proto, char *dataset, int grouperr) 6084327Sdougm { 6094327Sdougm int err = SA_OK; 6105331Samw sa_resource_t resource; 6115331Samw uint64_t features; 6124327Sdougm 6134327Sdougm set_node_attr(group, "zfs", "true"); 6145331Samw if (share == NULL) 6155331Samw share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 6165331Samw &err, (uint64_t)SA_FEATURE_NONE); 6176149Sdougm 6186149Sdougm if (err != SA_OK) 6196149Sdougm return (err); 6206149Sdougm 6216149Sdougm if (strcmp(shareopts, "on") == 0) 6226149Sdougm shareopts = ""; 6236149Sdougm if (shareopts != NULL) { 6246149Sdougm char *options; 6256149Sdougm if (grouperr == SA_PROP_SHARE_ONLY) { 6266149Sdougm /* 6276149Sdougm * Some properties may only be on shares, but 6286149Sdougm * due to the ZFS sub-groups being artificial, 6296149Sdougm * we sometimes get this and have to deal with 6306149Sdougm * it. We do it by attempting to put it on the 6316149Sdougm * share. 6326149Sdougm */ 6336149Sdougm options = strdup(shareopts); 6346149Sdougm if (options != NULL) { 6356149Sdougm err = sa_parse_legacy_options(share, 6366149Sdougm options, proto); 6376149Sdougm free(options); 6385331Samw } 6395331Samw } 6406149Sdougm /* Unmark the share's changed state */ 6416149Sdougm set_node_attr(share, "changed", NULL); 6426149Sdougm } 6436149Sdougm features = sa_proto_get_featureset(proto); 6446149Sdougm if (share != NULL && features & SA_FEATURE_RESOURCE) { 6456149Sdougm /* 6466149Sdougm * We have a share and the protocol requires that at 6476149Sdougm * least one resource exist (probably SMB). We need to 6486149Sdougm * make sure that there is at least one. 6496149Sdougm */ 6506149Sdougm resource = sa_get_share_resource(share, NULL); 6516149Sdougm if (resource == NULL) { 6526149Sdougm zfs_construct_resource(share, dataset); 6534327Sdougm } 6544327Sdougm } 6554327Sdougm return (err); 6564327Sdougm } 6574327Sdougm 6584327Sdougm /* 6594327Sdougm * zfs_grp_error(err) 6604327Sdougm * 6614327Sdougm * Print group create error, but only once. If err is 0 do the 6624327Sdougm * print else don't. 6634327Sdougm */ 6644327Sdougm 6654327Sdougm static void 6664327Sdougm zfs_grp_error(int err) 6674327Sdougm { 6684327Sdougm if (err == 0) { 6694327Sdougm /* only print error once */ 6704327Sdougm (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 6714327Sdougm "Cannot create ZFS subgroup during initialization:" 6724327Sdougm " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 6734327Sdougm } 6744327Sdougm } 6754327Sdougm 6764327Sdougm /* 6775331Samw * zfs_process_share(handle, share, mountpoint, proto, source, 6785331Samw * shareopts, sourcestr) 6795331Samw * 6805951Sdougm * Creates the subgroup, if necessary and adds shares, resources 6815331Samw * and properties. 6825331Samw */ 6835951Sdougm int 6845951Sdougm sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 6855331Samw char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 6865331Samw char *sourcestr, char *dataset) 6875331Samw { 6885331Samw int err = SA_OK; 6895331Samw 6905331Samw if (source & ZPROP_SRC_INHERITED) { 6915331Samw err = zfs_inherited(handle, share, sourcestr, shareopts, 6925331Samw mountpoint, proto, dataset); 6935331Samw } else { 6945331Samw group = find_or_create_zfs_subgroup(handle, dataset, proto, 6955331Samw shareopts, &err); 6965331Samw if (group == NULL) { 6975454Sdougm static boolean_t reported_error = B_FALSE; 6985331Samw /* 6995454Sdougm * There is a problem, but we can't do 7005331Samw * anything about it at this point so we issue 7015454Sdougm * a warning and move on. 7025331Samw */ 7035454Sdougm zfs_grp_error(reported_error); 7045454Sdougm reported_error = B_TRUE; 7055331Samw } 7065331Samw set_node_attr(group, "zfs", "true"); 7075331Samw /* 7085331Samw * Add share with local opts via zfs_notinherited. 7095331Samw */ 7105331Samw err = zfs_notinherited(group, share, mountpoint, shareopts, 7115454Sdougm proto, dataset, err); 7125331Samw } 7135331Samw return (err); 7145331Samw } 7155331Samw 7165331Samw /* 7173910Sdougm * sa_get_zfs_shares(handle, groupname) 7183034Sdougm * 7193034Sdougm * Walk the mnttab for all zfs mounts and determine which are 7203034Sdougm * shared. Find or create the appropriate group/sub-group to contain 7213034Sdougm * the shares. 7223034Sdougm * 7233034Sdougm * All shares are in a sub-group that will hold the properties. This 7243034Sdougm * allows representing the inherited property model. 7256149Sdougm * 7266149Sdougm * One area of complication is if "sharenfs" is set at one level of 7276149Sdougm * the directory tree and "sharesmb" is set at a different level, the 7286149Sdougm * a sub-group must be formed at the lower level for both 7296149Sdougm * protocols. That is the nature of the problem in CR 6667349. 7303034Sdougm */ 7313034Sdougm 7323034Sdougm int 7333910Sdougm sa_get_zfs_shares(sa_handle_t handle, char *groupname) 7343034Sdougm { 7353034Sdougm sa_group_t zfsgroup; 7366149Sdougm boolean_t nfs; 7376149Sdougm boolean_t nfs_inherited; 7386149Sdougm boolean_t smb; 7396149Sdougm boolean_t smb_inherited; 7403218Sdougm zfs_handle_t **zlist; 7416149Sdougm char nfsshareopts[ZFS_MAXPROPLEN]; 7426149Sdougm char smbshareopts[ZFS_MAXPROPLEN]; 7433034Sdougm sa_share_t share; 7445094Slling zprop_source_t source; 7456149Sdougm char nfssourcestr[ZFS_MAXPROPLEN]; 7466149Sdougm char smbsourcestr[ZFS_MAXPROPLEN]; 7473218Sdougm char mountpoint[ZFS_MAXPROPLEN]; 7483218Sdougm size_t count = 0, i; 7493910Sdougm libzfs_handle_t *zfs_libhandle; 7506149Sdougm int err = SA_OK; 7513034Sdougm 7523034Sdougm /* 7533910Sdougm * If we can't access libzfs, don't bother doing anything. 7543034Sdougm */ 7553910Sdougm zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 7563218Sdougm if (zfs_libhandle == NULL) 7574327Sdougm return (SA_SYSTEM_ERR); 7583034Sdougm 7595331Samw zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 7606149Sdougm /* Not an error, this could be a legacy condition */ 7614524Sdougm if (zfsgroup == NULL) 7626149Sdougm return (SA_OK); 7633218Sdougm 7644524Sdougm /* 7654524Sdougm * need to walk the mounted ZFS pools and datasets to 7664524Sdougm * find shares that are possible. 7674524Sdougm */ 7684524Sdougm get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 7694524Sdougm qsort(zlist, count, sizeof (void *), mountpoint_compare); 7704524Sdougm 7714524Sdougm for (i = 0; i < count; i++) { 7724524Sdougm char *dataset; 7733218Sdougm 7745094Slling source = ZPROP_SRC_ALL; 7754524Sdougm /* If no mountpoint, skip. */ 7764524Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 7774524Sdougm mountpoint, sizeof (mountpoint), NULL, NULL, 0, 7784524Sdougm B_FALSE) != 0) 7794524Sdougm continue; 7804327Sdougm 7814524Sdougm /* 7824524Sdougm * zfs_get_name value must not be freed. It is just a 7834524Sdougm * pointer to a value in the handle. 7844524Sdougm */ 7854524Sdougm if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 7864524Sdougm continue; 7874327Sdougm 7884524Sdougm /* 7894524Sdougm * only deal with "mounted" file systems since 7904524Sdougm * unmounted file systems can't actually be shared. 7914524Sdougm */ 7924327Sdougm 7934524Sdougm if (!zfs_is_mounted(zlist[i], NULL)) 7944524Sdougm continue; 7954327Sdougm 7966149Sdougm nfs = nfs_inherited = B_FALSE; 7976149Sdougm 7986149Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts, 7996149Sdougm sizeof (nfsshareopts), &source, nfssourcestr, 8006149Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 8016149Sdougm strcmp(nfsshareopts, "off") != 0) { 8026149Sdougm if (source & ZPROP_SRC_INHERITED) 8036149Sdougm nfs_inherited = B_TRUE; 8046149Sdougm else 8056149Sdougm nfs = B_TRUE; 8066149Sdougm } 8076149Sdougm 8086149Sdougm smb = smb_inherited = B_FALSE; 8096149Sdougm if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts, 8106149Sdougm sizeof (smbshareopts), &source, smbsourcestr, 8114524Sdougm ZFS_MAXPROPLEN, B_FALSE) == 0 && 8126149Sdougm strcmp(smbshareopts, "off") != 0) { 8136149Sdougm if (source & ZPROP_SRC_INHERITED) 8146149Sdougm smb_inherited = B_TRUE; 8156149Sdougm else 8166149Sdougm smb = B_TRUE; 8176149Sdougm } 8186149Sdougm 8196149Sdougm /* 8206149Sdougm * If the mountpoint is already shared, it must be a 8216149Sdougm * non-ZFS share. We want to remove the share from its 8226149Sdougm * parent group and reshare it under ZFS. 8236149Sdougm */ 8246149Sdougm share = sa_find_share(handle, mountpoint); 8256149Sdougm if (share != NULL && 8266149Sdougm (nfs || smb || nfs_inherited || smb_inherited)) { 8276149Sdougm err = sa_remove_share(share); 8286149Sdougm share = NULL; 8296149Sdougm } 8306149Sdougm 8316149Sdougm /* 8326149Sdougm * At this point, we have the information needed to 8336149Sdougm * determine what to do with the share. 8346149Sdougm * 8356149Sdougm * If smb or nfs is set, we have a new sub-group. 8366149Sdougm * If smb_inherit and/or nfs_inherit is set, then 8376149Sdougm * place on an existing sub-group. If both are set, 8386149Sdougm * the existing sub-group is the closest up the tree. 8396149Sdougm */ 8406149Sdougm if (nfs || smb) { 8416149Sdougm /* 8426149Sdougm * Non-inherited is the straightforward 8436149Sdougm * case. sa_zfs_process_share handles it 8446149Sdougm * directly. Make sure that if the "other" 8456149Sdougm * protocol is inherited, that we treat it as 8466149Sdougm * non-inherited as well. 8476149Sdougm */ 8486149Sdougm if (nfs || nfs_inherited) { 8496149Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8506149Sdougm share, mountpoint, "nfs", 8516149Sdougm 0, nfsshareopts, 8526149Sdougm nfssourcestr, dataset); 8536149Sdougm share = sa_find_share(handle, mountpoint); 8545331Samw } 8556149Sdougm if (smb || smb_inherited) { 8566149Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8576149Sdougm share, mountpoint, "smb", 8586149Sdougm 0, smbshareopts, 8596149Sdougm smbsourcestr, dataset); 8605331Samw } 8616149Sdougm } else if (nfs_inherited || smb_inherited) { 8626149Sdougm char *grpdataset; 8636149Sdougm /* 8646149Sdougm * If we only have inherited groups, it is 8656149Sdougm * important to find the closer of the two if 8666149Sdougm * the protocols are set at different 8676149Sdougm * levels. The closest sub-group is the one we 8686149Sdougm * want to work with. 8696149Sdougm */ 8706149Sdougm if (nfs_inherited && smb_inherited) { 8716149Sdougm if (strcmp(nfssourcestr, smbsourcestr) <= 0) 8726149Sdougm grpdataset = nfssourcestr; 8736149Sdougm else 8746149Sdougm grpdataset = smbsourcestr; 8756149Sdougm } else if (nfs_inherited) { 8766149Sdougm grpdataset = nfssourcestr; 8776149Sdougm } else if (smb_inherited) { 8786149Sdougm grpdataset = smbsourcestr; 8796149Sdougm } 8806149Sdougm if (nfs_inherited) { 8816149Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8826149Sdougm share, mountpoint, "nfs", 8836149Sdougm ZPROP_SRC_INHERITED, nfsshareopts, 8846149Sdougm grpdataset, dataset); 8856149Sdougm share = sa_find_share(handle, mountpoint); 8866149Sdougm } 8876149Sdougm if (smb_inherited) { 8886149Sdougm err = sa_zfs_process_share(handle, zfsgroup, 8896149Sdougm share, mountpoint, "smb", 8906149Sdougm ZPROP_SRC_INHERITED, smbshareopts, 8916149Sdougm grpdataset, dataset); 8923034Sdougm } 8933034Sdougm } 8943034Sdougm } 8953218Sdougm /* 8963218Sdougm * Don't need to free the "zlist" variable since it is only a 8973218Sdougm * pointer to a cached value that will be freed when 8983218Sdougm * sa_fini() is called. 8993218Sdougm */ 9006149Sdougm return (err); 9013034Sdougm } 9023034Sdougm 9033034Sdougm #define COMMAND "/usr/sbin/zfs" 9043034Sdougm 9053034Sdougm /* 9063034Sdougm * sa_zfs_set_sharenfs(group, path, on) 9073034Sdougm * 9083034Sdougm * Update the "sharenfs" property on the path. If on is true, then set 9093034Sdougm * to the properties on the group or "on" if no properties are 9103034Sdougm * defined. Set to "off" if on is false. 9113034Sdougm */ 9123034Sdougm 9133034Sdougm int 9143034Sdougm sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 9153034Sdougm { 9163034Sdougm int ret = SA_NOT_IMPLEMENTED; 9173034Sdougm char *command; 9183034Sdougm 9193034Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 9203034Sdougm if (command != NULL) { 9214327Sdougm char *opts = NULL; 9224327Sdougm char *dataset = NULL; 9234327Sdougm FILE *pfile; 9244327Sdougm sa_handle_impl_t impl_handle; 9254327Sdougm /* for now, NFS is always available for "zfs" */ 9264327Sdougm if (on) { 9274327Sdougm opts = sa_proto_legacy_format("nfs", group, 1); 9284327Sdougm if (opts != NULL && strlen(opts) == 0) { 9294327Sdougm free(opts); 9304327Sdougm opts = strdup("on"); 9314327Sdougm } 9323034Sdougm } 9333910Sdougm 9344327Sdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 9354327Sdougm assert(impl_handle != NULL); 9364327Sdougm if (impl_handle != NULL) 9374592Smarks dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 9384327Sdougm else 9394327Sdougm ret = SA_SYSTEM_ERR; 9403910Sdougm 9414327Sdougm if (dataset != NULL) { 9424327Sdougm (void) snprintf(command, ZFS_MAXPROPLEN * 2, 9434327Sdougm "%s set sharenfs=\"%s\" %s", COMMAND, 9444327Sdougm opts != NULL ? opts : "off", dataset); 9454327Sdougm pfile = popen(command, "r"); 9464327Sdougm if (pfile != NULL) { 9474327Sdougm ret = pclose(pfile); 9484327Sdougm if (ret != 0) 9494327Sdougm ret = SA_SYSTEM_ERR; 9504327Sdougm } 9513034Sdougm } 9524327Sdougm if (opts != NULL) 9534327Sdougm free(opts); 9544327Sdougm if (dataset != NULL) 9554327Sdougm free(dataset); 9564327Sdougm free(command); 9573034Sdougm } 9583034Sdougm return (ret); 9593034Sdougm } 9603034Sdougm 9613034Sdougm /* 9625331Samw * add_resources(share, opt) 9635331Samw * 9645331Samw * Add resource properties to those in "opt". Resources are prefixed 9655331Samw * with name=resourcename. 9665331Samw */ 9675331Samw static char * 9685331Samw add_resources(sa_share_t share, char *opt) 9695331Samw { 9705331Samw char *newopt = NULL; 9715331Samw char *propstr; 9725331Samw sa_resource_t resource; 9735331Samw 9745331Samw newopt = strdup(opt); 9755331Samw if (newopt == NULL) 9765331Samw return (newopt); 9775331Samw 9785331Samw for (resource = sa_get_share_resource(share, NULL); 9795331Samw resource != NULL; 9805331Samw resource = sa_get_next_resource(resource)) { 9815331Samw char *name; 9825331Samw size_t size; 9835331Samw 9845331Samw name = sa_get_resource_attr(resource, "name"); 9855331Samw if (name == NULL) { 9865331Samw free(newopt); 9875331Samw return (NULL); 9885331Samw } 9895331Samw size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 9905331Samw newopt = calloc(1, size); 9915331Samw if (newopt != NULL) 9925331Samw (void) snprintf(newopt, size, "%s,name=%s", opt, name); 993*11337SWilliam.Krier@Sun.COM sa_free_attr_string(name); 9945331Samw free(opt); 9955331Samw opt = newopt; 9965331Samw propstr = sa_proto_legacy_format("smb", resource, 0); 9975331Samw if (propstr == NULL) { 9985331Samw free(opt); 9995331Samw return (NULL); 10005331Samw } 10015331Samw size = strlen(propstr) + strlen(opt) + 2; 10025331Samw newopt = calloc(1, size); 10035331Samw if (newopt != NULL) 10045331Samw (void) snprintf(newopt, size, "%s,%s", opt, propstr); 10055331Samw free(opt); 10065331Samw opt = newopt; 10075331Samw } 10085331Samw return (opt); 10095331Samw } 10105331Samw 10115331Samw /* 10125331Samw * sa_zfs_set_sharesmb(group, path, on) 10135331Samw * 10145331Samw * Update the "sharesmb" property on the path. If on is true, then set 10155331Samw * to the properties on the group or "on" if no properties are 10165331Samw * defined. Set to "off" if on is false. 10175331Samw */ 10185331Samw 10195331Samw int 10205331Samw sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 10215331Samw { 10225331Samw int ret = SA_NOT_IMPLEMENTED; 10235331Samw char *command; 10245331Samw sa_share_t share; 10255331Samw 10265331Samw /* In case SMB not enabled */ 10275331Samw if (sa_get_optionset(group, "smb") == NULL) 10285331Samw return (SA_NOT_SUPPORTED); 10295331Samw 10305331Samw command = malloc(ZFS_MAXPROPLEN * 2); 10315331Samw if (command != NULL) { 10325331Samw char *opts = NULL; 10335331Samw char *dataset = NULL; 10345331Samw FILE *pfile; 10355331Samw sa_handle_impl_t impl_handle; 10365331Samw 10375331Samw if (on) { 10385331Samw char *newopt; 10395331Samw 10405331Samw share = sa_get_share(group, NULL); 10415331Samw opts = sa_proto_legacy_format("smb", share, 1); 10425331Samw if (opts != NULL && strlen(opts) == 0) { 10435331Samw free(opts); 10445331Samw opts = strdup("on"); 10455331Samw } 10465331Samw newopt = add_resources(opts, share); 10475331Samw free(opts); 10485331Samw opts = newopt; 10495331Samw } 10505331Samw 10515331Samw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 10525331Samw assert(impl_handle != NULL); 10535331Samw if (impl_handle != NULL) 10545331Samw dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 10555331Samw else 10565331Samw ret = SA_SYSTEM_ERR; 10575331Samw 10585331Samw if (dataset != NULL) { 10595331Samw (void) snprintf(command, ZFS_MAXPROPLEN * 2, 10605331Samw "echo %s set sharesmb=\"%s\" %s", COMMAND, 10615331Samw opts != NULL ? opts : "off", dataset); 10625331Samw pfile = popen(command, "r"); 10635331Samw if (pfile != NULL) { 10645331Samw ret = pclose(pfile); 10655331Samw if (ret != 0) 10665331Samw ret = SA_SYSTEM_ERR; 10675331Samw } 10685331Samw } 10695331Samw if (opts != NULL) 10705331Samw free(opts); 10715331Samw if (dataset != NULL) 10725331Samw free(dataset); 10735331Samw free(command); 10745331Samw } 10755331Samw return (ret); 10765331Samw } 10775331Samw 10785331Samw /* 10793034Sdougm * sa_zfs_update(group) 10803034Sdougm * 10813034Sdougm * call back to ZFS to update the share if necessary. 10823034Sdougm * Don't do it if it isn't a real change. 10833034Sdougm */ 10843034Sdougm int 10853034Sdougm sa_zfs_update(sa_group_t group) 10863034Sdougm { 10873034Sdougm sa_optionset_t protopt; 10883034Sdougm sa_group_t parent; 10893034Sdougm char *command; 10903034Sdougm char *optstring; 10913034Sdougm int ret = SA_OK; 10923034Sdougm int doupdate = 0; 10933034Sdougm FILE *pfile; 10943034Sdougm 10953034Sdougm if (sa_is_share(group)) 10964327Sdougm parent = sa_get_parent_group(group); 10973034Sdougm else 10984327Sdougm parent = group; 10993034Sdougm 11003034Sdougm if (parent != NULL) { 11014327Sdougm command = malloc(ZFS_MAXPROPLEN * 2); 11024327Sdougm if (command == NULL) 11034327Sdougm return (SA_NO_MEMORY); 11044327Sdougm 11054327Sdougm *command = '\0'; 11064327Sdougm for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 11074327Sdougm protopt = sa_get_next_optionset(protopt)) { 11083034Sdougm 11094327Sdougm char *proto = sa_get_optionset_attr(protopt, "type"); 11104327Sdougm char *path; 11114327Sdougm char *dataset = NULL; 11124327Sdougm char *zfsopts = NULL; 11133034Sdougm 11144327Sdougm if (sa_is_share(group)) { 11154327Sdougm path = sa_get_share_attr((sa_share_t)group, 11164327Sdougm "path"); 11174327Sdougm if (path != NULL) { 11184327Sdougm sa_handle_impl_t impl_handle; 11193034Sdougm 11204327Sdougm impl_handle = sa_find_group_handle( 11214327Sdougm group); 11224327Sdougm if (impl_handle != NULL) 11234327Sdougm dataset = get_zfs_dataset( 11244592Smarks impl_handle, path, B_FALSE); 11254327Sdougm else 11264327Sdougm ret = SA_SYSTEM_ERR; 11273910Sdougm 11284327Sdougm sa_free_attr_string(path); 11294327Sdougm } 11304327Sdougm } else { 11314327Sdougm dataset = sa_get_group_attr(group, "name"); 11324327Sdougm } 11334327Sdougm /* update only when there is an optstring found */ 11344327Sdougm doupdate = 0; 11354327Sdougm if (proto != NULL && dataset != NULL) { 11364327Sdougm optstring = sa_proto_legacy_format(proto, 11374327Sdougm group, 1); 11384327Sdougm zfsopts = get_zfs_property(dataset, 11394327Sdougm ZFS_PROP_SHARENFS); 11403034Sdougm 11414327Sdougm if (optstring != NULL && zfsopts != NULL) { 11424327Sdougm if (strcmp(optstring, zfsopts) != 0) 11434327Sdougm doupdate++; 11444327Sdougm } 11454327Sdougm if (doupdate) { 11464327Sdougm if (optstring != NULL && 11474327Sdougm strlen(optstring) > 0) { 11484327Sdougm (void) snprintf(command, 11494327Sdougm ZFS_MAXPROPLEN * 2, 11507483SDoug.McCallum@Sun.COM "%s set share%s=%s %s", 11517483SDoug.McCallum@Sun.COM COMMAND, proto, 11524327Sdougm optstring, dataset); 11534327Sdougm } else { 11544327Sdougm (void) snprintf(command, 11554327Sdougm ZFS_MAXPROPLEN * 2, 11567483SDoug.McCallum@Sun.COM "%s set share%s=on %s", 11577483SDoug.McCallum@Sun.COM COMMAND, proto, 11584327Sdougm dataset); 11594327Sdougm } 11604327Sdougm pfile = popen(command, "r"); 11614327Sdougm if (pfile != NULL) 11624327Sdougm ret = pclose(pfile); 11634327Sdougm switch (ret) { 11644327Sdougm default: 11654327Sdougm case 1: 11664327Sdougm ret = SA_SYSTEM_ERR; 11674327Sdougm break; 11684327Sdougm case 2: 11694327Sdougm ret = SA_SYNTAX_ERR; 11704327Sdougm break; 11714327Sdougm case 0: 11724327Sdougm break; 11734327Sdougm } 11744327Sdougm } 11754327Sdougm if (optstring != NULL) 11764327Sdougm free(optstring); 11774327Sdougm if (zfsopts != NULL) 11784327Sdougm free(zfsopts); 11793034Sdougm } 11804327Sdougm if (proto != NULL) 11814327Sdougm sa_free_attr_string(proto); 11824327Sdougm if (dataset != NULL) 11834327Sdougm free(dataset); 11843034Sdougm } 11854327Sdougm free(command); 11863034Sdougm } 11873034Sdougm return (ret); 11883034Sdougm } 11893034Sdougm 11903034Sdougm /* 11913034Sdougm * sa_group_is_zfs(group) 11923034Sdougm * 11933034Sdougm * Given the group, determine if the zfs attribute is set. 11943034Sdougm */ 11953034Sdougm 11963034Sdougm int 11973034Sdougm sa_group_is_zfs(sa_group_t group) 11983034Sdougm { 11993034Sdougm char *zfs; 12003034Sdougm int ret = 0; 12013034Sdougm 12023034Sdougm zfs = sa_get_group_attr(group, "zfs"); 12033034Sdougm if (zfs != NULL) { 12044327Sdougm ret = 1; 12054327Sdougm sa_free_attr_string(zfs); 12063034Sdougm } 12073034Sdougm return (ret); 12083034Sdougm } 12093034Sdougm 12103034Sdougm /* 12113034Sdougm * sa_path_is_zfs(path) 12123034Sdougm * 12133034Sdougm * Check to see if the file system path represents is of type "zfs". 12143034Sdougm */ 12153034Sdougm 12163034Sdougm int 12173034Sdougm sa_path_is_zfs(char *path) 12183034Sdougm { 12193034Sdougm char *fstype; 12203034Sdougm int ret = 0; 12213034Sdougm 12223034Sdougm fstype = sa_fstype(path); 12234327Sdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) 12244327Sdougm ret = 1; 12253034Sdougm if (fstype != NULL) 12264327Sdougm sa_free_fstype(fstype); 12273034Sdougm return (ret); 12283034Sdougm } 12294543Smarks 12304543Smarks int 12314543Smarks sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 12324543Smarks { 12334543Smarks char *path; 12344543Smarks 12354713Smarks /* Make sure path is valid */ 12364713Smarks 12374543Smarks path = sa_get_share_attr(share, "path"); 12384543Smarks if (path != NULL) { 12394543Smarks (void) memset(sh, 0, sizeof (sh)); 12404543Smarks (void) sa_fillshare(share, proto, sh); 12414713Smarks sa_free_attr_string(path); 12424543Smarks return (0); 12434543Smarks } else 12444543Smarks return (1); 12454543Smarks } 12464543Smarks 12474543Smarks #define SMAX(i, j) \ 12484543Smarks if ((j) > (i)) { \ 12494543Smarks (i) = (j); \ 12504543Smarks } 12514543Smarks 12524543Smarks int 12538845Samw@Sun.COM sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh, 12545331Samw void *exportdata, zfs_share_op_t operation) 12554543Smarks { 12564543Smarks libzfs_handle_t *libhandle; 12574543Smarks sa_group_t group; 12584543Smarks sa_handle_t sahandle; 12594543Smarks char *dataset; 12604543Smarks int err = EINVAL; 12614543Smarks int i, j; 12624566Smarks char newpath[MAXPATHLEN]; 12634592Smarks char *pathp; 12644543Smarks 12654543Smarks /* 12664543Smarks * First find the dataset name 12674543Smarks */ 12684543Smarks if ((group = sa_get_parent_group(share)) == NULL) { 126910761SWilliam.Krier@Sun.COM return (EINVAL); 12704543Smarks } 12714543Smarks if ((sahandle = sa_find_group_handle(group)) == NULL) { 127210761SWilliam.Krier@Sun.COM return (EINVAL); 12734543Smarks } 12744543Smarks 12754566Smarks /* 12764566Smarks * If get_zfs_dataset fails, see if it is a subdirectory 12774566Smarks */ 12784592Smarks 12794592Smarks pathp = path; 12804592Smarks while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 12814566Smarks char *p; 12824566Smarks 12834592Smarks if (pathp == path) { 12844592Smarks (void) strlcpy(newpath, path, sizeof (newpath)); 12854592Smarks pathp = newpath; 12864592Smarks } 12874592Smarks 12884592Smarks /* 12897602SDoug.McCallum@Sun.COM * Make sure only one leading '/' This condition came 12907602SDoug.McCallum@Sun.COM * about when using HAStoragePlus which insisted on 12917602SDoug.McCallum@Sun.COM * putting an extra leading '/' in the ZFS path 12927602SDoug.McCallum@Sun.COM * name. The problem is fixed in other areas, but this 12937602SDoug.McCallum@Sun.COM * will catch any other ways that a double slash might 12947602SDoug.McCallum@Sun.COM * get introduced. 12957602SDoug.McCallum@Sun.COM */ 12967602SDoug.McCallum@Sun.COM while (*pathp == '/' && *(pathp + 1) == '/') 12977602SDoug.McCallum@Sun.COM pathp++; 12987602SDoug.McCallum@Sun.COM 12997602SDoug.McCallum@Sun.COM /* 13004592Smarks * chop off part of path, but if we are at root then 13014592Smarks * make sure path is a / 13024592Smarks */ 13034592Smarks if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 13044592Smarks if (pathp == p) { 13054592Smarks *(p + 1) = '\0'; /* skip over /, root case */ 13064592Smarks } else { 13074592Smarks *p = '\0'; 13084592Smarks } 13094592Smarks } else { 131010761SWilliam.Krier@Sun.COM return (EINVAL); 13114592Smarks } 13124543Smarks } 13134543Smarks 13144543Smarks libhandle = libzfs_init(); 13154543Smarks if (libhandle != NULL) { 13168845Samw@Sun.COM char *resource_name; 13174543Smarks 13184543Smarks i = (sh->sh_path ? strlen(sh->sh_path) : 0); 13194543Smarks sh->sh_size = i; 13204543Smarks 13214543Smarks j = (sh->sh_res ? strlen(sh->sh_res) : 0); 13224543Smarks sh->sh_size += j; 13234543Smarks SMAX(i, j); 13244543Smarks 13254543Smarks j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 13264543Smarks sh->sh_size += j; 13274543Smarks SMAX(i, j); 13284543Smarks 13294543Smarks j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 13304543Smarks sh->sh_size += j; 13314543Smarks SMAX(i, j); 13324543Smarks 13334543Smarks j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 13344543Smarks sh->sh_size += j; 13354543Smarks SMAX(i, j); 13368845Samw@Sun.COM 13378845Samw@Sun.COM resource_name = sa_get_resource_attr(resource, "name"); 13388845Samw@Sun.COM 13394543Smarks err = zfs_deleg_share_nfs(libhandle, dataset, path, 13408845Samw@Sun.COM resource_name, exportdata, sh, i, operation); 13415951Sdougm if (err == SA_OK) 13425951Sdougm sa_update_sharetab_ts(sahandle); 134310761SWilliam.Krier@Sun.COM else 134410761SWilliam.Krier@Sun.COM err = errno; 13458845Samw@Sun.COM if (resource_name) 13468845Samw@Sun.COM sa_free_attr_string(resource_name); 13478845Samw@Sun.COM 13484543Smarks libzfs_fini(libhandle); 13494543Smarks } 13504543Smarks free(dataset); 13514543Smarks return (err); 13524543Smarks } 13535951Sdougm 13545951Sdougm /* 13555951Sdougm * sa_get_zfs_handle(handle) 13565951Sdougm * 13575951Sdougm * Given an sa_handle_t, return the libzfs_handle_t *. This is only 13585951Sdougm * used internally by libzfs. Needed in order to avoid including 13595951Sdougm * libshare_impl.h in libzfs. 13605951Sdougm */ 13615951Sdougm 13625951Sdougm libzfs_handle_t * 13635951Sdougm sa_get_zfs_handle(sa_handle_t handle) 13645951Sdougm { 13655951Sdougm sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 13665951Sdougm 13675951Sdougm return (implhandle->zfs_libhandle); 13685951Sdougm } 13698845Samw@Sun.COM 13708845Samw@Sun.COM /* 13718845Samw@Sun.COM * sa_get_zfs_info(libzfs, path, mountpoint, dataset) 13728845Samw@Sun.COM * 13738845Samw@Sun.COM * Find the ZFS dataset and mountpoint for a given path 13748845Samw@Sun.COM */ 13758845Samw@Sun.COM int 13768845Samw@Sun.COM sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp, 13778845Samw@Sun.COM char *datasetp) 13788845Samw@Sun.COM { 13798845Samw@Sun.COM get_all_cbdata_t cb = { 0 }; 13808845Samw@Sun.COM int i; 13818845Samw@Sun.COM char mountpoint[ZFS_MAXPROPLEN]; 13828845Samw@Sun.COM char dataset[ZFS_MAXPROPLEN]; 13838845Samw@Sun.COM char canmount[ZFS_MAXPROPLEN]; 13848845Samw@Sun.COM char *dp; 13858845Samw@Sun.COM int count; 13868845Samw@Sun.COM int ret = 0; 13878845Samw@Sun.COM 13888845Samw@Sun.COM cb.cb_types = ZFS_TYPE_FILESYSTEM; 13898845Samw@Sun.COM 13908845Samw@Sun.COM if (libzfs == NULL) 13918845Samw@Sun.COM return (0); 13928845Samw@Sun.COM 13938845Samw@Sun.COM (void) zfs_iter_root(libzfs, get_one_filesystem, &cb); 13948845Samw@Sun.COM count = cb.cb_used; 13958845Samw@Sun.COM 13968845Samw@Sun.COM qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare); 13978845Samw@Sun.COM for (i = 0; i < count; i++) { 13988845Samw@Sun.COM /* must have a mountpoint */ 13998845Samw@Sun.COM if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT, 14008845Samw@Sun.COM mountpoint, sizeof (mountpoint), 14018845Samw@Sun.COM NULL, NULL, 0, B_FALSE) != 0) { 14028845Samw@Sun.COM /* no mountpoint */ 14038845Samw@Sun.COM continue; 14048845Samw@Sun.COM } 14058845Samw@Sun.COM 14068845Samw@Sun.COM /* mountpoint must be a path */ 14078845Samw@Sun.COM if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 14088845Samw@Sun.COM strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 14098845Samw@Sun.COM /* 14108845Samw@Sun.COM * Search mmttab for mountpoint 14118845Samw@Sun.COM */ 14128845Samw@Sun.COM 14138845Samw@Sun.COM if (get_legacy_mountpoint(path, dataset, 14148845Samw@Sun.COM ZFS_MAXPROPLEN, mountpoint, 14158845Samw@Sun.COM ZFS_MAXPROPLEN) == 0) { 14168845Samw@Sun.COM ret = 1; 14178845Samw@Sun.COM break; 14188845Samw@Sun.COM } 14198845Samw@Sun.COM continue; 14208845Samw@Sun.COM } 14218845Samw@Sun.COM 14228845Samw@Sun.COM /* canmount must be set */ 14238845Samw@Sun.COM canmount[0] = '\0'; 14248845Samw@Sun.COM if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount, 14258845Samw@Sun.COM sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 14268845Samw@Sun.COM strcmp(canmount, "off") == 0) 14278845Samw@Sun.COM continue; 14288845Samw@Sun.COM 14298845Samw@Sun.COM /* 14308845Samw@Sun.COM * have a mountable handle but want to skip those marked none 14318845Samw@Sun.COM * and legacy 14328845Samw@Sun.COM */ 14338845Samw@Sun.COM if (strcmp(mountpoint, path) == 0) { 14348845Samw@Sun.COM dp = (char *)zfs_get_name(cb.cb_handles[i]); 14358845Samw@Sun.COM if (dp != NULL) { 14368845Samw@Sun.COM if (datasetp != NULL) 14378845Samw@Sun.COM (void) strcpy(datasetp, dp); 14388845Samw@Sun.COM if (mountpointp != NULL) 14398845Samw@Sun.COM (void) strcpy(mountpointp, mountpoint); 14408845Samw@Sun.COM ret = 1; 14418845Samw@Sun.COM } 14428845Samw@Sun.COM break; 14438845Samw@Sun.COM } 14448845Samw@Sun.COM 14458845Samw@Sun.COM } 14468845Samw@Sun.COM 14478845Samw@Sun.COM return (ret); 14488845Samw@Sun.COM } 1449