Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
changeset 194:379d3178f3ce
mount and umount support for ZFS datasets: recursively mount and unmount
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Sun, 21 Aug 2022 08:35:18 +0200 |
| parents | 62a24dfb238c |
| children | 4a0cb73945a8 |
| files | sbin/fjail |
| diffstat | 1 files changed, 133 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/sbin/fjail Sat Aug 20 13:07:53 2022 +0200 +++ b/sbin/fjail Sun Aug 21 08:35:18 2022 +0200 @@ -39,6 +39,18 @@ -T Create only an extra tiny set of datasets -u Do not automatically mount newly created datasets + mount [-u] [-n] DATASET MOUNTPOINT + + Mount the ZFS dataset DATASET and all its children to mountpoint + MOUNTPOINT + + -n Do not really mount but show what would be mounted where + -u Alias of -n + + umount DATASET + + Unmount the mounted DATASET and all its children + privs MOUNTPOINT Adjust some Unix privileges to mounted jail datasets @@ -337,6 +349,121 @@ # +# "mount" -- recursively mount a dataset including subordinate datasets +# +# command_mount dataset mountpoint +# +command_mount() { + local _dsname _mountpoint + local _name _mp _canmount _mounted + local _rootds_mountpoint _relative_mp _real_mp + local _dry_run + + _dry_run="" + while getopts "nu" _opt ; do + case ${_opt} in + n|u) + _dry_run="yes" + ;; + \?|:) + return 2; + ;; + esac + done + shift $((OPTIND-1)) + OPTIND=1 + + _dsname="${1-}" + _mountpoint="${2-}" + + if [ -z "${_dsname}" ]; then + echo "ERROR: no dataset given" >&2 + return 2 + fi + if [ -z "${_mountpoint}" ]; then + echo "ERROR: no mountpoint given" >&2 + return 2 + fi + # Remove a trailing slash + _mountpoint="${_mountpoint%/}" + if [ -z "${_mountpoint}" ]; then + echo "ERROR: would mount over the root filesystem" >&2 + return 1 + fi + + _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" || \ + { echo "ERROR: root dataset does not exist" >&2; return 1; } + + zfs list -H -o name,mountpoint,canmount,mounted -s mountpoint -t filesystem -r "${_dsname}" | \ + while IFS=$'\t' read _name _mp _canmount _mounted ; do + # Skip filesystems that are already mounted + [ "${_mounted}" = "yes" ] && continue + # Skip filesystems that must not be mounted + [ "${_canmount}" = "off" ] && continue + case "${_mp}" in + "none"|"legacy") + # Do nothing for filesystem with unset or legacy mountpoints + ;; + "${_rootds_mountpoint}"|"${_rootds_mountpoint}/"*) + # + # Handle only mountpoints that have a mountpoint below + # the parent datasets mountpoint + # + + # Determine the mountpoint relative to the parent mountpoint + _relative_mp="${_mp#${_rootds_mountpoint}}" + # Remove a trailing slash + _relative_mp="${_relative_mp%/}" + _real_mp="${_mountpoint}${_relative_mp}" + if [ "${_dry_run}" = "yes" ]; then + echo "Would mount ${_name} on ${_real_mp}" + else + mkdir -p "${_real_mp}" 1> /dev/null 2> /dev/null || \ + { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; return 1; } + echo "Mounting ${_name} on ${_real_mp}" + mount -t zfs "${_name}" "${_real_mp}" || return 1 + fi + ;; + *) + # XXX FIXME Option to do a zfs mount $_name ??? + echo "Skipping ${_name} because its configured mountpoint is not relative to given root dataset" 2>&1 + ;; + esac + done + + return 0 +} + + +# +# "umount" -- Recursively unmount ZFS datasets +# +# command_umount dataset +# +command_umount() { + local _dsname + local _name _mp _rest + local _rootds_mountpoint + + _dsname="${1-}" + [ -z "${_dsname}" ] && \ + { echo "ERROR: no dataset given" >&2; return 2; } + + # Just determine whether the given dataset name exists + _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" | return 1 + + mount -t zfs -p | \ + grep -E "^${_dsname}(/|\s)" | \ + sort -n -r | \ + while IFS=' '$'\t' read _name _mp _rest ; do + echo "Umounting ${_name} on ${_mp}" + umount "${_mp}" || return 1 + done + return 0 +} + + +# # "privs" -- adjust privileges # # To be used when all ZFS datasets are mounted. @@ -424,6 +551,12 @@ datasets) command_datasets "$@" ;; + mount) + command_mount "$@" + ;; + umount|unmount) + command_umount "$@" + ;; privs) command_privs "$@" ;;
