comparison sbin/fjail @ 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 95a81116471a
children 90fa5b68bb62
comparison
equal deleted inserted replaced
275:5bb4c4044e48 276:3c24b07240f2
39 -s Also create a dataset for freebsd-update data files 39 -s Also create a dataset for freebsd-update data files
40 -t Create a more tiny set of datasets 40 -t Create a more tiny set of datasets
41 -T Create only an extra tiny set of datasets 41 -T Create only an extra tiny set of datasets
42 -u Do not automatically mount newly created datasets 42 -u Do not automatically mount newly created datasets
43 43
44 mount [-O] [-u] [-n] DATASET [MOUNTPOINT] 44 mount
45 45
46 Mount the ZFS dataset DATASET and all its children to mountpoint 46 See sibling tool `fzfs'"'"'
47 MOUNTPOINT 47
48 48 umount
49 -O Also mount datasets at mountpoints outside of their "natural" 49
50 and inherited mountpoints 50 See sibling tool `fzfs'"'"'
51 -N Mount at their "natural" configured ZFS mountpoints (MOUNTPOINT is not required)
52 -P Do not mount the given prent DATASET but only its children
53 -n Do not really mount but show what would be mounted where
54 -u Alias of -n
55
56 umount DATASET
57
58 Unmount the mounted DATASET and all its children
59 51
60 privs MOUNTPOINT 52 privs MOUNTPOINT
61 53
62 Adjust some Unix privileges to mounted jail datasets 54 Adjust some Unix privileges to mounted jail datasets
63 55
488 zfs send -R ${_zfscopyopts} "${_source}" | zfs receive ${_zfsopts} "${_dest}" || { echo "ERROR: ZFS operation failed" >&2; return 1; } 480 zfs send -R ${_zfscopyopts} "${_source}" | zfs receive ${_zfsopts} "${_dest}" || { echo "ERROR: ZFS operation failed" >&2; return 1; }
489 } 481 }
490 482
491 483
492 # 484 #
493 # "mount" -- recursively mount a dataset including subordinate datasets
494 #
495 # command_mount dataset mountpoint
496 #
497 command_mount() {
498 local _dsname _mountpoint
499 local _name _mp _canmount _mounted
500 local _rootds_mountpoint _relative_mp _real_mp
501 local _dry_run _mount_outside _mount_natural _mount_children_only
502
503 _dry_run=""
504 _mount_outside=""
505 _mount_natural=""
506 _mount_children_only=""
507 while getopts "ONPnu" _opt ; do
508 case ${_opt} in
509 O)
510 _mount_outside="yes"
511 ;;
512 N)
513 _mount_natural="yes"
514 ;;
515 P)
516 _mount_children_only="yes"
517 ;;
518 n|u)
519 _dry_run="yes"
520 ;;
521 \?|:)
522 return 2;
523 ;;
524 esac
525 done
526 shift $((OPTIND-1))
527 OPTIND=1
528
529 _dsname="${1-}"
530 _mountpoint="${2-}"
531
532 if [ -z "${_dsname}" ]; then
533 echo "ERROR: no dataset given" >&2
534 return 2
535 fi
536
537 _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" || \
538 { echo "ERROR: root dataset does not exist" >&2; return 1; }
539
540 if [ -z "${_mountpoint}" ]; then
541 if [ "${_mount_natural}" = "yes" ]; then
542 _mountpoint="${_rootds_mountpoint}"
543 else
544 echo "ERROR: no mountpoint given" >&2
545 return 2
546 fi
547 else
548 if [ "${_mount_natural}" = "yes" ]; then
549 echo "ERROR: Cannot have a custom mountpoint when \"-O\" is given" >&2
550 return 2
551 fi
552 fi
553
554 # Eventually remove a trailing slash
555 _mountpoint="${_mountpoint%/}"
556 if [ -z "${_mountpoint}" ]; then
557 echo "ERROR: would mount over the root filesystem" >&2
558 return 1
559 fi
560
561 zfs list -H -o name,mountpoint,canmount,mounted -s mountpoint -t filesystem -r "${_dsname}" \
562 | {
563 while IFS=$'\t' read -r _name _mp _canmount _mounted ; do
564 # Skip filesystems that are already mounted
565 [ "${_mounted}" = "yes" ] && continue
566 # Skip filesystems that must not be mounted
567 [ "${_canmount}" = "off" ] && continue
568 # Mount only the children and skip the given dataset it required
569 [ \( "${_mount_children_only}" = "yes" \) -a \( "${_name}" = "${_dsname}" \) ] && continue
570 case "${_mp}" in
571 "none"|"legacy")
572 # Do nothing for filesystem with unset or legacy mountpoints
573 ;;
574 "${_rootds_mountpoint}"|"${_rootds_mountpoint}/"*)
575 #
576 # Handle only mountpoints that have a mountpoint below
577 # the parent datasets mountpoint
578 #
579
580 # Determine the mountpoint relative to the parent mountpoint
581 _relative_mp="${_mp#${_rootds_mountpoint}}"
582 # Eventually remove a trailing slash
583 _relative_mp="${_relative_mp%/}"
584 # The real effective full mountpoint
585 _real_mp="${_mountpoint}${_relative_mp}"
586
587 #
588 # Consistency and sanity check: computed real mountpoint must
589 # be equal to the configured mountpoint when no custom mountpoint
590 # is given.
591 #
592 if [ "${_mount_natural}" = "yes" ]; then
593 if [ "${_real_mp}" != "${_mp}" ]; then
594 echo "ERROR: mountpoint mismatch" >&2
595 return 1
596 fi
597 fi
598
599 if [ "${_dry_run}" = "yes" ]; then
600 echo "Would mount ${_name} on ${_real_mp}"
601 else
602 mkdir -p "${_real_mp}" 1> /dev/null 2> /dev/null || \
603 { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; return 1; }
604 echo "Mounting ${_name} on ${_real_mp}"
605 mount -t zfs "${_name}" "${_real_mp}" || return 1
606 fi
607 ;;
608 *)
609 if [ "${_mount_outside}" = "yes" ]; then
610 if [ "${_dry_run}" = "yes" ]; then
611 echo "Would mount ${_name} on configured ZFS dataset mountpoint ${_mp}"
612 else
613 echo "Mounting ${_name} on configured ZFS dataset mountpoint ${_mp}"
614 zfs mount "${_name}" || return 1
615 fi
616 else
617 echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 2>&1
618 fi
619 ;;
620 esac
621 done
622
623 return 0
624 }
625 }
626
627
628 #
629 # "umount" -- Recursively unmount ZFS datasets
630 #
631 # command_umount dataset
632 #
633 command_umount() {
634 local _dsname
635 local _name _mp _rest
636 local _rootds_mountpoint
637
638 _dsname="${1-}"
639 [ -z "${_dsname}" ] && \
640 { echo "ERROR: no dataset given" >&2; return 2; }
641
642 # Just determine whether the given dataset name exists
643 _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" || { echo "ERROR: dataset not found" >&2; return 1; }
644
645 mount -t zfs -p \
646 | grep -E "^${_dsname}(/|\s)" \
647 | sort -n -r \
648 | {
649 while IFS=' '$'\t' read -r _name _mp _rest ; do
650 echo "Umounting ${_name} on ${_mp}"
651 umount "${_mp}" || return 1
652 done
653 return 0
654 }
655 }
656
657
658 #
659 # "privs" -- adjust privileges 485 # "privs" -- adjust privileges
660 # 486 #
661 # To be used when all ZFS datasets are mounted. 487 # To be used when all ZFS datasets are mounted.
662 # 488 #
663 command_privs() { 489 command_privs() {
739 case "${command}" in 565 case "${command}" in
740 datasets) 566 datasets)
741 command_datasets "$@" 567 command_datasets "$@"
742 ;; 568 ;;
743 mount) 569 mount)
744 command_mount "$@" 570 exec "$(dirname $0)/fzfs" mount "$@"
745 ;; 571 ;;
746 umount|unmount) 572 umount|unmount)
747 command_umount "$@" 573 exec "$(dirname $0)/fzfs" umount "$@"
748 ;; 574 ;;
749 privs) 575 privs)
750 command_privs "$@" 576 command_privs "$@"
751 ;; 577 ;;
752 populate) 578 populate)