comparison sbin/ftjail @ 249:a91e1c5173cc

Also support direct mounting of the RW skeleton subdirs at a mountpoint
author Franz Glasner <fzglas.hg@dom66.de>
date Sun, 11 Sep 2022 13:02:39 +0200
parents 0b5dbf394aa2
children c4d835ccb4ae
comparison
equal deleted inserted replaced
248:0b5dbf394aa2 249:a91e1c5173cc
41 mount-tmpl [ OPTIONS ] BASE-RO SKELETON-RW MOUNTPOINT 41 mount-tmpl [ OPTIONS ] BASE-RO SKELETON-RW MOUNTPOINT
42 42
43 Canonically mount the RO base and the RW skeleton into MOUNTPOINT and 43 Canonically mount the RO base and the RW skeleton into MOUNTPOINT and
44 MOUNTPOINT/skeleton 44 MOUNTPOINT/skeleton
45 45
46 -L Mount the skeleton into a "skeleton" subdirectory
47 -P Mount the skeleton directly over the base
46 -n Do not really mount but show what would be mounted where 48 -n Do not really mount but show what would be mounted where
47 -u Alias of -n 49 -u Alias of -n
48 50
49 umount-tmpl BASE-RO SKELETON-RW 51 umount-tmpl BASE-RO SKELETON-RW
50 52
53 interlink-tmpl MOUNTPOINT 55 interlink-tmpl MOUNTPOINT
54 56
55 Create symbolic links between the RO base and the RW skeleton. 57 Create symbolic links between the RO base and the RW skeleton.
56 Base and skeleton must be canonically mounted already. 58 Base and skeleton must be canonically mounted already.
57 59
58 populate MOUNTPOINT BASETXZ 60 populate [ OPTIONS ] MOUNTPOINT BASETXZ
59 61
60 Populate the directory in MOUNTPOINT with the base system in BASETXZ 62 Populate the directory in MOUNTPOINT with the base system in BASETXZ
63
64 -L Populate having a "skeleton" subdirectory within the mountpoint
65 -P Populate directly into the mountpoint
61 66
62 ENVIRONMENT: 67 ENVIRONMENT:
63 68
64 All environment variables that affect "zfs" are effective also. 69 All environment variables that affect "zfs" are effective also.
65 70
287 # command_populate_tmpl mountpoint basetxz 292 # command_populate_tmpl mountpoint basetxz
288 # 293 #
289 command_populate_tmpl() { 294 command_populate_tmpl() {
290 # MOUNTPOINT -- base.txz 295 # MOUNTPOINT -- base.txz
291 local _mp _basetxz 296 local _mp _basetxz
292 297 local _opt_symlink
293 local _dir 298
294 299 local _opt _dir
295 _ensure_no_options "$@" 300
301 _opt_symlink=""
302
303 while getopts "LP" _opt ; do
304 case ${_opt} in
305 L)
306 _opt_symlink="yes"
307 ;;
308 P)
309 _opt_symlink="no"
310 ;;
311 \?)
312 return 2;
313 ;;
314 esac
315 done
316 shift $((OPTIND-1))
317 OPTIND=1
318
319 [ -z "${_opt_symlink}" ] && { echo "ERROR: -L or -P must be given" 1>&2; return 2; }
296 320
297 _mp="${1-}" 321 _mp="${1-}"
298 _basetxz="${2-}" 322 _basetxz="${2-}"
299 323
300 if [ -z "${_mp}" ]; then 324 if [ -z "${_mp}" ]; then
312 if [ ! -r "${_basetxz}" ]; then 336 if [ ! -r "${_basetxz}" ]; then
313 echo "ERROR: file \`${_basetxz}' is not readable" >&2 337 echo "ERROR: file \`${_basetxz}' is not readable" >&2
314 return 1 338 return 1
315 fi 339 fi
316 340
317 echo "Extracting RO base ..." 341 if [ "${_opt_symlink}" = "yes" ]; then
318 tar -C "${_mp}" --exclude=./etc --exclude=./root --exclude=./tmp --exclude=./usr/local --exclude=./var --no-safe-writes -xJp -f "${_basetxz}" || return 342 echo "Extracting RO base ..."
319 # "home" is not part of base 343 tar -C "${_mp}" --exclude=./etc --exclude=./root --exclude=./tmp --exclude=./usr/local --exclude=./var --no-safe-writes -xJp -f "${_basetxz}" || return
320 for _dir in etc root tmp usr/local var ; do 344 # "home" is not part of base
321 echo "Extracting RW skeleton: ${_dir} ..." 345 for _dir in etc root tmp usr/local var ; do
322 tar -C "${_mp}/skeleton" --include="./${_dir}" --exclude=./root/.cshrc --exclude=./root/.profile -xJp -f "${_basetxz}" || return 346 echo "Extracting RW skeleton: ${_dir} ..."
323 done 347 tar -C "${_mp}/skeleton" --include="./${_dir}" --exclude=./root/.cshrc --exclude=./root/.profile -xJp -f "${_basetxz}" || return
324 # In the original archive they are archived as hardlinks: make symlinks here 348 done
325 (cd "${_mp}/skeleton/root" && ln -s ../../.profile .profile) || return 349 # In the original archive they are archived as hardlinks: make proper symlinks here
326 (cd "${_mp}/skeleton/root" && ln -s ../../.cshrc .cshrc) || return 350 (cd "${_mp}/skeleton/root" && ln -s ../../.profile .profile) || return
351 (cd "${_mp}/skeleton/root" && ln -s ../../.cshrc .cshrc) || return
352 else
353 echo "Extracting base ..."
354 tar -C "${_mp}" --exclude=./root/.cshrc --exclude=./root/.profile --no-safe-writes -xJp -f "${_basetxz}" || return
355 # In the original archive they are archived as hardlinks: make proper symlinks here
356 (cd "${_mp}/root" && ln -s ../.profile .profile) || return
357 (cd "${_mp}/root" && ln -s ../.cshrc .cshrc) || return
358 fi
327 359
328 find "${_mp}/boot" -type f -delete || true 360 find "${_mp}/boot" -type f -delete || true
329 } 361 }
330 362
331 363
332 # 364 #
333 # _do_mount dataset mountpoint dry-run mount-natural 365 # _do_mount dataset mountpoint dry-run mount-natural childs-only
334 # 366 #
335 _do_mount() { 367 _do_mount() {
336 local _dsname _mountpoint _dry_run _mount_natural 368 local _dsname _mountpoint _dry_run _mount_natural _childs_only
337 369
338 local _name _mp _canmount _mounted 370 local _name _mp _canmount _mounted
339 local _rootds_mountpoint _relative_mp _real_mp 371 local _rootds_mountpoint _relative_mp _real_mp
340 372
341 _dsname="${1}" 373 _dsname="${1}"
342 _mountpoint="${2}" 374 _mountpoint="${2}"
343 _dry_run="${3}" 375 _dry_run="${3}"
344 _mount_natural="${4}" 376 _mount_natural="${4}"
377 _childs_only="${5}"
345 378
346 if [ -z "${_dsname}" ]; then 379 if [ -z "${_dsname}" ]; then
347 echo "ERROR: no dataset given" >&2 380 echo "ERROR: no dataset given" >&2
348 return 2 381 return 2
349 fi 382 fi
406 echo "ERROR: mountpoint mismatch" 1>&2 439 echo "ERROR: mountpoint mismatch" 1>&2
407 return 1 440 return 1
408 fi 441 fi
409 fi 442 fi
410 443
411 if [ "${_dry_run}" = "yes" ]; then 444 if [ \( "${_childs_only}" = "yes" \) -a \( "${_name}" = "${_dsname}" \) ]; then
412 echo "Would mount ${_name} on ${_real_mp}" 445 echo "Skipping ${_name} because mounting childs only" 1>&2
413 else 446 else
414 mkdir -p "${_real_mp}" 1> /dev/null 2> /dev/null || \ 447 if [ "${_dry_run}" = "yes" ]; then
415 { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; return 1; } 448 echo "Would mount ${_name} on ${_real_mp}"
416 echo "Mounting ${_name} on ${_real_mp}" 449 else
417 mount -t zfs "${_name}" "${_real_mp}" || return 1 450 mkdir -p "${_real_mp}" 1> /dev/null 2> /dev/null || \
451 { echo "ERROR: cannot create mountpoint ${_real_mp}" 1>&2; return 1; }
452 echo "Mounting ${_name} on ${_real_mp}"
453 mount -t zfs "${_name}" "${_real_mp}" || return 1
454 fi
418 fi 455 fi
419 ;; 456 ;;
420 *) 457 *)
421 echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 1>&2 458 echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 1>&2
422 ;; 459 ;;
433 # 470 #
434 # command_mount_tmpl base-ro skeleton-rw mountpoint 471 # command_mount_tmpl base-ro skeleton-rw mountpoint
435 # 472 #
436 command_mount_tmpl() { 473 command_mount_tmpl() {
437 local _ds_base _ds_skel _mountpoint 474 local _ds_base _ds_skel _mountpoint
438 local _opt_dry_run 475 local _opt_dry_run _opt_symlink
439 476
440 local _opt 477 local _opt
441 478
442 _opt_dry_run="" 479 _opt_dry_run=""
443 480 _opt_symlink=""
444 while getopts "nu" _opt ; do 481
482 while getopts "LPnu" _opt ; do
445 case ${_opt} in 483 case ${_opt} in
484 L)
485 _opt_symlink="yes"
486 ;;
487 P)
488 _opt_symlink="no"
489 ;;
446 n|u) 490 n|u)
447 _opt_dry_run="yes" 491 _opt_dry_run="yes"
448 ;; 492 ;;
449 \?|:) 493 \?|:)
450 return 2; 494 return 2;
452 esac 496 esac
453 done 497 done
454 shift $((OPTIND-1)) 498 shift $((OPTIND-1))
455 OPTIND=1 499 OPTIND=1
456 500
501 [ -z "${_opt_symlink}" ] && { echo "ERROR: -L or -P must be given" 1>&2; return 2; }
502
457 _ds_base="${1-}" 503 _ds_base="${1-}"
458 _ds_skel="${2-}" 504 _ds_skel="${2-}"
459 _mountpoint="${3-}" 505 _mountpoint="${3-}"
460 506
461 _do_mount "${_ds_base}" "${_mountpoint}" "${_opt_dry_run}" "" || return 507 _do_mount "${_ds_base}" "${_mountpoint}" "${_opt_dry_run}" "" "" || return
462 if [ "${_opt_dry_run}" != "yes" ]; then 508 if [ "${_opt_symlink}" = "yes" ]; then
463 if [ ! -d "${_mountpoint}/skeleton" ]; then 509 if [ "${_opt_dry_run}" != "yes" ]; then
464 mkdir "${_mountpoint}/skeleton" || return 510 if [ ! -d "${_mountpoint}/skeleton" ]; then
511 mkdir "${_mountpoint}/skeleton" || return
512 fi
465 fi 513 fi
466 fi 514 _do_mount "${_ds_skel}" "${_mountpoint}/skeleton" "${_opt_dry_run}" "" "" || return
467 _do_mount "${_ds_skel}" "${_mountpoint}/skeleton" "${_opt_dry_run}" "" || return 515 else
516 _do_mount "${_ds_skel}" "${_mountpoint}" "${_opt_dry_run}" "" "yes" || return
517 fi
468 518
469 return 0 519 return 0
470 } 520 }
471 521
472 522
473 # 523 #
474 # _do_umount dataset 524 # _do_umount dataset
475 # 525 #
476 _do_umount() { 526 _do_umount() {
477 local _dsname 527 local _dsname
478 528
479 local _name _mp _rest 529 local _name _mp _rest
480 local _rootds_mountpoint 530 local _rootds_mountpoint
481 531
482 _dsname="${1}" 532 _dsname="${1}"
483 [ -z "${_dsname}" ] && { echo "ERROR: no dataset given" >&2; return 2; } 533 [ -z "${_dsname}" ] && { echo "ERROR: no dataset given" >&2; return 2; }