/* * Unmount the given filesystem. */ int zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) { libzfs_handle_t *hdl = zhp->zfs_hdl; struct mnttab entry; char *mntpt = NULL; /* check to see if we 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 libzfs_mnttab_find which can * then get freed later. We strdup it to play it safe. */ if (mountpoint == NULL) mntpt = zfs_strdup(hdl, entry.mnt_mountp); else mntpt = zfs_strdup(hdl, mountpoint); #if defined(HAVE_ZPL) /* * Unshare and unmount the filesystem */ if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) return (-1); #else if (unmount_one(hdl, mntpt, flags) != 0) { free(mntpt); #if defined(HAVE_ZPL) (void) zfs_shareall(zhp); #endif return (-1); } #endif libzfs_mnttab_remove(hdl, zhp->zfs_name); #if defined(LINUX_PORT) /* remove a /etc/mtab entry */ if (zfs_linux_remove_entry(mntpt, zhp->zfs_name, MTAB_FILE) < 0) { free(mntpt); return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, dgettext(TEXT_DOMAIN, "failed to remove from /etc/mtab '%s'"), zhp->zfs_name)); } #endif free(mntpt); } return (0); }
/* * Checks to see if the mount is active. If the filesystem is mounted, we fill * in 'where' with the current mountpoint, and return 1. Otherwise, we return * 0. */ boolean_t is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where) { struct mnttab entry; if (libzfs_mnttab_find(zfs_hdl, special, &entry) != 0) return (B_FALSE); if (where != NULL) *where = zfs_strdup(zfs_hdl, entry.mnt_mountp); return (B_TRUE); }
/* * Unmount the given filesystem. */ int zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) { libzfs_handle_t *hdl = zhp->zfs_hdl; struct mnttab entry; char *mntpt = NULL; /* check to see if we need to unmount the filesystem */ if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 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 libzfs_mnttab_find which can * then get freed later. We strdup it to play it safe. */ if (mountpoint == NULL) mntpt = zfs_strdup(hdl, entry.mnt_mountp); else mntpt = zfs_strdup(hdl, mountpoint); /* * Unshare and unmount the filesystem */ if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) { free(mntpt); return (-1); } if (unmount_one(hdl, mntpt, flags) != 0) { free(mntpt); (void) zfs_shareall(zhp); return (-1); } libzfs_mnttab_remove(hdl, zhp->zfs_name); free(mntpt); } return (0); }
/* * Unshare the given filesystem. */ int zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, zfs_share_proto_t *proto) { libzfs_handle_t *hdl = zhp->zfs_hdl; struct mnttab entry; 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); if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) { zfs_share_proto_t *curr_proto; if (mountpoint == NULL) mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { while (is_shared(hdl, mntpt, *curr_proto)) { if (unshare_one(hdl, zhp->zfs_name, mntpt, *curr_proto) != 0) { if (mntpt != NULL) free(mntpt); return (-1); } } } } if (mntpt != NULL) free(mntpt); return (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); }