/* * Unshare a filesystem by mountpoint. */ static int unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, zfs_share_proto_t proto) { sa_share_t share; int err; char *mntpt; /* * Mountpoint could get trashed if libshare calls getmntany * which it does during API initialization, so strdup the * value. */ mntpt = zfs_strdup(hdl, mountpoint); /* make sure libshare initialized */ if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { free(mntpt); /* don't need the copy anymore */ return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), name, sa_errorstr(err))); } share = sa_find_share(hdl->libzfs_sharehdl, mntpt); free(mntpt); /* don't need the copy anymore */ if (share != NULL) { err = sa_disable_share(share, proto_table[proto].p_name); if (err != SA_OK) { return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), name, sa_errorstr(err))); } } else { return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"), name)); } return (0); }
/* * Share the given filesystem according to the options in the specified * protocol specific properties (sharenfs, sharesmb). We rely * on "libshare" to the dirty work for us. */ static int zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) { char mountpoint[ZFS_MAXPROPLEN]; char shareopts[ZFS_MAXPROPLEN]; char sourcestr[ZFS_MAXPROPLEN]; libzfs_handle_t *hdl = zhp->zfs_hdl; sa_share_t share; zfs_share_proto_t *curr_proto; zprop_source_t sourcetype; int ret; if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) return (0); if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), zfs_get_name(zhp), sa_errorstr(ret)); return (-1); } for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { /* * Return success if there are no share options. */ if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop, shareopts, sizeof (shareopts), &sourcetype, sourcestr, ZFS_MAXPROPLEN, B_FALSE) != 0 || strcmp(shareopts, "off") == 0) continue; /* * If the 'zoned' property is set, then zfs_is_mountable() * will have already bailed out if we are in the global zone. * But local zones cannot be NFS servers, so we ignore it for * local zones as well. */ if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) continue; share = sa_find_share(hdl->libzfs_sharehdl, mountpoint); if (share == NULL) { /* * This may be a new file system that was just * created so isn't in the internal cache * (second time through). Rather than * reloading the entire configuration, we can * assume ZFS has done the checking and it is * safe to add this to the internal * configuration. */ if (sa_zfs_process_share(hdl->libzfs_sharehdl, NULL, NULL, mountpoint, proto_table[*curr_proto].p_name, sourcetype, shareopts, sourcestr, zhp->zfs_name) != SA_OK) { (void) zfs_error_fmt(hdl, proto_table[*curr_proto].p_share_err, dgettext(TEXT_DOMAIN, "cannot share '%s'"), zfs_get_name(zhp)); return (-1); } hdl->libzfs_shareflags |= ZFSSHARE_MISS; share = sa_find_share(hdl->libzfs_sharehdl, mountpoint); } if (share != NULL) { int err; err = sa_enable_share(share, proto_table[*curr_proto].p_name); if (err != SA_OK) { (void) zfs_error_fmt(hdl, proto_table[*curr_proto].p_share_err, dgettext(TEXT_DOMAIN, "cannot share '%s'"), zfs_get_name(zhp)); return (-1); } } else { (void) zfs_error_fmt(hdl, proto_table[*curr_proto].p_share_err, dgettext(TEXT_DOMAIN, "cannot share '%s'"), zfs_get_name(zhp)); return (-1); } } return (0); }
int sa_get_zfs_shares(sa_handle_t handle, char *groupname) { sa_group_t zfsgroup; boolean_t nfs; boolean_t nfs_inherited; boolean_t smb; boolean_t smb_inherited; zfs_handle_t **zlist; char nfsshareopts[ZFS_MAXPROPLEN]; char smbshareopts[ZFS_MAXPROPLEN]; sa_share_t share; zprop_source_t source; char nfssourcestr[ZFS_MAXPROPLEN]; char smbsourcestr[ZFS_MAXPROPLEN]; char mountpoint[ZFS_MAXPROPLEN]; size_t count = 0, i; libzfs_handle_t *zfs_libhandle; int err = SA_OK; /* * If we can't access libzfs, don't bother doing anything. */ zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; if (zfs_libhandle == NULL) return (SA_SYSTEM_ERR); zfsgroup = find_or_create_group(handle, groupname, NULL, &err); /* Not an error, this could be a legacy condition */ if (zfsgroup == NULL) return (SA_OK); /* * need to walk the mounted ZFS pools and datasets to * find shares that are possible. */ get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); qsort(zlist, count, sizeof (void *), mountpoint_compare); for (i = 0; i < count; i++) { char *dataset; source = ZPROP_SRC_ALL; /* If no mountpoint, skip. */ if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) continue; /* * zfs_get_name value must not be freed. It is just a * pointer to a value in the handle. */ if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) continue; /* * only deal with "mounted" file systems since * unmounted file systems can't actually be shared. */ if (!zfs_is_mounted(zlist[i], NULL)) continue; nfs = nfs_inherited = B_FALSE; if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts, sizeof (nfsshareopts), &source, nfssourcestr, ZFS_MAXPROPLEN, B_FALSE) == 0 && strcmp(nfsshareopts, "off") != 0) { if (source & ZPROP_SRC_INHERITED) nfs_inherited = B_TRUE; else nfs = B_TRUE; } smb = smb_inherited = B_FALSE; if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts, sizeof (smbshareopts), &source, smbsourcestr, ZFS_MAXPROPLEN, B_FALSE) == 0 && strcmp(smbshareopts, "off") != 0) { if (source & ZPROP_SRC_INHERITED) smb_inherited = B_TRUE; else smb = B_TRUE; } /* * If the mountpoint is already shared, it must be a * non-ZFS share. We want to remove the share from its * parent group and reshare it under ZFS. */ share = sa_find_share(handle, mountpoint); if (share != NULL && (nfs || smb || nfs_inherited || smb_inherited)) { err = sa_remove_share(share); share = NULL; } /* * At this point, we have the information needed to * determine what to do with the share. * * If smb or nfs is set, we have a new sub-group. * If smb_inherit and/or nfs_inherit is set, then * place on an existing sub-group. If both are set, * the existing sub-group is the closest up the tree. */ if (nfs || smb) { /* * Non-inherited is the straightforward * case. sa_zfs_process_share handles it * directly. Make sure that if the "other" * protocol is inherited, that we treat it as * non-inherited as well. */ if (nfs || nfs_inherited) { err = sa_zfs_process_share(handle, zfsgroup, share, mountpoint, "nfs", 0, nfsshareopts, nfssourcestr, dataset); share = sa_find_share(handle, mountpoint); } if (smb || smb_inherited) { err = sa_zfs_process_share(handle, zfsgroup, share, mountpoint, "smb", 0, smbshareopts, smbsourcestr, dataset); } } else if (nfs_inherited || smb_inherited) { char *grpdataset; /* * If we only have inherited groups, it is * important to find the closer of the two if * the protocols are set at different * levels. The closest sub-group is the one we * want to work with. */ if (nfs_inherited && smb_inherited) { if (strcmp(nfssourcestr, smbsourcestr) <= 0) grpdataset = nfssourcestr; else grpdataset = smbsourcestr; } else if (nfs_inherited) { grpdataset = nfssourcestr; } else if (smb_inherited) { grpdataset = smbsourcestr; } if (nfs_inherited) { err = sa_zfs_process_share(handle, zfsgroup, share, mountpoint, "nfs", ZPROP_SRC_INHERITED, nfsshareopts, grpdataset, dataset); share = sa_find_share(handle, mountpoint); } if (smb_inherited) { err = sa_zfs_process_share(handle, zfsgroup, share, mountpoint, "smb", ZPROP_SRC_INHERITED, smbshareopts, grpdataset, dataset); } } } /* * Don't need to free the "zlist" variable since it is only a * pointer to a cached value that will be freed when * sa_fini() is called. */ return (err); }