Implemented sharing datasets via NFS using libshare.
[zfs.git] / lib / libzfs / libzfs_mount.c
index 75ce367..7b9cd80 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);
@@ -288,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;
@@ -329,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.
  */
@@ -344,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
@@ -358,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);
 
@@ -386,8 +442,7 @@ 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.
         */
-       if (strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
-           !dir_is_empty(mountpoint)) {
+       if (!remount && !dir_is_empty(mountpoint)) {
                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                    "directory is not empty"));
                return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
@@ -428,6 +483,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);
@@ -439,8 +498,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));
@@ -619,12 +680,12 @@ _zfs_init_libshare(void)
        char path[MAXPATHLEN];
        char isa[MAXISALEN];
 
-#if defined(_LP64)
+/*#if defined(_LP64)
        if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
                isa[0] = '\0';
-#else
+#else*/
        isa[0] = '\0';
-#endif
+/*#endif*/
        (void) snprintf(path, MAXPATHLEN,
            "/usr/lib/%s/libshare.so.1", isa);
 
@@ -1225,7 +1286,7 @@ mountpoint_compare(const void *a, const void *b)
  * Unshare and unmount all datasets within the given pool.  We don't want to
  * rely on traversing the DSL to discover the filesystems within the pool,
  * because this may be expensive (if not all of them are mounted), and can fail
- * arbitrarily (on I/O error, for example).  Instead, we walk /etc/mnttab and
+ * arbitrarily (on I/O error, for example).  Instead, we walk /etc/mtab and
  * gather all the filesystems that are currently mounted.
  */
 int
@@ -1356,53 +1417,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 */