No point in rewind() mtab in zfs_unshare_proto(). We're not really
[zfs.git] / lib / libzfs / libzfs_mount.c
index 977b2ee..bded1f0 100644 (file)
@@ -72,9 +72,6 @@
 #include <sys/mntent.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
-#ifdef HAVE_LIBSELINUX
-#include <selinux/selinux.h>
-#endif /* HAVE_LIBSELINUX */
 
 #include <libzfs.h>
 
@@ -84,7 +81,6 @@
 #include <sys/systeminfo.h>
 #define        MAXISALEN       257     /* based on sysinfo(2) man page */
 
-#ifdef HAVE_ZPL
 static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
 zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
     zfs_share_proto_t);
@@ -121,21 +117,20 @@ zfs_share_proto_t share_all_proto[] = {
 };
 
 /*
- * Search for NFS and SMB exports for the given mountpoint and protocol, returning
+ * Search the sharetab for the given mountpoint and protocol, returning
  * a zfs_share_type_t value.
  */
 static zfs_share_type_t
 is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
 {
        char buf[MAXPATHLEN], *tab;
+       char *ptr;
 
        if (hdl->libzfs_sharetab == NULL)
                return (SHARED_NOT_SHARED);
 
        (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
 
-       /* Search /etc/exports for NFS exports */
-       /* FIXME: Assumes the file is tab delimited. */
        while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
 
                /* the mountpoint is the first entry on each line */
@@ -144,15 +139,31 @@ is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
 
                *tab = '\0';
                if (strcmp(buf, mountpoint) == 0) {
-                       if (proto == PROTO_NFS)
-                               return (SHARED_NFS);
-                       else
-                               return (SHARED_NOT_SHARED);
+                       /*
+                        * the protocol field is the third field
+                        * skip over second field
+                        */
+                       ptr = ++tab;
+                       if ((tab = strchr(ptr, '\t')) == NULL)
+                               continue;
+                       ptr = ++tab;
+                       if ((tab = strchr(ptr, '\t')) == NULL)
+                               continue;
+                       *tab = '\0';
+                       if (strcmp(ptr,
+                           proto_table[proto].p_name) == 0) {
+                               switch (proto) {
+                               case PROTO_NFS:
+                                       return (SHARED_NFS);
+                               case PROTO_SMB:
+                                       return (SHARED_SMB);
+                               default:
+                                       return (0);
+                               }
+                       }
                }
        }
 
-       /* XXX: Search /etc/samba/smb.conf for SMB exports, return SHARED_SMB */
-
        return (SHARED_NOT_SHARED);
 }
 
@@ -273,7 +284,7 @@ do_mount(const char *src, const char *mntpt, char *opts)
        int rc;
 
        /* Return only the most critical mount error */
-       rc = libzfs_run_process(argv[0], argv);
+       rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE);
        if (rc) {
                if (rc & MOUNT_FILEIO)
                        return EIO;
@@ -314,11 +325,57 @@ do_unmount(const char *mntpt, int flags)
        }
 
        argv[count] = (char *)mntpt;
-       rc = libzfs_run_process(argv[0], argv);
+       rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE);
 
        return (rc ? EINVAL : 0);
 }
 
+static int
+zfs_add_option(zfs_handle_t *zhp, char *options, int len,
+    zfs_prop_t prop, char *on, char *off)
+{
+       char *source;
+       uint64_t value;
+
+       /* Skip adding duplicate default options */
+       if ((strstr(options, on) != NULL) || (strstr(options, off) != NULL))
+               return (0);
+
+       /*
+        * zfs_prop_get_int() to not used to ensure our mount options
+        * are not influenced by the current /etc/mtab contents.
+        */
+       value = getprop_uint64(zhp, prop, &source);
+
+       (void) strlcat(options, ",", len);
+       (void) strlcat(options, value ? on : off, len);
+
+       return (0);
+}
+
+static int
+zfs_add_options(zfs_handle_t *zhp, char *options, int len)
+{
+       int error = 0;
+
+       error = zfs_add_option(zhp, options, len,
+           ZFS_PROP_ATIME, MNTOPT_ATIME, MNTOPT_NOATIME);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_DEVICES, MNTOPT_DEVICES, MNTOPT_NODEVICES);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_EXEC, MNTOPT_EXEC, MNTOPT_NOEXEC);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_READONLY, MNTOPT_RO, MNTOPT_RW);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_SETUID, MNTOPT_SETUID, MNTOPT_NOSETUID);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_XATTR, MNTOPT_XATTR, MNTOPT_NOXATTR);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_NBMAND, MNTOPT_NBMAND, MNTOPT_NONBMAND);
+
+       return (error);
+}
+
 /*
  * Mount the given filesystem.
  */
@@ -329,12 +386,16 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
        char mountpoint[ZFS_MAXPROPLEN];
        char mntopts[MNT_LINE_MAX];
        libzfs_handle_t *hdl = zhp->zfs_hdl;
-       int rc;
+       int remount = 0, rc;
 
-       if (options == NULL)
+       if (options == NULL) {
                (void) strlcpy(mntopts, MNTOPT_DEFAULTS, sizeof (mntopts));
-       else
+       } else {
                (void) strlcpy(mntopts, options, sizeof (mntopts));
+       }
+
+       if (strstr(mntopts, MNTOPT_REMOUNT) != NULL)
+               remount = 1;
 
        /*
         * If the pool is imported read-only then all mounts must be read-only
@@ -343,16 +404,26 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
                (void) strlcat(mntopts, "," MNTOPT_RO, sizeof (mntopts));
 
        /*
+        * Append default mount options which apply to the mount point.
+        * This is done because under Linux (unlike Solaris) multiple mount
+        * points may reference a single super block.  This means that just
+        * given a super block there is no back reference to update the per
+        * mount point options.
+        */
+       rc = zfs_add_options(zhp, mntopts, sizeof (mntopts));
+       if (rc) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "default options unavailable"));
+               return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
+                   dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
+                   mountpoint));
+       }
+
+       /*
         * Append zfsutil option so the mount helper allow the mount
         */
        strlcat(mntopts, "," MNTOPT_ZFSUTIL, sizeof (mntopts));
 
-#ifdef HAVE_LIBSELINUX
-       if (is_selinux_enabled())
-               (void) strlcat(mntopts, ",context=\"system_u:"
-                   "object_r:file_t:s0\"", sizeof (mntopts));
-#endif /* HAVE_LIBSELINUX */
-
        if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
                return (0);
 
@@ -369,9 +440,10 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
 
        /*
         * Determine if the mountpoint is empty.  If so, refuse to perform the
-        * mount.  We don't perform this check if 'remount' is specified.
+        * mount.  We don't perform this check if 'remount' is
+        * specified or if overlay option(-O) is given
         */
-       if (strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
+       if ((flags & MS_OVERLAY) == 0 && !remount &&
            !dir_is_empty(mountpoint)) {
                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                    "directory is not empty"));
@@ -413,6 +485,10 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
                    zhp->zfs_name));
        }
 
+       /* remove the mounted entry before re-adding on remount */
+       if (remount)
+               libzfs_mnttab_remove(hdl, zhp->zfs_name);
+
        /* add the mounted entry into our cache */
        libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint, mntopts);
        return (0);
@@ -424,8 +500,10 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
 static int
 unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
 {
-       if (do_unmount(mountpoint, flags) != 0) {
-               zfs_error_aux(hdl, strerror(errno));
+       int error;
+
+       error = do_unmount(mountpoint, flags);
+       if (error != 0) {
                return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
                    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
                    mountpoint));
@@ -566,97 +644,6 @@ zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
 }
 
 /*
- * Make sure things will work if libshare isn't installed by using
- * wrapper functions that check to see that the pointers to functions
- * initialized in _zfs_init_libshare() are actually present.
- */
-
-static sa_handle_t (*_sa_init)(int);
-static void (*_sa_fini)(sa_handle_t);
-static sa_share_t (*_sa_find_share)(sa_handle_t, char *);
-static int (*_sa_enable_share)(sa_share_t, char *);
-static int (*_sa_disable_share)(sa_share_t, char *);
-static char *(*_sa_errorstr)(int);
-static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *);
-static boolean_t (*_sa_needs_refresh)(sa_handle_t *);
-static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t);
-static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t,
-    char *, char *, zprop_source_t, char *, char *, char *);
-static void (*_sa_update_sharetab_ts)(sa_handle_t);
-
-/*
- * _zfs_init_libshare()
- *
- * Find the libshare.so.1 entry points that we use here and save the
- * values to be used later. This is triggered by the runtime loader.
- * Make sure the correct ISA version is loaded.
- */
-#ifdef __GNUC__
-static void
-_zfs_init_libshare(void) __attribute__((constructor));
-#else
-#pragma init(_zfs_init_libshare)
-#endif
-static void
-_zfs_init_libshare(void)
-{
-       void *libshare;
-       char path[MAXPATHLEN];
-       char isa[MAXISALEN];
-
-#if defined(_LP64)
-       if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
-               isa[0] = '\0';
-#else
-       isa[0] = '\0';
-#endif
-       (void) snprintf(path, MAXPATHLEN,
-           "/usr/lib/%s/libshare.so.1", isa);
-
-       if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) {
-               _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init");
-               _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini");
-               _sa_find_share = (sa_share_t (*)(sa_handle_t, char *))
-                   dlsym(libshare, "sa_find_share");
-               _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
-                   "sa_enable_share");
-               _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
-                   "sa_disable_share");
-               _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr");
-               _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *))
-                   dlsym(libshare, "sa_parse_legacy_options");
-               _sa_needs_refresh = (boolean_t (*)(sa_handle_t *))
-                   dlsym(libshare, "sa_needs_refresh");
-               _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t))
-                   dlsym(libshare, "sa_get_zfs_handle");
-               _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t,
-                   sa_share_t, char *, char *, zprop_source_t, char *,
-                   char *, char *))dlsym(libshare, "sa_zfs_process_share");
-               _sa_update_sharetab_ts = (void (*)(sa_handle_t))
-                   dlsym(libshare, "sa_update_sharetab_ts");
-               if (_sa_init == NULL || _sa_fini == NULL ||
-                   _sa_find_share == NULL || _sa_enable_share == NULL ||
-                   _sa_disable_share == NULL || _sa_errorstr == NULL ||
-                   _sa_parse_legacy_options == NULL ||
-                   _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL ||
-                   _sa_zfs_process_share == NULL ||
-                   _sa_update_sharetab_ts == NULL) {
-                       _sa_init = NULL;
-                       _sa_fini = NULL;
-                       _sa_disable_share = NULL;
-                       _sa_enable_share = NULL;
-                       _sa_errorstr = NULL;
-                       _sa_parse_legacy_options = NULL;
-                       (void) dlclose(libshare);
-                       _sa_needs_refresh = NULL;
-                       _sa_get_zfs_handle = NULL;
-                       _sa_zfs_process_share = NULL;
-                       _sa_update_sharetab_ts = NULL;
-               }
-       }
-}
-
-/*
  * zfs_init_libshare(zhandle, service)
  *
  * Initialize the libshare API if it hasn't already been initialized.
@@ -669,9 +656,6 @@ zfs_init_libshare(libzfs_handle_t *zhandle, int service)
 {
        int ret = SA_OK;
 
-       if (_sa_init == NULL)
-               ret = SA_CONFIG_ERR;
-
        if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) {
                /*
                 * We had a cache miss. Most likely it is a new ZFS
@@ -682,15 +666,14 @@ zfs_init_libshare(libzfs_handle_t *zhandle, int service)
                 * internal cache.
                 */
                zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS;
-               if (_sa_needs_refresh != NULL &&
-                   _sa_needs_refresh(zhandle->libzfs_sharehdl)) {
+               if (sa_needs_refresh(zhandle->libzfs_sharehdl)) {
                        zfs_uninit_libshare(zhandle);
-                       zhandle->libzfs_sharehdl = _sa_init(service);
+                       zhandle->libzfs_sharehdl = sa_init(service);
                }
        }
 
        if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL)
-               zhandle->libzfs_sharehdl = _sa_init(service);
+               zhandle->libzfs_sharehdl = sa_init(service);
 
        if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL)
                ret = SA_NO_MEMORY;
@@ -708,8 +691,7 @@ void
 zfs_uninit_libshare(libzfs_handle_t *zhandle)
 {
        if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
-               if (_sa_fini != NULL)
-                       _sa_fini(zhandle->libzfs_sharehdl);
+               sa_fini(zhandle->libzfs_sharehdl);
                zhandle->libzfs_sharehdl = NULL;
        }
 }
@@ -723,59 +705,14 @@ zfs_uninit_libshare(libzfs_handle_t *zhandle)
 int
 zfs_parse_options(char *options, zfs_share_proto_t proto)
 {
-       if (_sa_parse_legacy_options != NULL) {
-               return (_sa_parse_legacy_options(NULL, options,
-                   proto_table[proto].p_name));
-       }
-       return (SA_CONFIG_ERR);
-}
-
-/*
- * zfs_sa_find_share(handle, path)
- *
- * wrapper around sa_find_share to find a share path in the
- * configuration.
- */
-static sa_share_t
-zfs_sa_find_share(sa_handle_t handle, char *path)
-{
-       if (_sa_find_share != NULL)
-               return (_sa_find_share(handle, path));
-       return (NULL);
-}
-
-/*
- * zfs_sa_enable_share(share, proto)
- *
- * Wrapper for sa_enable_share which enables a share for a specified
- * protocol.
- */
-static int
-zfs_sa_enable_share(sa_share_t share, char *proto)
-{
-       if (_sa_enable_share != NULL)
-               return (_sa_enable_share(share, proto));
-       return (SA_CONFIG_ERR);
-}
-
-/*
- * zfs_sa_disable_share(share, proto)
- *
- * Wrapper for sa_enable_share which disables a share for a specified
- * protocol.
- */
-static int
-zfs_sa_disable_share(sa_share_t share, char *proto)
-{
-       if (_sa_disable_share != NULL)
-               return (_sa_disable_share(share, proto));
-       return (SA_CONFIG_ERR);
+       return (sa_parse_legacy_options(NULL, options,
+           proto_table[proto].p_name));
 }
 
 /*
  * Share the given filesystem according to the options in the specified
  * protocol specific properties (sharenfs, sharesmb).  We rely
- * on "libshare" to the dirty work for us.
+ * on "libshare" to do the dirty work for us.
  */
 static int
 zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
@@ -793,12 +730,9 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
                return (0);
 
        if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
-#ifdef HAVE_SHARE
                (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
                    dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
-                   zfs_get_name(zhp), _sa_errorstr != NULL ?
-                   _sa_errorstr(ret) : "");
-#endif /* HAVE_SHARE */
+                   zfs_get_name(zhp), sa_errorstr(ret));
                return (-1);
        }
 
@@ -821,7 +755,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
                if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
                        continue;
 
-               share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
+               share = sa_find_share(hdl->libzfs_sharehdl, mountpoint);
                if (share == NULL) {
                        /*
                         * This may be a new file system that was just
@@ -832,7 +766,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
                         * safe to add this to the internal
                         * configuration.
                         */
-                       if (_sa_zfs_process_share(hdl->libzfs_sharehdl,
+                       if (sa_zfs_process_share(hdl->libzfs_sharehdl,
                            NULL, NULL, mountpoint,
                            proto_table[*curr_proto].p_name, sourcetype,
                            shareopts, sourcestr, zhp->zfs_name) != SA_OK) {
@@ -843,12 +777,12 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
                                return (-1);
                        }
                        hdl->libzfs_shareflags |= ZFSSHARE_MISS;
-                       share = zfs_sa_find_share(hdl->libzfs_sharehdl,
+                       share = sa_find_share(hdl->libzfs_sharehdl,
                            mountpoint);
                }
                if (share != NULL) {
                        int err;
-                       err = zfs_sa_enable_share(share,
+                       err = sa_enable_share(share,
                            proto_table[*curr_proto].p_name);
                        if (err != SA_OK) {
                                (void) zfs_error_fmt(hdl,
@@ -910,18 +844,18 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
                free(mntpt);    /* don't need the copy anymore */
                return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
                    dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
-                   name, _sa_errorstr(err)));
+                   name, sa_errorstr(err)));
        }
 
-       share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt);
+       share = sa_find_share(hdl->libzfs_sharehdl, mntpt);
        free(mntpt);    /* don't need the copy anymore */
 
        if (share != NULL) {
-               err = zfs_sa_disable_share(share, proto_table[proto].p_name);
+               err = sa_disable_share(share, proto_table[proto].p_name);
                if (err != SA_OK) {
                        return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
                            dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
-                           name, _sa_errorstr(err)));
+                           name, sa_errorstr(err)));
                }
        } else {
                return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
@@ -943,7 +877,6 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
        char *mntpt = NULL;
 
        /* check to see if need to unmount the filesystem */
-       rewind(zhp->zfs_hdl->libzfs_mnttab);
        if (mountpoint != NULL)
                mountpoint = mntpt = zfs_strdup(hdl, mountpoint);
 
@@ -955,11 +888,11 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
                        mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
 
                for (curr_proto = proto; *curr_proto != PROTO_END;
-                   curr_proto++) {
+                    curr_proto++) {
 
                        if (is_shared(hdl, mntpt, *curr_proto) &&
                            unshare_one(hdl, zhp->zfs_name,
-                           mntpt, *curr_proto) != 0) {
+                                       mntpt, *curr_proto) != 0) {
                                if (mntpt != NULL)
                                        free(mntpt);
                                return (-1);
@@ -1343,53 +1276,3 @@ out:
 
        return (ret);
 }
-
-#else  /* HAVE_ZPL */
-
-int
-zfs_unshare_iscsi(zfs_handle_t *zhp)
-{
-       return 0;
-}
-
-int
-zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
-{
-       return 0;
-}
-
-void
-remove_mountpoint(zfs_handle_t *zhp) {
-       return;
-}
-
-boolean_t
-is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where)
-{
-       return B_FALSE;
-}
-
-boolean_t
-zfs_is_mounted(zfs_handle_t *zhp, char **where)
-{
-       return is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where);
-}
-
-boolean_t
-zfs_is_shared(zfs_handle_t *zhp)
-{
-       return B_FALSE;
-}
-
-int
-zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
-{
-       return B_FALSE;
-}
-
-int
-zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
-{
-       return B_FALSE;
-}
-#endif /* HAVE_ZPL */