Implemented sharing datasets via NFS using libshare.
[zfs.git] / lib / libshare / libshare.c
diff --git a/lib/libshare/libshare.c b/lib/libshare/libshare.c
new file mode 100644 (file)
index 0000000..c34e839
--- /dev/null
@@ -0,0 +1,810 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Gunnar Beutner
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+#include <libintl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libzfs.h>
+#include <libshare.h>
+#include "libshare_impl.h"
+#include "nfs.h"
+
+static sa_share_impl_t find_share(sa_handle_impl_t handle,
+    const char *sharepath);
+static sa_share_impl_t alloc_share(const char *sharepath);
+static void free_share(sa_share_impl_t share);
+
+static void parse_sharetab(sa_handle_impl_t impl_handle);
+static int process_share(sa_handle_impl_t impl_handle,
+    sa_share_impl_t impl_share, char *pathname, char *resource,
+    char *fstype, char *options, char *description,
+    char *dataset, boolean_t from_sharetab);
+static void update_sharetab(sa_handle_impl_t impl_handle);
+
+static int update_zfs_share(sa_share_impl_t impl_handle, const char *proto);
+static int update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto);
+
+static int fstypes_count;
+static sa_fstype_t *fstypes;
+
+sa_fstype_t *
+register_fstype(const char *name, const sa_share_ops_t *ops)
+{
+       sa_fstype_t *fstype;
+
+       fstype = calloc(sizeof (sa_fstype_t), 1);
+
+       if (fstype == NULL)
+               return NULL;
+
+       fstype->name = name;
+       fstype->ops = ops;
+       fstype->fsinfo_index = fstypes_count;
+
+       fstypes_count++;
+
+       fstype->next = fstypes;
+       fstypes = fstype;
+
+       return fstype;
+}
+
+sa_handle_t
+sa_init(int init_service)
+{
+       sa_handle_impl_t impl_handle;
+
+       impl_handle = calloc(sizeof (struct sa_handle_impl), 1);
+
+       if (impl_handle == NULL)
+               return NULL;
+
+       impl_handle->zfs_libhandle = libzfs_init();
+
+       if (impl_handle->zfs_libhandle != NULL) {
+               libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
+       }
+
+       parse_sharetab(impl_handle);
+       update_zfs_shares(impl_handle, NULL);
+
+       return ((sa_handle_t)impl_handle);
+}
+
+__attribute__((constructor)) static void
+libshare_init(void)
+{
+       libshare_nfs_init();
+
+       /*
+        * This bit causes /etc/dfs/sharetab to be updated before libzfs gets a
+        * chance to read that file; this is necessary because the sharetab file
+        * might be out of sync with the NFS kernel exports (e.g. due to reboots
+        * or users manually removing shares)
+        */
+       sa_fini(sa_init(0));
+}
+
+static void
+parse_sharetab(sa_handle_impl_t impl_handle) {
+       FILE *fp;
+       char line[512];
+       char *eol, *pathname, *resource, *fstype, *options, *description;
+
+       fp = fopen("/etc/dfs/sharetab", "r");
+
+       if (fp == NULL)
+               return;
+
+       while (fgets(line, sizeof (line), fp) != NULL) {
+               eol = line + strlen(line) - 1;
+
+               while (eol >= line) {
+                       if (*eol != '\r' && *eol != '\n')
+                               break;
+
+                       *eol = '\0';
+                       eol--;
+               }
+
+               pathname = line;
+
+               if ((resource = strchr(pathname, '\t')) == NULL)
+                       continue;
+
+               *resource = '\0';
+               resource++;
+
+               if ((fstype = strchr(resource, '\t')) == NULL)
+                       continue;
+
+               *fstype = '\0';
+               fstype++;
+
+               if ((options = strchr(fstype, '\t')) == NULL)
+                       continue;
+
+               *options = '\0';
+               options++;
+
+               if ((description = strchr(fstype, '\t')) != NULL) {
+                       *description = '\0';
+                       description++;
+               }
+
+               if (strcmp(resource, "-") == 0)
+                       resource = NULL;
+
+               (void) process_share(impl_handle, NULL, pathname, resource,
+                   fstype, options, description, NULL, B_TRUE);
+       }
+
+       fclose(fp);
+}
+
+static void
+update_sharetab(sa_handle_impl_t impl_handle)
+{
+       sa_share_impl_t impl_share;
+       int temp_fd;
+       FILE *temp_fp;
+       char tempfile[] = "/etc/dfs/sharetab.XXXXXX";
+       sa_fstype_t *fstype;
+       const char *resource;
+
+       if (mkdir("/etc/dfs", 0755) < 0 && errno != EEXIST) {
+               return;
+       }
+
+       temp_fd = mkstemp(tempfile);
+
+       if (temp_fd < 0)
+               return;
+
+       temp_fp = fdopen(temp_fd, "w");
+
+       if (temp_fp == NULL)
+               return;
+
+       impl_share = impl_handle->shares;
+       while (impl_share != NULL) {
+               fstype = fstypes;
+               while (fstype != NULL) {
+                       if (FSINFO(impl_share, fstype)->active &&
+                           FSINFO(impl_share, fstype)->shareopts != NULL) {
+                               resource = FSINFO(impl_share, fstype)->resource;
+
+                               if (resource == NULL)
+                                       resource = "-";
+
+                               fprintf(temp_fp, "%s\t%s\t%s\t%s\n",
+                                   impl_share->sharepath, resource,
+                                   fstype->name,
+                                   FSINFO(impl_share, fstype)->shareopts);
+                       }
+
+                       fstype = fstype->next;
+               }
+
+               impl_share = impl_share->next;
+       }
+
+       fflush(temp_fp);
+       fsync(temp_fd);
+       fclose(temp_fp);
+
+       rename(tempfile, "/etc/dfs/sharetab");
+}
+
+typedef struct update_cookie_s {
+       sa_handle_impl_t handle;
+       const char *proto;
+} update_cookie_t;
+
+static int
+update_zfs_shares_cb(zfs_handle_t *zhp, void *pcookie)
+{
+       update_cookie_t *udata = (update_cookie_t *)pcookie;
+       char mountpoint[ZFS_MAXPROPLEN];
+       char shareopts[ZFS_MAXPROPLEN];
+       char *dataset;
+       zfs_type_t type = zfs_get_type(zhp);
+
+       if (type == ZFS_TYPE_FILESYSTEM &&
+           zfs_iter_filesystems(zhp, update_zfs_shares_cb, pcookie) != 0) {
+               zfs_close(zhp);
+               return 1;
+       }
+
+       if (type != ZFS_TYPE_FILESYSTEM) {
+               zfs_close(zhp);
+               return 0;
+       }
+
+       if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
+           sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
+               zfs_close(zhp);
+               return 0;
+       }
+
+       dataset = (char *)zfs_get_name(zhp);
+
+       if (dataset == NULL) {
+               zfs_close(zhp);
+               return 0;
+       }
+
+       if (!zfs_is_mounted(zhp, NULL)) {
+               zfs_close(zhp);
+               return 0;
+       }
+
+       if ((udata->proto == NULL || strcmp(udata->proto, "nfs") == 0) &&
+           zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
+           sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
+           strcmp(shareopts, "off") != 0) {
+               (void) process_share(udata->handle, NULL, mountpoint, NULL,
+                   "nfs", shareopts, NULL, dataset, B_FALSE);
+       }
+
+       if ((udata->proto == NULL || strcmp(udata->proto, "smb") == 0) &&
+           zfs_prop_get(zhp, ZFS_PROP_SHARESMB, shareopts,
+           sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
+           strcmp(shareopts, "off") != 0) {
+               (void) process_share(udata->handle, NULL, mountpoint, NULL,
+                   "smb", shareopts, NULL, dataset, B_FALSE);
+       }
+
+       zfs_close(zhp);
+
+       return 0;
+}
+
+static int
+update_zfs_share(sa_share_impl_t impl_share, const char *proto)
+{
+       sa_handle_impl_t impl_handle = impl_share->handle;
+       zfs_handle_t *zhp;
+       update_cookie_t udata;
+
+       if (impl_handle->zfs_libhandle == NULL)
+                       return SA_SYSTEM_ERR;
+
+       assert(impl_share->dataset != NULL);
+
+       zhp = zfs_open(impl_share->handle->zfs_libhandle, impl_share->dataset,
+           ZFS_TYPE_FILESYSTEM);
+
+       if (zhp == NULL)
+               return SA_SYSTEM_ERR;
+
+       udata.handle = impl_handle;
+       udata.proto = proto;
+       (void) update_zfs_shares_cb(zhp, &udata);
+
+       return SA_OK;
+}
+
+static int
+update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto)
+{
+       update_cookie_t udata;
+
+       if (impl_handle->zfs_libhandle == NULL)
+               return SA_SYSTEM_ERR;
+
+       udata.handle = impl_handle;
+       udata.proto = proto;
+       (void) zfs_iter_root(impl_handle->zfs_libhandle, update_zfs_shares_cb,
+           &udata);
+
+       return SA_OK;
+}
+
+static int
+process_share(sa_handle_impl_t impl_handle, sa_share_impl_t impl_share,
+    char *pathname, char *resource, char *proto,
+    char *options, char *description, char *dataset,
+    boolean_t from_sharetab)
+{
+       struct stat statbuf;
+       int rc;
+       char *resource_dup = NULL, *dataset_dup = NULL;
+       boolean_t new_share;
+       sa_fstype_t *fstype;
+
+       new_share = B_FALSE;
+
+       if (impl_share == NULL)
+               impl_share = find_share(impl_handle, pathname);
+
+       if (impl_share == NULL) {
+               if (lstat(pathname, &statbuf) != 0 ||
+                   !S_ISDIR(statbuf.st_mode))
+                       return SA_BAD_PATH;
+
+               impl_share = alloc_share(pathname);
+
+               if (impl_share == NULL) {
+                       rc = SA_NO_MEMORY;
+                       goto err;
+               }
+
+               new_share = B_TRUE;
+       }
+
+       if (dataset != NULL) {
+               dataset_dup = strdup(dataset);
+
+               if (dataset_dup == NULL) {
+                       rc = SA_NO_MEMORY;
+                       goto err;
+               }
+       }
+
+       free(impl_share->dataset);
+       impl_share->dataset = dataset_dup;
+
+       rc = SA_INVALID_PROTOCOL;
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               if (strcmp(fstype->name, proto) == 0) {
+                       if (resource != NULL) {
+                               resource_dup = strdup(resource);
+
+                               if (resource_dup == NULL) {
+                                       rc = SA_NO_MEMORY;
+                                       goto err;
+                               }
+                       }
+
+                       free(FSINFO(impl_share, fstype)->resource);
+                       FSINFO(impl_share, fstype)->resource = resource_dup;
+
+                       rc = fstype->ops->update_shareopts(impl_share,
+                           resource, options);
+
+                       if (rc == SA_OK && from_sharetab)
+                               FSINFO(impl_share, fstype)->active = B_TRUE;
+
+                       break;
+               }
+
+               fstype = fstype->next;
+       }
+
+       if (rc != SA_OK)
+               goto err;
+
+       if (new_share) {
+               impl_share->handle = impl_handle;
+
+               impl_share->next = impl_handle->shares;
+               impl_handle->shares = impl_share;
+
+       }
+
+err:
+       if (rc != SA_OK) {
+               if (new_share)
+                       free_share(impl_share);
+       }
+
+       return rc;
+}
+
+void
+sa_fini(sa_handle_t handle)
+{
+       sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
+       sa_share_impl_t impl_share, next;
+       sa_share_impl_t *pcurr;
+
+       if (impl_handle == NULL)
+               return;
+
+       /*
+        * clean up shares which don't have a non-NULL dataset property,
+        * which means they're in sharetab but we couldn't find their
+        * ZFS dataset.
+        */
+       pcurr = &(impl_handle->shares);
+       impl_share = *pcurr;
+       while (impl_share != NULL) {
+               next = impl_share->next;
+
+               if (impl_share->dataset == NULL) {
+                       /* remove item from the linked list */
+                       *pcurr = next;
+
+                       sa_disable_share(impl_share, NULL);
+
+                       free_share(impl_share);
+               } else {
+                       pcurr = &(impl_share->next);
+               }
+
+               impl_share = next;
+       }
+
+       update_sharetab(impl_handle);
+
+       if (impl_handle->zfs_libhandle != NULL)
+               libzfs_fini(impl_handle->zfs_libhandle);
+
+       impl_share = impl_handle->shares;
+       while (impl_share != NULL) {
+               next = impl_share->next;
+               free_share(impl_share);
+               impl_share = next;
+       }
+
+       free(impl_handle);
+}
+
+static sa_share_impl_t
+find_share(sa_handle_impl_t impl_handle, const char *sharepath)
+{
+       sa_share_impl_t impl_share;
+
+       impl_share = impl_handle->shares;
+       while (impl_share != NULL) {
+               if (strcmp(impl_share->sharepath, sharepath) == 0) {
+                       break;
+               }
+
+               impl_share = impl_share->next;
+       }
+
+       return impl_share;
+}
+
+sa_share_t
+sa_find_share(sa_handle_t handle, char *sharepath)
+{
+       return (sa_share_t)find_share((sa_handle_impl_t)handle, sharepath);
+}
+
+int
+sa_enable_share(sa_share_t share, char *protocol)
+{
+       sa_share_impl_t impl_share = (sa_share_impl_t)share;
+       int rc, ret;
+       boolean_t found_protocol;
+       sa_fstype_t *fstype;
+
+#ifdef DEBUG
+       fprintf(stderr, "sa_enable_share: share->sharepath=%s, protocol=%s\n",
+               impl_share->sharepath, protocol);
+#endif
+
+       assert(impl_share->handle != NULL);
+
+       ret = SA_OK;
+       found_protocol = B_FALSE;
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
+                       update_zfs_share(impl_share, fstype->name);
+
+                       rc = fstype->ops->enable_share(impl_share);
+
+                       if (rc != SA_OK)
+                               ret = rc;
+                       else
+                               FSINFO(impl_share, fstype)->active = B_TRUE;
+
+                       found_protocol = B_TRUE;
+               }
+
+               fstype = fstype->next;
+       }
+
+       update_sharetab(impl_share->handle);
+
+       return (found_protocol ? ret : SA_INVALID_PROTOCOL);
+}
+
+int
+sa_disable_share(sa_share_t share, char *protocol)
+{
+       sa_share_impl_t impl_share = (sa_share_impl_t)share;
+       int rc, ret;
+       boolean_t found_protocol;
+       sa_fstype_t *fstype;
+
+#ifdef DEBUG
+       fprintf(stderr, "sa_disable_share: share->sharepath=%s, protocol=%s\n",
+               impl_share->sharepath, protocol);
+#endif
+
+       ret = SA_OK;
+       found_protocol = B_FALSE;
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
+                       rc = fstype->ops->disable_share(impl_share);
+
+                       if (rc == SA_OK) {
+                               fstype->ops->clear_shareopts(impl_share);
+
+                               FSINFO(impl_share, fstype)->active = B_FALSE;
+                       } else
+                               ret = rc;
+
+                       found_protocol = B_TRUE;
+               }
+
+               fstype = fstype->next;
+       }
+
+       update_sharetab(impl_share->handle);
+
+       return (found_protocol ? ret : SA_INVALID_PROTOCOL);
+}
+
+/*
+ * sa_errorstr(err)
+ *
+ * convert an error value to an error string
+ */
+char *
+sa_errorstr(int err)
+{
+       static char errstr[32];
+       char *ret = NULL;
+
+       switch (err) {
+       case SA_OK:
+               ret = dgettext(TEXT_DOMAIN, "ok");
+               break;
+       case SA_NO_SUCH_PATH:
+               ret = dgettext(TEXT_DOMAIN, "path doesn't exist");
+               break;
+       case SA_NO_MEMORY:
+               ret = dgettext(TEXT_DOMAIN, "no memory");
+               break;
+       case SA_DUPLICATE_NAME:
+               ret = dgettext(TEXT_DOMAIN, "name in use");
+               break;
+       case SA_BAD_PATH:
+               ret = dgettext(TEXT_DOMAIN, "bad path");
+               break;
+       case SA_NO_SUCH_GROUP:
+               ret = dgettext(TEXT_DOMAIN, "no such group");
+               break;
+       case SA_CONFIG_ERR:
+               ret = dgettext(TEXT_DOMAIN, "configuration error");
+               break;
+       case SA_SYSTEM_ERR:
+               ret = dgettext(TEXT_DOMAIN, "system error");
+               break;
+       case SA_SYNTAX_ERR:
+               ret = dgettext(TEXT_DOMAIN, "syntax error");
+               break;
+       case SA_NO_PERMISSION:
+               ret = dgettext(TEXT_DOMAIN, "no permission");
+               break;
+       case SA_BUSY:
+               ret = dgettext(TEXT_DOMAIN, "busy");
+               break;
+       case SA_NO_SUCH_PROP:
+               ret = dgettext(TEXT_DOMAIN, "no such property");
+               break;
+       case SA_INVALID_NAME:
+               ret = dgettext(TEXT_DOMAIN, "invalid name");
+               break;
+       case SA_INVALID_PROTOCOL:
+               ret = dgettext(TEXT_DOMAIN, "invalid protocol");
+               break;
+       case SA_NOT_ALLOWED:
+               ret = dgettext(TEXT_DOMAIN, "operation not allowed");
+               break;
+       case SA_BAD_VALUE:
+               ret = dgettext(TEXT_DOMAIN, "bad property value");
+               break;
+       case SA_INVALID_SECURITY:
+               ret = dgettext(TEXT_DOMAIN, "invalid security type");
+               break;
+       case SA_NO_SUCH_SECURITY:
+               ret = dgettext(TEXT_DOMAIN, "security type not found");
+               break;
+       case SA_VALUE_CONFLICT:
+               ret = dgettext(TEXT_DOMAIN, "property value conflict");
+               break;
+       case SA_NOT_IMPLEMENTED:
+               ret = dgettext(TEXT_DOMAIN, "not implemented");
+               break;
+       case SA_INVALID_PATH:
+               ret = dgettext(TEXT_DOMAIN, "invalid path");
+               break;
+       case SA_NOT_SUPPORTED:
+               ret = dgettext(TEXT_DOMAIN, "operation not supported");
+               break;
+       case SA_PROP_SHARE_ONLY:
+               ret = dgettext(TEXT_DOMAIN, "property not valid for group");
+               break;
+       case SA_NOT_SHARED:
+               ret = dgettext(TEXT_DOMAIN, "not shared");
+               break;
+       case SA_NO_SUCH_RESOURCE:
+               ret = dgettext(TEXT_DOMAIN, "no such resource");
+               break;
+       case SA_RESOURCE_REQUIRED:
+               ret = dgettext(TEXT_DOMAIN, "resource name required");
+               break;
+       case SA_MULTIPLE_ERROR:
+               ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
+               break;
+       case SA_PATH_IS_SUBDIR:
+               ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
+               break;
+       case SA_PATH_IS_PARENTDIR:
+               ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
+               break;
+       case SA_NO_SECTION:
+               ret = dgettext(TEXT_DOMAIN, "protocol requires a section");
+               break;
+       case SA_NO_PROPERTIES:
+               ret = dgettext(TEXT_DOMAIN, "properties not found");
+               break;
+       case SA_NO_SUCH_SECTION:
+               ret = dgettext(TEXT_DOMAIN, "section not found");
+               break;
+       case SA_PASSWORD_ENC:
+               ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
+               break;
+       case SA_SHARE_EXISTS:
+               ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
+               break;
+       default:
+               (void) snprintf(errstr, sizeof (errstr),
+                   dgettext(TEXT_DOMAIN, "unknown %d"), err);
+               ret = errstr;
+       }
+       return (ret);
+}
+
+int
+sa_parse_legacy_options(sa_group_t group, char *options, char *proto)
+{
+       sa_fstype_t *fstype;
+
+#ifdef DEBUG
+       fprintf(stderr, "sa_parse_legacy_options: options=%s, proto=%s\n",
+               options, proto);
+#endif
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               if (strcmp(fstype->name, proto) != 0) {
+                       fstype = fstype->next;
+                       continue;
+               }
+
+               return fstype->ops->validate_shareopts(options);
+       }
+
+       return SA_INVALID_PROTOCOL;
+}
+
+boolean_t
+sa_needs_refresh(sa_handle_t handle)
+{
+       return B_TRUE;
+}
+
+libzfs_handle_t *
+sa_get_zfs_handle(sa_handle_t handle)
+{
+       sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
+
+       if (impl_handle == NULL)
+               return NULL;
+
+       return impl_handle->zfs_libhandle;
+}
+
+static sa_share_impl_t
+alloc_share(const char *sharepath)
+{
+       sa_share_impl_t impl_share;
+
+       impl_share = calloc(sizeof (struct sa_share_impl), 1);
+
+       if (impl_share == NULL)
+               return NULL;
+
+       impl_share->sharepath = strdup(sharepath);
+
+       if (impl_share->sharepath == NULL) {
+               free(impl_share);
+               return NULL;
+       }
+
+       impl_share->fsinfo = calloc(sizeof (sa_share_fsinfo_t), fstypes_count);
+
+       if (impl_share->fsinfo == NULL) {
+               free(impl_share->sharepath);
+               free(impl_share);
+               return NULL;
+       }
+
+       return impl_share;
+}
+
+static void
+free_share(sa_share_impl_t impl_share) {
+       sa_fstype_t *fstype;
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               fstype->ops->clear_shareopts(impl_share);
+
+               free(FSINFO(impl_share, fstype)->resource);
+
+               fstype = fstype->next;
+       }
+
+       free(impl_share->sharepath);
+       free(impl_share->dataset);
+       free(impl_share->fsinfo);
+       free(impl_share);
+}
+
+int
+sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
+    char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
+    char *sourcestr, char *dataset)
+{
+       sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
+       sa_share_impl_t impl_share = (sa_share_impl_t)share;
+
+#ifdef DEBUG
+       fprintf(stderr, "sa_zfs_process_share: mountpoint=%s, proto=%s, "
+           "shareopts=%s, sourcestr=%s, dataset=%s\n", mountpoint, proto,
+           shareopts, sourcestr, dataset);
+#endif
+
+       return process_share(impl_handle, impl_share, mountpoint, NULL,
+           proto, shareopts, NULL, dataset, B_FALSE);
+}
+
+void
+sa_update_sharetab_ts(sa_handle_t handle)
+{
+       sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
+
+       update_sharetab(impl_handle);
+}