4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27 * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
28 * Copyright 2017 RackTop Systems.
37 #include "libshare_impl.h"
39 #include <sys/mnttab.h>
40 #include <sys/mntent.h>
43 extern sa_share_t
_sa_add_share(sa_group_t
, char *, int, int *, uint64_t);
44 extern sa_group_t
_sa_create_zfs_group(sa_group_t
, char *);
45 extern char *sa_fstype(char *);
46 extern void set_node_attr(void *, char *, char *);
47 extern int sa_is_share(void *);
48 extern void sa_update_sharetab_ts(sa_handle_t
);
51 * File system specific code for ZFS. The original code was stolen
52 * from the "zfs" command and modified to better suit this library's
56 typedef struct get_all_cbdata
{
57 zfs_handle_t
**cb_handles
;
64 * sa_zfs_init(impl_handle)
66 * Initialize an access handle into libzfs. The handle needs to stay
67 * around until sa_zfs_fini() in order to maintain the cache of
72 sa_zfs_init(sa_handle_impl_t impl_handle
)
74 impl_handle
->zfs_libhandle
= libzfs_init();
75 if (impl_handle
->zfs_libhandle
!= NULL
) {
76 libzfs_print_on_error(impl_handle
->zfs_libhandle
, B_TRUE
);
83 * sa_zfs_fini(impl_handle)
85 * cleanup data structures and the libzfs handle used for accessing
86 * zfs file share info.
90 sa_zfs_fini(sa_handle_impl_t impl_handle
)
92 if (impl_handle
->zfs_libhandle
!= NULL
) {
93 if (impl_handle
->zfs_list
!= NULL
) {
94 zfs_handle_t
**zhp
= impl_handle
->zfs_list
;
98 * Contents of zfs_list need to be freed so we
99 * don't lose ZFS handles.
101 for (i
= 0; i
< impl_handle
->zfs_list_count
; i
++) {
104 free(impl_handle
->zfs_list
);
105 impl_handle
->zfs_list
= NULL
;
106 impl_handle
->zfs_list_count
= 0;
109 libzfs_fini(impl_handle
->zfs_libhandle
);
110 impl_handle
->zfs_libhandle
= NULL
;
115 * get_one_filesystem(zfs_handle_t, data)
117 * an iterator function called while iterating through the ZFS
118 * root. It accumulates into an array of file system handles that can
119 * be used to derive info about those file systems.
121 * Note that as this function is called, we close all zhp handles that
122 * are not going to be places into the cp_handles list. We don't want
123 * to close the ones we are keeping, but all others would be leaked if
128 get_one_filesystem(zfs_handle_t
*zhp
, void *data
)
130 get_all_cbdata_t
*cbp
= data
;
131 zfs_type_t type
= zfs_get_type(zhp
);
134 * Interate over any nested datasets.
136 if (type
== ZFS_TYPE_FILESYSTEM
&&
137 zfs_iter_filesystems(zhp
, get_one_filesystem
, data
) != 0) {
143 * Skip any datasets whose type does not match.
145 if ((type
& cbp
->cb_types
) == 0) {
150 if (cbp
->cb_alloc
== cbp
->cb_used
) {
151 zfs_handle_t
**handles
;
153 if (cbp
->cb_alloc
== 0)
158 handles
= (zfs_handle_t
**)calloc(1,
159 cbp
->cb_alloc
* sizeof (void *));
161 if (handles
== NULL
) {
165 if (cbp
->cb_handles
) {
166 bcopy(cbp
->cb_handles
, handles
,
167 cbp
->cb_used
* sizeof (void *));
168 free(cbp
->cb_handles
);
171 cbp
->cb_handles
= handles
;
174 cbp
->cb_handles
[cbp
->cb_used
++] = zhp
;
180 * get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
182 * iterate through all ZFS file systems starting at the root. Returns
183 * a count and an array of handle pointers. Allocating is only done
184 * once. The caller does not need to free since it will be done at
185 * sa_zfs_fini() time.
189 get_all_filesystems(sa_handle_impl_t impl_handle
,
190 zfs_handle_t
***fslist
, size_t *count
)
192 get_all_cbdata_t cb
= { 0 };
193 cb
.cb_types
= ZFS_TYPE_FILESYSTEM
;
195 if (impl_handle
->zfs_list
!= NULL
) {
196 *fslist
= impl_handle
->zfs_list
;
197 *count
= impl_handle
->zfs_list_count
;
201 (void) zfs_iter_root(impl_handle
->zfs_libhandle
,
202 get_one_filesystem
, &cb
);
204 impl_handle
->zfs_list
= *fslist
= cb
.cb_handles
;
205 impl_handle
->zfs_list_count
= *count
= cb
.cb_used
;
209 * mountpoint_compare(a, b)
211 * compares the mountpoint on two zfs file systems handles.
212 * returns values following strcmp() model.
216 mountpoint_compare(const void *a
, const void *b
)
218 zfs_handle_t
**za
= (zfs_handle_t
**)a
;
219 zfs_handle_t
**zb
= (zfs_handle_t
**)b
;
220 char mounta
[MAXPATHLEN
];
221 char mountb
[MAXPATHLEN
];
223 verify(zfs_prop_get(*za
, ZFS_PROP_MOUNTPOINT
, mounta
,
224 sizeof (mounta
), NULL
, NULL
, 0, B_FALSE
) == 0);
225 verify(zfs_prop_get(*zb
, ZFS_PROP_MOUNTPOINT
, mountb
,
226 sizeof (mountb
), NULL
, NULL
, 0, B_FALSE
) == 0);
228 return (strcmp(mounta
, mountb
));
232 * return legacy mountpoint. Caller provides space for mountpoint and
236 get_legacy_mountpoint(const char *path
, char *dataset
, size_t dlen
,
237 char *mountpoint
, size_t mlen
)
242 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
246 while (getmntent(fp
, &entry
) == 0) {
248 if (entry
.mnt_fstype
== NULL
||
249 strcmp(entry
.mnt_fstype
, MNTTYPE_ZFS
) != 0)
252 if (strcmp(entry
.mnt_mountp
, path
) == 0) {
254 (void) strlcpy(mountpoint
, entry
.mnt_mountp
,
257 (void) strlcpy(dataset
, entry
.mnt_special
,
268 * Verifies that a specific zfs filesystem handle meets the criteria necessary
269 * to be used by libshare operations. See get_zfs_dataset.
272 verify_zfs_handle(zfs_handle_t
*hdl
, const char *path
, boolean_t search_mnttab
)
274 char mountpoint
[ZFS_MAXPROPLEN
];
275 char canmount
[ZFS_MAXPROPLEN
] = { 0 };
276 /* must have a mountpoint */
277 if (zfs_prop_get(hdl
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
278 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
283 /* mountpoint must be a path */
284 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_NONE
) == 0 ||
285 strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0) {
287 * Search mmttab for mountpoint and get dataset.
290 if (search_mnttab
== B_TRUE
&&
291 get_legacy_mountpoint(path
, mountpoint
,
292 sizeof (mountpoint
), NULL
, 0) == 0) {
293 return (strdup(mountpoint
));
298 /* canmount must be set */
299 if (zfs_prop_get(hdl
, ZFS_PROP_CANMOUNT
, canmount
,
300 sizeof (canmount
), NULL
, NULL
, 0, B_FALSE
) != 0 ||
301 strcmp(canmount
, "off") == 0)
305 * have a mountable handle but want to skip those marked none
308 if (strcmp(mountpoint
, path
) == 0) {
309 return (strdup((char *)zfs_get_name(hdl
)));
316 * get_zfs_dataset(impl_handle, path)
318 * get the name of the ZFS dataset the path is equivalent to. The
319 * dataset name is used for get/set of ZFS properties since libzfs
320 * requires a dataset to do a zfs_open().
324 get_zfs_dataset(sa_handle_impl_t impl_handle
, char *path
,
325 boolean_t search_mnttab
)
328 zfs_handle_t
**zlist
;
330 zfs_handle_t
*handle_from_path
;
334 * First we optimistically assume that the mount path for the filesystem
335 * is the same as the name of the filesystem (minus some number of
336 * leading slashes). If this is true, then zfs_open should properly open
337 * the filesystem. We duplicate the error checking done later in the
338 * function for consistency. If anything fails, we resort to the
339 * (extremely slow) search of all the filesystems.
341 cutpath
= path
+ strspn(path
, "/");
343 assert(impl_handle
->zfs_libhandle
!= NULL
);
344 libzfs_print_on_error(impl_handle
->zfs_libhandle
, B_FALSE
);
345 handle_from_path
= zfs_open(impl_handle
->zfs_libhandle
, cutpath
,
346 ZFS_TYPE_FILESYSTEM
);
347 libzfs_print_on_error(impl_handle
->zfs_libhandle
, B_TRUE
);
348 if (handle_from_path
!= NULL
) {
349 ret
= verify_zfs_handle(handle_from_path
, path
, search_mnttab
);
350 zfs_close(handle_from_path
);
356 * Couldn't find a filesystem optimistically, check all the handles we
359 get_all_filesystems(impl_handle
, &zlist
, &count
);
360 for (i
= 0; i
< count
; i
++) {
362 if ((ret
= verify_zfs_handle(zlist
[i
], path
,
363 search_mnttab
)) != NULL
)
367 /* Couldn't find a matching dataset */
372 * get_zfs_property(dataset, property)
374 * Get the file system property specified from the ZFS dataset.
378 get_zfs_property(char *dataset
, zfs_prop_t property
)
380 zfs_handle_t
*handle
= NULL
;
381 char shareopts
[ZFS_MAXPROPLEN
];
382 libzfs_handle_t
*libhandle
;
384 libhandle
= libzfs_init();
385 if (libhandle
!= NULL
) {
386 handle
= zfs_open(libhandle
, dataset
, ZFS_TYPE_FILESYSTEM
);
387 if (handle
!= NULL
) {
388 if (zfs_prop_get(handle
, property
, shareopts
,
389 sizeof (shareopts
), NULL
, NULL
, 0,
392 libzfs_fini(libhandle
);
393 return (strdup(shareopts
));
397 libzfs_fini(libhandle
);
403 * sa_zfs_is_shared(handle, path)
405 * Check to see if the ZFS path provided has the sharenfs option set
410 sa_zfs_is_shared(sa_handle_t sahandle
, char *path
)
414 zfs_handle_t
*handle
= NULL
;
415 char shareopts
[ZFS_MAXPROPLEN
];
416 libzfs_handle_t
*libhandle
;
418 dataset
= get_zfs_dataset((sa_handle_t
)sahandle
, path
, B_FALSE
);
419 if (dataset
!= NULL
) {
420 libhandle
= libzfs_init();
421 if (libhandle
!= NULL
) {
422 handle
= zfs_open(libhandle
, dataset
,
423 ZFS_TYPE_FILESYSTEM
);
424 if (handle
!= NULL
) {
425 if (zfs_prop_get(handle
, ZFS_PROP_SHARENFS
,
426 shareopts
, sizeof (shareopts
), NULL
, NULL
,
428 strcmp(shareopts
, "off") != 0) {
429 ret
= 1; /* it is shared */
433 libzfs_fini(libhandle
);
441 * find_or_create_group(handle, groupname, proto, *err)
443 * While walking the ZFS tree, we need to add shares to a defined
444 * group. If the group doesn't exist, create it first, making sure it
445 * is marked as a ZFS group.
447 * Note that all ZFS shares are in a subgroup of the top level group
452 find_or_create_group(sa_handle_t handle
, char *groupname
, char *proto
, int *err
)
455 sa_optionset_t optionset
;
459 * we check to see if the "zfs" group exists. Since this
460 * should be the top level group, we don't want the
461 * parent. This is to make sure the zfs group has been created
462 * and to created if it hasn't been.
464 group
= sa_get_group(handle
, groupname
);
466 group
= sa_create_group(handle
, groupname
, &ret
);
468 /* make sure this is flagged as a ZFS group */
470 ret
= sa_set_group_attr(group
, "zfs", "true");
474 optionset
= sa_get_optionset(group
, proto
);
475 if (optionset
== NULL
)
476 optionset
= sa_create_optionset(group
, proto
);
485 * find_or_create_zfs_subgroup(groupname, optstring, *err)
487 * ZFS shares will be in a subgroup of the "zfs" master group. This
488 * function looks to see if the groupname exists and returns it if it
489 * does or else creates a new one with the specified name and returns
490 * that. The "zfs" group will exist before we get here, but we make
493 * err must be a valid pointer.
497 find_or_create_zfs_subgroup(sa_handle_t handle
, char *groupname
, char *proto
,
498 char *optstring
, int *err
)
500 sa_group_t group
= NULL
;
505 /* start with the top-level "zfs" group */
506 zfs
= sa_get_group(handle
, "zfs");
509 for (group
= sa_get_sub_group(zfs
); group
!= NULL
;
510 group
= sa_get_next_group(group
)) {
511 name
= sa_get_group_attr(group
, "name");
512 if (name
!= NULL
&& strcmp(name
, groupname
) == 0) {
513 /* have the group so break out of here */
514 sa_free_attr_string(name
);
518 sa_free_attr_string(name
);
523 * Need to create the sub-group since it doesn't exist
525 group
= _sa_create_zfs_group(zfs
, groupname
);
530 set_node_attr(group
, "zfs", "true");
532 if (strcmp(optstring
, "on") == 0)
534 options
= strdup(optstring
);
535 if (options
!= NULL
) {
536 *err
= sa_parse_legacy_options(group
, options
,
538 /* If no optionset, add one. */
539 if (sa_get_optionset(group
, proto
) == NULL
)
540 (void) sa_create_optionset(group
, proto
);
543 * Do not forget to update an optionset of
544 * the parent group so that it contains
545 * all protocols its subgroups have.
547 if (sa_get_optionset(zfs
, proto
) == NULL
)
548 (void) sa_create_optionset(zfs
, proto
);
559 * zfs_construct_resource(share, name, base, dataset)
561 * Add a resource to the share using name as a template. If name ==
562 * NULL, then construct a name based on the dataset value.
566 zfs_construct_resource(sa_share_t share
, char *dataset
)
568 char buff
[SA_MAX_RESOURCE_NAME
+ 1];
571 (void) snprintf(buff
, SA_MAX_RESOURCE_NAME
, "%s", dataset
);
572 sa_fix_resource_name(buff
);
573 (void) sa_add_resource(share
, buff
, SA_SHARE_TRANSIENT
, &ret
);
577 * zfs_inherited(handle, source, sourcestr)
579 * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares
583 zfs_inherited(sa_handle_t handle
, sa_share_t share
, char *sourcestr
,
584 char *shareopts
, char *mountpoint
, char *proto
, char *dataset
)
589 sa_resource_t resource
;
593 * Need to find the "real" parent sub-group. It may not be
594 * mounted, but it was identified in the "sourcestr"
595 * variable. The real parent not mounted can occur if
596 * "canmount=off and sharenfs=on".
598 group
= find_or_create_zfs_subgroup(handle
, sourcestr
, proto
,
599 shareopts
, &doshopt
);
602 * We may need the first share for resource
603 * prototype. We only care about it if it has a
604 * resource that sets a prefix value.
607 share
= _sa_add_share(group
, mountpoint
,
608 SA_SHARE_TRANSIENT
, &err
,
609 (uint64_t)SA_FEATURE_NONE
);
611 * some options may only be on shares. If the opt
612 * string contains one of those, we put it just on the
615 if (share
!= NULL
&& doshopt
== SA_PROP_SHARE_ONLY
) {
617 options
= strdup(shareopts
);
618 if (options
!= NULL
) {
619 set_node_attr(share
, "dataset", dataset
);
620 err
= sa_parse_legacy_options(share
, options
,
622 set_node_attr(share
, "dataset", NULL
);
625 if (sa_get_optionset(group
, proto
) == NULL
)
626 (void) sa_create_optionset(group
, proto
);
628 features
= sa_proto_get_featureset(proto
);
629 if (share
!= NULL
&& features
& SA_FEATURE_RESOURCE
) {
631 * We have a share and the protocol requires
632 * that at least one resource exist (probably
633 * SMB). We need to make sure that there is at
636 resource
= sa_get_share_resource(share
, NULL
);
637 if (resource
== NULL
) {
638 zfs_construct_resource(share
, dataset
);
648 * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset,
651 * handle case where this is the top of a sub-group in ZFS. Pulled out
652 * of sa_get_zfs_shares for readability. We need the grouperr from the
653 * creation of the subgroup to know whether to add the public
654 * property, etc. to the specific share.
657 zfs_notinherited(sa_group_t group
, sa_share_t share
, char *mountpoint
,
658 char *shareopts
, char *proto
, char *dataset
, int grouperr
)
661 sa_resource_t resource
;
664 set_node_attr(group
, "zfs", "true");
666 share
= _sa_add_share(group
, mountpoint
, SA_SHARE_TRANSIENT
,
667 &err
, (uint64_t)SA_FEATURE_NONE
);
672 if (strcmp(shareopts
, "on") == 0)
674 if (shareopts
!= NULL
) {
676 if (grouperr
== SA_PROP_SHARE_ONLY
) {
678 * Some properties may only be on shares, but
679 * due to the ZFS sub-groups being artificial,
680 * we sometimes get this and have to deal with
681 * it. We do it by attempting to put it on the
684 options
= strdup(shareopts
);
685 if (options
!= NULL
) {
686 err
= sa_parse_legacy_options(share
,
691 /* Unmark the share's changed state */
692 set_node_attr(share
, "changed", NULL
);
694 features
= sa_proto_get_featureset(proto
);
695 if (share
!= NULL
&& features
& SA_FEATURE_RESOURCE
) {
697 * We have a share and the protocol requires that at
698 * least one resource exist (probably SMB). We need to
699 * make sure that there is at least one.
701 resource
= sa_get_share_resource(share
, NULL
);
702 if (resource
== NULL
) {
703 zfs_construct_resource(share
, dataset
);
712 * Print group create error, but only once. If err is 0 do the
717 zfs_grp_error(int err
)
720 /* only print error once */
721 (void) fprintf(stderr
, dgettext(TEXT_DOMAIN
,
722 "Cannot create ZFS subgroup during initialization:"
723 " %s\n"), sa_errorstr(SA_SYSTEM_ERR
));
728 * zfs_process_share(handle, share, mountpoint, proto, source,
729 * shareopts, sourcestr)
731 * Creates the subgroup, if necessary and adds shares, resources
735 sa_zfs_process_share(sa_handle_t handle
, sa_group_t group
, sa_share_t share
,
736 char *mountpoint
, char *proto
, zprop_source_t source
, char *shareopts
,
737 char *sourcestr
, char *dataset
)
741 if (source
& ZPROP_SRC_INHERITED
) {
742 err
= zfs_inherited(handle
, share
, sourcestr
, shareopts
,
743 mountpoint
, proto
, dataset
);
745 group
= find_or_create_zfs_subgroup(handle
, dataset
, proto
,
748 static boolean_t reported_error
= B_FALSE
;
750 * There is a problem, but we can't do
751 * anything about it at this point so we issue
752 * a warning and move on.
754 zfs_grp_error(reported_error
);
755 reported_error
= B_TRUE
;
757 set_node_attr(group
, "zfs", "true");
759 * Add share with local opts via zfs_notinherited.
761 err
= zfs_notinherited(group
, share
, mountpoint
, shareopts
,
762 proto
, dataset
, err
);
768 * Walk the mnttab for all zfs mounts and determine which are
769 * shared. Find or create the appropriate group/sub-group to contain
772 * All shares are in a sub-group that will hold the properties. This
773 * allows representing the inherited property model.
775 * One area of complication is if "sharenfs" is set at one level of
776 * the directory tree and "sharesmb" is set at a different level, the
777 * a sub-group must be formed at the lower level for both
778 * protocols. That is the nature of the problem in CR 6667349.
781 sa_get_zfs_share_common(sa_handle_t handle
, zfs_handle_t
*fs_handle
, char *path
,
785 boolean_t smb_inherited
, nfs_inherited
;
786 char nfsshareopts
[ZFS_MAXPROPLEN
];
787 char smbshareopts
[ZFS_MAXPROPLEN
];
788 char nfssourcestr
[ZFS_MAXPROPLEN
];
789 char smbsourcestr
[ZFS_MAXPROPLEN
];
790 char mountpoint
[ZFS_MAXPROPLEN
];
792 zprop_source_t source
;
796 source
= ZPROP_SRC_ALL
;
797 /* If no mountpoint, skip. */
798 if (zfs_prop_get(fs_handle
, ZFS_PROP_MOUNTPOINT
,
799 mountpoint
, sizeof (mountpoint
), NULL
, NULL
, 0,
801 return (SA_SYSTEM_ERR
);
804 (void) strncpy(path
, mountpoint
, sizeof (mountpoint
));
806 * zfs_get_name value must not be freed. It is just a
807 * pointer to a value in the handle.
809 if ((dataset
= (char *)zfs_get_name(fs_handle
)) == NULL
)
810 return (SA_SYSTEM_ERR
);
813 * only deal with "mounted" file systems since
814 * unmounted file systems can't actually be shared.
817 if (!zfs_is_mounted(fs_handle
, NULL
))
818 return (SA_SYSTEM_ERR
);
820 nfs
= nfs_inherited
= B_FALSE
;
822 if (zfs_prop_get(fs_handle
, ZFS_PROP_SHARENFS
, nfsshareopts
,
823 sizeof (nfsshareopts
), &source
, nfssourcestr
,
824 ZFS_MAXPROPLEN
, B_FALSE
) == 0 &&
825 strcmp(nfsshareopts
, "off") != 0) {
826 if (source
& ZPROP_SRC_INHERITED
)
827 nfs_inherited
= B_TRUE
;
832 smb
= smb_inherited
= B_FALSE
;
833 if (zfs_prop_get(fs_handle
, ZFS_PROP_SHARESMB
, smbshareopts
,
834 sizeof (smbshareopts
), &source
, smbsourcestr
,
835 ZFS_MAXPROPLEN
, B_FALSE
) == 0 &&
836 strcmp(smbshareopts
, "off") != 0) {
837 if (source
& ZPROP_SRC_INHERITED
)
838 smb_inherited
= B_TRUE
;
844 * If the mountpoint is already shared, it must be a
845 * non-ZFS share. We want to remove the share from its
846 * parent group and reshare it under ZFS.
848 share
= sa_find_share(handle
, mountpoint
);
850 (nfs
|| smb
|| nfs_inherited
|| smb_inherited
)) {
851 err
= sa_remove_share(share
);
856 * At this point, we have the information needed to
857 * determine what to do with the share.
859 * If smb or nfs is set, we have a new sub-group.
860 * If smb_inherit and/or nfs_inherit is set, then
861 * place on an existing sub-group. If both are set,
862 * the existing sub-group is the closest up the tree.
866 * Non-inherited is the straightforward
867 * case. sa_zfs_process_share handles it
868 * directly. Make sure that if the "other"
869 * protocol is inherited, that we treat it as
870 * non-inherited as well.
872 if (nfs
|| nfs_inherited
) {
873 err
= sa_zfs_process_share(handle
, zfsgroup
,
874 share
, mountpoint
, "nfs",
876 nfssourcestr
, dataset
);
877 share
= sa_find_share(handle
, mountpoint
);
879 if (smb
|| smb_inherited
) {
880 err
= sa_zfs_process_share(handle
, zfsgroup
,
881 share
, mountpoint
, "smb",
883 smbsourcestr
, dataset
);
885 } else if (nfs_inherited
|| smb_inherited
) {
888 * If we only have inherited groups, it is
889 * important to find the closer of the two if
890 * the protocols are set at different
891 * levels. The closest sub-group is the one we
894 if (nfs_inherited
&& smb_inherited
) {
895 if (strcmp(nfssourcestr
, smbsourcestr
) <= 0)
896 grpdataset
= nfssourcestr
;
898 grpdataset
= smbsourcestr
;
899 } else if (nfs_inherited
) {
900 grpdataset
= nfssourcestr
;
901 } else if (smb_inherited
) {
902 grpdataset
= smbsourcestr
;
905 err
= sa_zfs_process_share(handle
, zfsgroup
,
906 share
, mountpoint
, "nfs",
907 ZPROP_SRC_INHERITED
, nfsshareopts
,
908 grpdataset
, dataset
);
909 share
= sa_find_share(handle
, mountpoint
);
912 err
= sa_zfs_process_share(handle
, zfsgroup
,
913 share
, mountpoint
, "smb",
914 ZPROP_SRC_INHERITED
, smbshareopts
,
915 grpdataset
, dataset
);
922 * Handles preparing generic objects such as the libzfs handle and group for
923 * sa_get_one_zfs_share, sa_get_zfs_share_for_name, and sa_get_zfs_shares.
926 prep_zfs_handle_and_group(sa_handle_t handle
, char *groupname
,
927 libzfs_handle_t
**zfs_libhandle
, sa_group_t
*zfsgroup
, int *err
)
930 * If we can't access libzfs, don't bother doing anything.
932 *zfs_libhandle
= ((sa_handle_impl_t
)handle
)->zfs_libhandle
;
933 if (*zfs_libhandle
== NULL
)
934 return (SA_SYSTEM_ERR
);
936 *zfsgroup
= find_or_create_group(handle
, groupname
, NULL
, err
);
941 * The O.G. zfs share preparation function. This initializes all zfs shares for
945 sa_get_zfs_shares(sa_handle_t handle
, char *groupname
)
948 zfs_handle_t
**zlist
;
950 libzfs_handle_t
*zfs_libhandle
;
953 if ((err
= prep_zfs_handle_and_group(handle
, groupname
, &zfs_libhandle
,
954 &zfsgroup
, &err
)) != SA_OK
) {
957 /* Not an error, this could be a legacy condition */
958 if (zfsgroup
== NULL
)
962 * need to walk the mounted ZFS pools and datasets to
963 * find shares that are possible.
965 get_all_filesystems((sa_handle_impl_t
)handle
, &zlist
, &count
);
966 qsort(zlist
, count
, sizeof (void *), mountpoint_compare
);
968 for (int i
= 0; i
< count
; i
++) {
969 err
= sa_get_zfs_share_common(handle
, zlist
[i
], NULL
, zfsgroup
);
972 * Don't need to free the "zlist" variable since it is only a
973 * pointer to a cached value that will be freed when
974 * sa_fini() is called.
980 * Initializes only the handles specified in the sharearg for use with libshare.
981 * This is used as a performance optimization relative to sa_get_zfs_shares.
984 sa_get_one_zfs_share(sa_handle_t handle
, char *groupname
,
985 sa_init_selective_arg_t
*sharearg
, char ***paths
, size_t *paths_len
)
988 libzfs_handle_t
*zfs_libhandle
;
991 if ((err
= prep_zfs_handle_and_group(handle
, groupname
, &zfs_libhandle
,
992 &zfsgroup
, &err
)) != SA_OK
) {
995 /* Not an error, this could be a legacy condition */
996 if (zfsgroup
== NULL
)
999 *paths_len
= sharearg
->zhandle_len
;
1000 *paths
= malloc(sizeof (char *) * (*paths_len
));
1001 for (int i
= 0; i
< sharearg
->zhandle_len
; ++i
) {
1002 zfs_handle_t
*fs_handle
=
1003 ((zfs_handle_t
**)(sharearg
->zhandle_arr
))[i
];
1004 if (fs_handle
== NULL
) {
1005 return (SA_SYSTEM_ERR
);
1007 (*paths
)[i
] = malloc(sizeof (char) * ZFS_MAXPROPLEN
);
1008 err
|= sa_get_zfs_share_common(handle
, fs_handle
, (*paths
)[i
],
1015 * Initializes only the share with the specified sharename for use with
1019 sa_get_zfs_share_for_name(sa_handle_t handle
, char *groupname
,
1020 const char *sharename
, char *outpath
)
1022 sa_group_t zfsgroup
;
1023 libzfs_handle_t
*zfs_libhandle
;
1026 if ((err
= prep_zfs_handle_and_group(handle
, groupname
, &zfs_libhandle
,
1027 &zfsgroup
, &err
)) != SA_OK
) {
1030 /* Not an error, this could be a legacy condition */
1031 if (zfsgroup
== NULL
)
1034 zfs_handle_t
*fs_handle
= zfs_open(zfs_libhandle
,
1035 sharename
+ strspn(sharename
, "/"), ZFS_TYPE_DATASET
);
1036 if (fs_handle
== NULL
)
1037 return (SA_SYSTEM_ERR
);
1039 err
= sa_get_zfs_share_common(handle
, fs_handle
, outpath
, zfsgroup
);
1040 zfs_close(fs_handle
);
1046 #define COMMAND "/usr/sbin/zfs"
1049 * sa_zfs_set_sharenfs(group, path, on)
1051 * Update the "sharenfs" property on the path. If on is true, then set
1052 * to the properties on the group or "on" if no properties are
1053 * defined. Set to "off" if on is false.
1057 sa_zfs_set_sharenfs(sa_group_t group
, char *path
, int on
)
1059 int ret
= SA_NOT_IMPLEMENTED
;
1062 command
= malloc(ZFS_MAXPROPLEN
* 2);
1063 if (command
!= NULL
) {
1065 char *dataset
= NULL
;
1067 sa_handle_impl_t impl_handle
;
1068 /* for now, NFS is always available for "zfs" */
1070 opts
= sa_proto_legacy_format("nfs", group
, 1);
1071 if (opts
!= NULL
&& strlen(opts
) == 0) {
1073 opts
= strdup("on");
1077 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
1078 assert(impl_handle
!= NULL
);
1079 if (impl_handle
!= NULL
)
1080 dataset
= get_zfs_dataset(impl_handle
, path
, B_FALSE
);
1082 ret
= SA_SYSTEM_ERR
;
1084 if (dataset
!= NULL
) {
1085 (void) snprintf(command
, ZFS_MAXPROPLEN
* 2,
1086 "%s set sharenfs=\"%s\" %s", COMMAND
,
1087 opts
!= NULL
? opts
: "off", dataset
);
1088 pfile
= popen(command
, "r");
1089 if (pfile
!= NULL
) {
1090 ret
= pclose(pfile
);
1092 ret
= SA_SYSTEM_ERR
;
1103 * add_resources(share, opt)
1105 * Add resource properties to those in "opt". Resources are prefixed
1106 * with name=resourcename.
1109 add_resources(sa_share_t share
, char *opt
)
1111 char *newopt
= NULL
;
1113 sa_resource_t resource
;
1115 newopt
= strdup(opt
);
1119 for (resource
= sa_get_share_resource(share
, NULL
);
1121 resource
= sa_get_next_resource(resource
)) {
1125 name
= sa_get_resource_attr(resource
, "name");
1130 size
= strlen(name
) + strlen(opt
) + sizeof ("name=") + 1;
1131 newopt
= calloc(1, size
);
1133 (void) snprintf(newopt
, size
, "%s,name=%s", opt
, name
);
1134 sa_free_attr_string(name
);
1137 propstr
= sa_proto_legacy_format("smb", resource
, 0);
1138 if (propstr
== NULL
) {
1142 size
= strlen(propstr
) + strlen(opt
) + 2;
1143 newopt
= calloc(1, size
);
1145 (void) snprintf(newopt
, size
, "%s,%s", opt
, propstr
);
1153 * sa_zfs_set_sharesmb(group, path, on)
1155 * Update the "sharesmb" property on the path. If on is true, then set
1156 * to the properties on the group or "on" if no properties are
1157 * defined. Set to "off" if on is false.
1161 sa_zfs_set_sharesmb(sa_group_t group
, char *path
, int on
)
1163 int ret
= SA_NOT_IMPLEMENTED
;
1167 /* In case SMB not enabled */
1168 if (sa_get_optionset(group
, "smb") == NULL
)
1169 return (SA_NOT_SUPPORTED
);
1171 command
= malloc(ZFS_MAXPROPLEN
* 2);
1172 if (command
!= NULL
) {
1174 char *dataset
= NULL
;
1176 sa_handle_impl_t impl_handle
;
1181 share
= sa_get_share(group
, NULL
);
1182 opts
= sa_proto_legacy_format("smb", share
, 1);
1183 if (opts
!= NULL
&& strlen(opts
) == 0) {
1185 opts
= strdup("on");
1187 newopt
= add_resources(opts
, share
);
1192 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
1193 assert(impl_handle
!= NULL
);
1194 if (impl_handle
!= NULL
)
1195 dataset
= get_zfs_dataset(impl_handle
, path
, B_FALSE
);
1197 ret
= SA_SYSTEM_ERR
;
1199 if (dataset
!= NULL
) {
1200 (void) snprintf(command
, ZFS_MAXPROPLEN
* 2,
1201 "echo %s set sharesmb=\"%s\" %s", COMMAND
,
1202 opts
!= NULL
? opts
: "off", dataset
);
1203 pfile
= popen(command
, "r");
1204 if (pfile
!= NULL
) {
1205 ret
= pclose(pfile
);
1207 ret
= SA_SYSTEM_ERR
;
1218 * sa_zfs_update(group)
1220 * call back to ZFS to update the share if necessary.
1221 * Don't do it if it isn't a real change.
1224 sa_zfs_update(sa_group_t group
)
1226 sa_optionset_t protopt
;
1234 if (sa_is_share(group
))
1235 parent
= sa_get_parent_group(group
);
1239 if (parent
!= NULL
) {
1240 command
= malloc(ZFS_MAXPROPLEN
* 2);
1241 if (command
== NULL
)
1242 return (SA_NO_MEMORY
);
1245 for (protopt
= sa_get_optionset(parent
, NULL
); protopt
!= NULL
;
1246 protopt
= sa_get_next_optionset(protopt
)) {
1248 char *proto
= sa_get_optionset_attr(protopt
, "type");
1250 char *dataset
= NULL
;
1251 char *zfsopts
= NULL
;
1253 if (sa_is_share(group
)) {
1254 path
= sa_get_share_attr((sa_share_t
)group
,
1257 sa_handle_impl_t impl_handle
;
1259 impl_handle
= sa_find_group_handle(
1261 if (impl_handle
!= NULL
)
1262 dataset
= get_zfs_dataset(
1263 impl_handle
, path
, B_FALSE
);
1265 ret
= SA_SYSTEM_ERR
;
1267 sa_free_attr_string(path
);
1270 dataset
= sa_get_group_attr(group
, "name");
1272 /* update only when there is an optstring found */
1274 if (proto
!= NULL
&& dataset
!= NULL
) {
1275 optstring
= sa_proto_legacy_format(proto
,
1277 zfsopts
= get_zfs_property(dataset
,
1280 if (optstring
!= NULL
&& zfsopts
!= NULL
) {
1281 if (strcmp(optstring
, zfsopts
) != 0)
1285 if (optstring
!= NULL
&&
1286 strlen(optstring
) > 0) {
1287 (void) snprintf(command
,
1289 "%s set share%s=%s %s",
1291 optstring
, dataset
);
1293 (void) snprintf(command
,
1295 "%s set share%s=on %s",
1299 pfile
= popen(command
, "r");
1301 ret
= pclose(pfile
);
1305 ret
= SA_SYSTEM_ERR
;
1308 ret
= SA_SYNTAX_ERR
;
1318 sa_free_attr_string(proto
);
1327 * sa_group_is_zfs(group)
1329 * Given the group, determine if the zfs attribute is set.
1333 sa_group_is_zfs(sa_group_t group
)
1338 zfs
= sa_get_group_attr(group
, "zfs");
1341 sa_free_attr_string(zfs
);
1347 * sa_path_is_zfs(path)
1349 * Check to see if the file system path represents is of type "zfs".
1353 sa_path_is_zfs(char *path
)
1358 fstype
= sa_fstype(path
);
1359 if (fstype
!= NULL
&& strcmp(fstype
, "zfs") == 0)
1362 sa_free_fstype(fstype
);
1367 sa_sharetab_fill_zfs(sa_share_t share
, share_t
*sh
, char *proto
)
1371 /* Make sure path is valid */
1373 path
= sa_get_share_attr(share
, "path");
1375 (void) memset(sh
, 0, sizeof (sh
));
1376 (void) sa_fillshare(share
, proto
, sh
);
1377 sa_free_attr_string(path
);
1383 #define SMAX(i, j) \
1389 sa_share_zfs(sa_share_t share
, sa_resource_t resource
, char *path
, share_t
*sh
,
1390 void *exportdata
, zfs_share_op_t operation
)
1392 libzfs_handle_t
*libhandle
;
1394 sa_handle_t sahandle
;
1398 char newpath
[MAXPATHLEN
];
1402 * First find the dataset name
1404 if ((group
= sa_get_parent_group(share
)) == NULL
) {
1407 if ((sahandle
= sa_find_group_handle(group
)) == NULL
) {
1412 * If get_zfs_dataset fails, see if it is a subdirectory
1416 while ((dataset
= get_zfs_dataset(sahandle
, pathp
, B_TRUE
)) == NULL
) {
1419 if (pathp
== path
) {
1420 (void) strlcpy(newpath
, path
, sizeof (newpath
));
1425 * Make sure only one leading '/' This condition came
1426 * about when using HAStoragePlus which insisted on
1427 * putting an extra leading '/' in the ZFS path
1428 * name. The problem is fixed in other areas, but this
1429 * will catch any other ways that a double slash might
1432 while (*pathp
== '/' && *(pathp
+ 1) == '/')
1436 * chop off part of path, but if we are at root then
1437 * make sure path is a /
1439 if ((strlen(pathp
) > 1) && (p
= strrchr(pathp
, '/'))) {
1441 *(p
+ 1) = '\0'; /* skip over /, root case */
1450 libhandle
= libzfs_init();
1451 if (libhandle
!= NULL
) {
1452 char *resource_name
;
1454 i
= (sh
->sh_path
? strlen(sh
->sh_path
) : 0);
1457 j
= (sh
->sh_res
? strlen(sh
->sh_res
) : 0);
1461 j
= (sh
->sh_fstype
? strlen(sh
->sh_fstype
) : 0);
1465 j
= (sh
->sh_opts
? strlen(sh
->sh_opts
) : 0);
1469 j
= (sh
->sh_descr
? strlen(sh
->sh_descr
) : 0);
1473 resource_name
= sa_get_resource_attr(resource
, "name");
1475 err
= zfs_deleg_share_nfs(libhandle
, dataset
, path
,
1476 resource_name
, exportdata
, sh
, i
, operation
);
1478 sa_update_sharetab_ts(sahandle
);
1482 sa_free_attr_string(resource_name
);
1484 libzfs_fini(libhandle
);
1491 * sa_get_zfs_handle(handle)
1493 * Given an sa_handle_t, return the libzfs_handle_t *. This is only
1494 * used internally by libzfs. Needed in order to avoid including
1495 * libshare_impl.h in libzfs.
1499 sa_get_zfs_handle(sa_handle_t handle
)
1501 sa_handle_impl_t implhandle
= (sa_handle_impl_t
)handle
;
1503 return (implhandle
->zfs_libhandle
);
1507 * sa_get_zfs_info(libzfs, path, mountpoint, dataset)
1509 * Find the ZFS dataset and mountpoint for a given path
1512 sa_zfs_get_info(libzfs_handle_t
*libzfs
, char *path
, char *mountpointp
,
1515 get_all_cbdata_t cb
= { 0 };
1517 char mountpoint
[ZFS_MAXPROPLEN
];
1518 char dataset
[ZFS_MAXPROPLEN
];
1519 char canmount
[ZFS_MAXPROPLEN
];
1524 cb
.cb_types
= ZFS_TYPE_FILESYSTEM
;
1529 (void) zfs_iter_root(libzfs
, get_one_filesystem
, &cb
);
1532 qsort(cb
.cb_handles
, count
, sizeof (void *), mountpoint_compare
);
1533 for (i
= 0; i
< count
; i
++) {
1534 /* must have a mountpoint */
1535 if (zfs_prop_get(cb
.cb_handles
[i
], ZFS_PROP_MOUNTPOINT
,
1536 mountpoint
, sizeof (mountpoint
),
1537 NULL
, NULL
, 0, B_FALSE
) != 0) {
1542 /* mountpoint must be a path */
1543 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_NONE
) == 0 ||
1544 strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0) {
1546 * Search mmttab for mountpoint
1549 if (get_legacy_mountpoint(path
, dataset
,
1550 ZFS_MAXPROPLEN
, mountpoint
,
1551 ZFS_MAXPROPLEN
) == 0) {
1558 /* canmount must be set */
1560 if (zfs_prop_get(cb
.cb_handles
[i
], ZFS_PROP_CANMOUNT
, canmount
,
1561 sizeof (canmount
), NULL
, NULL
, 0, B_FALSE
) != 0 ||
1562 strcmp(canmount
, "off") == 0)
1566 * have a mountable handle but want to skip those marked none
1569 if (strcmp(mountpoint
, path
) == 0) {
1570 dp
= (char *)zfs_get_name(cb
.cb_handles
[i
]);
1572 if (datasetp
!= NULL
)
1573 (void) strcpy(datasetp
, dp
);
1574 if (mountpointp
!= NULL
)
1575 (void) strcpy(mountpointp
, mountpoint
);
1587 * This method builds values for "sharesmb" property from the
1588 * nvlist argument. The values are returned in sharesmb_val variable.
1591 sa_zfs_sprintf_new_prop(nvlist_t
*nvl
, char *sharesmb_val
)
1593 char cur_val
[MAXPATHLEN
];
1598 cur
= nvlist_next_nvpair(nvl
, NULL
);
1599 while (cur
!= NULL
) {
1600 name
= nvpair_name(cur
);
1601 err
= nvpair_value_string(cur
, &val
);
1602 if ((err
!= 0) || (name
== NULL
) || (val
== NULL
))
1605 (void) snprintf(cur_val
, MAXPATHLEN
, "%s=%s,", name
, val
);
1606 (void) strlcat(sharesmb_val
, cur_val
, MAXPATHLEN
);
1608 cur
= nvlist_next_nvpair(nvl
, cur
);
1615 * This method builds values for "sharesmb" property from values
1616 * already existing on the share. The properties set via sa_zfs_sprint_new_prop
1617 * method are passed in sharesmb_val. If a existing property is already
1618 * set via sa_zfs_sprint_new_prop method, then they are not appended
1619 * to the sharesmb_val string. The returned sharesmb_val string is a combination
1620 * of new and existing values for 'sharesmb' property.
1623 sa_zfs_sprintf_existing_prop(zfs_handle_t
*handle
, char *sharesmb_val
)
1625 char shareopts
[ZFS_MAXPROPLEN
], cur_val
[MAXPATHLEN
];
1626 char *token
, *last
, *value
;
1628 if (zfs_prop_get(handle
, ZFS_PROP_SHARESMB
, shareopts
,
1629 sizeof (shareopts
), NULL
, NULL
, 0, B_FALSE
) != 0)
1632 if (strstr(shareopts
, "=") == NULL
)
1635 for (token
= strtok_r(shareopts
, ",", &last
); token
!= NULL
;
1636 token
= strtok_r(NULL
, ",", &last
)) {
1637 value
= strchr(token
, '=');
1642 (void) snprintf(cur_val
, MAXPATHLEN
, "%s=", token
);
1643 if (strstr(sharesmb_val
, cur_val
) == NULL
) {
1644 (void) strlcat(cur_val
, value
, MAXPATHLEN
);
1645 (void) strlcat(cur_val
, ",", MAXPATHLEN
);
1646 (void) strlcat(sharesmb_val
, cur_val
, MAXPATHLEN
);
1654 * Sets the share properties on a ZFS share. For now, this method sets only
1655 * the "sharesmb" property.
1657 * This method includes building a comma seperated name-value string to be
1658 * set on the "sharesmb" property of a ZFS share. This name-value string is
1660 * - New property values given as name-value pair are set first.
1661 * - Existing optionset properties, which are not part of the new properties
1662 * passed in step 1, are appended to the newly set properties.
1665 sa_zfs_setprop(sa_handle_t handle
, char *path
, nvlist_t
*nvl
)
1668 libzfs_handle_t
*z_lib
;
1669 char sharesmb_val
[MAXPATHLEN
];
1670 char *dataset
, *lastcomma
;
1672 if (nvlist_empty(nvl
))
1675 if ((handle
== NULL
) || (path
== NULL
))
1678 if ((dataset
= get_zfs_dataset(handle
, path
, B_FALSE
)) == NULL
)
1681 if ((z_lib
= libzfs_init()) == NULL
) {
1686 z_fs
= zfs_open(z_lib
, dataset
, ZFS_TYPE_DATASET
);
1693 bzero(sharesmb_val
, MAXPATHLEN
);
1694 if (sa_zfs_sprintf_new_prop(nvl
, sharesmb_val
) != 0) {
1701 if (sa_zfs_sprintf_existing_prop(z_fs
, sharesmb_val
) != 0) {
1708 lastcomma
= strrchr(sharesmb_val
, ',');
1709 if ((lastcomma
!= NULL
) && (lastcomma
[1] == '\0'))
1712 (void) zfs_prop_set(z_fs
, zfs_prop_to_name(ZFS_PROP_SHARESMB
),