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"
41 static sa_share_impl_t find_share(sa_handle_impl_t handle,
42 const char *sharepath);
43 static sa_share_impl_t alloc_share(const char *sharepath);
44 static void free_share(sa_share_impl_t share);
46 static void parse_sharetab(sa_handle_impl_t impl_handle);
47 static int process_share(sa_handle_impl_t impl_handle,
48 sa_share_impl_t impl_share, char *pathname, char *resource,
49 char *fstype, char *options, char *description,
50 char *dataset, boolean_t from_sharetab);
51 static void update_sharetab(sa_handle_impl_t impl_handle);
53 static int update_zfs_share(sa_share_impl_t impl_handle, const char *proto);
54 static int update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto);
56 static int fstypes_count;
57 static sa_fstype_t *fstypes;
60 register_fstype(const char *name, const sa_share_ops_t *ops)
64 fstype = calloc(sizeof (sa_fstype_t), 1);
71 fstype->fsinfo_index = fstypes_count;
75 fstype->next = fstypes;
82 sa_init(int init_service)
84 sa_handle_impl_t impl_handle;
86 impl_handle = calloc(sizeof (struct sa_handle_impl), 1);
88 if (impl_handle == NULL)
91 impl_handle->zfs_libhandle = libzfs_init();
93 if (impl_handle->zfs_libhandle != NULL) {
94 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
97 parse_sharetab(impl_handle);
98 update_zfs_shares(impl_handle, NULL);
100 return ((sa_handle_t)impl_handle);
103 __attribute__((constructor)) static void
110 * This bit causes /etc/dfs/sharetab to be updated before libzfs gets a
111 * chance to read that file; this is necessary because the sharetab file
112 * might be out of sync with the NFS kernel exports (e.g. due to reboots
113 * or users manually removing shares)
119 parse_sharetab(sa_handle_impl_t impl_handle) {
122 char *eol, *pathname, *resource, *fstype, *options, *description;
124 fp = fopen("/etc/dfs/sharetab", "r");
129 while (fgets(line, sizeof (line), fp) != NULL) {
130 eol = line + strlen(line) - 1;
132 while (eol >= line) {
133 if (*eol != '\r' && *eol != '\n')
142 if ((resource = strchr(pathname, '\t')) == NULL)
148 if ((fstype = strchr(resource, '\t')) == NULL)
154 if ((options = strchr(fstype, '\t')) == NULL)
160 if ((description = strchr(fstype, '\t')) != NULL) {
165 if (strcmp(resource, "-") == 0)
168 (void) process_share(impl_handle, NULL, pathname, resource,
169 fstype, options, description, NULL, B_TRUE);
176 update_sharetab(sa_handle_impl_t impl_handle)
178 sa_share_impl_t impl_share;
181 char tempfile[] = "/etc/dfs/sharetab.XXXXXX";
183 const char *resource;
185 if (mkdir("/etc/dfs", 0755) < 0 && errno != EEXIST) {
189 temp_fd = mkstemp(tempfile);
194 temp_fp = fdopen(temp_fd, "w");
199 impl_share = impl_handle->shares;
200 while (impl_share != NULL) {
202 while (fstype != NULL) {
203 if (FSINFO(impl_share, fstype)->active &&
204 FSINFO(impl_share, fstype)->shareopts != NULL) {
205 resource = FSINFO(impl_share, fstype)->resource;
207 if (resource == NULL)
210 fprintf(temp_fp, "%s\t%s\t%s\t%s\n",
211 impl_share->sharepath, resource,
213 FSINFO(impl_share, fstype)->shareopts);
216 fstype = fstype->next;
219 impl_share = impl_share->next;
226 rename(tempfile, "/etc/dfs/sharetab");
229 typedef struct update_cookie_s {
230 sa_handle_impl_t handle;
235 update_zfs_shares_cb(zfs_handle_t *zhp, void *pcookie)
237 update_cookie_t *udata = (update_cookie_t *)pcookie;
238 char mountpoint[ZFS_MAXPROPLEN];
239 char shareopts[ZFS_MAXPROPLEN];
241 zfs_type_t type = zfs_get_type(zhp);
243 if (type == ZFS_TYPE_FILESYSTEM &&
244 zfs_iter_filesystems(zhp, update_zfs_shares_cb, pcookie) != 0) {
249 if (type != ZFS_TYPE_FILESYSTEM) {
254 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
255 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
260 dataset = (char *)zfs_get_name(zhp);
262 if (dataset == NULL) {
267 if (!zfs_is_mounted(zhp, NULL)) {
272 if ((udata->proto == NULL || strcmp(udata->proto, "nfs") == 0) &&
273 zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
274 sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
275 strcmp(shareopts, "off") != 0) {
276 (void) process_share(udata->handle, NULL, mountpoint, NULL,
277 "nfs", shareopts, NULL, dataset, B_FALSE);
280 if ((udata->proto == NULL || strcmp(udata->proto, "smb") == 0) &&
281 zfs_prop_get(zhp, ZFS_PROP_SHARESMB, shareopts,
282 sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
283 strcmp(shareopts, "off") != 0) {
284 (void) process_share(udata->handle, NULL, mountpoint, NULL,
285 "smb", shareopts, NULL, dataset, B_FALSE);
294 update_zfs_share(sa_share_impl_t impl_share, const char *proto)
296 sa_handle_impl_t impl_handle = impl_share->handle;
298 update_cookie_t udata;
300 if (impl_handle->zfs_libhandle == NULL)
301 return (SA_SYSTEM_ERR);
303 assert(impl_share->dataset != NULL);
305 zhp = zfs_open(impl_share->handle->zfs_libhandle, impl_share->dataset,
306 ZFS_TYPE_FILESYSTEM);
309 return (SA_SYSTEM_ERR);
311 udata.handle = impl_handle;
313 (void) update_zfs_shares_cb(zhp, &udata);
319 update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto)
321 update_cookie_t udata;
323 if (impl_handle->zfs_libhandle == NULL)
324 return (SA_SYSTEM_ERR);
326 udata.handle = impl_handle;
328 (void) zfs_iter_root(impl_handle->zfs_libhandle, update_zfs_shares_cb,
335 process_share(sa_handle_impl_t impl_handle, sa_share_impl_t impl_share,
336 char *pathname, char *resource, char *proto,
337 char *options, char *description, char *dataset,
338 boolean_t from_sharetab)
342 char *resource_dup = NULL, *dataset_dup = NULL;
348 if (impl_share == NULL)
349 impl_share = find_share(impl_handle, pathname);
351 if (impl_share == NULL) {
352 if (lstat(pathname, &statbuf) != 0 ||
353 !S_ISDIR(statbuf.st_mode))
354 return (SA_BAD_PATH);
356 impl_share = alloc_share(pathname);
358 if (impl_share == NULL) {
366 if (dataset != NULL) {
367 dataset_dup = strdup(dataset);
369 if (dataset_dup == NULL) {
375 free(impl_share->dataset);
376 impl_share->dataset = dataset_dup;
378 rc = SA_INVALID_PROTOCOL;
381 while (fstype != NULL) {
382 if (strcmp(fstype->name, proto) == 0) {
383 if (resource != NULL) {
384 resource_dup = strdup(resource);
386 if (resource_dup == NULL) {
392 free(FSINFO(impl_share, fstype)->resource);
393 FSINFO(impl_share, fstype)->resource = resource_dup;
395 rc = fstype->ops->update_shareopts(impl_share,
398 if (rc == SA_OK && from_sharetab)
399 FSINFO(impl_share, fstype)->active = B_TRUE;
404 fstype = fstype->next;
411 impl_share->handle = impl_handle;
413 impl_share->next = impl_handle->shares;
414 impl_handle->shares = impl_share;
421 free_share(impl_share);
428 sa_fini(sa_handle_t handle)
430 sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
431 sa_share_impl_t impl_share, next;
432 sa_share_impl_t *pcurr;
434 if (impl_handle == NULL)
438 * clean up shares which don't have a non-NULL dataset property,
439 * which means they're in sharetab but we couldn't find their
442 pcurr = &(impl_handle->shares);
444 while (impl_share != NULL) {
445 next = impl_share->next;
447 if (impl_share->dataset == NULL) {
448 /* remove item from the linked list */
451 sa_disable_share(impl_share, NULL);
453 free_share(impl_share);
455 pcurr = &(impl_share->next);
461 update_sharetab(impl_handle);
463 if (impl_handle->zfs_libhandle != NULL)
464 libzfs_fini(impl_handle->zfs_libhandle);
466 impl_share = impl_handle->shares;
467 while (impl_share != NULL) {
468 next = impl_share->next;
469 free_share(impl_share);
476 static sa_share_impl_t
477 find_share(sa_handle_impl_t impl_handle, const char *sharepath)
479 sa_share_impl_t impl_share;
481 impl_share = impl_handle->shares;
482 while (impl_share != NULL) {
483 if (strcmp(impl_share->sharepath, sharepath) == 0) {
487 impl_share = impl_share->next;
494 sa_find_share(sa_handle_t handle, char *sharepath)
496 return ((sa_share_t)find_share((sa_handle_impl_t)handle, sharepath));
500 sa_enable_share(sa_share_t share, char *protocol)
502 sa_share_impl_t impl_share = (sa_share_impl_t)share;
504 boolean_t found_protocol;
508 fprintf(stderr, "sa_enable_share: share->sharepath=%s, protocol=%s\n",
509 impl_share->sharepath, protocol);
512 assert(impl_share->handle != NULL);
515 found_protocol = B_FALSE;
518 while (fstype != NULL) {
519 if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
520 update_zfs_share(impl_share, fstype->name);
522 rc = fstype->ops->enable_share(impl_share);
527 FSINFO(impl_share, fstype)->active = B_TRUE;
529 found_protocol = B_TRUE;
532 fstype = fstype->next;
535 update_sharetab(impl_share->handle);
537 return (found_protocol ? ret : SA_INVALID_PROTOCOL);
541 sa_disable_share(sa_share_t share, char *protocol)
543 sa_share_impl_t impl_share = (sa_share_impl_t)share;
545 boolean_t found_protocol;
549 fprintf(stderr, "sa_disable_share: share->sharepath=%s, protocol=%s\n",
550 impl_share->sharepath, protocol);
554 found_protocol = B_FALSE;
557 while (fstype != NULL) {
558 if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
559 rc = fstype->ops->disable_share(impl_share);
562 fstype->ops->clear_shareopts(impl_share);
564 FSINFO(impl_share, fstype)->active = B_FALSE;
568 found_protocol = B_TRUE;
571 fstype = fstype->next;
574 update_sharetab(impl_share->handle);
576 return (found_protocol ? ret : SA_INVALID_PROTOCOL);
582 * convert an error value to an error string
587 static char errstr[32];
592 ret = dgettext(TEXT_DOMAIN, "ok");
594 case SA_NO_SUCH_PATH:
595 ret = dgettext(TEXT_DOMAIN, "path doesn't exist");
598 ret = dgettext(TEXT_DOMAIN, "no memory");
600 case SA_DUPLICATE_NAME:
601 ret = dgettext(TEXT_DOMAIN, "name in use");
604 ret = dgettext(TEXT_DOMAIN, "bad path");
606 case SA_NO_SUCH_GROUP:
607 ret = dgettext(TEXT_DOMAIN, "no such group");
610 ret = dgettext(TEXT_DOMAIN, "configuration error");
613 ret = dgettext(TEXT_DOMAIN, "system error");
616 ret = dgettext(TEXT_DOMAIN, "syntax error");
618 case SA_NO_PERMISSION:
619 ret = dgettext(TEXT_DOMAIN, "no permission");
622 ret = dgettext(TEXT_DOMAIN, "busy");
624 case SA_NO_SUCH_PROP:
625 ret = dgettext(TEXT_DOMAIN, "no such property");
627 case SA_INVALID_NAME:
628 ret = dgettext(TEXT_DOMAIN, "invalid name");
630 case SA_INVALID_PROTOCOL:
631 ret = dgettext(TEXT_DOMAIN, "invalid protocol");
634 ret = dgettext(TEXT_DOMAIN, "operation not allowed");
637 ret = dgettext(TEXT_DOMAIN, "bad property value");
639 case SA_INVALID_SECURITY:
640 ret = dgettext(TEXT_DOMAIN, "invalid security type");
642 case SA_NO_SUCH_SECURITY:
643 ret = dgettext(TEXT_DOMAIN, "security type not found");
645 case SA_VALUE_CONFLICT:
646 ret = dgettext(TEXT_DOMAIN, "property value conflict");
648 case SA_NOT_IMPLEMENTED:
649 ret = dgettext(TEXT_DOMAIN, "not implemented");
651 case SA_INVALID_PATH:
652 ret = dgettext(TEXT_DOMAIN, "invalid path");
654 case SA_NOT_SUPPORTED:
655 ret = dgettext(TEXT_DOMAIN, "operation not supported");
657 case SA_PROP_SHARE_ONLY:
658 ret = dgettext(TEXT_DOMAIN, "property not valid for group");
661 ret = dgettext(TEXT_DOMAIN, "not shared");
663 case SA_NO_SUCH_RESOURCE:
664 ret = dgettext(TEXT_DOMAIN, "no such resource");
666 case SA_RESOURCE_REQUIRED:
667 ret = dgettext(TEXT_DOMAIN, "resource name required");
669 case SA_MULTIPLE_ERROR:
670 ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
672 case SA_PATH_IS_SUBDIR:
673 ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
675 case SA_PATH_IS_PARENTDIR:
676 ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
679 ret = dgettext(TEXT_DOMAIN, "protocol requires a section");
681 case SA_NO_PROPERTIES:
682 ret = dgettext(TEXT_DOMAIN, "properties not found");
684 case SA_NO_SUCH_SECTION:
685 ret = dgettext(TEXT_DOMAIN, "section not found");
687 case SA_PASSWORD_ENC:
688 ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
690 case SA_SHARE_EXISTS:
691 ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
694 (void) snprintf(errstr, sizeof (errstr),
695 dgettext(TEXT_DOMAIN, "unknown %d"), err);
702 sa_parse_legacy_options(sa_group_t group, char *options, char *proto)
707 fprintf(stderr, "sa_parse_legacy_options: options=%s, proto=%s\n",
712 while (fstype != NULL) {
713 if (strcmp(fstype->name, proto) != 0) {
714 fstype = fstype->next;
718 return (fstype->ops->validate_shareopts(options));
721 return (SA_INVALID_PROTOCOL);
725 sa_needs_refresh(sa_handle_t handle)
731 sa_get_zfs_handle(sa_handle_t handle)
733 sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
735 if (impl_handle == NULL)
738 return (impl_handle->zfs_libhandle);
741 static sa_share_impl_t
742 alloc_share(const char *sharepath)
744 sa_share_impl_t impl_share;
746 impl_share = calloc(sizeof (struct sa_share_impl), 1);
748 if (impl_share == NULL)
751 impl_share->sharepath = strdup(sharepath);
753 if (impl_share->sharepath == NULL) {
758 impl_share->fsinfo = calloc(sizeof (sa_share_fsinfo_t), fstypes_count);
760 if (impl_share->fsinfo == NULL) {
761 free(impl_share->sharepath);
770 free_share(sa_share_impl_t impl_share) {
774 while (fstype != NULL) {
775 fstype->ops->clear_shareopts(impl_share);
777 free(FSINFO(impl_share, fstype)->resource);
779 fstype = fstype->next;
782 free(impl_share->sharepath);
783 free(impl_share->dataset);
784 free(impl_share->fsinfo);
789 sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
790 char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
791 char *sourcestr, char *dataset)
793 sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
794 sa_share_impl_t impl_share = (sa_share_impl_t)share;
797 fprintf(stderr, "sa_zfs_process_share: mountpoint=%s, proto=%s, "
798 "shareopts=%s, sourcestr=%s, dataset=%s\n", mountpoint, proto,
799 shareopts, sourcestr, dataset);
802 return (process_share(impl_handle, impl_share, mountpoint, NULL,
803 proto, shareopts, NULL, dataset, B_FALSE));
807 sa_update_sharetab_ts(sa_handle_t handle)
809 sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
811 update_sharetab(impl_handle);