Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
diff sbin/fzfs @ 380:6be930eb7490
Implement the "fzfs create-tree" command
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 20 Feb 2023 00:43:30 +0100 |
| parents | 1fc3b04b39fa |
| children | 84d2735fe7f6 |
line wrap: on
line diff
--- a/sbin/fzfs Sun Feb 19 14:47:17 2023 +0100 +++ b/sbin/fzfs Mon Feb 20 00:43:30 2023 +0100 @@ -28,6 +28,8 @@ COMMANDS: + create-tree [-A] [-M MOUNTPOINT] [-n] [-p] [-u] SOURCE-DATASET DEST-DATASET + mount [-O] [-N] [-P] [-u] [-n] DATASET [MOUNTPOINT] umount DATASET @@ -36,6 +38,48 @@ ' + +#: +#: Determine some important dataset properties that are set locally +#: +#: Args: +#: $1: the dataset +#: $2 ...: the properties to check for +#: +#: Output (stdout): +#: An option string suited for use in "zfs create" +#: +_get_local_properties() { + local ds + + local _res _prop _value _source + + ds="${1}" + shift + + _res="" + + for _prop in "$@" ; do + IFS=$'\t' read -r _value _source <<EOF73GHASGJKKJ354 +$(zfs get -H -p -o value,source "${_prop}" "${ds}") +EOF73GHASGJKKJ354 + case "${_source}" in + local) + if [ -z "${_res}" ]; then + _res="-o ${_prop}=${_value}" + else + _res="${_res} -o ${_prop}=${_value}" + fi + ;; + *) + # VOID + ;; + esac + done + echo "${_res}" +} + + # #: Implementation of the "mount" command. #: @@ -204,6 +248,128 @@ return 0 } + +#: +#: Implement the "create-tree" command +#: +#: Create a ZFS dataset tree from a source tree tree including important properties +#: +command_create_tree() { + local _source_ds _target_ds + local _opt_dry_run _opt_mountpoint _opt_noauto _opt_nomount _opt_canmount_parent_only + + local _opt _source_name _snapshot_name _current_name _current_type _relative_name _zfs_opts _zfs_canmount _zfs_mountpoint + + _opt_noauto="" + _opt_dry_run="" + _opt_mountpoint="" + _opt_nomount="" + _opt_canmount_parent_only="" + + while getopts "AM:npu" _opt ; do + case ${_opt} in + A) + _opt_noauto="-o canmount=noauto" + ;; + M) + _opt_mountpoint="${OPTARG}" + ;; + n) + _opt_dry_run="yes" + ;; + p) + _opt_canmount_parent_only="yes" + ;; + u) + _opt_nomount="-u" + ;; + \?|:) + return 2; + ;; + esac + done + shift $((OPTIND-1)) + OPTIND=1 + + _source_ds="${1-}" + _target_ds="${2-}" + + [ -z "${_source_ds}" ] && { echo "ERROR: no source dataset given" 1>&2; return 2; } + [ -z "${_target_ds}" ] && { echo "ERROR: no destination dataset given" 1>&2; return 2; } + + _source_name="${_source_ds%@*}" + if [ "${_source_name}" != "${_source_ds}" ]; then + _snapshot_name="${_source_ds##*@}" + else + _snapshot_name="" + fi + + [ -n "${_snapshot_name}" ] && { echo "ERROR: No snapshot sources are supported yet" 1>&2; return 2; } + + zfs list -H -r -t filesystem -o name,type "${_source_ds}" \ + | { + while IFS=$'\t' read -r _current_name _current_type ; do + # Determine the relative name of the dataset + _relative_name="${_current_name#${_source_name}}" + _relative_name="${_relative_name%@*}" + if [ "${_current_type}" != "filesystem" ]; then + echo "ERROR: Got a snapshot but expected a filesystem" 1>&2 + return 1 + fi + _zfs_opts="$(_get_local_properties "${_current_name}" atime exec setuid compression primarycache sync readonly)" + if [ -z "${_relative_name}" ]; then + # + # Root + # + if [ -z "${_opt_noauto}" ]; then + _zfs_canmount="$(_get_local_properties "${_current_name}" canmount)" + else + _zfs_canmount="${_opt_noauto}" + fi + if [ -n "${_opt_mountpoint}" ]; then + _zfs_mountpoint="${_opt_mountpoint}" + else + _zfs_mountpoint="" + fi + + if [ "${_opt_dry_run}" = "yes" ]; then + if [ -z "${_zfs_mountpoint}" ]; then + echo "Would call: zfs create ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} ${_target_ds}${_relative_name}" + else + echo "Would call: zfs create ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} -o mountpoint=${_zfs_mountpoint} ${_target_ds}${_relative_name}" + fi + else + if [ -z "${_zfs_mountpoint}" ]; then + zfs create -v ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} "${_target_ds}${_relative_name}" + else + zfs create -v ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} -o "mountpoint=${_zfs_mountpoint}" "${_target_ds}${_relative_name}" + fi + fi + else + # + # Children + # + if [ -z "${_opt_noauto}" ]; then + if [ "${_opt_canmount_parent_only}" = "yes" ]; then + _zfs_canmount="" + else + _zfs_canmount="$(_get_local_properties "${_current_name}" canmount)" + fi + else + _zfs_canmount="${_opt_noauto}" + fi + if [ "${_opt_dry_run}" = "yes" ]; then + echo "Would call: zfs create ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} ${_target_ds}${_relative_name}" + else + zfs create -v ${_opt_nomount} ${_zfs_opts} ${_zfs_canmount} "${_target_ds}${_relative_name}" + fi + fi + done + } + return 0 +} + + # # Global option handling # @@ -245,6 +411,9 @@ umount|unmount) command_umount "$@" ;; + create-tree) + command_create_tree "$@" + ;; *) echo "ERROR: unknown command \`${command}'" 1>&2 exit 2
