/*
 * Remove the mountpoint associated with the current dataset, if necessary.
 * We only remove the underlying directory if:
 *
 *	- The mountpoint is not 'none' or 'legacy'
 *	- The mountpoint is non-empty
 *	- The mountpoint is the default or inherited
 *	- The 'zoned' property is set, or we're in a local zone
 *
 * Any other directories we leave alone.
 */
void
remove_mountpoint(zfs_handle_t *zhp)
{
	char mountpoint[ZFS_MAXPROPLEN];
	zprop_source_t source;

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
	    &source))
		return;

	if (source == ZPROP_SRC_DEFAULT ||
	    source == ZPROP_SRC_INHERITED) {
		/*
		 * Try to remove the directory, silently ignoring any errors.
		 * The filesystem may have since been removed or moved around,
		 * and this error isn't really useful to the administrator in
		 * any way.
		 */
		(void) rmdir(mountpoint);
	}
}
/*
 * 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.
 */
static int
zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
{
	char mountpoint[ZFS_MAXPROPLEN];
	char shareopts[ZFS_MAXPROPLEN];
	char sourcestr[ZFS_MAXPROPLEN];
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	sa_share_t share;
	zfs_share_proto_t *curr_proto;
	zprop_source_t sourcetype;
	int ret;

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
		return (0);

	if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
		(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
		    dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
		    zfs_get_name(zhp), sa_errorstr(ret));
		return (-1);
	}

	for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
		/*
		 * Return success if there are no share options.
		 */
		if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
		    shareopts, sizeof (shareopts), &sourcetype, sourcestr,
		    ZFS_MAXPROPLEN, B_FALSE) != 0 ||
		    strcmp(shareopts, "off") == 0)
			continue;

		/*
		 * If the 'zoned' property is set, then zfs_is_mountable()
		 * will have already bailed out if we are in the global zone.
		 * But local zones cannot be NFS servers, so we ignore it for
		 * local zones as well.
		 */
		if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
			continue;

		share = sa_find_share(hdl->libzfs_sharehdl, mountpoint);
		if (share == NULL) {
			/*
			 * This may be a new file system that was just
			 * created so isn't in the internal cache
			 * (second time through). Rather than
			 * reloading the entire configuration, we can
			 * assume ZFS has done the checking and it is
			 * safe to add this to the internal
			 * configuration.
			 */
			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) {
				(void) zfs_error_fmt(hdl,
				    proto_table[*curr_proto].p_share_err,
				    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
				    zfs_get_name(zhp));
				return (-1);
			}
			hdl->libzfs_shareflags |= ZFSSHARE_MISS;
			share = sa_find_share(hdl->libzfs_sharehdl,
			    mountpoint);
		}
		if (share != NULL) {
			int err;
			err = sa_enable_share(share,
			    proto_table[*curr_proto].p_name);
			if (err != SA_OK) {
				(void) zfs_error_fmt(hdl,
				    proto_table[*curr_proto].p_share_err,
				    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
				    zfs_get_name(zhp));
				return (-1);
			}
		} else {
			(void) zfs_error_fmt(hdl,
			    proto_table[*curr_proto].p_share_err,
			    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
			    zfs_get_name(zhp));
			return (-1);
		}

	}
	return (0);
}
/*
 * Mount the given filesystem.
 */
int
zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
{
	struct stat buf;
	char mountpoint[ZFS_MAXPROPLEN];
	char mntopts[MNT_LINE_MAX];
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	int remount = 0, rc;

	if (options == NULL) {
		(void) strlcpy(mntopts, MNTOPT_DEFAULTS, sizeof (mntopts));
	} 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
	 */
	if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
		(void) strlcat(mntopts, "," MNTOPT_RO, sizeof (mntopts));

    /*
     * Load encryption key if required and not already present.
     * Don't need to check ZFS_PROP_ENCRYPTION because encrypted
     * datasets have keystatus of ZFS_CRYPT_KEY_NONE.
     */
    fprintf(stderr, "zfs_mount: mount, keystatus is %d\r\n",
            zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS));
    if (zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS) ==
        ZFS_CRYPT_KEY_UNAVAILABLE) {
        fprintf(stderr, "loading KEY\r\n");
        (void )zfs_key_load(zhp, B_FALSE, B_FALSE, B_FALSE);
    }

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

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
		return (0);

	/* Create the directory if it doesn't already exist */
	if (lstat(mountpoint, &buf) != 0) {
		if (mkdirp(mountpoint, 0755) != 0) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "failed to create mountpoint"));
			return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
			    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
			    mountpoint));
		}
	}

	/*
	 * Determine if the mountpoint is empty.  If so, refuse to perform the
	 * mount.  We don't perform this check if 'remount' is
	 * specified or if overlay option(-O) is given
	 */
	if ((flags & MS_OVERLAY) == 0 && !remount &&
	    !dir_is_empty(mountpoint)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "directory is not empty"));
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
	}

	/* perform the mount */
	rc = do_mount(zfs_get_name(zhp), mountpoint, mntopts);
	if (rc) {
		/*
		 * Generic errors are nasty, but there are just way too many
		 * from mount(), and they're well-understood.  We pick a few
		 * common ones to improve upon.
		 */
		if (rc == EBUSY) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "mountpoint or dataset is busy"));
		} else if (rc == EPERM) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "Insufficient privileges"));
		} else if (rc == ENOTSUP) {
			char buf[256];
			int spa_version;

			VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
			(void) snprintf(buf, sizeof (buf),
			    dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
			    "file system on a version %d pool. Pool must be"
			    " upgraded to mount this file system."),
			    (u_longlong_t)zfs_prop_get_int(zhp,
			    ZFS_PROP_VERSION), spa_version);
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
		} else {
			zfs_error_aux(hdl, strerror(rc));
		}
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
		    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);
}
/*
 * Mount the given filesystem.
 */
int
zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
{
    struct stat buf;
    char mountpoint[ZFS_MAXPROPLEN];
    char mntopts[MNT_LINE_MAX];
    libzfs_handle_t *hdl = zhp->zfs_hdl;

    if (options == NULL)
        mntopts[0] = '\0';
    else
        (void) strlcpy(mntopts, options, sizeof (mntopts));

    /*
     * If the pool is imported read-only then all mounts must be read-only
     */
    if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
        flags |= MS_RDONLY;

    if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
        return (0);

    /* Create the directory if it doesn't already exist */
    if (lstat(mountpoint, &buf) != 0) {
        if (mkdirp(mountpoint, 0755) != 0) {
            zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                                        "failed to create mountpoint"));
            return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
                                  dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
                                  mountpoint));
        }
    }

    /*
     * Determine if the mountpoint is empty.  If so, refuse to perform the
     * mount.  We don't perform this check if MS_OVERLAY is specified, which
     * would defeat the point.  We also avoid this check if 'remount' is
     * specified.
     */
    if ((flags & MS_OVERLAY) == 0 &&
            strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
            !dir_is_empty(mountpoint)) {
        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                                    "directory is not empty"));
        return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
                              dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
    }

    /* perform the mount */
    if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
              MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
        /*
         * Generic errors are nasty, but there are just way too many
         * from mount(), and they're well-understood.  We pick a few
         * common ones to improve upon.
         */
        if (errno == EBUSY) {
            zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                                        "mountpoint or dataset is busy"));
        } else if (errno == EPERM) {
            zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                                        "Insufficient privileges"));
        } else if (errno == ENOTSUP) {
            char buf[256];
            int spa_version;

            VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
            (void) snprintf(buf, sizeof (buf),
                            dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
                                     "file system on a version %d pool. Pool must be"
                                     " upgraded to mount this file system."),
                            (u_longlong_t)zfs_prop_get_int(zhp,
                                    ZFS_PROP_VERSION), spa_version);
            zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
        } else {
            zfs_error_aux(hdl, strerror(errno));
        }
        return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
                              dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
                              zhp->zfs_name));
    }

    /* add the mounted entry into our cache */
    libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint,
                      mntopts);
    return (0);
}
/*
 * Mount the given filesystem.
 */
int
zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
{
	struct stat buf;
	char mountpoint[ZFS_MAXPROPLEN];
	char mntopts[MNT_LINE_MAX];
	libzfs_handle_t *hdl = zhp->zfs_hdl;

	if (options == NULL)
		mntopts[0] = '\0';
	else
		(void) strlcpy(mntopts, options, sizeof (mntopts));

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
		return (0);

	/* Create the directory if it doesn't already exist */
	if (lstat(mountpoint, &buf) != 0) {
		if (mkdirp(mountpoint, 0755) != 0) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "failed to create mountpoint"));
			return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
			    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
			    mountpoint));
		}
	}

	/*
	 * Determine if the mountpoint is empty.  If so, refuse to perform the
	 * mount.  We don't perform this check if MS_OVERLAY is specified, which
	 * would defeat the point.  We also avoid this check if 'remount' is
	 * specified.
	 */
	if ((flags & MS_OVERLAY) == 0 &&
	    strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
	    !dir_is_empty(mountpoint)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "directory is not empty"));
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
	}

	/* perform the mount */
	/* ZFSFUSE */
	if (zfsfuse_mount(hdl, zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
	    MNTTYPE_ZFS, NULL, 0, mntopts, strlen (mntopts)) != 0) {
		/*
		 * Generic errors are nasty, but there are just way too many
		 * from mount(), and they're well-understood.  We pick a few
		 * common ones to improve upon.
		 */
		if (errno == EBUSY) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "mountpoint or dataset is busy"));
		} else if (errno == EPERM) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "Insufficient privileges"));
		} else {
			zfs_error_aux(hdl, strerror(errno));
		}

		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
		    zhp->zfs_name));
	}

	return (0);
}
Exemple #6
0
/*
 * 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.
 */
static int
zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
{
	char mountpoint[ZFS_MAXPROPLEN];
	char shareopts[ZFS_MAXPROPLEN];
	char sourcestr[ZFS_MAXPROPLEN];
#if defined(HAVE_ZPL)
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	sa_share_t share;
#endif
	zfs_share_proto_t *curr_proto;
	zprop_source_t sourcetype;
#if defined(HAVE_ZPL)
	int ret;
#endif

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
		return (0);

#if defined(HAVE_ZPL)
	if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
		(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
		    dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
		    zfs_get_name(zhp), _sa_errorstr != NULL ?
		    _sa_errorstr(ret) : "");
		return (-1);
	}
#endif

	for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
		/*
		 * Return success if there are no share options.
		 */
		if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
		    shareopts, sizeof (shareopts), &sourcetype, sourcestr,
		    ZFS_MAXPROPLEN, B_FALSE) != 0 ||
		    strcmp(shareopts, "off") == 0)
			continue;

		/*
		 * If the 'zoned' property is set, then zfs_is_mountable()
		 * will have already bailed out if we are in the global zone.
		 * But local zones cannot be NFS servers, so we ignore it for
		 * local zones as well.
		 */
		if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
			continue;
#if !defined(HAVE_ZPL)
       if (*curr_proto == PROTO_NFS) {
           int pid;
           int rc;
           if ((pid = fork()) < 0) {
               fprintf(stderr, "cannot share '%s'", zfs_get_name(zhp));
               return -1;
           } else if (pid == 0) {
               /* child process */
               /* exec exportfs */
               char export_string[PATH_MAX];
               char options[100];
               char *argv [] = {
                   "exportfs",
                   "-v",
                   "-i",
                   export_string,
                   "-o",
                   options,
                   NULL
               };
               struct statfs buf;
               int fsid_arr[2];
               uint64_t fsid;

               if (statfs(mountpoint, &buf) < 0)
                   return -1;

               memcpy((void *)fsid_arr, (void *) &buf.f_fsid, sizeof(int) * 2);
               fsid = fsid_arr[0];
               fsid |= (((uint64_t)fsid_arr[1]) << 32);
//               fprintf(stderr, "using fsid=%lu\n", fsid);

               sprintf(export_string, "*:%s", mountpoint);
               sprintf(options, "rw,sync,fsid=%lu", fsid);
               execvp("exportfs", argv);
               return -1;
           }
           /* parent process */
           if (waitpid(pid, &rc, WUNTRACED) != pid) {
               fprintf(stderr, "cannot share '%s'", zfs_get_name(zhp));
               return -1;
           }

           if (!WIFEXITED(rc) || WEXITSTATUS(rc) != 0) {
               fprintf(stderr, "cannot share '%s'", zfs_get_name(zhp));
               return -1;
           }
       }
#else
		share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
		if (share == NULL) {
			/*
			 * This may be a new file system that was just
			 * created so isn't in the internal cache
			 * (second time through). Rather than
			 * reloading the entire configuration, we can
			 * assume ZFS has done the checking and it is
			 * safe to add this to the internal
			 * configuration.
			 */
			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) {
				(void) zfs_error_fmt(hdl,
				    proto_table[*curr_proto].p_share_err,
				    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
				    zfs_get_name(zhp));
				return (-1);
			}
			hdl->libzfs_shareflags |= ZFSSHARE_MISS;
			share = zfs_sa_find_share(hdl->libzfs_sharehdl,
			    mountpoint);
		}
		if (share != NULL) {
			int err;
			err = zfs_sa_enable_share(share,
			    proto_table[*curr_proto].p_name);
			if (err != SA_OK) {
				(void) zfs_error_fmt(hdl,
				    proto_table[*curr_proto].p_share_err,
				    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
				    zfs_get_name(zhp));
				return (-1);
			}
		} else {
			(void) zfs_error_fmt(hdl,
			    proto_table[*curr_proto].p_share_err,
			    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
			    zfs_get_name(zhp));
			return (-1);
		}
#endif
	}
	return (0);
}
Exemple #7
0
/*
 * 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.
 */
static int
zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
{
	char mountpoint[ZFS_MAXPROPLEN];
	char shareopts[ZFS_MAXPROPLEN];
	char sourcestr[ZFS_MAXPROPLEN];
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	zfs_share_proto_t *curr_proto;
	zprop_source_t sourcetype;
	int error, ret;

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
		return (0);

	for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
		/*
		 * Return success if there are no share options.
		 */
		if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
		    shareopts, sizeof (shareopts), &sourcetype, sourcestr,
		    ZFS_MAXPROPLEN, B_FALSE) != 0 ||
		    strcmp(shareopts, "off") == 0)
			continue;
#ifdef illumos
		ret = zfs_init_libshare_arg(hdl, SA_INIT_ONE_SHARE_FROM_HANDLE,
		    zhp);
		if (ret != SA_OK) {
			(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
			    dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
			    zfs_get_name(zhp), _sa_errorstr != NULL ?
			    _sa_errorstr(ret) : "");
			return (-1);
		}
#endif

		/*
		 * If the 'zoned' property is set, then zfs_is_mountable()
		 * will have already bailed out if we are in the global zone.
		 * But local zones cannot be NFS servers, so we ignore it for
		 * local zones as well.
		 */
		if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
			continue;

#ifdef illumos
		share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
		if (share == NULL) {
			/*
			 * This may be a new file system that was just
			 * created so isn't in the internal cache
			 * (second time through). Rather than
			 * reloading the entire configuration, we can
			 * assume ZFS has done the checking and it is
			 * safe to add this to the internal
			 * configuration.
			 */
			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) {
				(void) zfs_error_fmt(hdl,
				    proto_table[*curr_proto].p_share_err,
				    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
				    zfs_get_name(zhp));
				return (-1);
			}
			share = zfs_sa_find_share(hdl->libzfs_sharehdl,
			    mountpoint);
		}
		if (share != NULL) {
			int err;
			err = zfs_sa_enable_share(share,
			    proto_table[*curr_proto].p_name);
			if (err != SA_OK) {
				(void) zfs_error_fmt(hdl,
				    proto_table[*curr_proto].p_share_err,
				    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
				    zfs_get_name(zhp));
				return (-1);
			}
		} else
#else
		if (*curr_proto != PROTO_NFS) {
			fprintf(stderr, "Unsupported share protocol: %d.\n",
			    *curr_proto);
			continue;
		}

		if (strcmp(shareopts, "on") == 0)
			error = fsshare(ZFS_EXPORTS_PATH, mountpoint, "");
		else
			error = fsshare(ZFS_EXPORTS_PATH, mountpoint, shareopts);
		if (error != 0)
#endif
		{
			(void) zfs_error_fmt(hdl,
			    proto_table[*curr_proto].p_share_err,
			    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
			    zfs_get_name(zhp));
			return (-1);
		}

	}
	return (0);
}
Exemple #8
0
/*
 * Mount the given filesystem.
 *
 * 'flags' appears pretty much always 0 here.
 */
int
zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
{
	struct stat buf;
	char mountpoint[ZFS_MAXPROPLEN];
	char mntopts[MNT_LINE_MAX];
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	int remount;

	if (options == NULL) {
		mntopts[0] = '\0';
	} 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
	 */
#ifdef __LINUX__
	if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
		(void) strlcat(mntopts, "," MNTOPT_RO, sizeof (mntopts));
#else
	if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
		flags |= MS_RDONLY;
#endif /* __LINUX__ */

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
		return (0);

#ifdef __LINUX__

	/*
	 * 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, &flags);
	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));
#endif /* __LINUX__ */

	/* Create the directory if it doesn't already exist */
#ifdef __APPLE__
	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT &&
	    lstat(mountpoint, &buf) != 0) {
#else
	if (lstat(mountpoint, &buf) != 0) {
#endif
		if (mkdirp(mountpoint, 0755) != 0) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "failed to create mountpoint"));
			return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
			    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
			    mountpoint));
		}

	}

	/*
	 * Determine if the mountpoint is empty.  If so, refuse to perform the
	 * mount.  We don't perform this check if 'remount' is
	 * specified or if overlay option(-O) is given
	 */
	if ((flags & MS_OVERLAY) == 0 && !remount &&
	    !dir_is_empty(mountpoint)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "directory is not empty"));
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
	}

	/* perform the mount */
#ifdef __LINUX__
	rc = do_mount(zfs_get_name(zhp), mountpoint, mntopts);
#elif defined(__APPLE__) || defined (__FREEBSD__)
	if (zmount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
#elif defined(__illumos__)
	if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
#endif /* __LINUX__*/
		/*
		 * Generic errors are nasty, but there are just way too many
		 * from mount(), and they're well-understood.  We pick a few
		 * common ones to improve upon.
		 */
		if (errno == EBUSY) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "mountpoint or dataset is busy"));
		} else if (errno == EPERM) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "Insufficient privileges"));
		} else if (errno == ENOTSUP) {
			char buf[256];
			int spa_version;

			VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
			(void) snprintf(buf, sizeof (buf),
			    dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
			    "file system on a version %d pool. Pool must be"
			    " upgraded to mount this file system."),
			    (u_longlong_t)zfs_prop_get_int(zhp,
			    ZFS_PROP_VERSION), spa_version);
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
#ifdef __APPLE__
		} else if (((errno == ESRCH) || (errno == EINVAL) ||
		    (errno == ENOENT && lstat(mountpoint, &buf) != 0)) &&
		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "The parent file system must be mounted first."));
#endif
		} else {
			zfs_error_aux(hdl, strerror(errno));
		}
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
		    zhp->zfs_name));
	}

#ifdef __APPLE__
	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
		fprintf(stderr, "ZFS: snapshot mountpoint '%s'\n", mountpoint);

	if (!(flags & MS_RDONLY))
		zfs_mount_seticon(mountpoint);
#endif

	/* 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);
}

/*
 * Unmount a single filesystem.
 */
static int
unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
{
    int error;
#if 0
    error = unmount(mountpoint, flags);
    if (unmount(mountpoint, flags) != 0) {
		return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
		    mountpoint));
	}
#else
    error = do_unmount(mountpoint, flags);
    if (error != 0) {
        return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
                              dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
                    mountpoint));
    }
#endif

	return (0);
}

/*
 * Unmount the given filesystem.
 */
int
zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
{
	libzfs_handle_t *hdl = zhp->zfs_hdl;
#ifdef __LINUX__
	struct mnttab search = { 0 }, entry;
#else
	struct mnttab entry;
#endif /* __LINUX__ */
	char *mntpt = NULL;

	/* check to see if need to unmount the filesystem */
	if (mountpoint != NULL ||
	    (((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) ||
	    (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)) &&
	    libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) {

		/*
		 * mountpoint may have come from a call to
		 * getmnt/getmntany if it isn't NULL. If it is NULL,
		 * we know it comes from getmntany which can then get
		 * overwritten later. We strdup it to play it safe.
		 */
		if (mountpoint == NULL)
			mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
		else
			mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);

		/*
		 * Unshare and unmount the filesystem
		 */
#ifdef __illumos__
		if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
#else
		if (zfs_unshare_nfs(zhp, mntpt) != 0)
#endif
		return (-1);

		if (unmount_one(hdl, mntpt, flags) != 0) {
			free(mntpt);
#ifdef __illumos__
			(void) zfs_shareall(zhp);
#else
			(void) zfs_share_nfs(zhp);
#endif
			return (-1);
		}
		libzfs_mnttab_remove(hdl, zhp->zfs_name);
		free(mntpt);

	}

	return (0);
}
Exemple #9
0
/*
 * Mount the given filesystem.
 */
int
zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
{
	struct stat buf;
	char mountpoint[ZFS_MAXPROPLEN];
	char mntopts[MNT_LINE_MAX];
	libzfs_handle_t *hdl = zhp->zfs_hdl;
#ifdef __APPLE__
	struct zfs_mount_args mnt_args = {0};
	char  devpath[MAXPATHLEN];
#endif

	if (options == NULL)
		mntopts[0] = '\0';
	else
		(void) strlcpy(mntopts, options, sizeof (mntopts));

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
		return (0);

#ifdef __APPLE__
	/*
	 * Check for optional paths
	 */
	if (hasoptionalpath(mntopts, "mountdev=", devpath, sizeof (devpath)))
		mnt_args.mountdev = devpath;

	if (hasoptionalpath(mntopts, "mountpoint=", mountpoint,
	    sizeof (mountpoint)))
		goto callmount;
#endif

	/* Create the directory if it doesn't already exist */
	if (lstat(mountpoint, &buf) != 0) {
		if (mkdirp(mountpoint, 0755) != 0) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "failed to create mountpoint"));
			return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
			    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
			    mountpoint));
		}
	}

#ifndef __APPLE__
	/*
	 * Determine if the mountpoint is empty.  If so, refuse to perform the
	 * mount.  We don't perform this check if MS_OVERLAY is specified, which
	 * would defeat the point.  We also avoid this check if 'remount' is
	 * specified.
	 */
	if ((flags & MS_OVERLAY) == 0 &&
	    strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
	    !dir_is_empty(mountpoint)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "directory is not empty"));
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
	}
#endif /*!__APPLE__*/

	/* perform the mount */
#ifdef __APPLE__
callmount:
	mnt_args.dataset = zfs_get_name(zhp);
	mnt_args.flags = 0;

	if (mount(MNTTYPE_ZFS, mountpoint, flags, &mnt_args) != 0) {
#else
	if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
#endif

#ifdef __APPLE__
		/*
		 * If this was a top-level filesystem, then IOKit
		 * probing may have already mounted it, causing
		 * our call to mount() to fail.
		 */
		if (zfs_is_mounted(zhp, NULL)) {
			goto success;
		}
#endif       
		/*
		 * Generic errors are nasty, but there are just way too many
		 * from mount(), and they're well-understood.  We pick a few
		 * common ones to improve upon.
		 */
		if (errno == EBUSY) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "mountpoint or dataset is busy"));
		} else if (errno == EPERM) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "Insufficient privileges"));
		} else {
			zfs_error_aux(hdl, strerror(errno));
		}

		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
		    zhp->zfs_name));
	}
#ifdef __APPLE__
success:
	/*
	 * Remove any legacy custom volume icons.
	 */
	{
		char  path[MAXPATHLEN];
		struct stat sbuf;

		snprintf(path, MAXPATHLEN, "%s/%s", mountpoint, MOUNT_POINT_CUSTOM_ICON);
		if (stat(path, &sbuf) == 0 &&
		    sbuf.st_size == 35014 &&
		    sbuf.st_uid == 0) {
			/* Clear "has custom icon" flag */
			(void) removexattr(mountpoint, XATTR_FINDERINFO_NAME, 0);

			/* Clear custom icon file */
			(void) unlink(path);
		}

	}
#endif
	return (0);
}

#ifdef __APPLE__

/*
 * When unmounting, we first talk to diskarb and attempt to unmount via that
 * route. This allows diskarb to tell fsevents, mds, etc. to stop using the
 * filesystem.
 *
 * This code was borrowed from umount(8).
 */

#include <CoreFoundation/CoreFoundation.h>
#include <TargetConditionals.h>

#if !TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE
#include <DiskArbitration/DiskArbitrationPrivate.h>

static void __diskarb_unmount( DADiskRef disk, DADissenterRef dissenter, void * context )
{
    *( ( int * ) context ) = dissenter ? DADissenterGetStatus( dissenter ) : 0;

    CFRunLoopStop( CFRunLoopGetCurrent( ) );
}