Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
changeset 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 | 5bb4c4044e48 |
| children | 0da26750b6fb |
| files | Makefile pkg-plist sbin/fjail sbin/fzfs |
| diffstat | 4 files changed, 276 insertions(+), 182 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Sat Sep 17 16:29:17 2022 +0200 +++ b/Makefile Sat Sep 17 16:47:32 2022 +0200 @@ -30,7 +30,7 @@ do-extract: ${MKDIR} ${WRKSRC}/bin ${MKDIR} ${WRKSRC}/sbin -.for _rp in sbin/check-ports sbin/fjail sbin/ftjail sbin/fpkg sbin/bsmtp2dma +.for _rp in sbin/check-ports sbin/fjail sbin/ftjail sbin/fzfs sbin/fpkg sbin/bsmtp2dma ${CP} -v ${SRC}/${_rp} ${WRKSRC}/${_rp} ${SED} -i "" -E -e "s|\\\$$Date\\\$$|\$$Date: ${HGDATE} \$$|" ${WRKSRC}/${_rp} ${SED} -i "" -E -e "s|\\\$$Revision\\\$$|\$$Revision: ${HGREVISION} \$$|" ${WRKSRC}/${_rp} @@ -52,7 +52,7 @@ .endfor do-install: -.for _rp in sbin/check-ports sbin/fjail sbin/ftjail sbin/fpkg sbin/bsmtp2dma +.for _rp in sbin/check-ports sbin/fjail sbin/ftjail sbin/fzfs sbin/fpkg sbin/bsmtp2dma ${INSTALL_SCRIPT} ${WRKSRC}/${_rp} ${STAGEDIR}${PREFIX}/${_rp} .endfor ${MKDIR} ${STAGEDIR}${ETCDIR}
--- a/pkg-plist Sat Sep 17 16:29:17 2022 +0200 +++ b/pkg-plist Sat Sep 17 16:47:32 2022 +0200 @@ -5,6 +5,7 @@ sbin/fjail sbin/ftjail sbin/fpkg +sbin/fzfs @sample %%ETCDIR%%/bsmtp2dma.conf.sample @sample %%ETCDIR%%/package-mapping.conf.sample @sample %%ETCDIR%%/pkgtools.conf.sample
--- a/sbin/fjail Sat Sep 17 16:29:17 2022 +0200 +++ b/sbin/fjail Sat Sep 17 16:47:32 2022 +0200 @@ -41,21 +41,13 @@ -T Create only an extra tiny set of datasets -u Do not automatically mount newly created datasets - mount [-O] [-u] [-n] DATASET [MOUNTPOINT] + mount - Mount the ZFS dataset DATASET and all its children to mountpoint - MOUNTPOINT + See sibling tool `fzfs'"'"' - -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 prent DATASET but only its children - -n Do not really mount but show what would be mounted where - -u Alias of -n + umount - umount DATASET - - Unmount the mounted DATASET and all its children + See sibling tool `fzfs'"'"' privs MOUNTPOINT @@ -490,172 +482,6 @@ # -# "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 _mount_outside _mount_natural _mount_children_only - - _dry_run="" - _mount_outside="" - _mount_natural="" - _mount_children_only="" - while getopts "ONPnu" _opt ; do - case ${_opt} in - O) - _mount_outside="yes" - ;; - N) - _mount_natural="yes" - ;; - P) - _mount_children_only="yes" - ;; - 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 - - _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 [ "${_mount_natural}" = "yes" ]; then - _mountpoint="${_rootds_mountpoint}" - else - echo "ERROR: no mountpoint given" >&2 - return 2 - fi - else - if [ "${_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 dataset it required - [ \( "${_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 [ "${_mount_natural}" = "yes" ]; then - if [ "${_real_mp}" != "${_mp}" ]; then - echo "ERROR: mountpoint mismatch" >&2 - return 1 - fi - fi - - 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 - ;; - *) - if [ "${_mount_outside}" = "yes" ]; then - if [ "${_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 - } -} - - -# -# "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}")" || { echo "ERROR: dataset not found" >&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 - } -} - - -# # "privs" -- adjust privileges # # To be used when all ZFS datasets are mounted. @@ -741,10 +567,10 @@ command_datasets "$@" ;; mount) - command_mount "$@" + exec "$(dirname $0)/fzfs" mount "$@" ;; umount|unmount) - command_umount "$@" + exec "$(dirname $0)/fzfs" umount "$@" ;; privs) command_privs "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbin/fzfs Sat Sep 17 16:47:32 2022 +0200 @@ -0,0 +1,267 @@ +#!/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
