comparison sbin/fjail @ 194:379d3178f3ce

mount and umount support for ZFS datasets: recursively mount and unmount
author Franz Glasner <fzglas.hg@dom66.de>
date Sun, 21 Aug 2022 08:35:18 +0200
parents 62a24dfb238c
children 4a0cb73945a8
comparison
equal deleted inserted replaced
193:62a24dfb238c 194:379d3178f3ce
36 36
37 -s Also create a dataset for freebsd-update data files 37 -s Also create a dataset for freebsd-update data files
38 -t Create a more tiny set of datasets 38 -t Create a more tiny set of datasets
39 -T Create only an extra tiny set of datasets 39 -T Create only an extra tiny set of datasets
40 -u Do not automatically mount newly created datasets 40 -u Do not automatically mount newly created datasets
41
42 mount [-u] [-n] DATASET MOUNTPOINT
43
44 Mount the ZFS dataset DATASET and all its children to mountpoint
45 MOUNTPOINT
46
47 -n Do not really mount but show what would be mounted where
48 -u Alias of -n
49
50 umount DATASET
51
52 Unmount the mounted DATASET and all its children
41 53
42 privs MOUNTPOINT 54 privs MOUNTPOINT
43 55
44 Adjust some Unix privileges to mounted jail datasets 56 Adjust some Unix privileges to mounted jail datasets
45 57
335 zfs send -R ${_zfscopyopts} "${_source}" | zfs receive ${_zfsopts} "${_dest}" || { echo "ERROR: ZFS operation failed" >&2; return 1; } 347 zfs send -R ${_zfscopyopts} "${_source}" | zfs receive ${_zfsopts} "${_dest}" || { echo "ERROR: ZFS operation failed" >&2; return 1; }
336 } 348 }
337 349
338 350
339 # 351 #
352 # "mount" -- recursively mount a dataset including subordinate datasets
353 #
354 # command_mount dataset mountpoint
355 #
356 command_mount() {
357 local _dsname _mountpoint
358 local _name _mp _canmount _mounted
359 local _rootds_mountpoint _relative_mp _real_mp
360 local _dry_run
361
362 _dry_run=""
363 while getopts "nu" _opt ; do
364 case ${_opt} in
365 n|u)
366 _dry_run="yes"
367 ;;
368 \?|:)
369 return 2;
370 ;;
371 esac
372 done
373 shift $((OPTIND-1))
374 OPTIND=1
375
376 _dsname="${1-}"
377 _mountpoint="${2-}"
378
379 if [ -z "${_dsname}" ]; then
380 echo "ERROR: no dataset given" >&2
381 return 2
382 fi
383 if [ -z "${_mountpoint}" ]; then
384 echo "ERROR: no mountpoint given" >&2
385 return 2
386 fi
387 # Remove a trailing slash
388 _mountpoint="${_mountpoint%/}"
389 if [ -z "${_mountpoint}" ]; then
390 echo "ERROR: would mount over the root filesystem" >&2
391 return 1
392 fi
393
394 _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" || \
395 { echo "ERROR: root dataset does not exist" >&2; return 1; }
396
397 zfs list -H -o name,mountpoint,canmount,mounted -s mountpoint -t filesystem -r "${_dsname}" | \
398 while IFS=$'\t' read _name _mp _canmount _mounted ; do
399 # Skip filesystems that are already mounted
400 [ "${_mounted}" = "yes" ] && continue
401 # Skip filesystems that must not be mounted
402 [ "${_canmount}" = "off" ] && continue
403 case "${_mp}" in
404 "none"|"legacy")
405 # Do nothing for filesystem with unset or legacy mountpoints
406 ;;
407 "${_rootds_mountpoint}"|"${_rootds_mountpoint}/"*)
408 #
409 # Handle only mountpoints that have a mountpoint below
410 # the parent datasets mountpoint
411 #
412
413 # Determine the mountpoint relative to the parent mountpoint
414 _relative_mp="${_mp#${_rootds_mountpoint}}"
415 # Remove a trailing slash
416 _relative_mp="${_relative_mp%/}"
417 _real_mp="${_mountpoint}${_relative_mp}"
418 if [ "${_dry_run}" = "yes" ]; then
419 echo "Would mount ${_name} on ${_real_mp}"
420 else
421 mkdir -p "${_real_mp}" 1> /dev/null 2> /dev/null || \
422 { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; return 1; }
423 echo "Mounting ${_name} on ${_real_mp}"
424 mount -t zfs "${_name}" "${_real_mp}" || return 1
425 fi
426 ;;
427 *)
428 # XXX FIXME Option to do a zfs mount $_name ???
429 echo "Skipping ${_name} because its configured mountpoint is not relative to given root dataset" 2>&1
430 ;;
431 esac
432 done
433
434 return 0
435 }
436
437
438 #
439 # "umount" -- Recursively unmount ZFS datasets
440 #
441 # command_umount dataset
442 #
443 command_umount() {
444 local _dsname
445 local _name _mp _rest
446 local _rootds_mountpoint
447
448 _dsname="${1-}"
449 [ -z "${_dsname}" ] && \
450 { echo "ERROR: no dataset given" >&2; return 2; }
451
452 # Just determine whether the given dataset name exists
453 _rootds_mountpoint="$(zfs list -H -o mountpoint -t filesystem "${_dsname}")" | return 1
454
455 mount -t zfs -p | \
456 grep -E "^${_dsname}(/|\s)" | \
457 sort -n -r | \
458 while IFS=' '$'\t' read _name _mp _rest ; do
459 echo "Umounting ${_name} on ${_mp}"
460 umount "${_mp}" || return 1
461 done
462 return 0
463 }
464
465
466 #
340 # "privs" -- adjust privileges 467 # "privs" -- adjust privileges
341 # 468 #
342 # To be used when all ZFS datasets are mounted. 469 # To be used when all ZFS datasets are mounted.
343 # 470 #
344 command_privs() { 471 command_privs() {
422 549
423 case "${command}" in 550 case "${command}" in
424 datasets) 551 datasets)
425 command_datasets "$@" 552 command_datasets "$@"
426 ;; 553 ;;
554 mount)
555 command_mount "$@"
556 ;;
557 umount|unmount)
558 command_umount "$@"
559 ;;
427 privs) 560 privs)
428 command_privs "$@" 561 command_privs "$@"
429 ;; 562 ;;
430 populate) 563 populate)
431 command_populate "$@" 564 command_populate "$@"