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
;
1097 if (dataset
!= NULL
)
1105 * add_resources(share, opt)
1107 * Add resource properties to those in "opt". Resources are prefixed
1108 * with name=resourcename.
1111 add_resources(sa_share_t share
, char *opt
)
1113 char *newopt
= NULL
;
1115 sa_resource_t resource
;
1117 newopt
= strdup(opt
);
1121 for (resource
= sa_get_share_resource(share
, NULL
);
1123 resource
= sa_get_next_resource(resource
)) {
1127 name
= sa_get_resource_attr(resource
, "name");
1132 size
= strlen(name
) + strlen(opt
) + sizeof ("name=") + 1;
1133 newopt
= calloc(1, size
);
1135 (void) snprintf(newopt
, size
, "%s,name=%s", opt
, name
);
1136 sa_free_attr_string(name
);
1139 propstr
= sa_proto_legacy_format("smb", resource
, 0);
1140 if (propstr
== NULL
) {
1144 size
= strlen(propstr
) + strlen(opt
) + 2;
1145 newopt
= calloc(1, size
);
1147 (void) snprintf(newopt
, size
, "%s,%s", opt
, propstr
);
1155 * sa_zfs_set_sharesmb(group, path, on)
1157 * Update the "sharesmb" property on the path. If on is true, then set
1158 * to the properties on the group or "on" if no properties are
1159 * defined. Set to "off" if on is false.
1163 sa_zfs_set_sharesmb(sa_group_t group
, char *path
, int on
)
1165 int ret
= SA_NOT_IMPLEMENTED
;
1169 /* In case SMB not enabled */
1170 if (sa_get_optionset(group
, "smb") == NULL
)
1171 return (SA_NOT_SUPPORTED
);
1173 command
= malloc(ZFS_MAXPROPLEN
* 2);
1174 if (command
!= NULL
) {
1176 char *dataset
= NULL
;
1178 sa_handle_impl_t impl_handle
;
1183 share
= sa_get_share(group
, NULL
);
1184 opts
= sa_proto_legacy_format("smb", share
, 1);
1185 if (opts
!= NULL
&& strlen(opts
) == 0) {
1187 opts
= strdup("on");
1189 newopt
= add_resources(opts
, share
);
1194 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
1195 assert(impl_handle
!= NULL
);
1196 if (impl_handle
!= NULL
)
1197 dataset
= get_zfs_dataset(impl_handle
, path
, B_FALSE
);
1199 ret
= SA_SYSTEM_ERR
;
1201 if (dataset
!= NULL
) {
1202 (void) snprintf(command
, ZFS_MAXPROPLEN
* 2,
1203 "echo %s set sharesmb=\"%s\" %s", COMMAND
,
1204 opts
!= NULL
? opts
: "off", dataset
);
1205 pfile
= popen(command
, "r");
1206 if (pfile
!= NULL
) {
1207 ret
= pclose(pfile
);
1209 ret
= SA_SYSTEM_ERR
;
1214 if (dataset
!= NULL
)
1222 * sa_zfs_update(group)
1224 * call back to ZFS to update the share if necessary.
1225 * Don't do it if it isn't a real change.
1228 sa_zfs_update(sa_group_t group
)
1230 sa_optionset_t protopt
;
1238 if (sa_is_share(group
))
1239 parent
= sa_get_parent_group(group
);
1243 if (parent
!= NULL
) {
1244 command
= malloc(ZFS_MAXPROPLEN
* 2);
1245 if (command
== NULL
)
1246 return (SA_NO_MEMORY
);
1249 for (protopt
= sa_get_optionset(parent
, NULL
); protopt
!= NULL
;
1250 protopt
= sa_get_next_optionset(protopt
)) {
1252 char *proto
= sa_get_optionset_attr(protopt
, "type");
1254 char *dataset
= NULL
;
1255 char *zfsopts
= NULL
;
1257 if (sa_is_share(group
)) {
1258 path
= sa_get_share_attr((sa_share_t
)group
,
1261 sa_handle_impl_t impl_handle
;
1263 impl_handle
= sa_find_group_handle(
1265 if (impl_handle
!= NULL
)
1266 dataset
= get_zfs_dataset(
1267 impl_handle
, path
, B_FALSE
);
1269 ret
= SA_SYSTEM_ERR
;
1271 sa_free_attr_string(path
);
1274 dataset
= sa_get_group_attr(group
, "name");
1276 /* update only when there is an optstring found */
1278 if (proto
!= NULL
&& dataset
!= NULL
) {
1279 optstring
= sa_proto_legacy_format(proto
,
1281 zfsopts
= get_zfs_property(dataset
,
1284 if (optstring
!= NULL
&& zfsopts
!= NULL
) {
1285 if (strcmp(optstring
, zfsopts
) != 0)
1289 if (optstring
!= NULL
&&
1290 strlen(optstring
) > 0) {
1291 (void) snprintf(command
,
1293 "%s set share%s=%s %s",
1295 optstring
, dataset
);
1297 (void) snprintf(command
,
1299 "%s set share%s=on %s",
1303 pfile
= popen(command
, "r");
1305 ret
= pclose(pfile
);
1309 ret
= SA_SYSTEM_ERR
;
1312 ret
= SA_SYNTAX_ERR
;
1318 if (optstring
!= NULL
)
1320 if (zfsopts
!= NULL
)
1324 sa_free_attr_string(proto
);
1325 if (dataset
!= NULL
)
1334 * sa_group_is_zfs(group)
1336 * Given the group, determine if the zfs attribute is set.
1340 sa_group_is_zfs(sa_group_t group
)
1345 zfs
= sa_get_group_attr(group
, "zfs");
1348 sa_free_attr_string(zfs
);
1354 * sa_path_is_zfs(path)
1356 * Check to see if the file system path represents is of type "zfs".
1360 sa_path_is_zfs(char *path
)
1365 fstype
= sa_fstype(path
);
1366 if (fstype
!= NULL
&& strcmp(fstype
, "zfs") == 0)
1369 sa_free_fstype(fstype
);
1374 sa_sharetab_fill_zfs(sa_share_t share
, share_t
*sh
, char *proto
)
1378 /* Make sure path is valid */
1380 path
= sa_get_share_attr(share
, "path");
1382 (void) memset(sh
, 0, sizeof (sh
));
1383 (void) sa_fillshare(share
, proto
, sh
);
1384 sa_free_attr_string(path
);
1390 #define SMAX(i, j) \
1396 sa_share_zfs(sa_share_t share
, sa_resource_t resource
, char *path
, share_t
*sh
,
1397 void *exportdata
, zfs_share_op_t operation
)
1399 libzfs_handle_t
*libhandle
;
1401 sa_handle_t sahandle
;
1405 char newpath
[MAXPATHLEN
];
1409 * First find the dataset name
1411 if ((group
= sa_get_parent_group(share
)) == NULL
) {
1414 if ((sahandle
= sa_find_group_handle(group
)) == NULL
) {
1419 * If get_zfs_dataset fails, see if it is a subdirectory
1423 while ((dataset
= get_zfs_dataset(sahandle
, pathp
, B_TRUE
)) == NULL
) {
1426 if (pathp
== path
) {
1427 (void) strlcpy(newpath
, path
, sizeof (newpath
));
1432 * Make sure only one leading '/' This condition came
1433 * about when using HAStoragePlus which insisted on
1434 * putting an extra leading '/' in the ZFS path
1435 * name. The problem is fixed in other areas, but this
1436 * will catch any other ways that a double slash might
1439 while (*pathp
== '/' && *(pathp
+ 1) == '/')
1443 * chop off part of path, but if we are at root then
1444 * make sure path is a /
1446 if ((strlen(pathp
) > 1) && (p
= strrchr(pathp
, '/'))) {
1448 *(p
+ 1) = '\0'; /* skip over /, root case */
1457 libhandle
= libzfs_init();
1458 if (libhandle
!= NULL
) {
1459 char *resource_name
;
1461 i
= (sh
->sh_path
? strlen(sh
->sh_path
) : 0);
1464 j
= (sh
->sh_res
? strlen(sh
->sh_res
) : 0);
1468 j
= (sh
->sh_fstype
? strlen(sh
->sh_fstype
) : 0);
1472 j
= (sh
->sh_opts
? strlen(sh
->sh_opts
) : 0);
1476 j
= (sh
->sh_descr
? strlen(sh
->sh_descr
) : 0);
1480 resource_name
= sa_get_resource_attr(resource
, "name");
1482 err
= zfs_deleg_share_nfs(libhandle
, dataset
, path
,
1483 resource_name
, exportdata
, sh
, i
, operation
);
1485 sa_update_sharetab_ts(sahandle
);
1489 sa_free_attr_string(resource_name
);
1491 libzfs_fini(libhandle
);
1498 * sa_get_zfs_handle(handle)
1500 * Given an sa_handle_t, return the libzfs_handle_t *. This is only
1501 * used internally by libzfs. Needed in order to avoid including
1502 * libshare_impl.h in libzfs.
1506 sa_get_zfs_handle(sa_handle_t handle
)
1508 sa_handle_impl_t implhandle
= (sa_handle_impl_t
)handle
;
1510 return (implhandle
->zfs_libhandle
);
1514 * sa_get_zfs_info(libzfs, path, mountpoint, dataset)
1516 * Find the ZFS dataset and mountpoint for a given path
1519 sa_zfs_get_info(libzfs_handle_t
*libzfs
, char *path
, char *mountpointp
,
1522 get_all_cbdata_t cb
= { 0 };
1524 char mountpoint
[ZFS_MAXPROPLEN
];
1525 char dataset
[ZFS_MAXPROPLEN
];
1526 char canmount
[ZFS_MAXPROPLEN
];
1531 cb
.cb_types
= ZFS_TYPE_FILESYSTEM
;
1536 (void) zfs_iter_root(libzfs
, get_one_filesystem
, &cb
);
1539 qsort(cb
.cb_handles
, count
, sizeof (void *), mountpoint_compare
);
1540 for (i
= 0; i
< count
; i
++) {
1541 /* must have a mountpoint */
1542 if (zfs_prop_get(cb
.cb_handles
[i
], ZFS_PROP_MOUNTPOINT
,
1543 mountpoint
, sizeof (mountpoint
),
1544 NULL
, NULL
, 0, B_FALSE
) != 0) {
1549 /* mountpoint must be a path */
1550 if (strcmp(mountpoint
, ZFS_MOUNTPOINT_NONE
) == 0 ||
1551 strcmp(mountpoint
, ZFS_MOUNTPOINT_LEGACY
) == 0) {
1553 * Search mmttab for mountpoint
1556 if (get_legacy_mountpoint(path
, dataset
,
1557 ZFS_MAXPROPLEN
, mountpoint
,
1558 ZFS_MAXPROPLEN
) == 0) {
1565 /* canmount must be set */
1567 if (zfs_prop_get(cb
.cb_handles
[i
], ZFS_PROP_CANMOUNT
, canmount
,
1568 sizeof (canmount
), NULL
, NULL
, 0, B_FALSE
) != 0 ||
1569 strcmp(canmount
, "off") == 0)
1573 * have a mountable handle but want to skip those marked none
1576 if (strcmp(mountpoint
, path
) == 0) {
1577 dp
= (char *)zfs_get_name(cb
.cb_handles
[i
]);
1579 if (datasetp
!= NULL
)
1580 (void) strcpy(datasetp
, dp
);
1581 if (mountpointp
!= NULL
)
1582 (void) strcpy(mountpointp
, mountpoint
);
1594 * This method builds values for "sharesmb" property from the
1595 * nvlist argument. The values are returned in sharesmb_val variable.
1598 sa_zfs_sprintf_new_prop(nvlist_t
*nvl
, char *sharesmb_val
)
1600 char cur_val
[MAXPATHLEN
];
1605 cur
= nvlist_next_nvpair(nvl
, NULL
);
1606 while (cur
!= NULL
) {
1607 name
= nvpair_name(cur
);
1608 err
= nvpair_value_string(cur
, &val
);
1609 if ((err
!= 0) || (name
== NULL
) || (val
== NULL
))
1612 (void) snprintf(cur_val
, MAXPATHLEN
, "%s=%s,", name
, val
);
1613 (void) strlcat(sharesmb_val
, cur_val
, MAXPATHLEN
);
1615 cur
= nvlist_next_nvpair(nvl
, cur
);
1622 * This method builds values for "sharesmb" property from values
1623 * already existing on the share. The properties set via sa_zfs_sprint_new_prop
1624 * method are passed in sharesmb_val. If a existing property is already
1625 * set via sa_zfs_sprint_new_prop method, then they are not appended
1626 * to the sharesmb_val string. The returned sharesmb_val string is a combination
1627 * of new and existing values for 'sharesmb' property.
1630 sa_zfs_sprintf_existing_prop(zfs_handle_t
*handle
, char *sharesmb_val
)
1632 char shareopts
[ZFS_MAXPROPLEN
], cur_val
[MAXPATHLEN
];
1633 char *token
, *last
, *value
;
1635 if (zfs_prop_get(handle
, ZFS_PROP_SHARESMB
, shareopts
,
1636 sizeof (shareopts
), NULL
, NULL
, 0, B_FALSE
) != 0)
1639 if (strstr(shareopts
, "=") == NULL
)
1642 for (token
= strtok_r(shareopts
, ",", &last
); token
!= NULL
;
1643 token
= strtok_r(NULL
, ",", &last
)) {
1644 value
= strchr(token
, '=');
1649 (void) snprintf(cur_val
, MAXPATHLEN
, "%s=", token
);
1650 if (strstr(sharesmb_val
, cur_val
) == NULL
) {
1651 (void) strlcat(cur_val
, value
, MAXPATHLEN
);
1652 (void) strlcat(cur_val
, ",", MAXPATHLEN
);
1653 (void) strlcat(sharesmb_val
, cur_val
, MAXPATHLEN
);
1661 * Sets the share properties on a ZFS share. For now, this method sets only
1662 * the "sharesmb" property.
1664 * This method includes building a comma seperated name-value string to be
1665 * set on the "sharesmb" property of a ZFS share. This name-value string is
1667 * - New property values given as name-value pair are set first.
1668 * - Existing optionset properties, which are not part of the new properties
1669 * passed in step 1, are appended to the newly set properties.
1672 sa_zfs_setprop(sa_handle_t handle
, char *path
, nvlist_t
*nvl
)
1675 libzfs_handle_t
*z_lib
;
1676 char sharesmb_val
[MAXPATHLEN
];
1677 char *dataset
, *lastcomma
;
1679 if (nvlist_empty(nvl
))
1682 if ((handle
== NULL
) || (path
== NULL
))
1685 if ((dataset
= get_zfs_dataset(handle
, path
, B_FALSE
)) == NULL
)
1688 if ((z_lib
= libzfs_init()) == NULL
) {
1693 z_fs
= zfs_open(z_lib
, dataset
, ZFS_TYPE_DATASET
);
1700 bzero(sharesmb_val
, MAXPATHLEN
);
1701 if (sa_zfs_sprintf_new_prop(nvl
, sharesmb_val
) != 0) {
1708 if (sa_zfs_sprintf_existing_prop(z_fs
, sharesmb_val
) != 0) {
1715 lastcomma
= strrchr(sharesmb_val
, ',');
1716 if ((lastcomma
!= NULL
) && (lastcomma
[1] == '\0'))
1719 (void) zfs_prop_set(z_fs
, zfs_prop_to_name(ZFS_PROP_SHARESMB
),