Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
view sbin/fzfs @ 276:3c24b07240f2
Move the implementation of "mount" and "umount" into the new tool fzfs.
It is not jail-specific but in reality a helper for some ZFS management
issues.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Sat, 17 Sep 2022 16:47:32 +0200 |
| parents | |
| children | 1fc3b04b39fa |
line wrap: on
line source
#!/bin/sh # -*- indent-tabs-mode: nil; -*- #: #: A ZFS management helper tool. #: #: :Author: Franz Glasner #: :Copyright: (c) 2022 Franz Glasner. #: All rights reserved. #: :License: BSD 3-Clause "New" or "Revised" License. #: See LICENSE for details. #: If you cannot find LICENSE see #: <https://opensource.org/licenses/BSD-3-Clause> #: :ID: @(#)@@PKGORIGIN@@ $HGid$ #: set -eu VERSION="@@VERSION@@" USAGE=' USAGE: fzfs [ OPTIONS ] COMMAND [ COMMAND OPTIONS ] [ ARG ... ] OPTIONS: -V Print the program name and version number to stdout and exit -h Print this help message to stdout and exit COMMANDS: mount [-O] [-u] [-n] DATASET [MOUNTPOINT] Mount the ZFS dataset DATASET and all its children to mountpoint MOUNTPOINT -O Also mount datasets at mountpoints outside of their "natural" and inherited mountpoints -N Mount at their "natural" configured ZFS mountpoints (MOUNTPOINT is not required) -P Do not mount the given parent DATASET but only its children -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 unmount Alias for `umount'"'"' ' # #: Implementation of the "mount" command. #: #: Mount a dataset and recursively all its children datasets. #: command_mount() { local _dsname _mountpoint local _opt_dry_run _opt_mount_outside _opt_mount_natural local _opt_mount_children_only local _name _mp _canmount _mounted _rootds_mountpoint _relative_mp _real_mp _opt_dry_run="" _opt_mount_outside="" _opt_mount_natural="" _opt_mount_children_only="" while getopts "ONPnu" _opt ; do case ${_opt} in O) _opt_mount_outside="yes" ;; N) _opt_mount_natural="yes" ;; P) _opt_mount_children_only="yes" ;; n|u) _opt_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 _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" || \ { echo "ERROR: root dataset does not exist" >&2; return 1; } if [ -z "${_mountpoint}" ]; then if [ "${_opt_mount_natural}" = "yes" ]; then _mountpoint="${_rootds_mountpoint}" else echo "ERROR: no mountpoint given" >&2 return 2 fi else if [ "${_opt_mount_natural}" = "yes" ]; then echo "ERROR: Cannot have a custom mountpoint when \"-O\" is given" >&2 return 2 fi fi # Eventually remove a trailing slash _mountpoint="${_mountpoint%/}" if [ -z "${_mountpoint}" ]; then echo "ERROR: would mount over the root filesystem" >&2 return 1 fi zfs list -H -o name,mountpoint,canmount,mounted -s mountpoint -t filesystem -r "${_dsname}" \ | { while IFS=$'\t' read -r _name _mp _canmount _mounted ; do # Skip filesystems that are already mounted [ "${_mounted}" = "yes" ] && continue # Skip filesystems that must not be mounted [ "${_canmount}" = "off" ] && continue # # Mount only the children and skip the given parent dataset # if required # [ \( "${_opt_mount_children_only}" = "yes" \) -a \( "${_name}" = "${_dsname}" \) ] && 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}}" # Eventually remove a trailing slash _relative_mp="${_relative_mp%/}" # The real effective full mountpoint _real_mp="${_mountpoint}${_relative_mp}" # # Consistency and sanity check: computed real mountpoint must # be equal to the configured mountpoint when no custom mountpoint # is given. # if [ "${_opt_mount_natural}" = "yes" ]; then if [ "${_real_mp}" != "${_mp}" ]; then echo "ERROR: mountpoint mismatch" >&2 return 1 fi fi if [ "${_opt_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 ;; *) if [ "${_opt_mount_outside}" = "yes" ]; then if [ "${_opt_dry_run}" = "yes" ]; then echo "Would mount ${_name} on configured ZFS dataset mountpoint ${_mp}" else echo "Mounting ${_name} on configured ZFS dataset mountpoint ${_mp}" zfs mount "${_name}" || return 1 fi else echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 2>&1 fi ;; esac done return 0 } } #: #: Implement the "umount" command. #: #: Umount a datasets and recursively all its children datasets. #: command_umount() { local _dsname local _name _mp _rest _rootds_mountpoint _dsname="${1-}" [ -z "${_dsname}" ] && { echo "ERROR: no dataset given" 1>&2; return 2; } # Just determine whether the given dataset name exists _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" || { echo "ERROR: dataset not found" 1>&2; return 1; } mount -t zfs -p \ | grep -E "^${_dsname}(/|\s)" \ | sort -n -r \ | { while IFS=' '$'\t' read -r _name _mp _rest ; do echo "Umounting ${_name} on ${_mp}" umount "${_mp}" || return 1 done } return 0 } # # Global option handling # while getopts "Vh" _opt ; do case ${_opt} in V) printf 'ftjail v%s (rv:%s)\n' "${VERSION}" '@@HGREVISION@@' exit 0 ;; h) echo "${USAGE}" exit 0 ;; \?) exit 2; ;; *) echo "ERROR: option handling failed" 1>&2 exit 2 ;; esac done # # Reset the Shell's option handling system to prepare for handling # command-local options. # shift $((OPTIND-1)) OPTIND=1 test $# -gt 0 || { echo "ERROR: no command given" 1>&2; exit 2; } command="$1" shift case "${command}" in mount) command_mount "$@" ;; umount|unmount) command_umount "$@" ;; *) echo "ERROR: unknown command \`${command}'" 1>&2 exit 2 ;; esac
