libshare: fold into libzfs and reorg headers a little

libzfs is the only user of libshare, and only internally, so there's no
particular reason to build it separately, nor to export its symbols. So,
pull it into libzfs proper, remove its "public" header, and hide its
symbols.

The bare minimum "public" API is just to count and enumerate the
supported share types. These are moved to libzfs.h with the other share
API.

Sponsored-by: https://despairlabs.com/sponsor/
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rob Norris <robn@despairlabs.com>
Closes #18072
This commit is contained in:
Rob Norris
2025-12-20 14:52:33 +11:00
committed by GitHub
parent 962e68865e
commit 0d44b58d7f
20 changed files with 337 additions and 449 deletions
+7 -1
View File
@@ -7,6 +7,7 @@ CPPCHECKTARGETS += libzfs.la
dist_libzfs_la_SOURCES = \
%D%/libzfs_impl.h \
%D%/libzfs_share.h \
%D%/libzfs_changelist.c \
%D%/libzfs_config.c \
%D%/libzfs_crypto.c \
@@ -16,6 +17,8 @@ dist_libzfs_la_SOURCES = \
%D%/libzfs_iter.c \
%D%/libzfs_mount.c \
%D%/libzfs_pool.c \
%D%/libzfs_share.c \
%D%/libzfs_share_nfs.c \
%D%/libzfs_sendrecv.c \
%D%/libzfs_status.c \
%D%/libzfs_util.c
@@ -23,6 +26,8 @@ dist_libzfs_la_SOURCES = \
if BUILD_FREEBSD
dist_libzfs_la_SOURCES += \
%D%/os/freebsd/libzfs_compat.c \
%D%/os/freebsd/libzfs_share_nfs.c \
%D%/os/freebsd/libzfs_share_smb.c \
%D%/os/freebsd/libzfs_zmount.c
endif
@@ -30,6 +35,8 @@ if BUILD_LINUX
dist_libzfs_la_SOURCES += \
%D%/os/linux/libzfs_mount_os.c \
%D%/os/linux/libzfs_pool_os.c \
%D%/os/linux/libzfs_share_nfs.c \
%D%/os/linux/libzfs_share_smb.c \
%D%/os/linux/libzfs_util_os.c
endif
@@ -52,7 +59,6 @@ nodist_libzfs_la_SOURCES = \
module/zcommon/zprop_common.c
libzfs_la_LIBADD = \
libshare.la \
libzfs_core.la \
libnvpair.la \
libzutil.la
+218 -222
View File
@@ -296,13 +296,6 @@
<elf-symbol name='rw_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='rw_tryenter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='rw_tryupgrade' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='sa_commit_shares' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='sa_disable_share' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='sa_enable_share' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='sa_errorstr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='sa_is_shared' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='sa_truncate_shares' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='sa_validate_shareopts' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='seq_printf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='snapshot_namecheck' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='spl_fstrans_mark' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -496,6 +489,7 @@
<elf-symbol name='zfs_setproctitle' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_setproctitle_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_share' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_share_protocol_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_show_diffs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_smb_acl_add' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_smb_acl_purge' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -696,7 +690,6 @@
<elf-symbol name='fletcher_4_superscalar4_ops' size='128' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='fletcher_4_superscalar_ops' size='128' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_config_ops' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='sa_protocol_names' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='spa_feature_table' size='2632' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfeature_checks_disable' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_deleg_perm_tab' size='544' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -726,147 +719,6 @@
<return type-id='48b5725f'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libshare/libshare.c' language='LANG_C99'>
<array-type-def dimensions='1' type-id='b99c00c9' size-in-bits='128' id='2d6895a3'>
<subrange length='2' type-id='7359adad' id='52efc4ef'/>
</array-type-def>
<var-decl name='sa_protocol_names' type-id='2d6895a3' mangled-name='sa_protocol_names' visibility='default' elf-symbol-id='sa_protocol_names'/>
<type-decl name='unsigned long int' size-in-bits='64' id='7359adad'/>
</abi-instr>
<abi-instr address-size='64' path='lib/libshare/nfs.c' language='LANG_C99'>
<function-decl name='rename' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='memchr' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='eaa32e2f'/>
<parameter type-id='95e97e5e'/>
<parameter type-id='b59d7dce'/>
<return type-id='eaa32e2f'/>
</function-decl>
<function-decl name='flock' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='fchmod' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<parameter type-id='e1c52942'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='mkdir' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='e1c52942'/>
<return type-id='95e97e5e'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libshare/os/linux/nfs.c' language='LANG_C99'>
<class-decl name='sa_share_impl' size-in-bits='192' is-struct='yes' visibility='default' id='72b09bf8'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='sa_zfsname' type-id='80f4b756' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='64'>
<var-decl name='sa_mountpoint' type-id='80f4b756' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='128'>
<var-decl name='sa_shareopts' type-id='80f4b756' visibility='default'/>
</data-member>
</class-decl>
<typedef-decl name='sa_share_impl_t' type-id='946a2c6b' id='a48b47d0'/>
<class-decl name='sa_fstype_t' size-in-bits='384' is-struct='yes' naming-typedef-id='639af739' visibility='default' id='944afa86'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='enable_share' type-id='2f78a9c1' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='64'>
<var-decl name='disable_share' type-id='2f78a9c1' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='128'>
<var-decl name='is_shared' type-id='81020bc2' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='192'>
<var-decl name='validate_shareopts' type-id='f194a8fb' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='256'>
<var-decl name='commit_shares' type-id='797ee7da' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='320'>
<var-decl name='truncate_shares' type-id='5d51038b' visibility='default'/>
</data-member>
</class-decl>
<typedef-decl name='sa_fstype_t' type-id='944afa86' id='639af739'/>
<qualified-type-def type-id='639af739' const='yes' id='d19dbca9'/>
<qualified-type-def type-id='72b09bf8' const='yes' id='484950e3'/>
<pointer-type-def type-id='484950e3' size-in-bits='64' id='946a2c6b'/>
<pointer-type-def type-id='276427e1' size-in-bits='64' id='1db260e5'/>
<qualified-type-def type-id='1db260e5' const='yes' id='797ee7da'/>
<pointer-type-def type-id='5113b296' size-in-bits='64' id='70487b28'/>
<qualified-type-def type-id='70487b28' const='yes' id='f194a8fb'/>
<pointer-type-def type-id='c13578bc' size-in-bits='64' id='fa1f29ce'/>
<qualified-type-def type-id='fa1f29ce' const='yes' id='2f78a9c1'/>
<pointer-type-def type-id='723e6cf2' size-in-bits='64' id='1d99e49c'/>
<pointer-type-def type-id='86373eb1' size-in-bits='64' id='f337456d'/>
<qualified-type-def type-id='f337456d' const='yes' id='81020bc2'/>
<qualified-type-def type-id='953b12f8' const='yes' id='5d51038b'/>
<var-decl name='libshare_nfs_type' type-id='d19dbca9' visibility='default'/>
<function-decl name='nfs_escape_mountpoint' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='9b23c9ad'/>
<parameter type-id='37e3bd22'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nfs_is_shared_impl' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='a48b47d0'/>
<return type-id='c19b74c3'/>
</function-decl>
<function-decl name='nfs_toggle_share' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<parameter type-id='a48b47d0'/>
<parameter type-id='1d99e49c'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nfs_reset_shares' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='48b5725f'/>
</function-decl>
<function-type size-in-bits='64' id='276427e1'>
<return type-id='95e97e5e'/>
</function-type>
<function-type size-in-bits='64' id='5113b296'>
<parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/>
</function-type>
<function-type size-in-bits='64' id='c13578bc'>
<parameter type-id='a48b47d0'/>
<return type-id='95e97e5e'/>
</function-type>
<function-type size-in-bits='64' id='723e6cf2'>
<parameter type-id='a48b47d0'/>
<parameter type-id='822cd80b'/>
<return type-id='95e97e5e'/>
</function-type>
<function-type size-in-bits='64' id='86373eb1'>
<parameter type-id='a48b47d0'/>
<return type-id='c19b74c3'/>
</function-type>
<function-type size-in-bits='64' id='ee076206'>
<return type-id='48b5725f'/>
</function-type>
</abi-instr>
<abi-instr address-size='64' path='lib/libshare/os/linux/smb.c' language='LANG_C99'>
<var-decl name='libshare_smb_type' type-id='d19dbca9' visibility='default'/>
<function-decl name='__fgets_chk' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='266fe297'/>
<parameter type-id='b59d7dce'/>
<parameter type-id='95e97e5e'/>
<parameter type-id='e75a27e9'/>
<return type-id='26a90f95'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libspl/assert.c' language='LANG_C99'>
<function-decl name='libspl_backtrace' mangled-name='libspl_backtrace' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libspl_backtrace'>
<parameter type-id='95e97e5e'/>
@@ -1374,6 +1226,7 @@
<parameter type-id='3e0601f0'/>
<return type-id='95e97e5e'/>
</function-decl>
<type-decl name='unsigned long int' size-in-bits='64' id='7359adad'/>
<type-decl name='unsigned short int' size-in-bits='16' id='8efea9e5'/>
</abi-instr>
<abi-instr address-size='64' path='lib/libspl/condvar.c' language='LANG_C99'>
@@ -1571,14 +1424,13 @@
</class-decl>
<typedef-decl name='kstat_t' type-id='5f5c9d88' id='dd12e024'/>
<typedef-decl name='uchar_t' type-id='002ac4a6' id='d8bf0010'/>
<typedef-decl name='__loff_t' type-id='724e4de6' id='00c9d214'/>
<typedef-decl name='loff_t' type-id='00c9d214' id='69bf7bee'/>
<typedef-decl name='off_t' type-id='724e4de6' id='ad707ada'/>
<pointer-type-def type-id='9d5d322a' size-in-bits='64' id='bbe97414'/>
<pointer-type-def type-id='05b3c714' size-in-bits='64' id='27cc5c36'/>
<pointer-type-def type-id='7a9ace65' size-in-bits='64' id='8cf7b7e1'/>
<pointer-type-def type-id='5f5c9d88' size-in-bits='64' id='0e87f9be'/>
<pointer-type-def type-id='dd12e024' size-in-bits='64' id='46e5e463'/>
<pointer-type-def type-id='527a97c5' size-in-bits='64' id='673f2af9'/>
<pointer-type-def type-id='56e84909' size-in-bits='64' id='874be675'/>
<function-decl name='kstat_create' mangled-name='kstat_create' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='kstat_create'>
<parameter type-id='80f4b756' name='module'/>
<parameter type-id='95e97e5e' name='instance'/>
@@ -1597,7 +1449,7 @@
<parameter type-id='46e5e463' name='ksp'/>
<parameter type-id='bbe97414' name='headers'/>
<parameter type-id='27cc5c36' name='data'/>
<parameter type-id='673f2af9' name='addr'/>
<parameter type-id='874be675' name='addr'/>
<return type-id='48b5725f'/>
</function-decl>
<function-type size-in-bits='64' id='9d5d322a'>
@@ -1616,9 +1468,9 @@
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-type>
<function-type size-in-bits='64' id='527a97c5'>
<function-type size-in-bits='64' id='56e84909'>
<parameter type-id='46e5e463'/>
<parameter type-id='69bf7bee'/>
<parameter type-id='ad707ada'/>
<return type-id='eaa32e2f'/>
</function-type>
</abi-instr>
@@ -2146,6 +1998,9 @@
<function-decl name='system_taskq_fini' mangled-name='system_taskq_fini' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='system_taskq_fini'>
<return type-id='48b5725f'/>
</function-decl>
<function-type size-in-bits='64' id='ee076206'>
<return type-id='48b5725f'/>
</function-type>
<function-type size-in-bits='64' id='c5c76c9c'>
<parameter type-id='eaa32e2f'/>
<return type-id='48b5725f'/>
@@ -2260,6 +2115,12 @@
<typedef-decl name='zpool_handle_t' type-id='67002a8a' id='b1efc708'/>
<typedef-decl name='libzfs_handle_t' type-id='c8a9d9d8' id='95942d0c'/>
<typedef-decl name='zfs_iter_f' type-id='5571cde4' id='d8e49ab9'/>
<enum-decl name='sa_protocol' id='9155d4b5'>
<underlying-type type-id='9cac1fee'/>
<enumerator name='SA_PROTOCOL_NFS' value='0'/>
<enumerator name='SA_PROTOCOL_SMB' value='1'/>
<enumerator name='SA_PROTOCOL_COUNT' value='2'/>
</enum-decl>
<typedef-decl name='avl_tree_t' type-id='b351119f' id='f20fbd51'/>
<typedef-decl name='avl_index_t' type-id='e475ab95' id='fba6cb51'/>
<class-decl name='avl_node' size-in-bits='192' is-struct='yes' visibility='default' id='428b67b3'>
@@ -2481,12 +2342,6 @@
</data-member>
</class-decl>
<typedef-decl name='nvlist_t' type-id='ac266fd9' id='8e8d4be3'/>
<enum-decl name='sa_protocol' id='9155d4b5'>
<underlying-type type-id='9cac1fee'/>
<enumerator name='SA_PROTOCOL_NFS' value='0'/>
<enumerator name='SA_PROTOCOL_SMB' value='1'/>
<enumerator name='SA_PROTOCOL_COUNT' value='2'/>
</enum-decl>
<enum-decl name='boolean_t' naming-typedef-id='c19b74c3' id='f58c8277'>
<underlying-type type-id='9cac1fee'/>
<enumerator name='B_FALSE' value='0'/>
@@ -2908,10 +2763,6 @@
<parameter type-id='95e97e5e'/>
<return type-id='eaa32e2f'/>
</function-decl>
<function-decl name='sa_commit_shares' mangled-name='sa_commit_shares' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sa_commit_shares'>
<parameter type-id='9155d4b5'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='strlcat' mangled-name='strlcat' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='strlcat'>
<parameter type-id='26a90f95'/>
<parameter type-id='80f4b756'/>
@@ -2955,6 +2806,10 @@
<parameter type-id='9200a744'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='sa_commit_shares' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='9155d4b5'/>
<return type-id='48b5725f'/>
</function-decl>
<function-type size-in-bits='64' id='96ee24a5'>
<parameter type-id='eaa32e2f'/>
<parameter type-id='eaa32e2f'/>
@@ -4825,11 +4680,6 @@
<parameter type-id='58603c44'/>
<return type-id='31429eff'/>
</function-decl>
<function-decl name='sa_validate_shareopts' mangled-name='sa_validate_shareopts' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sa_validate_shareopts'>
<parameter type-id='80f4b756'/>
<parameter type-id='9155d4b5'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='getmntany' mangled-name='getmntany' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='getmntany'>
<parameter type-id='822cd80b'/>
<parameter type-id='9d424d31'/>
@@ -5331,6 +5181,11 @@
<parameter type-id='80f4b756'/>
<return type-id='c19b74c3'/>
</function-decl>
<function-decl name='sa_validate_shareopts' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='9155d4b5'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-type size-in-bits='64' id='02362c02'>
<parameter type-id='eaa32e2f'/>
<parameter type-id='80f4b756'/>
@@ -6106,31 +5961,6 @@
<parameter type-id='d50d396c'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='sa_errorstr' mangled-name='sa_errorstr' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sa_errorstr'>
<parameter type-id='95e97e5e'/>
<return type-id='80f4b756'/>
</function-decl>
<function-decl name='sa_enable_share' mangled-name='sa_enable_share' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sa_enable_share'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<parameter type-id='9155d4b5'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='sa_disable_share' mangled-name='sa_disable_share' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sa_disable_share'>
<parameter type-id='80f4b756'/>
<parameter type-id='9155d4b5'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='sa_is_shared' mangled-name='sa_is_shared' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sa_is_shared'>
<parameter type-id='80f4b756'/>
<parameter type-id='9155d4b5'/>
<return type-id='c19b74c3'/>
</function-decl>
<function-decl name='sa_truncate_shares' mangled-name='sa_truncate_shares' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='sa_truncate_shares'>
<parameter type-id='9155d4b5'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='taskq_create' mangled-name='taskq_create' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='taskq_create'>
<parameter type-id='80f4b756'/>
<parameter type-id='95e97e5e'/>
@@ -6214,6 +6044,10 @@
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zfs_share_protocol_name' mangled-name='zfs_share_protocol_name' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_share_protocol_name'>
<parameter type-id='9155d4b5' name='protocol'/>
<return type-id='80f4b756'/>
</function-decl>
<function-decl name='zfs_mount_at' mangled-name='zfs_mount_at' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_mount_at'>
<parameter type-id='9200a744' name='zhp'/>
<parameter type-id='80f4b756' name='options'/>
@@ -6261,6 +6095,31 @@
<parameter type-id='c19b74c3' name='force'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='sa_errorstr' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<return type-id='80f4b756'/>
</function-decl>
<function-decl name='sa_enable_share' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<parameter type-id='9155d4b5'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='sa_disable_share' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='9155d4b5'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='sa_is_shared' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='9155d4b5'/>
<return type-id='c19b74c3'/>
</function-decl>
<function-decl name='sa_truncate_shares' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='9155d4b5'/>
<return type-id='48b5725f'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfs/libzfs_pool.c' language='LANG_C99'>
<class-decl name='splitflags' size-in-bits='64' is-struct='yes' visibility='default' id='dc01bf52'>
@@ -8498,6 +8357,45 @@
<return type-id='48b5725f'/>
</function-type>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfs/libzfs_share.c' language='LANG_C99'>
<array-type-def dimensions='1' type-id='b99c00c9' size-in-bits='128' id='2d6895a3'>
<subrange length='2' type-id='7359adad' id='52efc4ef'/>
</array-type-def>
<var-decl name='sa_protocol_names' type-id='2d6895a3' visibility='default'/>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfs/libzfs_share_nfs.c' language='LANG_C99'>
<function-decl name='rename' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='memchr' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='eaa32e2f'/>
<parameter type-id='95e97e5e'/>
<parameter type-id='b59d7dce'/>
<return type-id='eaa32e2f'/>
</function-decl>
<function-decl name='strpbrk' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='26a90f95'/>
</function-decl>
<function-decl name='flock' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='fchmod' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='95e97e5e'/>
<parameter type-id='e1c52942'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='mkdir' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='e1c52942'/>
<return type-id='95e97e5e'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfs/libzfs_status.c' language='LANG_C99'>
<function-decl name='zpool_import_status' mangled-name='zpool_import_status' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_import_status'>
<parameter type-id='5ce45b60' name='config'/>
@@ -9270,6 +9168,131 @@
<return type-id='95e97e5e'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfs/os/linux/libzfs_share_nfs.c' language='LANG_C99'>
<class-decl name='sa_share_impl' size-in-bits='192' is-struct='yes' visibility='default' id='72b09bf8'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='sa_zfsname' type-id='80f4b756' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='64'>
<var-decl name='sa_mountpoint' type-id='80f4b756' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='128'>
<var-decl name='sa_shareopts' type-id='80f4b756' visibility='default'/>
</data-member>
</class-decl>
<typedef-decl name='sa_share_impl_t' type-id='946a2c6b' id='a48b47d0'/>
<class-decl name='sa_fstype_t' size-in-bits='384' is-struct='yes' naming-typedef-id='639af739' visibility='default' id='944afa86'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='enable_share' type-id='2f78a9c1' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='64'>
<var-decl name='disable_share' type-id='2f78a9c1' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='128'>
<var-decl name='is_shared' type-id='81020bc2' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='192'>
<var-decl name='validate_shareopts' type-id='f194a8fb' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='256'>
<var-decl name='commit_shares' type-id='797ee7da' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='320'>
<var-decl name='truncate_shares' type-id='5d51038b' visibility='default'/>
</data-member>
</class-decl>
<typedef-decl name='sa_fstype_t' type-id='944afa86' id='639af739'/>
<qualified-type-def type-id='639af739' const='yes' id='d19dbca9'/>
<qualified-type-def type-id='72b09bf8' const='yes' id='484950e3'/>
<pointer-type-def type-id='484950e3' size-in-bits='64' id='946a2c6b'/>
<pointer-type-def type-id='276427e1' size-in-bits='64' id='1db260e5'/>
<qualified-type-def type-id='1db260e5' const='yes' id='797ee7da'/>
<pointer-type-def type-id='5113b296' size-in-bits='64' id='70487b28'/>
<qualified-type-def type-id='70487b28' const='yes' id='f194a8fb'/>
<pointer-type-def type-id='c13578bc' size-in-bits='64' id='fa1f29ce'/>
<qualified-type-def type-id='fa1f29ce' const='yes' id='2f78a9c1'/>
<pointer-type-def type-id='723e6cf2' size-in-bits='64' id='1d99e49c'/>
<pointer-type-def type-id='86373eb1' size-in-bits='64' id='f337456d'/>
<qualified-type-def type-id='f337456d' const='yes' id='81020bc2'/>
<qualified-type-def type-id='953b12f8' const='yes' id='5d51038b'/>
<var-decl name='libshare_nfs_type' type-id='d19dbca9' visibility='default'/>
<function-decl name='nfs_escape_mountpoint' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='9b23c9ad'/>
<parameter type-id='37e3bd22'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nfs_is_shared_impl' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='a48b47d0'/>
<return type-id='c19b74c3'/>
</function-decl>
<function-decl name='nfs_toggle_share' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<parameter type-id='a48b47d0'/>
<parameter type-id='1d99e49c'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nfs_reset_shares' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='48b5725f'/>
</function-decl>
<function-type size-in-bits='64' id='276427e1'>
<return type-id='95e97e5e'/>
</function-type>
<function-type size-in-bits='64' id='5113b296'>
<parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/>
</function-type>
<function-type size-in-bits='64' id='c13578bc'>
<parameter type-id='a48b47d0'/>
<return type-id='95e97e5e'/>
</function-type>
<function-type size-in-bits='64' id='723e6cf2'>
<parameter type-id='a48b47d0'/>
<parameter type-id='822cd80b'/>
<return type-id='95e97e5e'/>
</function-type>
<function-type size-in-bits='64' id='86373eb1'>
<parameter type-id='a48b47d0'/>
<return type-id='c19b74c3'/>
</function-type>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfs/os/linux/libzfs_share_smb.c' language='LANG_C99'>
<class-decl name='dirent' size-in-bits='2240' is-struct='yes' visibility='default' id='611586a1'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='d_ino' type-id='71288a47' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='64'>
<var-decl name='d_off' type-id='724e4de6' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='128'>
<var-decl name='d_reclen' type-id='8efea9e5' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='144'>
<var-decl name='d_type' type-id='002ac4a6' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='152'>
<var-decl name='d_name' type-id='d1617432' visibility='default'/>
</data-member>
</class-decl>
<pointer-type-def type-id='611586a1' size-in-bits='64' id='2e243169'/>
<function-decl name='opendir' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<return type-id='f09217ba'/>
</function-decl>
<function-decl name='__fgets_chk' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='266fe297'/>
<parameter type-id='b59d7dce'/>
<parameter type-id='95e97e5e'/>
<parameter type-id='e75a27e9'/>
<return type-id='26a90f95'/>
</function-decl>
<var-decl name='libshare_smb_type' type-id='d19dbca9' visibility='default'/>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfs/os/linux/libzfs_util_os.c' language='LANG_C99'>
<typedef-decl name='nfds_t' type-id='7359adad' id='555eef66'/>
<class-decl name='pollfd' size-in-bits='64' is-struct='yes' visibility='default' id='b440e872'>
@@ -9929,23 +9952,6 @@
</class-decl>
<typedef-decl name='zfeature_info_t' type-id='1178d146' id='83f29ca2'/>
<typedef-decl name='__free_fn_t' type-id='b7f9d8e6' id='3ff5e51e'/>
<class-decl name='dirent' size-in-bits='2240' is-struct='yes' visibility='default' id='611586a1'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='d_ino' type-id='71288a47' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='64'>
<var-decl name='d_off' type-id='724e4de6' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='128'>
<var-decl name='d_reclen' type-id='8efea9e5' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='144'>
<var-decl name='d_type' type-id='002ac4a6' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='152'>
<var-decl name='d_name' type-id='d1617432' visibility='default'/>
</data-member>
</class-decl>
<class-decl name='zfs_mod_supported_features' size-in-bits='128' is-struct='yes' visibility='default' id='3eee3342'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='tree' type-id='eaa32e2f' visibility='default'/>
@@ -9958,16 +9964,11 @@
<pointer-type-def type-id='81a65028' size-in-bits='64' id='1acff326'/>
<qualified-type-def type-id='3eee3342' const='yes' id='0c1d5bbb'/>
<pointer-type-def type-id='0c1d5bbb' size-in-bits='64' id='a3372543'/>
<pointer-type-def type-id='611586a1' size-in-bits='64' id='2e243169'/>
<pointer-type-def type-id='c5c76c9c' size-in-bits='64' id='b7f9d8e6'/>
<qualified-type-def type-id='eaa32e2f' const='yes' id='83be723c'/>
<pointer-type-def type-id='83be723c' size-in-bits='64' id='7acd98a2'/>
<var-decl name='spa_feature_table' type-id='fd43354e' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
<var-decl name='zfeature_checks_disable' type-id='c19b74c3' mangled-name='zfeature_checks_disable' visibility='default' elf-symbol-id='zfeature_checks_disable'/>
<function-decl name='opendir' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<return type-id='f09217ba'/>
</function-decl>
<function-decl name='tsearch' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='eaa32e2f'/>
<parameter type-id='63e171df'/>
@@ -10012,11 +10013,6 @@
<return type-id='95e97e5e'/>
</function-decl>
<var-decl name='zfs_history_event_names' type-id='5ce15418' mangled-name='zfs_history_event_names' visibility='default' elf-symbol-id='zfs_history_event_names'/>
<function-decl name='strpbrk' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='26a90f95'/>
</function-decl>
<function-decl name='zfs_allocatable_devs' mangled-name='zfs_allocatable_devs' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_allocatable_devs'>
<parameter type-id='5ce45b60' name='nv'/>
<return type-id='c19b74c3'/>
+2 -1
View File
@@ -37,9 +37,10 @@
#include <regex.h>
#include <libzfs.h>
#include <libshare.h>
#include <libzfs_core.h>
#include "libzfs_share.h"
#ifdef __cplusplus
extern "C" {
#endif
+5 -2
View File
@@ -79,7 +79,6 @@
#include "libzfs_impl.h"
#include <libshare.h>
#include <sys/systeminfo.h>
#define MAXISALEN 257 /* based on sysinfo(2) man page */
@@ -98,7 +97,11 @@ static const enum sa_protocol share_all_proto[SA_PROTOCOL_COUNT + 1] = {
SA_NO_PROTOCOL
};
const char *
zfs_share_protocol_name(enum sa_protocol protocol)
{
return (sa_protocol_names[protocol]);
}
static boolean_t
dir_is_empty_stat(const char *dirname)
+203
View File
@@ -0,0 +1,203 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Gunnar Beutner
* Copyright (c) 2018, 2022 by Delphix. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <libintl.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libzfs.h>
#include "libzfs_impl.h"
#define init_share(zfsname, path, shareopts) \
{ \
.sa_zfsname = zfsname, \
.sa_mountpoint = path, \
.sa_shareopts = shareopts, \
}
#define VALIDATE_PROTOCOL(proto, ...) \
if ((proto) < 0 || (proto) >= SA_PROTOCOL_COUNT) \
return __VA_ARGS__
const char *const sa_protocol_names[SA_PROTOCOL_COUNT] = {
[SA_PROTOCOL_NFS] = "nfs",
[SA_PROTOCOL_SMB] = "smb",
};
static const sa_fstype_t *fstypes[SA_PROTOCOL_COUNT] =
{&libshare_nfs_type, &libshare_smb_type};
int
sa_enable_share(const char *zfsname, const char *mountpoint,
const char *shareopts, enum sa_protocol protocol)
{
VALIDATE_PROTOCOL(protocol, SA_INVALID_PROTOCOL);
const struct sa_share_impl args =
init_share(zfsname, mountpoint, shareopts);
return (fstypes[protocol]->enable_share(&args));
}
int
sa_disable_share(const char *mountpoint, enum sa_protocol protocol)
{
VALIDATE_PROTOCOL(protocol, SA_INVALID_PROTOCOL);
const struct sa_share_impl args = init_share(NULL, mountpoint, NULL);
return (fstypes[protocol]->disable_share(&args));
}
boolean_t
sa_is_shared(const char *mountpoint, enum sa_protocol protocol)
{
VALIDATE_PROTOCOL(protocol, B_FALSE);
const struct sa_share_impl args = init_share(NULL, mountpoint, NULL);
return (fstypes[protocol]->is_shared(&args));
}
void
sa_commit_shares(enum sa_protocol protocol)
{
/* CSTYLED */
VALIDATE_PROTOCOL(protocol, );
fstypes[protocol]->commit_shares();
}
void
sa_truncate_shares(enum sa_protocol protocol)
{
/* CSTYLED */
VALIDATE_PROTOCOL(protocol, );
if (fstypes[protocol]->truncate_shares != NULL)
fstypes[protocol]->truncate_shares();
}
int
sa_validate_shareopts(const char *options, enum sa_protocol protocol)
{
VALIDATE_PROTOCOL(protocol, SA_INVALID_PROTOCOL);
return (fstypes[protocol]->validate_shareopts(options));
}
/*
* sa_errorstr(err)
*
* convert an error value to an error string
*/
const char *
sa_errorstr(int err)
{
static char errstr[32];
switch (err) {
case SA_OK:
return (dgettext(TEXT_DOMAIN, "ok"));
case SA_NO_SUCH_PATH:
return (dgettext(TEXT_DOMAIN, "path doesn't exist"));
case SA_NO_MEMORY:
return (dgettext(TEXT_DOMAIN, "no memory"));
case SA_DUPLICATE_NAME:
return (dgettext(TEXT_DOMAIN, "name in use"));
case SA_BAD_PATH:
return (dgettext(TEXT_DOMAIN, "bad path"));
case SA_NO_SUCH_GROUP:
return (dgettext(TEXT_DOMAIN, "no such group"));
case SA_CONFIG_ERR:
return (dgettext(TEXT_DOMAIN, "configuration error"));
case SA_SYSTEM_ERR:
return (dgettext(TEXT_DOMAIN, "system error"));
case SA_SYNTAX_ERR:
return (dgettext(TEXT_DOMAIN, "syntax error"));
case SA_NO_PERMISSION:
return (dgettext(TEXT_DOMAIN, "no permission"));
case SA_BUSY:
return (dgettext(TEXT_DOMAIN, "busy"));
case SA_NO_SUCH_PROP:
return (dgettext(TEXT_DOMAIN, "no such property"));
case SA_INVALID_NAME:
return (dgettext(TEXT_DOMAIN, "invalid name"));
case SA_INVALID_PROTOCOL:
return (dgettext(TEXT_DOMAIN, "invalid protocol"));
case SA_NOT_ALLOWED:
return (dgettext(TEXT_DOMAIN, "operation not allowed"));
case SA_BAD_VALUE:
return (dgettext(TEXT_DOMAIN, "bad property value"));
case SA_INVALID_SECURITY:
return (dgettext(TEXT_DOMAIN, "invalid security type"));
case SA_NO_SUCH_SECURITY:
return (dgettext(TEXT_DOMAIN, "security type not found"));
case SA_VALUE_CONFLICT:
return (dgettext(TEXT_DOMAIN, "property value conflict"));
case SA_NOT_IMPLEMENTED:
return (dgettext(TEXT_DOMAIN, "not implemented"));
case SA_INVALID_PATH:
return (dgettext(TEXT_DOMAIN, "invalid path"));
case SA_NOT_SUPPORTED:
return (dgettext(TEXT_DOMAIN, "operation not supported"));
case SA_PROP_SHARE_ONLY:
return (dgettext(TEXT_DOMAIN, "property not valid for group"));
case SA_NOT_SHARED:
return (dgettext(TEXT_DOMAIN, "not shared"));
case SA_NO_SUCH_RESOURCE:
return (dgettext(TEXT_DOMAIN, "no such resource"));
case SA_RESOURCE_REQUIRED:
return (dgettext(TEXT_DOMAIN, "resource name required"));
case SA_MULTIPLE_ERROR:
return (dgettext(TEXT_DOMAIN,
"errors from multiple protocols"));
case SA_PATH_IS_SUBDIR:
return (dgettext(TEXT_DOMAIN, "path is a subpath of share"));
case SA_PATH_IS_PARENTDIR:
return (dgettext(TEXT_DOMAIN, "path is parent of a share"));
case SA_NO_SECTION:
return (dgettext(TEXT_DOMAIN, "protocol requires a section"));
case SA_NO_PROPERTIES:
return (dgettext(TEXT_DOMAIN, "properties not found"));
case SA_NO_SUCH_SECTION:
return (dgettext(TEXT_DOMAIN, "section not found"));
case SA_PASSWORD_ENC:
return (dgettext(TEXT_DOMAIN, "passwords must be encrypted"));
case SA_SHARE_EXISTS:
return (dgettext(TEXT_DOMAIN,
"path or file is already shared"));
default:
(void) snprintf(errstr, sizeof (errstr),
dgettext(TEXT_DOMAIN, "unknown %d"), err);
return (errstr);
}
}
+141
View File
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Gunnar Beutner
* Copyright (c) 2019, 2022 by Delphix. All rights reserved.
*/
#ifndef _LIBZFS_SHARE_H
#define _LIBZFS_SHARE_H
#include <sys/types.h>
/*
* defined error values
*/
#define SA_OK 0
#define SA_SYSTEM_ERR 7 /* system error, use errno */
#define SA_SYNTAX_ERR 8 /* syntax error on command line */
#define SA_NO_MEMORY 2 /* no memory for data structures */
#define SA_INVALID_PROTOCOL 13 /* specified protocol not valid */
#define SA_NOT_SUPPORTED 21 /* operation not supported for proto */
/* The following errors are never returned by libshare */
#define SA_NO_SUCH_PATH 1 /* provided path doesn't exist */
#define SA_DUPLICATE_NAME 3 /* object name is already in use */
#define SA_BAD_PATH 4 /* not a full path */
#define SA_NO_SUCH_GROUP 5 /* group is not defined */
#define SA_CONFIG_ERR 6 /* system configuration error */
#define SA_NO_PERMISSION 9 /* no permission for operation */
#define SA_BUSY 10 /* resource is busy */
#define SA_NO_SUCH_PROP 11 /* property doesn't exist */
#define SA_INVALID_NAME 12 /* name of object is invalid */
#define SA_NOT_ALLOWED 14 /* operation not allowed */
#define SA_BAD_VALUE 15 /* bad value for property */
#define SA_INVALID_SECURITY 16 /* invalid security type */
#define SA_NO_SUCH_SECURITY 17 /* security set not found */
#define SA_VALUE_CONFLICT 18 /* property value conflict */
#define SA_NOT_IMPLEMENTED 19 /* plugin interface not implemented */
#define SA_INVALID_PATH 20 /* path is sub-dir of existing share */
#define SA_PROP_SHARE_ONLY 22 /* property valid on share only */
#define SA_NOT_SHARED 23 /* path is not shared */
#define SA_NO_SUCH_RESOURCE 24 /* resource not found */
#define SA_RESOURCE_REQUIRED 25 /* resource name is required */
#define SA_MULTIPLE_ERROR 26 /* multiple protocols reported error */
#define SA_PATH_IS_SUBDIR 27 /* check_path found path is subdir */
#define SA_PATH_IS_PARENTDIR 28 /* check_path found path is parent */
#define SA_NO_SECTION 29 /* protocol requires section info */
#define SA_NO_SUCH_SECTION 30 /* no section found */
#define SA_NO_PROPERTIES 31 /* no properties found */
#define SA_PASSWORD_ENC 32 /* passwords must be encrypted */
#define SA_SHARE_EXISTS 33 /* path or file is already shared */
/* initialization */
extern const char *sa_errorstr(int);
/* lower-case */
extern const char *const sa_protocol_names[SA_PROTOCOL_COUNT];
/* share control */
extern int sa_enable_share(const char *, const char *, const char *,
enum sa_protocol);
extern int sa_disable_share(const char *, enum sa_protocol);
extern boolean_t sa_is_shared(const char *, enum sa_protocol);
extern void sa_commit_shares(enum sa_protocol);
extern void sa_truncate_shares(enum sa_protocol);
/* protocol specific interfaces */
extern int sa_validate_shareopts(const char *, enum sa_protocol);
/* internal definitions */
typedef const struct sa_share_impl {
const char *sa_zfsname;
const char *sa_mountpoint;
const char *sa_shareopts;
} *sa_share_impl_t;
typedef struct {
int (*const enable_share)(sa_share_impl_t share);
int (*const disable_share)(sa_share_impl_t share);
boolean_t (*const is_shared)(sa_share_impl_t share);
int (*const validate_shareopts)(const char *shareopts);
int (*const commit_shares)(void);
void (*const truncate_shares)(void);
} sa_fstype_t;
extern const sa_fstype_t libshare_nfs_type, libshare_smb_type;
/* internal NFS definitions */
#define NFS_FILE_HEADER "# !!! DO NOT EDIT THIS FILE MANUALLY !!!\n\n"
extern int nfs_escape_mountpoint(const char *mp, char **out,
boolean_t *need_free);
extern boolean_t nfs_is_shared_impl(const char *exports,
sa_share_impl_t impl_share);
extern int nfs_toggle_share(const char *lockfile, const char *exports,
const char *expdir, sa_share_impl_t impl_share,
int(*cbk)(sa_share_impl_t impl_share, FILE *tmpfile));
extern void nfs_reset_shares(const char *lockfile, const char *exports);
/* internal SMB definitions */
#define SMB_NAME_MAX 255
#define SMB_COMMENT_MAX 255
#define SMB_SHARE_DIR "/var/lib/samba/usershares"
#define SMB_NET_CMD_PATH "/usr/bin/net"
#define SMB_NET_CMD_ARG_HOST "127.0.0.1"
typedef struct smb_share_s {
char name[SMB_NAME_MAX]; /* Share name */
char path[PATH_MAX]; /* Share path */
char comment[SMB_COMMENT_MAX]; /* Share's comment */
boolean_t guest_ok; /* 'y' or 'n' */
struct smb_share_s *next;
} smb_share_t;
#endif /* _LIBZFS_SHARE_H */
+317
View File
@@ -0,0 +1,317 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <libzutil.h>
#include "libzfs_impl.h"
/*
* nfs_exports_[lock|unlock] are used to guard against conconcurrent
* updates to the exports file. Each protocol is responsible for
* providing the necessary locking to ensure consistency.
*/
static int
nfs_exports_lock(const char *name, int *nfs_lock_fd)
{
int err;
*nfs_lock_fd = open(name, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
if (*nfs_lock_fd == -1) {
err = errno;
fprintf(stderr, "failed to lock %s: %s\n", name,
zfs_strerror(err));
return (err);
}
while ((err = flock(*nfs_lock_fd, LOCK_EX)) != 0 && errno == EINTR)
;
if (err != 0) {
err = errno;
fprintf(stderr, "failed to lock %s: %s\n", name,
zfs_strerror(err));
(void) close(*nfs_lock_fd);
*nfs_lock_fd = -1;
return (err);
}
return (0);
}
static void
nfs_exports_unlock(const char *name, int *nfs_lock_fd)
{
verify(*nfs_lock_fd > 0);
if (flock(*nfs_lock_fd, LOCK_UN) != 0)
fprintf(stderr, "failed to unlock %s: %s\n",
name, zfs_strerror(errno));
(void) close(*nfs_lock_fd);
*nfs_lock_fd = -1;
}
struct tmpfile {
/*
* This only needs to be as wide as ZFS_EXPORTS_FILE and mktemp suffix,
* 64 is more than enough.
*/
char name[64];
FILE *fp;
};
static boolean_t
nfs_init_tmpfile(const char *prefix, const char *mdir, struct tmpfile *tmpf)
{
if (mdir != NULL &&
mkdir(mdir, 0755) < 0 &&
errno != EEXIST) {
fprintf(stderr, "failed to create %s: %s\n",
// cppcheck-suppress uninitvar
mdir, zfs_strerror(errno));
return (B_FALSE);
}
strlcpy(tmpf->name, prefix, sizeof (tmpf->name));
strlcat(tmpf->name, ".XXXXXXXX", sizeof (tmpf->name));
int fd = mkostemp(tmpf->name, O_CLOEXEC);
if (fd == -1) {
fprintf(stderr, "Unable to create temporary file: %s",
zfs_strerror(errno));
return (B_FALSE);
}
tmpf->fp = fdopen(fd, "w+");
if (tmpf->fp == NULL) {
fprintf(stderr, "Unable to reopen temporary file: %s",
zfs_strerror(errno));
close(fd);
return (B_FALSE);
}
return (B_TRUE);
}
static void
nfs_abort_tmpfile(struct tmpfile *tmpf)
{
unlink(tmpf->name);
fclose(tmpf->fp);
}
static int
nfs_fini_tmpfile(const char *exports, struct tmpfile *tmpf)
{
if (fflush(tmpf->fp) != 0) {
fprintf(stderr, "Failed to write to temporary file: %s\n",
zfs_strerror(errno));
nfs_abort_tmpfile(tmpf);
return (SA_SYSTEM_ERR);
}
if (rename(tmpf->name, exports) == -1) {
fprintf(stderr, "Unable to rename %s -> %s: %s\n",
tmpf->name, exports, zfs_strerror(errno));
nfs_abort_tmpfile(tmpf);
return (SA_SYSTEM_ERR);
}
(void) fchmod(fileno(tmpf->fp), 0644);
fclose(tmpf->fp);
return (SA_OK);
}
int
nfs_escape_mountpoint(const char *mp, char **out, boolean_t *need_free)
{
if (strpbrk(mp, "\t\n\v\f\r \\") == NULL) {
*out = (char *)mp;
*need_free = B_FALSE;
return (SA_OK);
} else {
size_t len = strlen(mp);
*out = malloc(len * 4 + 1);
if (!*out)
return (SA_NO_MEMORY);
*need_free = B_TRUE;
char *oc = *out;
for (const char *c = mp; c < mp + len; ++c)
if (memchr("\t\n\v\f\r \\", *c,
strlen("\t\n\v\f\r \\"))) {
sprintf(oc, "\\%03hho", *c);
oc += 4;
} else
*oc++ = *c;
*oc = '\0';
}
return (SA_OK);
}
static int
nfs_process_exports(const char *exports, const char *mountpoint,
boolean_t (*cbk)(void *userdata, char *line, boolean_t found_mountpoint),
void *userdata)
{
int error = SA_OK;
boolean_t cont = B_TRUE;
FILE *oldfp = fopen(exports, "re");
if (oldfp != NULL) {
boolean_t need_mp_free;
char *mp;
if ((error = nfs_escape_mountpoint(mountpoint,
&mp, &need_mp_free)) != SA_OK) {
(void) fclose(oldfp);
return (error);
}
char *buf = NULL, *sep;
size_t buflen = 0, mplen = strlen(mp);
while (cont && getline(&buf, &buflen, oldfp) != -1) {
if (buf[0] == '\n' || buf[0] == '#')
continue;
cont = cbk(userdata, buf,
(sep = strpbrk(buf, "\t \n")) != NULL &&
sep - buf == mplen &&
strncmp(buf, mp, mplen) == 0);
}
free(buf);
if (need_mp_free)
free(mp);
if (ferror(oldfp) != 0)
error = ferror(oldfp);
if (fclose(oldfp) != 0) {
fprintf(stderr, "Unable to close file %s: %s\n",
exports, zfs_strerror(errno));
error = error != SA_OK ? error : SA_SYSTEM_ERR;
}
}
return (error);
}
static boolean_t
nfs_copy_entries_cb(void *userdata, char *line, boolean_t found_mountpoint)
{
FILE *newfp = userdata;
if (!found_mountpoint)
fputs(line, newfp);
return (B_TRUE);
}
/*
* Copy all entries from the exports file (if it exists) to newfp,
* omitting any entries for the specified mountpoint.
*/
static int
nfs_copy_entries(FILE *newfp, const char *exports, const char *mountpoint)
{
fputs(NFS_FILE_HEADER, newfp);
int error = nfs_process_exports(
exports, mountpoint, nfs_copy_entries_cb, newfp);
if (error == SA_OK && ferror(newfp) != 0)
error = ferror(newfp);
return (error);
}
int
nfs_toggle_share(const char *lockfile, const char *exports,
const char *expdir, sa_share_impl_t impl_share,
int(*cbk)(sa_share_impl_t impl_share, FILE *tmpfile))
{
int error, nfs_lock_fd = -1;
struct tmpfile tmpf;
if (!nfs_init_tmpfile(exports, expdir, &tmpf))
return (SA_SYSTEM_ERR);
error = nfs_exports_lock(lockfile, &nfs_lock_fd);
if (error != 0) {
nfs_abort_tmpfile(&tmpf);
return (error);
}
error = nfs_copy_entries(tmpf.fp, exports, impl_share->sa_mountpoint);
if (error != SA_OK)
goto fullerr;
error = cbk(impl_share, tmpf.fp);
if (error != SA_OK)
goto fullerr;
error = nfs_fini_tmpfile(exports, &tmpf);
nfs_exports_unlock(lockfile, &nfs_lock_fd);
return (error);
fullerr:
nfs_abort_tmpfile(&tmpf);
nfs_exports_unlock(lockfile, &nfs_lock_fd);
return (error);
}
void
nfs_reset_shares(const char *lockfile, const char *exports)
{
int nfs_lock_fd = -1;
if (nfs_exports_lock(lockfile, &nfs_lock_fd) == 0) {
(void) ! truncate(exports, 0);
nfs_exports_unlock(lockfile, &nfs_lock_fd);
}
}
static boolean_t
nfs_is_shared_cb(void *userdata, char *line, boolean_t found_mountpoint)
{
(void) line;
boolean_t *found = userdata;
*found = found_mountpoint;
return (!found_mountpoint);
}
boolean_t
nfs_is_shared_impl(const char *exports, sa_share_impl_t impl_share)
{
boolean_t found = B_FALSE;
nfs_process_exports(exports, impl_share->sa_mountpoint,
nfs_is_shared_cb, &found);
return (found);
}
+243
View File
@@ -0,0 +1,243 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Copyright (c) 2020, 2022 by Delphix. All rights reserved.
*/
#include <sys/param.h>
#include <sys/vfs.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <libutil.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libintl.h>
#include <libzfs.h>
#include "../../libzfs_share.h"
#define _PATH_MOUNTDPID "/var/run/mountd.pid"
#define ZFS_EXPORTS_FILE "/etc/zfs/exports"
#define ZFS_EXPORTS_LOCK ZFS_EXPORTS_FILE".lock"
/*
* This function translates options to a format acceptable by exports(5), eg.
*
* -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 \
* zfs.freebsd.org 69.147.83.54
*
* Accepted input formats:
*
* ro,network=192.168.0.0,mask=255.255.255.0,maproot=0,zfs.freebsd.org
* ro network=192.168.0.0 mask=255.255.255.0 maproot=0 zfs.freebsd.org
* -ro,-network=192.168.0.0,-mask=255.255.255.0,-maproot=0,zfs.freebsd.org
* -ro -network=192.168.0.0 -mask=255.255.255.0 -maproot=0 \
* zfs.freebsd.org
*
* Recognized keywords:
*
* ro, maproot, mapall, mask, network, sec, alldirs, public, webnfs,
* index, quiet
*/
static int
translate_opts(char *oldopts, FILE *out)
{
static const char *const known_opts[] = { "ro", "maproot", "mapall",
"mask", "network", "sec", "alldirs", "public", "webnfs", "index",
"quiet" };
char *newopts, *o, *s = NULL;
unsigned int i;
size_t len, newopts_len;
int ret;
/*
* Calculate the length needed for the worst case of a single
* character option:
* - Add one to strlen(oldopts) so that the trailing nul is counted
* as a separator.
* - Multiply by 3/2 since the single character option plus separator
* is expanded to 3 characters.
* - Add one for the trailing nul. Needed for a single repetition of
* the single character option and certain other cases.
*/
newopts_len = (strlen(oldopts) + 1) * 3 / 2 + 1;
newopts = malloc(newopts_len);
if (newopts == NULL)
return (EOF);
newopts[0] = '\0';
s = oldopts;
while ((o = strsep(&s, ", ")) != NULL) {
if (o[0] == '-')
o++;
if (o[0] == '\0')
continue;
for (i = 0; i < ARRAY_SIZE(known_opts); ++i) {
len = strlen(known_opts[i]);
if (strncmp(known_opts[i], o, len) == 0 &&
(o[len] == '\0' || o[len] == '=')) {
strlcat(newopts, "-", newopts_len);
break;
}
}
strlcat(newopts, o, newopts_len);
strlcat(newopts, " ", newopts_len);
}
ret = fputs(newopts, out);
free(newopts);
return (ret);
}
static int
nfs_enable_share_impl(sa_share_impl_t impl_share, FILE *tmpfile)
{
const char *shareopts = impl_share->sa_shareopts;
if (strcmp(shareopts, "on") == 0)
shareopts = "";
boolean_t need_free, fnd_semi;
char *mp, *lineopts, *exportopts, *s;
size_t whitelen;
int rc = nfs_escape_mountpoint(impl_share->sa_mountpoint, &mp,
&need_free);
if (rc != SA_OK)
return (rc);
lineopts = strdup(shareopts);
if (lineopts == NULL)
return (SA_SYSTEM_ERR);
s = lineopts;
fnd_semi = B_FALSE;
while ((exportopts = strsep(&s, ";")) != NULL) {
if (s != NULL)
fnd_semi = B_TRUE;
/* Ignore only whitespace between ';' separated option sets. */
if (fnd_semi) {
whitelen = strspn(exportopts, "\t ");
if (exportopts[whitelen] == '\0')
continue;
}
if (fputs(mp, tmpfile) == EOF ||
fputc('\t', tmpfile) == EOF ||
translate_opts(exportopts, tmpfile) == EOF ||
fputc('\n', tmpfile) == EOF) {
fprintf(stderr, "failed to write to temporary file\n");
rc = SA_SYSTEM_ERR;
break;
}
}
free(lineopts);
if (need_free)
free(mp);
return (rc);
}
static int
nfs_enable_share(sa_share_impl_t impl_share)
{
return (nfs_toggle_share(
ZFS_EXPORTS_LOCK, ZFS_EXPORTS_FILE, NULL, impl_share,
nfs_enable_share_impl));
}
static int
nfs_disable_share_impl(sa_share_impl_t impl_share, FILE *tmpfile)
{
(void) impl_share, (void) tmpfile;
return (SA_OK);
}
static int
nfs_disable_share(sa_share_impl_t impl_share)
{
return (nfs_toggle_share(
ZFS_EXPORTS_LOCK, ZFS_EXPORTS_FILE, NULL, impl_share,
nfs_disable_share_impl));
}
static boolean_t
nfs_is_shared(sa_share_impl_t impl_share)
{
return (nfs_is_shared_impl(ZFS_EXPORTS_FILE, impl_share));
}
static int
nfs_validate_shareopts(const char *shareopts)
{
if (strlen(shareopts) == 0)
return (SA_SYNTAX_ERR);
return (SA_OK);
}
/*
* Commit the shares by restarting mountd.
*/
static int
nfs_commit_shares(void)
{
struct pidfh *pfh;
pid_t mountdpid;
start:
pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &mountdpid);
if (pfh != NULL) {
/* mountd(8) is not running. */
pidfile_remove(pfh);
return (SA_OK);
}
if (errno != EEXIST) {
/* Cannot open pidfile for some reason. */
return (SA_SYSTEM_ERR);
}
if (mountdpid == -1) {
/* mountd(8) exists, but didn't write the PID yet */
usleep(500);
goto start;
}
/* We have mountd(8) PID in mountdpid variable. */
kill(mountdpid, SIGHUP);
return (SA_OK);
}
static void
nfs_truncate_shares(void)
{
nfs_reset_shares(ZFS_EXPORTS_LOCK, ZFS_EXPORTS_FILE);
}
const sa_fstype_t libshare_nfs_type = {
.enable_share = nfs_enable_share,
.disable_share = nfs_disable_share,
.is_shared = nfs_is_shared,
.validate_shareopts = nfs_validate_shareopts,
.commit_shares = nfs_commit_shares,
.truncate_shares = nfs_truncate_shares,
};
+87
View File
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2020 by Delphix. All rights reserved.
*/
#include <stdio.h>
#include <libzfs.h>
#include "../../libzfs_share.h"
/*
* Enables SMB sharing for the specified share.
*/
static int
smb_enable_share(sa_share_impl_t impl_share)
{
(void) impl_share;
fputs("No SMB support in FreeBSD yet.\n", stderr);
return (SA_NOT_SUPPORTED);
}
/*
* Disables SMB sharing for the specified share.
*/
static int
smb_disable_share(sa_share_impl_t impl_share)
{
(void) impl_share;
fputs("No SMB support in FreeBSD yet.\n", stderr);
return (SA_NOT_SUPPORTED);
}
/*
* Checks whether the specified SMB share options are syntactically correct.
*/
static int
smb_validate_shareopts(const char *shareopts)
{
(void) shareopts;
fputs("No SMB support in FreeBSD yet.\n", stderr);
return (SA_NOT_SUPPORTED);
}
/*
* Checks whether a share is currently active.
*/
static boolean_t
smb_is_share_active(sa_share_impl_t impl_share)
{
(void) impl_share;
return (B_FALSE);
}
static int
smb_update_shares(void)
{
/* Not implemented */
return (0);
}
const sa_fstype_t libshare_smb_type = {
.enable_share = smb_enable_share,
.disable_share = smb_disable_share,
.is_shared = smb_is_share_active,
.validate_shareopts = smb_validate_shareopts,
.commit_shares = smb_update_shares,
};
+585
View File
@@ -0,0 +1,585 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Gunnar Beutner
* Copyright (c) 2012 Cyril Plisko. All rights reserved.
* Copyright (c) 2019, 2022 by Delphix. All rights reserved.
*/
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <libzfs.h>
#include "../../libzfs_impl.h"
#define ZFS_EXPORTS_DIR "/etc/exports.d"
#define ZFS_EXPORTS_FILE ZFS_EXPORTS_DIR"/zfs.exports"
#define ZFS_EXPORTS_LOCK ZFS_EXPORTS_FILE".lock"
static boolean_t nfs_available(void);
static boolean_t exports_available(void);
typedef int (*nfs_shareopt_callback_t)(const char *opt, const char *value,
void *cookie);
typedef int (*nfs_host_callback_t)(FILE *tmpfile, const char *sharepath,
const char *host, const char *security, const char *access, void *cookie);
/*
* Invokes the specified callback function for each Solaris share option
* listed in the specified string.
*/
static int
foreach_nfs_shareopt(const char *shareopts,
nfs_shareopt_callback_t callback, void *cookie)
{
char *shareopts_dup, *opt, *cur, *value;
int was_nul, error;
if (shareopts == NULL)
return (SA_OK);
if (strcmp(shareopts, "on") == 0)
shareopts = "rw,crossmnt";
shareopts_dup = strdup(shareopts);
if (shareopts_dup == NULL)
return (SA_NO_MEMORY);
opt = shareopts_dup;
was_nul = 0;
while (1) {
cur = opt;
while (*cur != ',' && *cur != '\0')
cur++;
if (*cur == '\0')
was_nul = 1;
*cur = '\0';
if (cur > opt) {
value = strchr(opt, '=');
if (value != NULL) {
*value = '\0';
value++;
}
error = callback(opt, value, cookie);
if (error != SA_OK) {
free(shareopts_dup);
return (error);
}
}
opt = cur + 1;
if (was_nul)
break;
}
free(shareopts_dup);
return (SA_OK);
}
typedef struct nfs_host_cookie_s {
nfs_host_callback_t callback;
const char *sharepath;
void *cookie;
FILE *tmpfile;
const char *security;
} nfs_host_cookie_t;
/*
* Helper function for foreach_nfs_host. This function checks whether the
* current share option is a host specification and invokes a callback
* function with information about the host.
*/
static int
foreach_nfs_host_cb(const char *opt, const char *value, void *pcookie)
{
int error;
const char *access;
char *host_dup, *host, *next, *v6Literal;
nfs_host_cookie_t *udata = (nfs_host_cookie_t *)pcookie;
int cidr_len;
#ifdef DEBUG
fprintf(stderr, "foreach_nfs_host_cb: key=%s, value=%s\n", opt, value);
#endif
if (strcmp(opt, "sec") == 0)
udata->security = value;
if (strcmp(opt, "rw") == 0 || strcmp(opt, "ro") == 0) {
if (value == NULL)
value = "*";
access = opt;
host_dup = strdup(value);
if (host_dup == NULL)
return (SA_NO_MEMORY);
host = host_dup;
do {
if (*host == '[') {
host++;
v6Literal = strchr(host, ']');
if (v6Literal == NULL) {
free(host_dup);
return (SA_SYNTAX_ERR);
}
if (v6Literal[1] == '\0') {
*v6Literal = '\0';
next = NULL;
} else if (v6Literal[1] == '/') {
next = strchr(v6Literal + 2, ':');
if (next == NULL) {
cidr_len =
strlen(v6Literal + 1);
memmove(v6Literal,
v6Literal + 1,
cidr_len);
v6Literal[cidr_len] = '\0';
} else {
cidr_len = next - v6Literal - 1;
memmove(v6Literal,
v6Literal + 1,
cidr_len);
v6Literal[cidr_len] = '\0';
next++;
}
} else if (v6Literal[1] == ':') {
*v6Literal = '\0';
next = v6Literal + 2;
} else {
free(host_dup);
return (SA_SYNTAX_ERR);
}
} else {
next = strchr(host, ':');
if (next != NULL) {
*next = '\0';
next++;
}
}
error = udata->callback(udata->tmpfile,
udata->sharepath, host, udata->security,
access, udata->cookie);
if (error != SA_OK) {
free(host_dup);
return (error);
}
host = next;
} while (host != NULL);
free(host_dup);
}
return (SA_OK);
}
/*
* Invokes a callback function for all NFS hosts that are set for a share.
*/
static int
foreach_nfs_host(sa_share_impl_t impl_share, FILE *tmpfile,
nfs_host_callback_t callback, void *cookie)
{
nfs_host_cookie_t udata;
udata.callback = callback;
udata.sharepath = impl_share->sa_mountpoint;
udata.cookie = cookie;
udata.tmpfile = tmpfile;
udata.security = "sys";
return (foreach_nfs_shareopt(impl_share->sa_shareopts,
foreach_nfs_host_cb, &udata));
}
/*
* Converts a Solaris NFS host specification to its Linux equivalent.
*/
static const char *
get_linux_hostspec(const char *solaris_hostspec)
{
/*
* For now we just support CIDR masks (e.g. @192.168.0.0/16) and host
* wildcards (e.g. *.example.org).
*/
if (solaris_hostspec[0] == '@') {
/*
* Solaris host specifier, e.g. @192.168.0.0/16; we just need
* to skip the @ in this case
*/
return (solaris_hostspec + 1);
} else {
return (solaris_hostspec);
}
}
/*
* Adds a Linux share option to an array of NFS options.
*/
static int
add_linux_shareopt(char **plinux_opts, const char *key, const char *value)
{
size_t len = 0;
char *new_linux_opts;
if (*plinux_opts != NULL)
len = strlen(*plinux_opts);
new_linux_opts = realloc(*plinux_opts, len + 1 + strlen(key) +
(value ? 1 + strlen(value) : 0) + 1);
if (new_linux_opts == NULL)
return (SA_NO_MEMORY);
new_linux_opts[len] = '\0';
if (len > 0)
strcat(new_linux_opts, ",");
strcat(new_linux_opts, key);
if (value != NULL) {
strcat(new_linux_opts, "=");
strcat(new_linux_opts, value);
}
*plinux_opts = new_linux_opts;
return (SA_OK);
}
static int string_cmp(const void *lhs, const void *rhs) {
const char *const *l = lhs, *const *r = rhs;
return (strcmp(*l, *r));
}
/*
* Validates and converts a single Solaris share option to its Linux
* equivalent.
*/
static int
get_linux_shareopts_cb(const char *key, const char *value, void *cookie)
{
/* This list must remain sorted, since we bsearch() it */
static const char *const valid_keys[] = { "all_squash", "anongid",
"anonuid", "async", "auth_nlm", "crossmnt", "fsid", "fsuid", "hide",
"insecure", "insecure_locks", "mountpoint", "mp", "no_acl",
"no_all_squash", "no_auth_nlm", "no_root_squash",
"no_subtree_check", "no_wdelay", "nohide", "refer", "replicas",
"root_squash", "secure", "secure_locks", "subtree_check", "sync",
"wdelay" };
char **plinux_opts = (char **)cookie;
char *host, *val_dup, *literal, *next;
if (strcmp(key, "sec") == 0)
return (SA_OK);
if (strcmp(key, "ro") == 0 || strcmp(key, "rw") == 0) {
if (value == NULL || strlen(value) == 0)
return (SA_OK);
val_dup = strdup(value);
host = val_dup;
if (host == NULL)
return (SA_NO_MEMORY);
do {
if (*host == '[') {
host++;
literal = strchr(host, ']');
if (literal == NULL) {
free(val_dup);
return (SA_SYNTAX_ERR);
}
if (literal[1] == '\0')
next = NULL;
else if (literal[1] == '/') {
next = strchr(literal + 2, ':');
if (next != NULL)
++next;
} else if (literal[1] == ':')
next = literal + 2;
else {
free(val_dup);
return (SA_SYNTAX_ERR);
}
} else {
next = strchr(host, ':');
if (next != NULL)
++next;
}
host = next;
} while (host != NULL);
free(val_dup);
return (SA_OK);
}
if (strcmp(key, "anon") == 0)
key = "anonuid";
if (strcmp(key, "root_mapping") == 0) {
(void) add_linux_shareopt(plinux_opts, "root_squash", NULL);
key = "anonuid";
}
if (strcmp(key, "nosub") == 0)
key = "subtree_check";
if (bsearch(&key, valid_keys, ARRAY_SIZE(valid_keys),
sizeof (*valid_keys), string_cmp) == NULL)
return (SA_SYNTAX_ERR);
(void) add_linux_shareopt(plinux_opts, key, value);
return (SA_OK);
}
/*
* Takes a string containing Solaris share options (e.g. "sync,no_acl") and
* converts them to a NULL-terminated array of Linux NFS options.
*/
static int
get_linux_shareopts(const char *shareopts, char **plinux_opts)
{
int error;
assert(plinux_opts != NULL);
*plinux_opts = NULL;
/* no_subtree_check - Default as of nfs-utils v1.1.0 */
(void) add_linux_shareopt(plinux_opts, "no_subtree_check", NULL);
/* mountpoint - Restrict exports to ZFS mountpoints */
(void) add_linux_shareopt(plinux_opts, "mountpoint", NULL);
error = foreach_nfs_shareopt(shareopts, get_linux_shareopts_cb,
plinux_opts);
if (error != SA_OK) {
free(*plinux_opts);
*plinux_opts = NULL;
}
return (error);
}
/*
* This function populates an entry into /etc/exports.d/zfs.exports.
* This file is consumed by the linux nfs server so that zfs shares are
* automatically exported upon boot or whenever the nfs server restarts.
*/
static int
nfs_add_entry(FILE *tmpfile, const char *sharepath,
const char *host, const char *security, const char *access_opts,
void *pcookie)
{
const char *linux_opts = (const char *)pcookie;
if (linux_opts == NULL)
linux_opts = "";
boolean_t need_free;
char *mp;
int rc = nfs_escape_mountpoint(sharepath, &mp, &need_free);
if (rc != SA_OK)
return (rc);
if (fprintf(tmpfile, "%s %s(sec=%s,%s,%s)\n", mp,
get_linux_hostspec(host), security, access_opts,
linux_opts) < 0) {
fprintf(stderr, "failed to write to temporary file\n");
rc = SA_SYSTEM_ERR;
}
if (need_free)
free(mp);
return (rc);
}
/*
* Enables NFS sharing for the specified share.
*/
static int
nfs_enable_share_impl(sa_share_impl_t impl_share, FILE *tmpfile)
{
char *linux_opts = NULL;
int error = get_linux_shareopts(impl_share->sa_shareopts, &linux_opts);
if (error != SA_OK)
return (error);
error = foreach_nfs_host(impl_share, tmpfile, nfs_add_entry,
linux_opts);
free(linux_opts);
return (error);
}
static int
nfs_enable_share(sa_share_impl_t impl_share)
{
if (!nfs_available())
return (SA_SYSTEM_ERR);
return (nfs_toggle_share(
ZFS_EXPORTS_LOCK, ZFS_EXPORTS_FILE, ZFS_EXPORTS_DIR, impl_share,
nfs_enable_share_impl));
}
/*
* Disables NFS sharing for the specified share.
*/
static int
nfs_disable_share_impl(sa_share_impl_t impl_share, FILE *tmpfile)
{
(void) impl_share, (void) tmpfile;
return (SA_OK);
}
static int
nfs_disable_share(sa_share_impl_t impl_share)
{
if (!nfs_available())
return (SA_OK);
return (nfs_toggle_share(
ZFS_EXPORTS_LOCK, ZFS_EXPORTS_FILE, ZFS_EXPORTS_DIR, impl_share,
nfs_disable_share_impl));
}
static boolean_t
nfs_is_shared(sa_share_impl_t impl_share)
{
if (!nfs_available())
return (SA_SYSTEM_ERR);
return (nfs_is_shared_impl(ZFS_EXPORTS_FILE, impl_share));
}
/*
* Checks whether the specified NFS share options are syntactically correct.
*/
static int
nfs_validate_shareopts(const char *shareopts)
{
char *linux_opts = NULL;
if (strlen(shareopts) == 0)
return (SA_SYNTAX_ERR);
int error = get_linux_shareopts(shareopts, &linux_opts);
if (error != SA_OK)
return (error);
free(linux_opts);
return (SA_OK);
}
static int
nfs_commit_shares(void)
{
if (!nfs_available())
return (SA_SYSTEM_ERR);
char *argv[] = {
(char *)"/usr/sbin/exportfs",
(char *)"-ra",
NULL
};
return (libzfs_run_process(argv[0], argv, 0));
}
static void
nfs_truncate_shares(void)
{
if (!exports_available())
return;
nfs_reset_shares(ZFS_EXPORTS_LOCK, ZFS_EXPORTS_FILE);
}
const sa_fstype_t libshare_nfs_type = {
.enable_share = nfs_enable_share,
.disable_share = nfs_disable_share,
.is_shared = nfs_is_shared,
.validate_shareopts = nfs_validate_shareopts,
.commit_shares = nfs_commit_shares,
.truncate_shares = nfs_truncate_shares,
};
static boolean_t
nfs_available(void)
{
static int avail;
if (!avail) {
if (access("/usr/sbin/exportfs", F_OK) != 0)
avail = -1;
else
avail = 1;
}
return (avail == 1);
}
static boolean_t
exports_available(void)
{
static int avail;
if (!avail) {
if (access(ZFS_EXPORTS_DIR, F_OK) != 0)
avail = -1;
else
avail = 1;
}
return (avail == 1);
}
+405
View File
@@ -0,0 +1,405 @@
// SPDX-License-Identifier: CDDL-1.0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011,2012 Turbo Fredriksson <turbo@bayour.com>, based on nfs.c
* by Gunnar Beutner
* Copyright (c) 2019, 2020 by Delphix. All rights reserved.
*
* This is an addition to the zfs device driver to add, modify and remove SMB
* shares using the 'net share' command that comes with Samba.
*
* TESTING
* Make sure that samba listens to 'localhost' (127.0.0.1) and that the options
* 'usershare max shares' and 'usershare owner only' have been reviewed/set
* accordingly (see zfs(8) for information).
*
* Once configuration in samba have been done, test that this
* works with the following three commands (in this case, my ZFS
* filesystem is called 'share/Test1'):
*
* (root)# net -U root -S 127.0.0.1 usershare add Test1 /share/Test1 \
* "Comment: /share/Test1" "Everyone:F"
* (root)# net usershare list | grep -i test
* (root)# net -U root -S 127.0.0.1 usershare delete Test1
*
* The first command will create a user share that gives everyone full access.
* To limit the access below that, use normal UNIX commands (chmod, chown etc).
*/
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <libzfs.h>
#include "../../libzfs_share.h"
static boolean_t smb_available(void);
static smb_share_t *smb_shares;
static int smb_disable_share(sa_share_impl_t impl_share);
static boolean_t smb_is_share_active(sa_share_impl_t impl_share);
/*
* Retrieve the list of SMB shares.
*/
static int
smb_retrieve_shares(void)
{
int rc = SA_OK;
char file_path[PATH_MAX], line[512], *token, *key, *value;
char *dup_value = NULL, *path = NULL, *comment = NULL, *name = NULL;
char *guest_ok = NULL;
DIR *shares_dir;
FILE *share_file_fp = NULL;
struct dirent *directory;
struct stat eStat;
smb_share_t *shares, *new_shares = NULL;
/* opendir(), stat() */
shares_dir = opendir(SMB_SHARE_DIR);
if (shares_dir == NULL)
return (SA_SYSTEM_ERR);
/* Go through the directory, looking for shares */
while ((directory = readdir(shares_dir))) {
int fd;
if (directory->d_name[0] == '.')
continue;
snprintf(file_path, sizeof (file_path),
"%s/%s", SMB_SHARE_DIR, directory->d_name);
if ((fd = open(file_path, O_RDONLY | O_CLOEXEC)) == -1) {
rc = SA_SYSTEM_ERR;
goto out;
}
if (fstat(fd, &eStat) == -1) {
close(fd);
rc = SA_SYSTEM_ERR;
goto out;
}
if (!S_ISREG(eStat.st_mode)) {
close(fd);
continue;
}
if ((share_file_fp = fdopen(fd, "r")) == NULL) {
close(fd);
rc = SA_SYSTEM_ERR;
goto out;
}
name = strdup(directory->d_name);
if (name == NULL) {
rc = SA_NO_MEMORY;
goto out;
}
while (fgets(line, sizeof (line), share_file_fp)) {
if (line[0] == '#')
continue;
/* Trim trailing new-line character(s). */
while (line[strlen(line) - 1] == '\r' ||
line[strlen(line) - 1] == '\n')
line[strlen(line) - 1] = '\0';
/* Split the line in two, separated by '=' */
token = strchr(line, '=');
if (token == NULL)
continue;
key = line;
value = token + 1;
*token = '\0';
dup_value = strdup(value);
if (dup_value == NULL) {
rc = SA_NO_MEMORY;
goto out;
}
if (strcmp(key, "path") == 0) {
free(path);
path = dup_value;
} else if (strcmp(key, "comment") == 0) {
free(comment);
comment = dup_value;
} else if (strcmp(key, "guest_ok") == 0) {
free(guest_ok);
guest_ok = dup_value;
} else
free(dup_value);
dup_value = NULL;
if (path == NULL || comment == NULL || guest_ok == NULL)
continue; /* Incomplete share definition */
else {
shares = (smb_share_t *)
malloc(sizeof (smb_share_t));
if (shares == NULL) {
rc = SA_NO_MEMORY;
goto out;
}
(void) strlcpy(shares->name, name,
sizeof (shares->name));
(void) strlcpy(shares->path, path,
sizeof (shares->path));
(void) strlcpy(shares->comment, comment,
sizeof (shares->comment));
shares->guest_ok = atoi(guest_ok);
shares->next = new_shares;
new_shares = shares;
free(path);
free(comment);
free(guest_ok);
path = NULL;
comment = NULL;
guest_ok = NULL;
}
}
out:
if (share_file_fp != NULL) {
fclose(share_file_fp);
share_file_fp = NULL;
}
free(name);
free(path);
free(comment);
free(guest_ok);
name = NULL;
path = NULL;
comment = NULL;
guest_ok = NULL;
}
closedir(shares_dir);
smb_shares = new_shares;
return (rc);
}
/*
* Used internally by smb_enable_share to enable sharing for a single host.
*/
static int
smb_enable_share_one(const char *sharename, const char *sharepath)
{
char name[SMB_NAME_MAX], comment[SMB_COMMENT_MAX];
/* Support ZFS share name regexp '[[:alnum:]_-.: ]' */
strlcpy(name, sharename, sizeof (name));
for (char *itr = name; *itr != '\0'; ++itr)
switch (*itr) {
case '/':
case '-':
case ':':
case ' ':
*itr = '_';
}
/*
* CMD: net -S SMB_NET_CMD_ARG_HOST usershare add Test1 /share/Test1 \
* "Comment" "Everyone:F"
*/
snprintf(comment, sizeof (comment), "Comment: %s", sharepath);
char *argv[] = {
(char *)SMB_NET_CMD_PATH,
(char *)"-S",
(char *)SMB_NET_CMD_ARG_HOST,
(char *)"usershare",
(char *)"add",
name,
(char *)sharepath,
comment,
(char *)"Everyone:F",
NULL,
};
if (libzfs_run_process(argv[0], argv, 0) != 0)
return (SA_SYSTEM_ERR);
/* Reload the share file */
(void) smb_retrieve_shares();
return (SA_OK);
}
/*
* Enables SMB sharing for the specified share.
*/
static int
smb_enable_share(sa_share_impl_t impl_share)
{
if (!smb_available())
return (SA_SYSTEM_ERR);
if (smb_is_share_active(impl_share))
smb_disable_share(impl_share);
if (impl_share->sa_shareopts == NULL) /* on/off */
return (SA_SYSTEM_ERR);
if (strcmp(impl_share->sa_shareopts, "off") == 0)
return (SA_OK);
/* Magic: Enable (i.e., 'create new') share */
return (smb_enable_share_one(impl_share->sa_zfsname,
impl_share->sa_mountpoint));
}
/*
* Used internally by smb_disable_share to disable sharing for a single host.
*/
static int
smb_disable_share_one(const char *sharename)
{
/* CMD: net -S SMB_NET_CMD_ARG_HOST usershare delete Test1 */
char *argv[] = {
(char *)SMB_NET_CMD_PATH,
(char *)"-S",
(char *)SMB_NET_CMD_ARG_HOST,
(char *)"usershare",
(char *)"delete",
(char *)sharename,
NULL,
};
if (libzfs_run_process(argv[0], argv, 0) != 0)
return (SA_SYSTEM_ERR);
else
return (SA_OK);
}
/*
* Disables SMB sharing for the specified share.
*/
static int
smb_disable_share(sa_share_impl_t impl_share)
{
if (!smb_available()) {
/*
* The share can't possibly be active, so nothing
* needs to be done to disable it.
*/
return (SA_OK);
}
for (const smb_share_t *i = smb_shares; i != NULL; i = i->next)
if (strcmp(impl_share->sa_mountpoint, i->path) == 0)
return (smb_disable_share_one(i->name));
return (SA_OK);
}
/*
* Checks whether the specified SMB share options are syntactically correct.
*/
static int
smb_validate_shareopts(const char *shareopts)
{
/* TODO: Accept 'name' and sec/acl (?) */
if ((strcmp(shareopts, "off") == 0) || (strcmp(shareopts, "on") == 0))
return (SA_OK);
return (SA_SYNTAX_ERR);
}
/*
* Checks whether a share is currently active.
*/
static boolean_t
smb_is_share_active(sa_share_impl_t impl_share)
{
if (!smb_available())
return (B_FALSE);
/* Retrieve the list of (possible) active shares */
smb_retrieve_shares();
for (const smb_share_t *i = smb_shares; i != NULL; i = i->next)
if (strcmp(impl_share->sa_mountpoint, i->path) == 0)
return (B_TRUE);
return (B_FALSE);
}
static int
smb_update_shares(void)
{
/* Not implemented */
return (0);
}
const sa_fstype_t libshare_smb_type = {
.enable_share = smb_enable_share,
.disable_share = smb_disable_share,
.is_shared = smb_is_share_active,
.validate_shareopts = smb_validate_shareopts,
.commit_shares = smb_update_shares,
};
/*
* Provides a convenient wrapper for determining SMB availability
*/
static boolean_t
smb_available(void)
{
static int avail;
if (!avail) {
struct stat statbuf;
if (access(SMB_NET_CMD_PATH, F_OK) != 0 ||
lstat(SMB_SHARE_DIR, &statbuf) != 0 ||
!S_ISDIR(statbuf.st_mode))
avail = -1;
else
avail = 1;
}
return (avail == 1);
}