Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
comparison sbin/fzfs @ 521:c05ef1c86c9c
fzfs: Implement option "-k" for clone-tree and mount to keep cloned datasets or keep datasets mounted on errors
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Sun, 01 Sep 2024 21:52:01 +0200 |
| parents | 7d08fd78775c |
| children | b7d60802b25f |
comparison
equal
deleted
inserted
replaced
| 520:7d08fd78775c | 521:c05ef1c86c9c |
|---|---|
| 26 | 26 |
| 27 -h Print this help message to stdout and exit | 27 -h Print this help message to stdout and exit |
| 28 | 28 |
| 29 COMMANDS: | 29 COMMANDS: |
| 30 | 30 |
| 31 clone-tree [-n] SOUECE-DATASET DEST-DATASET | 31 clone-tree [-k] [-n] SOUECE-DATASET DEST-DATASET |
| 32 | 32 |
| 33 copy-tree [-A] [-M MOUNTPOINT] [-n] [-u] SOURCE-DATASET DEST-DATASET | 33 copy-tree [-A] [-M MOUNTPOINT] [-n] [-u] SOURCE-DATASET DEST-DATASET |
| 34 | 34 |
| 35 create-tree [-A] [-M MOUNTPOINT] [-n] [-p] [-u] SOURCE-DATASET DEST-DATASET | 35 create-tree [-A] [-M MOUNTPOINT] [-n] [-p] [-u] SOURCE-DATASET DEST-DATASET |
| 36 | 36 |
| 37 mount [-O] [-N] [-P] [-u] [-n] DATASET [MOUNTPOINT] | 37 mount [-O] [-N] [-P] [-k] [-u] [-n] DATASET [MOUNTPOINT] |
| 38 | 38 |
| 39 umount DATASET | 39 umount DATASET |
| 40 | 40 |
| 41 unmount | 41 unmount |
| 42 | 42 |
| 54 #: Mount a dataset and recursively all its children datasets. | 54 #: Mount a dataset and recursively all its children datasets. |
| 55 #: | 55 #: |
| 56 command_mount() { | 56 command_mount() { |
| 57 local _dsname _mountpoint | 57 local _dsname _mountpoint |
| 58 local _opt_dry_run _opt_mount_outside _opt_mount_natural | 58 local _opt_dry_run _opt_mount_outside _opt_mount_natural |
| 59 local _opt_mount_children_only | 59 local _opt_mount_children_only _opt_keep |
| 60 | 60 |
| 61 local _name _mp _canmount _mounted _rootds_mountpoint _rootds_mountpoint_prefix _relative_mp _real_mp | 61 local _name _mp _canmount _mounted _rootds_mountpoint _rootds_mountpoint_prefix _relative_mp _real_mp |
| 62 | 62 |
| 63 _opt_dry_run="" | 63 _opt_dry_run="" |
| 64 _opt_keep="" | |
| 64 _opt_mount_outside="" | 65 _opt_mount_outside="" |
| 65 _opt_mount_natural="" | 66 _opt_mount_natural="" |
| 66 _opt_mount_children_only="" | 67 _opt_mount_children_only="" |
| 67 while getopts "ONPnu" _opt ; do | 68 while getopts "ONPknu" _opt ; do |
| 68 case ${_opt} in | 69 case ${_opt} in |
| 69 O) | 70 O) |
| 70 _opt_mount_outside="yes" | 71 _opt_mount_outside="yes" |
| 71 ;; | 72 ;; |
| 72 N) | 73 N) |
| 73 _opt_mount_natural="yes" | 74 _opt_mount_natural="yes" |
| 74 ;; | 75 ;; |
| 75 P) | 76 P) |
| 76 _opt_mount_children_only="yes" | 77 _opt_mount_children_only="yes" |
| 78 ;; | |
| 79 k) | |
| 80 _opt_keep="yes" | |
| 77 ;; | 81 ;; |
| 78 n|u) | 82 n|u) |
| 79 _opt_dry_run="yes" | 83 _opt_dry_run="yes" |
| 80 ;; | 84 ;; |
| 81 \?|:) | 85 \?|:) |
| 160 # filesystem mount is just a single slash. | 164 # filesystem mount is just a single slash. |
| 161 # | 165 # |
| 162 if [ "${_mp}" = "${_rootds_mountpoint}" ]; then | 166 if [ "${_mp}" = "${_rootds_mountpoint}" ]; then |
| 163 if [ "${_name}" != "${_dsname}" ]; then | 167 if [ "${_name}" != "${_dsname}" ]; then |
| 164 echo "ERROR: child dataset mounts over root dataset" >&2 | 168 echo "ERROR: child dataset mounts over root dataset" >&2 |
| 165 _umount_datasets _mounted_datasets || true | 169 if ! checkyes _opt_keep; then |
| 170 _umount_datasets _mounted_datasets || true | |
| 171 fi | |
| 166 return 1 | 172 return 1 |
| 167 fi | 173 fi |
| 168 _relative_mp="" | 174 _relative_mp="" |
| 169 _real_mp="${_mountpoint}" | 175 _real_mp="${_mountpoint}" |
| 170 else | 176 else |
| 171 _relative_mp="${_mp#${_rootds_mountpoint_prefix}}" | 177 _relative_mp="${_mp#${_rootds_mountpoint_prefix}}" |
| 172 # Eventually remove a trailing slash | 178 # Eventually remove a trailing slash |
| 173 _relative_mp="${_relative_mp%/}" | 179 _relative_mp="${_relative_mp%/}" |
| 174 if [ -z "${_relative_mp}" ]; then | 180 if [ -z "${_relative_mp}" ]; then |
| 175 echo "ERROR: got an empty relative mountpoint in child" >&2 | 181 echo "ERROR: got an empty relative mountpoint in child" >&2 |
| 176 _umount_datasets _mounted_datasets || true | 182 if ! checkyes _opt_keep; then |
| 183 _umount_datasets _mounted_datasets || true | |
| 184 fi | |
| 177 return 1 | 185 return 1 |
| 178 fi | 186 fi |
| 179 # The real effective full mountpoint | 187 # The real effective full mountpoint |
| 180 _real_mp="${_mountpoint}/${_relative_mp}" | 188 _real_mp="${_mountpoint}/${_relative_mp}" |
| 181 fi | 189 fi |
| 186 # is given. | 194 # is given. |
| 187 # | 195 # |
| 188 if [ "${_opt_mount_natural}" = "yes" ]; then | 196 if [ "${_opt_mount_natural}" = "yes" ]; then |
| 189 if [ "${_real_mp}" != "${_mp}" ]; then | 197 if [ "${_real_mp}" != "${_mp}" ]; then |
| 190 echo "ERROR: mountpoint mismatch" >&2 | 198 echo "ERROR: mountpoint mismatch" >&2 |
| 191 _umount_datasets _mounted_datasets || true | 199 if ! checkyes _opt_keep; then |
| 200 _umount_datasets _mounted_datasets || true | |
| 201 fi | |
| 192 return 1 | 202 return 1 |
| 193 fi | 203 fi |
| 194 fi | 204 fi |
| 195 | 205 |
| 196 if [ "${_opt_dry_run}" = "yes" ]; then | 206 if [ "${_opt_dry_run}" = "yes" ]; then |
| 200 { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; _umount_datasets _mounted_datasets || true; return 1; } | 210 { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; _umount_datasets _mounted_datasets || true; return 1; } |
| 201 echo "Mounting ${_name} on ${_real_mp}" | 211 echo "Mounting ${_name} on ${_real_mp}" |
| 202 if mount -t zfs "${_name}" "${_real_mp}"; then | 212 if mount -t zfs "${_name}" "${_real_mp}"; then |
| 203 array_append _mounted_datasets "${_name}" | 213 array_append _mounted_datasets "${_name}" |
| 204 else | 214 else |
| 205 _umount_datasets _mounted_datasets || true | 215 if ! checkyes _opt_keep; then |
| 216 _umount_datasets _mounted_datasets || true | |
| 217 fi | |
| 206 return 1 | 218 return 1 |
| 207 fi | 219 fi |
| 208 fi | 220 fi |
| 209 ;; | 221 ;; |
| 210 *) | 222 *) |
| 214 else | 226 else |
| 215 echo "Mounting ${_name} on configured ZFS dataset mountpoint ${_mp}" | 227 echo "Mounting ${_name} on configured ZFS dataset mountpoint ${_mp}" |
| 216 if zfs mount "${_name}"; then | 228 if zfs mount "${_name}"; then |
| 217 array_append _mounted_datasets "${_name}" | 229 array_append _mounted_datasets "${_name}" |
| 218 else | 230 else |
| 219 _umount_datasets _mounted_datasets || true | 231 if ! checkyes _opt_keep; then |
| 232 _umount_datasets _mounted_datasets || true | |
| 233 fi | |
| 220 return 1 | 234 return 1 |
| 221 fi | 235 fi |
| 222 fi | 236 fi |
| 223 else | 237 else |
| 224 echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 2>&1 | 238 echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 2>&1 |
| 434 #: | 448 #: |
| 435 #: Implementation of "clone-tree" | 449 #: Implementation of "clone-tree" |
| 436 #: | 450 #: |
| 437 command_clone_tree() { | 451 command_clone_tree() { |
| 438 local _ds_source _ds_dest | 452 local _ds_source _ds_dest |
| 439 local _opt_dry_run | 453 local _opt_keep _opt_dry_run |
| 440 | 454 |
| 441 local _ds snapshot_name _ds_source_base _ds_relname | 455 local _ds snapshot_name _ds_source_base _ds_relname |
| 442 local _ds_canmount _ds_mountpoint | 456 local _ds_canmount _ds_mountpoint |
| 443 local _clone_props _arg_canmount _arg_other_clone_props | 457 local _clone_props _arg_canmount _arg_other_clone_props |
| 444 local _opt _idx _idx_lp _prop _propval | 458 local _opt _idx _idx_lp _prop _propval |
| 445 | 459 |
| 446 _opt_dry_run="" | 460 _opt_dry_run="" |
| 447 | 461 _opt_keep="" |
| 448 while getopts "n" _opt ; do | 462 |
| 463 while getopts "kn" _opt ; do | |
| 449 case ${_opt} in | 464 case ${_opt} in |
| 465 k) | |
| 466 _opt_keep="yes" | |
| 467 ;; | |
| 450 n) | 468 n) |
| 451 _opt_dry_run="yes" | 469 _opt_dry_run="yes" |
| 452 ;; | 470 ;; |
| 453 \?|:) | 471 \?|:) |
| 454 return 2; | 472 return 2; |
| 491 | 509 |
| 492 # Check the existence of all intermediate datasets and their shapshots | 510 # Check the existence of all intermediate datasets and their shapshots |
| 493 _idx=1 | 511 _idx=1 |
| 494 while array_tryget _ds _ds_tree ${_idx}; do | 512 while array_tryget _ds _ds_tree ${_idx}; do |
| 495 if ! zfs get -H name "${_ds}@${_snapshot_name}" >/dev/null 2>&1; then | 513 if ! zfs get -H name "${_ds}@${_snapshot_name}" >/dev/null 2>&1; then |
| 496 err "child dataset does not exist: ${_ds}@${_snapshot_name}" 1>&2 | 514 err "child dataset (snapshot) does not exist: ${_ds}@${_snapshot_name}" 1>&2 |
| 497 array_destroy _ds_tree | |
| 498 return 1 | 515 return 1 |
| 499 fi | 516 fi |
| 500 _idx=$((${_idx} + 1)) | 517 _idx=$((${_idx} + 1)) |
| 501 done | 518 done |
| 502 | 519 |
| 554 if ! checkyes _opt_dry_run; then | 571 if ! checkyes _opt_dry_run; then |
| 555 echo "Cloning ${_ds}@${_snapshot_name} into ${_ds_dest}${_ds_relname} with ${_arg_canmount} ${_arg_other_clone_props}" | 572 echo "Cloning ${_ds}@${_snapshot_name} into ${_ds_dest}${_ds_relname} with ${_arg_canmount} ${_arg_other_clone_props}" |
| 556 if zfs clone ${_arg_canmount} ${_arg_other_clone_props} "${_ds}@${_snapshot_name}" "${_ds_dest}${_ds_relname}"; then | 573 if zfs clone ${_arg_canmount} ${_arg_other_clone_props} "${_ds}@${_snapshot_name}" "${_ds_dest}${_ds_relname}"; then |
| 557 array_append _cloned_datasets "${_ds_dest}${_ds_relname}" | 574 array_append _cloned_datasets "${_ds_dest}${_ds_relname}" |
| 558 else | 575 else |
| 559 _destroy_datasets _cloned_datasets || true | 576 if ! checkyes _opt_keep; then |
| 577 _destroy_datasets _cloned_datasets || true | |
| 578 fi | |
| 560 return 1 | 579 return 1 |
| 561 fi | 580 fi |
| 562 else | 581 else |
| 563 echo "Would execute: zfs clone ${_arg_canmount} ${_arg_other_clone_props} '${_ds}@${_snapshot_name}' '${_ds_dest}${_ds_relname}'" | 582 echo "Would execute: zfs clone ${_arg_canmount} ${_arg_other_clone_props} '${_ds}@${_snapshot_name}' '${_ds_dest}${_ds_relname}'" |
| 564 fi | 583 fi |
| 608 fi | 627 fi |
| 609 fi | 628 fi |
| 610 fi | 629 fi |
| 611 _idx=$((${_idx} + 1)) | 630 _idx=$((${_idx} + 1)) |
| 612 done | 631 done |
| 613 | 632 array_destroy _cloned_datasets |
| 614 return 0 | 633 return 0 |
| 615 } | 634 } |
| 616 | 635 |
| 617 | 636 |
| 618 #: | 637 #: |
