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);