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) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2011 Gunnar Beutner
32 #include <sys/types.h>
37 #include "libshare_impl.h"
40 static sa_share_impl_t
find_share(sa_handle_impl_t handle
,
41 const char *sharepath
);
42 static sa_share_impl_t
alloc_share(const char *sharepath
);
43 static void free_share(sa_share_impl_t share
);
45 static void parse_sharetab(sa_handle_impl_t impl_handle
);
46 static int process_share(sa_handle_impl_t impl_handle
,
47 sa_share_impl_t impl_share
, char *pathname
, char *resource
,
48 char *fstype
, char *options
, char *description
,
49 char *dataset
, boolean_t from_sharetab
);
50 static void update_sharetab(sa_handle_impl_t impl_handle
);
52 static int update_zfs_share(sa_share_impl_t impl_handle
, const char *proto
);
53 static int update_zfs_shares(sa_handle_impl_t impl_handle
, const char *proto
);
55 static int fstypes_count
;
56 static sa_fstype_t
*fstypes
;
59 register_fstype(const char *name
, const sa_share_ops_t
*ops
)
63 fstype
= calloc(sizeof (sa_fstype_t
), 1);
70 fstype
->fsinfo_index
= fstypes_count
;
74 fstype
->next
= fstypes
;
81 sa_init(int init_service
)
83 sa_handle_impl_t impl_handle
;
85 impl_handle
= calloc(sizeof (struct sa_handle_impl
), 1);
87 if (impl_handle
== NULL
)
90 impl_handle
->zfs_libhandle
= libzfs_init();
92 if (impl_handle
->zfs_libhandle
!= NULL
) {
93 libzfs_print_on_error(impl_handle
->zfs_libhandle
, B_TRUE
);
96 parse_sharetab(impl_handle
);
97 update_zfs_shares(impl_handle
, NULL
);
99 return ((sa_handle_t
)impl_handle
);
102 __attribute__((constructor
)) static void
108 * This bit causes /etc/dfs/sharetab to be updated before libzfs gets a
109 * chance to read that file; this is necessary because the sharetab file
110 * might be out of sync with the NFS kernel exports (e.g. due to reboots
111 * or users manually removing shares)
117 parse_sharetab(sa_handle_impl_t impl_handle
) {
120 char *eol
, *pathname
, *resource
, *fstype
, *options
, *description
;
122 fp
= fopen("/etc/dfs/sharetab", "r");
127 while (fgets(line
, sizeof (line
), fp
) != NULL
) {
128 eol
= line
+ strlen(line
) - 1;
130 while (eol
>= line
) {
131 if (*eol
!= '\r' && *eol
!= '\n')
140 if ((resource
= strchr(pathname
, '\t')) == NULL
)
146 if ((fstype
= strchr(resource
, '\t')) == NULL
)
152 if ((options
= strchr(fstype
, '\t')) == NULL
)
158 if ((description
= strchr(fstype
, '\t')) != NULL
) {
163 if (strcmp(resource
, "-") == 0)
166 (void) process_share(impl_handle
, NULL
, pathname
, resource
,
167 fstype
, options
, description
, NULL
, B_TRUE
);
174 update_sharetab(sa_handle_impl_t impl_handle
)
176 sa_share_impl_t impl_share
;
179 char tempfile
[] = "/etc/dfs/sharetab.XXXXXX";
181 const char *resource
;
183 if (mkdir("/etc/dfs", 0755) < 0 && errno
!= EEXIST
) {
187 temp_fd
= mkstemp(tempfile
);
192 temp_fp
= fdopen(temp_fd
, "w");
197 impl_share
= impl_handle
->shares
;
198 while (impl_share
!= NULL
) {
200 while (fstype
!= NULL
) {
201 if (FSINFO(impl_share
, fstype
)->active
&&
202 FSINFO(impl_share
, fstype
)->shareopts
!= NULL
) {
203 resource
= FSINFO(impl_share
, fstype
)->resource
;
205 if (resource
== NULL
)
208 fprintf(temp_fp
, "%s\t%s\t%s\t%s\n",
209 impl_share
->sharepath
, resource
,
211 FSINFO(impl_share
, fstype
)->shareopts
);
214 fstype
= fstype
->next
;
217 impl_share
= impl_share
->next
;
224 rename(tempfile
, "/etc/dfs/sharetab");
227 typedef struct update_cookie_s
{
228 sa_handle_impl_t handle
;
233 update_zfs_shares_cb(zfs_handle_t
*zhp
, void *pcookie
)
235 update_cookie_t
*udata
= (update_cookie_t
*)pcookie
;
236 char mountpoint
[ZFS_MAXPROPLEN
];
237 char shareopts
[ZFS_MAXPROPLEN
];
239 zfs_type_t type
= zfs_get_type(zhp
);
241 if (type
== ZFS_TYPE_FILESYSTEM
&&
242 zfs_iter_filesystems(zhp
, update_zfs_shares_cb
, pcookie
) != 0) {
247 if (type
!= ZFS_TYPE_FILESYSTEM
) {
252 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
,
253 sizeof (mountpoint
), NULL
, NULL
, 0, B_FALSE
) != 0) {
258 dataset
= (char *)zfs_get_name(zhp
);
260 if (dataset
== NULL
) {
265 if (!zfs_is_mounted(zhp
, NULL
)) {
270 if ((udata
->proto
== NULL
|| strcmp(udata
->proto
, "nfs") == 0) &&
271 zfs_prop_get(zhp
, ZFS_PROP_SHARENFS
, shareopts
,
272 sizeof (shareopts
), NULL
, NULL
, 0, B_FALSE
) == 0 &&
273 strcmp(shareopts
, "off") != 0) {
274 (void) process_share(udata
->handle
, NULL
, mountpoint
, NULL
,
275 "nfs", shareopts
, NULL
, dataset
, B_FALSE
);
278 if ((udata
->proto
== NULL
|| strcmp(udata
->proto
, "smb") == 0) &&
279 zfs_prop_get(zhp
, ZFS_PROP_SHARESMB
, shareopts
,
280 sizeof (shareopts
), NULL
, NULL
, 0, B_FALSE
) == 0 &&
281 strcmp(shareopts
, "off") != 0) {
282 (void) process_share(udata
->handle
, NULL
, mountpoint
, NULL
,
283 "smb", shareopts
, NULL
, dataset
, B_FALSE
);
292 update_zfs_share(sa_share_impl_t impl_share
, const char *proto
)
294 sa_handle_impl_t impl_handle
= impl_share
->handle
;
296 update_cookie_t udata
;
298 if (impl_handle
->zfs_libhandle
== NULL
)
299 return SA_SYSTEM_ERR
;
301 assert(impl_share
->dataset
!= NULL
);
303 zhp
= zfs_open(impl_share
->handle
->zfs_libhandle
, impl_share
->dataset
,
304 ZFS_TYPE_FILESYSTEM
);
307 return SA_SYSTEM_ERR
;
309 udata
.handle
= impl_handle
;
311 (void) update_zfs_shares_cb(zhp
, &udata
);
317 update_zfs_shares(sa_handle_impl_t impl_handle
, const char *proto
)
319 update_cookie_t udata
;
321 if (impl_handle
->zfs_libhandle
== NULL
)
322 return SA_SYSTEM_ERR
;
324 udata
.handle
= impl_handle
;
326 (void) zfs_iter_root(impl_handle
->zfs_libhandle
, update_zfs_shares_cb
,
333 process_share(sa_handle_impl_t impl_handle
, sa_share_impl_t impl_share
,
334 char *pathname
, char *resource
, char *proto
,
335 char *options
, char *description
, char *dataset
,
336 boolean_t from_sharetab
)
340 char *resource_dup
= NULL
, *dataset_dup
= NULL
;
346 if (impl_share
== NULL
)
347 impl_share
= find_share(impl_handle
, pathname
);
349 if (impl_share
== NULL
) {
350 if (lstat(pathname
, &statbuf
) != 0 ||
351 !S_ISDIR(statbuf
.st_mode
))
354 impl_share
= alloc_share(pathname
);
356 if (impl_share
== NULL
) {
364 if (dataset
!= NULL
) {
365 dataset_dup
= strdup(dataset
);
367 if (dataset_dup
== NULL
) {
373 free(impl_share
->dataset
);
374 impl_share
->dataset
= dataset_dup
;
376 rc
= SA_INVALID_PROTOCOL
;
379 while (fstype
!= NULL
) {
380 if (strcmp(fstype
->name
, proto
) == 0) {
381 if (resource
!= NULL
) {
382 resource_dup
= strdup(resource
);
384 if (resource_dup
== NULL
) {
390 free(FSINFO(impl_share
, fstype
)->resource
);
391 FSINFO(impl_share
, fstype
)->resource
= resource_dup
;
393 rc
= fstype
->ops
->update_shareopts(impl_share
,
396 if (rc
== SA_OK
&& from_sharetab
)
397 FSINFO(impl_share
, fstype
)->active
= B_TRUE
;
402 fstype
= fstype
->next
;
409 impl_share
->handle
= impl_handle
;
411 impl_share
->next
= impl_handle
->shares
;
412 impl_handle
->shares
= impl_share
;
419 free_share(impl_share
);
426 sa_fini(sa_handle_t handle
)
428 sa_handle_impl_t impl_handle
= (sa_handle_impl_t
)handle
;
429 sa_share_impl_t impl_share
, next
;
430 sa_share_impl_t
*pcurr
;
432 if (impl_handle
== NULL
)
436 * clean up shares which don't have a non-NULL dataset property,
437 * which means they're in sharetab but we couldn't find their
440 pcurr
= &(impl_handle
->shares
);
442 while (impl_share
!= NULL
) {
443 next
= impl_share
->next
;
445 if (impl_share
->dataset
== NULL
) {
446 /* remove item from the linked list */
449 sa_disable_share(impl_share
, NULL
);
451 free_share(impl_share
);
453 pcurr
= &(impl_share
->next
);
459 update_sharetab(impl_handle
);
461 if (impl_handle
->zfs_libhandle
!= NULL
)
462 libzfs_fini(impl_handle
->zfs_libhandle
);
464 impl_share
= impl_handle
->shares
;
465 while (impl_share
!= NULL
) {
466 next
= impl_share
->next
;
467 free_share(impl_share
);
474 static sa_share_impl_t
475 find_share(sa_handle_impl_t impl_handle
, const char *sharepath
)
477 sa_share_impl_t impl_share
;
479 impl_share
= impl_handle
->shares
;
480 while (impl_share
!= NULL
) {
481 if (strcmp(impl_share
->sharepath
, sharepath
) == 0) {
485 impl_share
= impl_share
->next
;
492 sa_find_share(sa_handle_t handle
, char *sharepath
)
494 return (sa_share_t
)find_share((sa_handle_impl_t
)handle
, sharepath
);
498 sa_enable_share(sa_share_t share
, char *protocol
)
500 sa_share_impl_t impl_share
= (sa_share_impl_t
)share
;
502 boolean_t found_protocol
;
506 fprintf(stderr
, "sa_enable_share: share->sharepath=%s, protocol=%s\n",
507 impl_share
->sharepath
, protocol
);
510 assert(impl_share
->handle
!= NULL
);
513 found_protocol
= B_FALSE
;
516 while (fstype
!= NULL
) {
517 if (protocol
== NULL
|| strcmp(fstype
->name
, protocol
) == 0) {
518 update_zfs_share(impl_share
, fstype
->name
);
520 rc
= fstype
->ops
->enable_share(impl_share
);
525 FSINFO(impl_share
, fstype
)->active
= B_TRUE
;
527 found_protocol
= B_TRUE
;
530 fstype
= fstype
->next
;
533 update_sharetab(impl_share
->handle
);
535 return (found_protocol
? ret
: SA_INVALID_PROTOCOL
);
539 sa_disable_share(sa_share_t share
, char *protocol
)
541 sa_share_impl_t impl_share
= (sa_share_impl_t
)share
;
543 boolean_t found_protocol
;
547 fprintf(stderr
, "sa_disable_share: share->sharepath=%s, protocol=%s\n",
548 impl_share
->sharepath
, protocol
);
552 found_protocol
= B_FALSE
;
555 while (fstype
!= NULL
) {
556 if (protocol
== NULL
|| strcmp(fstype
->name
, protocol
) == 0) {
557 rc
= fstype
->ops
->disable_share(impl_share
);
560 fstype
->ops
->clear_shareopts(impl_share
);
562 FSINFO(impl_share
, fstype
)->active
= B_FALSE
;
566 found_protocol
= B_TRUE
;
569 fstype
= fstype
->next
;
572 update_sharetab(impl_share
->handle
);
574 return (found_protocol
? ret
: SA_INVALID_PROTOCOL
);
580 * convert an error value to an error string
585 static char errstr
[32];
590 ret
= dgettext(TEXT_DOMAIN
, "ok");
592 case SA_NO_SUCH_PATH
:
593 ret
= dgettext(TEXT_DOMAIN
, "path doesn't exist");
596 ret
= dgettext(TEXT_DOMAIN
, "no memory");
598 case SA_DUPLICATE_NAME
:
599 ret
= dgettext(TEXT_DOMAIN
, "name in use");
602 ret
= dgettext(TEXT_DOMAIN
, "bad path");
604 case SA_NO_SUCH_GROUP
:
605 ret
= dgettext(TEXT_DOMAIN
, "no such group");
608 ret
= dgettext(TEXT_DOMAIN
, "configuration error");
611 ret
= dgettext(TEXT_DOMAIN
, "system error");
614 ret
= dgettext(TEXT_DOMAIN
, "syntax error");
616 case SA_NO_PERMISSION
:
617 ret
= dgettext(TEXT_DOMAIN
, "no permission");
620 ret
= dgettext(TEXT_DOMAIN
, "busy");
622 case SA_NO_SUCH_PROP
:
623 ret
= dgettext(TEXT_DOMAIN
, "no such property");
625 case SA_INVALID_NAME
:
626 ret
= dgettext(TEXT_DOMAIN
, "invalid name");
628 case SA_INVALID_PROTOCOL
:
629 ret
= dgettext(TEXT_DOMAIN
, "invalid protocol");
632 ret
= dgettext(TEXT_DOMAIN
, "operation not allowed");
635 ret
= dgettext(TEXT_DOMAIN
, "bad property value");
637 case SA_INVALID_SECURITY
:
638 ret
= dgettext(TEXT_DOMAIN
, "invalid security type");
640 case SA_NO_SUCH_SECURITY
:
641 ret
= dgettext(TEXT_DOMAIN
, "security type not found");
643 case SA_VALUE_CONFLICT
:
644 ret
= dgettext(TEXT_DOMAIN
, "property value conflict");
646 case SA_NOT_IMPLEMENTED
:
647 ret
= dgettext(TEXT_DOMAIN
, "not implemented");
649 case SA_INVALID_PATH
:
650 ret
= dgettext(TEXT_DOMAIN
, "invalid path");
652 case SA_NOT_SUPPORTED
:
653 ret
= dgettext(TEXT_DOMAIN
, "operation not supported");
655 case SA_PROP_SHARE_ONLY
:
656 ret
= dgettext(TEXT_DOMAIN
, "property not valid for group");
659 ret
= dgettext(TEXT_DOMAIN
, "not shared");
661 case SA_NO_SUCH_RESOURCE
:
662 ret
= dgettext(TEXT_DOMAIN
, "no such resource");
664 case SA_RESOURCE_REQUIRED
:
665 ret
= dgettext(TEXT_DOMAIN
, "resource name required");
667 case SA_MULTIPLE_ERROR
:
668 ret
= dgettext(TEXT_DOMAIN
, "errors from multiple protocols");
670 case SA_PATH_IS_SUBDIR
:
671 ret
= dgettext(TEXT_DOMAIN
, "path is a subpath of share");
673 case SA_PATH_IS_PARENTDIR
:
674 ret
= dgettext(TEXT_DOMAIN
, "path is parent of a share");
677 ret
= dgettext(TEXT_DOMAIN
, "protocol requires a section");
679 case SA_NO_PROPERTIES
:
680 ret
= dgettext(TEXT_DOMAIN
, "properties not found");
682 case SA_NO_SUCH_SECTION
:
683 ret
= dgettext(TEXT_DOMAIN
, "section not found");
685 case SA_PASSWORD_ENC
:
686 ret
= dgettext(TEXT_DOMAIN
, "passwords must be encrypted");
688 case SA_SHARE_EXISTS
:
689 ret
= dgettext(TEXT_DOMAIN
, "path or file is already shared");
692 (void) snprintf(errstr
, sizeof (errstr
),
693 dgettext(TEXT_DOMAIN
, "unknown %d"), err
);
700 sa_parse_legacy_options(sa_group_t group
, char *options
, char *proto
)
705 fprintf(stderr
, "sa_parse_legacy_options: options=%s, proto=%s\n",
710 while (fstype
!= NULL
) {
711 if (strcmp(fstype
->name
, proto
) != 0) {
712 fstype
= fstype
->next
;
716 return fstype
->ops
->validate_shareopts(options
);
719 return SA_INVALID_PROTOCOL
;
723 sa_needs_refresh(sa_handle_t handle
)
729 sa_get_zfs_handle(sa_handle_t handle
)
731 sa_handle_impl_t impl_handle
= (sa_handle_impl_t
)handle
;
733 if (impl_handle
== NULL
)
736 return impl_handle
->zfs_libhandle
;
739 static sa_share_impl_t
740 alloc_share(const char *sharepath
)
742 sa_share_impl_t impl_share
;
744 impl_share
= calloc(sizeof (struct sa_share_impl
), 1);
746 if (impl_share
== NULL
)
749 impl_share
->sharepath
= strdup(sharepath
);
751 if (impl_share
->sharepath
== NULL
) {
756 impl_share
->fsinfo
= calloc(sizeof (sa_share_fsinfo_t
), fstypes_count
);
758 if (impl_share
->fsinfo
== NULL
) {
759 free(impl_share
->sharepath
);
768 free_share(sa_share_impl_t impl_share
) {
772 while (fstype
!= NULL
) {
773 fstype
->ops
->clear_shareopts(impl_share
);
775 free(FSINFO(impl_share
, fstype
)->resource
);
777 fstype
= fstype
->next
;
780 free(impl_share
->sharepath
);
781 free(impl_share
->dataset
);
782 free(impl_share
->fsinfo
);
787 sa_zfs_process_share(sa_handle_t handle
, sa_group_t group
, sa_share_t share
,
788 char *mountpoint
, char *proto
, zprop_source_t source
, char *shareopts
,
789 char *sourcestr
, char *dataset
)
791 sa_handle_impl_t impl_handle
= (sa_handle_impl_t
)handle
;
792 sa_share_impl_t impl_share
= (sa_share_impl_t
)share
;
795 fprintf(stderr
, "sa_zfs_process_share: mountpoint=%s, proto=%s, "
796 "shareopts=%s, sourcestr=%s, dataset=%s\n", mountpoint
, proto
,
797 shareopts
, sourcestr
, dataset
);
800 return process_share(impl_handle
, impl_share
, mountpoint
, NULL
,
801 proto
, shareopts
, NULL
, dataset
, B_FALSE
);
805 sa_update_sharetab_ts(sa_handle_t handle
)
807 sa_handle_impl_t impl_handle
= (sa_handle_impl_t
)handle
;
809 update_sharetab(impl_handle
);