diff options
Diffstat (limited to 'usr/src/lib/libzfs')
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs.h | 12 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_changelist.c | 62 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_dataset.c | 80 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_impl.h | 23 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_mount.c | 313 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_util.c | 4 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/mapfile-vers | 7 |
7 files changed, 396 insertions, 105 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index 73bd80d201..265d22e66b 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -110,6 +110,8 @@ enum { EZFS_BADPERMSET, /* invalid permission set name */ EZFS_NODELEGATION, /* delegated administration is disabled */ EZFS_PERMRDONLY, /* pemissions are readonly */ + EZFS_UNSHARESMBFAILED, /* failed to unshare over smb */ + EZFS_SHARESMBFAILED, /* failed to share over smb */ EZFS_UNKNOWN }; @@ -320,7 +322,6 @@ extern const char *zfs_get_name(const zfs_handle_t *); /* * zfs dataset property management */ -extern int zfs_prop_valid_for_type(zfs_prop_t, int); extern const char *zfs_prop_default_string(zfs_prop_t); extern uint64_t zfs_prop_default_numeric(zfs_prop_t); extern const char *zfs_prop_column_name(zfs_prop_t); @@ -459,15 +460,22 @@ extern int zfs_unshare(zfs_handle_t *); * Protocol-specific share support functions. */ extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **); +extern boolean_t zfs_is_shared_smb(zfs_handle_t *, char **); extern int zfs_share_nfs(zfs_handle_t *); +extern int zfs_share_smb(zfs_handle_t *); +extern int zfs_shareall(zfs_handle_t *); extern int zfs_unshare_nfs(zfs_handle_t *, const char *); +extern int zfs_unshare_smb(zfs_handle_t *, const char *); extern int zfs_unshareall_nfs(zfs_handle_t *); +extern int zfs_unshareall_smb(zfs_handle_t *); +extern int zfs_unshareall_bypath(zfs_handle_t *, const char *); +extern int zfs_unshareall(zfs_handle_t *); extern boolean_t zfs_is_shared_iscsi(zfs_handle_t *); extern int zfs_share_iscsi(zfs_handle_t *); extern int zfs_unshare_iscsi(zfs_handle_t *); extern int zfs_iscsi_perm_check(libzfs_handle_t *, char *, ucred_t *); extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *, - void *, void *, int, boolean_t); + void *, void *, int, zfs_share_op_t); /* * When dealing with nvlists, verify() is extremely useful diff --git a/usr/src/lib/libzfs/common/libzfs_changelist.c b/usr/src/lib/libzfs/common/libzfs_changelist.c index 9ceefdc3b1..2b53f7d983 100644 --- a/usr/src/lib/libzfs/common/libzfs_changelist.c +++ b/usr/src/lib/libzfs/common/libzfs_changelist.c @@ -71,6 +71,7 @@ typedef struct prop_changenode { struct prop_changelist { zfs_prop_t cl_prop; zfs_prop_t cl_realprop; + zfs_prop_t cl_shareprop; /* used with sharenfs/sharesmb */ uu_list_pool_t *cl_pool; uu_list_t *cl_list; boolean_t cl_waslegacy; @@ -185,6 +186,7 @@ changelist_postfix(prop_changelist_t *clp) cn = uu_list_prev(clp->cl_list, cn)) { boolean_t sharenfs; + boolean_t sharesmb; /* * If we are in the global zone, but this dataset is exported @@ -222,14 +224,18 @@ changelist_postfix(prop_changelist_t *clp) /* * Remount if previously mounted or mountpoint was legacy, - * or sharenfs property is set. + * or sharenfs or sharesmb property is set. */ sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0) && (strcmp(shareopts, "off") != 0)); - if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs) && - !zfs_is_mounted(cn->cn_handle, NULL) && + sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB, + shareopts, sizeof (shareopts), NULL, NULL, 0, + B_FALSE) == 0) && (strcmp(shareopts, "off") != 0)); + + if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs || + sharesmb) && !zfs_is_mounted(cn->cn_handle, NULL) && zfs_mount(cn->cn_handle, NULL, 0) != 0) ret = -1; @@ -237,11 +243,16 @@ changelist_postfix(prop_changelist_t *clp) * We always re-share even if the filesystem is currently * shared, so that we can adopt any new options. */ - if (cn->cn_shared || clp->cl_waslegacy || sharenfs) { + if (cn->cn_shared || clp->cl_waslegacy || + sharenfs || sharesmb) { if (sharenfs) ret = zfs_share_nfs(cn->cn_handle); else ret = zfs_unshare_nfs(cn->cn_handle, NULL); + if (sharesmb) + ret = zfs_share_smb(cn->cn_handle); + else + ret = zfs_unshare_smb(cn->cn_handle, NULL); } } @@ -302,21 +313,22 @@ changelist_rename(prop_changelist_t *clp, const char *src, const char *dst) } /* - * Given a gathered changelist for the 'sharenfs' property, unshare all the - * datasets in the list. + * Given a gathered changelist for the 'sharenfs' or 'sharesmb' property, + * unshare all the datasets in the list. */ int -changelist_unshare(prop_changelist_t *clp) +changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto) { prop_changenode_t *cn; int ret = 0; - if (clp->cl_prop != ZFS_PROP_SHARENFS) + if (clp->cl_prop != ZFS_PROP_SHARENFS && + clp->cl_prop != ZFS_PROP_SHARESMB) return (0); for (cn = uu_list_first(clp->cl_list); cn != NULL; cn = uu_list_next(clp->cl_list, cn)) { - if (zfs_unshare_nfs(cn->cn_handle, NULL) != 0) + if (zfs_unshare_proto(cn->cn_handle, NULL, proto) != 0) ret = -1; } @@ -386,6 +398,7 @@ change_one(zfs_handle_t *zhp, void *data) char where[64]; prop_changenode_t *cn; zprop_source_t sourcetype; + zprop_source_t share_sourcetype; /* * We only want to unmount/unshare those filesystems that may inherit @@ -405,9 +418,25 @@ change_one(zfs_handle_t *zhp, void *data) return (0); } + /* + * If we are "watching" sharenfs or sharesmb + * then check out the companion property which is tracked + * in cl_shareprop + */ + if (clp->cl_shareprop != ZPROP_INVAL && + zfs_prop_get(zhp, clp->cl_shareprop, property, + sizeof (property), &share_sourcetype, where, sizeof (where), + B_FALSE) != 0) { + zfs_close(zhp); + return (0); + } + if (clp->cl_alldependents || clp->cl_allchildren || sourcetype == ZPROP_SRC_DEFAULT || - sourcetype == ZPROP_SRC_INHERITED) { + sourcetype == ZPROP_SRC_INHERITED || + (clp->cl_shareprop != ZPROP_INVAL && + (share_sourcetype == ZPROP_SRC_DEFAULT || + share_sourcetype == ZPROP_SRC_INHERITED))) { if ((cn = zfs_alloc(zfs_get_handle(zhp), sizeof (prop_changenode_t))) == NULL) { zfs_close(zhp); @@ -507,7 +536,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) * order, regardless of their position in the hierarchy. */ if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED || - prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) { + prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS || + prop == ZFS_PROP_SHARESMB) { compare = compare_mountpoints; clp->cl_sorted = B_TRUE; } @@ -561,9 +591,19 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) if (clp->cl_prop != ZFS_PROP_MOUNTPOINT && clp->cl_prop != ZFS_PROP_SHARENFS && + clp->cl_prop != ZFS_PROP_SHARESMB && clp->cl_prop != ZFS_PROP_SHAREISCSI) return (clp); + /* + * If watching SHARENFS or SHARESMB then + * also watch its companion property. + */ + if (clp->cl_prop == ZFS_PROP_SHARENFS) + clp->cl_shareprop = ZFS_PROP_SHARESMB; + else if (clp->cl_prop == ZFS_PROP_SHARESMB) + clp->cl_shareprop = ZFS_PROP_SHARENFS; + if (clp->cl_alldependents) { if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) { changelist_free(clp); diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index 04a37032ea..db912e7f20 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -51,6 +51,7 @@ #include <sys/spa.h> #include <sys/zio.h> #include <sys/zap.h> +#include <sys/zfs_i18n.h> #include <libzfs.h> #include "zfs_namecheck.h" @@ -376,7 +377,7 @@ top: if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) goto top; /* - * If we can sucessfully destroy it, pretend that it + * If we can successfully destroy it, pretend that it * never existed. */ if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { @@ -481,6 +482,8 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, char *strval; zfs_prop_t prop; nvlist_t *ret; + int chosen_normal = -1; + int chosen_utf = -1; if (type == ZFS_TYPE_SNAPSHOT) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, @@ -545,7 +548,7 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, } if (zfs_prop_readonly(prop) && - (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { + (!zfs_prop_setonce(prop) || zhp != NULL)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is readonly"), propname); @@ -636,19 +639,23 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, /*FALLTHRU*/ + case ZFS_PROP_SHARESMB: case ZFS_PROP_SHARENFS: /* - * For the mountpoint and sharenfs properties, check if - * it can be set in a global/non-global zone based on + * For the mountpoint and sharenfs or sharesmb + * properties, check if it can be set in a + * global/non-global zone based on * the zoned property value: * * global zone non-global zone * -------------------------------------------------- * zoned=on mountpoint (no) mountpoint (yes) * sharenfs (no) sharenfs (no) + * sharesmb (no) sharesmb (no) * * zoned=off mountpoint (yes) N/A * sharenfs (yes) + * sharesmb (yes) */ if (zoned) { if (getzoneid() == GLOBAL_ZONEID) { @@ -659,7 +666,8 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, (void) zfs_error(hdl, EZFS_ZONED, errbuf); goto error; - } else if (prop == ZFS_PROP_SHARENFS) { + } else if (prop == ZFS_PROP_SHARENFS || + prop == ZFS_PROP_SHARESMB) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set in " "a non-global zone"), propname); @@ -684,17 +692,24 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, * property. Now we want to make sure that the * property value is valid if it is sharenfs. */ - if (prop == ZFS_PROP_SHARENFS && + if ((prop == ZFS_PROP_SHARENFS || + prop == ZFS_PROP_SHARESMB) && strcmp(strval, "on") != 0 && strcmp(strval, "off") != 0) { + zfs_share_proto_t proto; + + if (prop == ZFS_PROP_SHARESMB) + proto = PROTO_SMB; + else + proto = PROTO_NFS; /* - * Must be an NFS option string so - * init the libshare in order to - * enable the parser and then parse - * the options. We use the control API - * since we don't care about the - * current configuration and don't + * Must be an valid sharing protocol + * option string so init the libshare + * in order to enable the parser and + * then parse the options. We use the + * control API since we don't care about + * the current configuration and don't * want the overhead of loading it * until we actually do something. */ @@ -714,7 +729,7 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, goto error; } - if (zfs_parse_options(strval, "nfs") != SA_OK) { + if (zfs_parse_options(strval, proto) != SA_OK) { /* * There was an error in parsing so * deal with it by issuing an error @@ -734,6 +749,12 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, } break; + case ZFS_PROP_UTF8ONLY: + chosen_utf = (int)intval; + break; + case ZFS_PROP_NORMALIZE: + chosen_normal = (int)intval; + break; } /* @@ -786,6 +807,27 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, } /* + * If normalization was chosen, but no UTF8 choice was made, + * enforce rejection of non-UTF8 names. + * + * If normalization was chosen, but rejecting non-UTF8 names + * was explicitly not chosen, it is an error. + */ + if (chosen_normal > ZFS_NORMALIZE_NONE && chosen_utf < 0) { + if (nvlist_add_uint64(ret, + zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { + (void) no_memory(hdl); + goto error; + } + } else if (chosen_normal > ZFS_NORMALIZE_NONE && chosen_utf == 0) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "'%s' must be set 'on' if normalization chosen"), + zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + } + + /* * If this is an existing volume, and someone is setting the volsize, * make sure that it matches the reservation, or add it if necessary. */ @@ -941,7 +983,7 @@ zfs_perms_add_who_nvlist(nvlist_t *who_nvp, uint64_t whoid, void *whostr, * whostr may be null for everyone or create perms. * who_type: is the type of entry in whostr. Typically this will be * ZFS_DELEG_WHO_UNKNOWN. - * perms: comman separated list of permissions. May be null if user + * perms: common separated list of permissions. May be null if user * is requested to remove permissions by who. * inherit: Specifies the inheritance of the permissions. Will be either * ZFS_DELEG_PERM_LOCAL and/or ZFS_DELEG_PERM_DESCENDENT. @@ -1833,6 +1875,11 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, mntopt_on = MNTOPT_XATTR; mntopt_off = MNTOPT_NOXATTR; break; + + case ZFS_PROP_NBMAND: + mntopt_on = MNTOPT_NBMAND; + mntopt_off = MNTOPT_NONBMAND; + break; } /* @@ -1871,6 +1918,7 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, case ZFS_PROP_READONLY: case ZFS_PROP_SETUID: case ZFS_PROP_XATTR: + case ZFS_PROP_NBMAND: *val = getprop_uint64(zhp, prop, source); if (hasmntopt(&mnt, mntopt_on) && !*val) { @@ -4177,7 +4225,7 @@ zfs_iscsi_perm_check(libzfs_handle_t *hdl, char *dataset, ucred_t *cred) int zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, - void *export, void *sharetab, int sharemax, boolean_t share_on) + void *export, void *sharetab, int sharemax, zfs_share_op_t operation) { zfs_cmd_t zc = { 0 }; int error; @@ -4186,7 +4234,7 @@ zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; - zc.zc_share.z_sharetype = share_on; + zc.zc_share.z_sharetype = operation; zc.zc_share.z_sharemax = sharemax; error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h index 19a7590cee..cfc03791dd 100644 --- a/usr/src/lib/libzfs/common/libzfs_impl.h +++ b/usr/src/lib/libzfs/common/libzfs_impl.h @@ -90,6 +90,23 @@ struct zpool_handle { diskaddr_t zpool_start_block; }; +typedef enum { + PROTO_NFS = 0, + PROTO_SMB = 1, + PROTO_END = 2 +} zfs_share_proto_t; + +/* + * The following can be used as a bitmask and any new values + * added must preserve that capability. + */ +typedef enum { + SHARED_NOT_SHARED = 0x0, + SHARED_ISCSI = 0x1, + SHARED_NFS = 0x2, + SHARED_SMB = 0x4 +} zfs_share_type_t; + int zfs_error(libzfs_handle_t *, int, const char *); int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...); void zfs_error_aux(libzfs_handle_t *, const char *, ...); @@ -127,7 +144,7 @@ void changelist_rename(prop_changelist_t *, const char *, const char *); void changelist_remove(zfs_handle_t *, prop_changelist_t *); void changelist_free(prop_changelist_t *); prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int); -int changelist_unshare(prop_changelist_t *); +int changelist_unshare(prop_changelist_t *, zfs_share_proto_t *); int changelist_haszonedchild(prop_changelist_t *); void remove_mountpoint(zfs_handle_t *); @@ -148,8 +165,10 @@ void namespace_clear(libzfs_handle_t *); extern int zfs_init_libshare(libzfs_handle_t *, int); extern void zfs_uninit_libshare(libzfs_handle_t *); -extern int zfs_parse_options(char *, char *); +extern int zfs_parse_options(char *, zfs_share_proto_t); +extern int zfs_unshare_proto(zfs_handle_t *zhp, + const char *, zfs_share_proto_t *); #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c index d7dd227bc8..6810f7efdc 100644 --- a/usr/src/lib/libzfs/common/libzfs_mount.c +++ b/usr/src/lib/libzfs/common/libzfs_mount.c @@ -45,11 +45,17 @@ * zfs_unshare() * * zfs_is_shared_nfs() - * zfs_share_nfs() - * zfs_unshare_nfs() - * zfs_unshareall_nfs() + * zfs_is_shared_smb() * zfs_is_shared_iscsi() + * zfs_share_proto() + * zfs_shareall(); * zfs_share_iscsi() + * zfs_unshare_nfs() + * zfs_unshare_smb() + * zfs_unshareall_nfs() + * zfs_unshareall_smb() + * zfs_unshareall() + * zfs_unshareall_bypath() * zfs_unshare_iscsi() * * The following functions are available for pool consumers, and will @@ -82,11 +88,46 @@ #include <sys/systeminfo.h> #define MAXISALEN 257 /* based on sysinfo(2) man page */ +static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *); +zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **, + zfs_share_proto_t); + static int (*iscsitgt_zfs_share)(const char *); static int (*iscsitgt_zfs_unshare)(const char *); static int (*iscsitgt_zfs_is_shared)(const char *); static int (*iscsitgt_svc_online)(); +/* + * The share protocols table must be in the same order as the zfs_share_prot_t + * enum in libzfs_impl.h + */ +typedef struct { + zfs_prop_t p_prop; + char *p_name; + int p_share_err; + int p_unshare_err; +} proto_table_t; + +proto_table_t proto_table[PROTO_END] = { + {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED}, + {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED}, +}; + +zfs_share_proto_t nfs_only[] = { + PROTO_NFS, + PROTO_END +}; + +zfs_share_proto_t smb_only[] = { + PROTO_SMB, + PROTO_END +}; +zfs_share_proto_t share_all_proto[] = { + PROTO_NFS, + PROTO_SMB, + PROTO_END +}; + #pragma init(zfs_iscsi_init) static void zfs_iscsi_init(void) @@ -111,29 +152,54 @@ zfs_iscsi_init(void) } /* - * Search the sharetab for the given mountpoint, returning true if it is found. + * Search the sharetab for the given mountpoint and protocol, returning + * a zfs_share_type_t value. */ -static boolean_t -is_shared(libzfs_handle_t *hdl, const char *mountpoint) +static zfs_share_type_t +is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto) { char buf[MAXPATHLEN], *tab; + char *ptr; if (hdl->libzfs_sharetab == NULL) - return (0); + return (SHARED_NOT_SHARED); (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { /* the mountpoint is the first entry on each line */ - if ((tab = strchr(buf, '\t')) != NULL) { + if ((tab = strchr(buf, '\t')) == NULL) + continue; + + *tab = '\0'; + if (strcmp(buf, mountpoint) == 0) { + /* + * the protocol field is the third field + * skip over second field + */ + ptr = ++tab; + if ((tab = strchr(ptr, '\t')) == NULL) + continue; + ptr = ++tab; + if ((tab = strchr(ptr, '\t')) == NULL) + continue; *tab = '\0'; - if (strcmp(buf, mountpoint) == 0) - return (B_TRUE); + if (strcmp(ptr, + proto_table[proto].p_name) == 0) { + switch (proto) { + case PROTO_NFS: + return (SHARED_NFS); + case PROTO_SMB: + return (SHARED_SMB); + default: + return (0); + } + } } } - return (B_FALSE); + return (SHARED_NOT_SHARED); } /* @@ -349,12 +415,12 @@ zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) /* * Unshare and unmount the filesystem */ - if (zfs_unshare_nfs(zhp, mntpt) != 0) + if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) return (-1); if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) { free(mntpt); - (void) zfs_share_nfs(zhp); + (void) zfs_shareall(zhp); return (-1); } free(mntpt); @@ -387,10 +453,17 @@ zfs_unmountall(zfs_handle_t *zhp, int flags) boolean_t zfs_is_shared(zfs_handle_t *zhp) { + zfs_share_type_t rc = 0; + zfs_share_proto_t *curr_proto; + if (ZFS_IS_VOLUME(zhp)) return (zfs_is_shared_iscsi(zhp)); - return (zfs_is_shared_nfs(zhp, NULL)); + for (curr_proto = share_all_proto; *curr_proto != PROTO_END; + curr_proto++) + rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto); + + return (rc ? B_TRUE : B_FALSE); } int @@ -399,7 +472,7 @@ zfs_share(zfs_handle_t *zhp) if (ZFS_IS_VOLUME(zhp)) return (zfs_share_iscsi(zhp)); - return (zfs_share_nfs(zhp)); + return (zfs_share_proto(zhp, share_all_proto)); } int @@ -408,32 +481,47 @@ zfs_unshare(zfs_handle_t *zhp) if (ZFS_IS_VOLUME(zhp)) return (zfs_unshare_iscsi(zhp)); - return (zfs_unshare_nfs(zhp, NULL)); + return (zfs_unshareall(zhp)); } /* * Check to see if the filesystem is currently shared. */ -boolean_t -zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) +zfs_share_type_t +zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto) { char *mountpoint; + zfs_share_type_t rc; if (!zfs_is_mounted(zhp, &mountpoint)) - return (B_FALSE); + return (SHARED_NOT_SHARED); - if (is_shared(zhp->zfs_hdl, mountpoint)) { + if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) { if (where != NULL) *where = mountpoint; else free(mountpoint); - return (B_TRUE); + return (rc); } else { free(mountpoint); - return (B_FALSE); + return (SHARED_NOT_SHARED); } } +boolean_t +zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) +{ + return (zfs_is_shared_proto(zhp, where, + PROTO_NFS) != SHARED_NOT_SHARED); +} + +boolean_t +zfs_is_shared_smb(zfs_handle_t *zhp, char **where) +{ + return (zfs_is_shared_proto(zhp, where, + PROTO_SMB) != SHARED_NOT_SHARED); +} + /* * Make sure things will work if libshare isn't installed by using * wrapper functions that check to see that the pointers to functions @@ -552,12 +640,13 @@ zfs_uninit_libshare(libzfs_handle_t *zhandle) */ int -zfs_parse_options(char *options, char *proto) +zfs_parse_options(char *options, zfs_share_proto_t proto) { int ret; if (_sa_parse_legacy_options != NULL) - ret = _sa_parse_legacy_options(NULL, options, proto); + ret = _sa_parse_legacy_options(NULL, options, + proto_table[proto].p_name); else ret = SA_CONFIG_ERR; return (ret); @@ -609,74 +698,102 @@ zfs_sa_disable_share(sa_share_t share, char *proto) } /* - * Share the given filesystem according to the options in 'sharenfs'. We rely + * 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. */ -int -zfs_share_nfs(zfs_handle_t *zhp) +static int +zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) { char mountpoint[ZFS_MAXPROPLEN]; char shareopts[ZFS_MAXPROPLEN]; libzfs_handle_t *hdl = zhp->zfs_hdl; sa_share_t share; + zfs_share_proto_t *curr_proto; int ret; if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) return (0); - /* - * Return success if there are no share options. - */ - if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts), - NULL, NULL, 0, B_FALSE) != 0 || - strcmp(shareopts, "off") == 0) - return (0); - - /* - * 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)) - 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); } - share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint); - if (share != NULL) { - int err; - err = zfs_sa_enable_share(share, "nfs"); - if (err != SA_OK) { - (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, + + 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), NULL, NULL, + 0, 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 = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint); + if (share != NULL) { + int err; + err = zfs_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); } - } else { - (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, - dgettext(TEXT_DOMAIN, "cannot share '%s'"), - zfs_get_name(zhp)); - return (-1); - } + } return (0); } + +int +zfs_share_nfs(zfs_handle_t *zhp) +{ + return (zfs_share_proto(zhp, nfs_only)); +} + +int +zfs_share_smb(zfs_handle_t *zhp) +{ + return (zfs_share_proto(zhp, smb_only)); +} + +int +zfs_shareall(zfs_handle_t *zhp) +{ + return (zfs_share_proto(zhp, share_all_proto)); +} + /* * Unshare a filesystem by mountpoint. */ static int -unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint) +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 id does during API initialization, so strdup the @@ -696,7 +813,7 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint) free(mntpt); /* don't need the copy anymore */ if (share != NULL) { - err = zfs_sa_disable_share(share, "nfs"); + err = zfs_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"), @@ -714,7 +831,8 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint) * Unshare the given filesystem. */ int -zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) +zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, + zfs_share_proto_t *proto) { struct mnttab search = { 0 }, entry; char *mntpt = NULL; @@ -724,19 +842,25 @@ zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) search.mnt_fstype = MNTTYPE_ZFS; rewind(zhp->zfs_hdl->libzfs_mnttab); if (mountpoint != NULL) - mountpoint = mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); + mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { + zfs_share_proto_t *curr_proto; if (mountpoint == NULL) - mountpoint = entry.mnt_mountp; + mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); - if (is_shared(zhp->zfs_hdl, mountpoint) && - unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0) { - if (mntpt != NULL) - free(mntpt); - return (-1); + for (curr_proto = proto; *curr_proto != PROTO_END; + curr_proto++) { + + if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) && + unshare_one(zhp->zfs_hdl, zhp->zfs_name, + mntpt, *curr_proto) != 0) { + if (mntpt != NULL) + free(mntpt); + return (-1); + } } } if (mntpt != NULL) @@ -745,11 +869,23 @@ zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) return (0); } +int +zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) +{ + return (zfs_unshare_proto(zhp, mountpoint, nfs_only)); +} + +int +zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint) +{ + return (zfs_unshare_proto(zhp, mountpoint, smb_only)); +} + /* - * Same as zfs_unmountall(), but for NFS unshares. + * Same as zfs_unmountall(), but for NFS and SMB unshares. */ int -zfs_unshareall_nfs(zfs_handle_t *zhp) +zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) { prop_changelist_t *clp; int ret; @@ -758,12 +894,36 @@ zfs_unshareall_nfs(zfs_handle_t *zhp) if (clp == NULL) return (-1); - ret = changelist_unshare(clp); + ret = changelist_unshare(clp, proto); changelist_free(clp); return (ret); } +int +zfs_unshareall_nfs(zfs_handle_t *zhp) +{ + return (zfs_unshareall_proto(zhp, nfs_only)); +} + +int +zfs_unshareall_smb(zfs_handle_t *zhp) +{ + return (zfs_unshareall_proto(zhp, smb_only)); +} + +int +zfs_unshareall(zfs_handle_t *zhp) +{ + return (zfs_unshareall_proto(zhp, share_all_proto)); +} + +int +zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint) +{ + return (zfs_unshare_proto(zhp, mountpoint, share_all_proto)); +} + /* * Remove the mountpoint associated with the current dataset, if necessary. * We only remove the underlying directory if: @@ -805,7 +965,7 @@ zfs_is_shared_iscsi(zfs_handle_t *zhp) * If iscsi deamon isn't running then we aren't shared */ if (iscsitgt_svc_online && iscsitgt_svc_online() == 1) - return (0); + return (B_FALSE); else return (iscsitgt_zfs_is_shared != NULL && iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); @@ -853,7 +1013,7 @@ zfs_unshare_iscsi(zfs_handle_t *zhp) /* * Return if the volume is not shared */ - if (!zfs_is_shared_iscsi(zhp)) + if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI) return (0); /* @@ -1143,9 +1303,14 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) * Walk through and first unshare everything. */ for (i = 0; i < used; i++) { - if (is_shared(hdl, mountpoints[i]) && - unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0) - goto out; + zfs_share_proto_t *curr_proto; + for (curr_proto = share_all_proto; *curr_proto != PROTO_END; + curr_proto++) { + if (is_shared(hdl, mountpoints[i], *curr_proto) && + unshare_one(hdl, mountpoints[i], + mountpoints[i], *curr_proto) != 0) + goto out; + } } /* diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c index d446b32091..8a1ad6d656 100644 --- a/usr/src/lib/libzfs/common/libzfs_util.c +++ b/usr/src/lib/libzfs/common/libzfs_util.c @@ -136,6 +136,10 @@ libzfs_error_description(libzfs_handle_t *hdl) return (dgettext(TEXT_DOMAIN, "unshare(1M) failed")); case EZFS_SHARENFSFAILED: return (dgettext(TEXT_DOMAIN, "share(1M) failed")); + case EZFS_UNSHARESMBFAILED: + return (dgettext(TEXT_DOMAIN, "smb remove share failed")); + case EZFS_SHARESMBFAILED: + return (dgettext(TEXT_DOMAIN, "smb add share failed")); case EZFS_ISCSISVCUNAVAIL: return (dgettext(TEXT_DOMAIN, "iscsitgt service need to be enabled by " diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers index 1ca0da3453..d7d68f8708 100644 --- a/usr/src/lib/libzfs/common/mapfile-vers +++ b/usr/src/lib/libzfs/common/mapfile-vers @@ -53,6 +53,7 @@ SUNWprivate_1.1 { zfs_is_shared; zfs_is_shared_iscsi; zfs_is_shared_nfs; + zfs_is_shared_smb; zfs_iter_children; zfs_iter_dependents; zfs_iter_filesystems; @@ -92,7 +93,9 @@ SUNWprivate_1.1 { zfs_rollback; zfs_send; zfs_share; + zfs_shareall; zfs_share_nfs; + zfs_share_smb; zfs_share_iscsi; zfs_snapshot; zfs_type_to_name; @@ -101,7 +104,11 @@ SUNWprivate_1.1 { zfs_unshare; zfs_unshare_iscsi; zfs_unshare_nfs; + zfs_unshare_smb; + zfs_unshareall; + zfs_unshareall_bypath; zfs_unshareall_nfs; + zfs_unshareall_smb; zpool_add; zpool_clear; zpool_close; |