127 lines
5.8 KiB
Bash
127 lines
5.8 KiB
Bash
#!/usr/local/bin/bash
|
|
#
|
|
# Mount non-boot-environment datasets.
|
|
#
|
|
# We can't leave datasets outside the boot environment (for example,
|
|
# jails or bhyve VMs) as canmount=on because then every boot
|
|
# environment's external datasets would all attempt to mount every
|
|
# time. To work around this, we mark those datasets as canmount=noauto
|
|
# and run this script to mount datasets under the root of our boot
|
|
# environment. This script depends heavily on my zfs dataset structure
|
|
# so it needs to be improved to be robust enough for different
|
|
# layouts. An example of my layout is:
|
|
#
|
|
## NAME MOUNTPOINT CANMOUNT TA:BEMOUNT
|
|
## zroot none off -
|
|
## zroot/global /global on -
|
|
## zroot/freebsd none on -
|
|
## zroot/freebsd/13.1-RELEASE none on -
|
|
## zroot/freebsd/13.1-RELEASE/be none on -
|
|
## zroot/freebsd/13.1-RELEASE/be/main / noauto -
|
|
## zroot/freebsd/13.1-RELEASE/jails none on -
|
|
## zroot/freebsd/13.1-RELEASE/jails/foo /jail/foo noauto on
|
|
## zroot/freebsd/13.1-RELEASE/jails/bar /jail/bar noauto on
|
|
## zroot/freebsd/13.1-RELEASE/jails/baz /jail/baz noauto on
|
|
## zroot/freebsd/13.1-RELEASE/vm-bhyve /vm noauto on
|
|
## zroot/linux none on -
|
|
## zroot/linux/arch none on -
|
|
## zroot/linux/arch/be none on -
|
|
## zroot/linux/arch/be/main / noauto -
|
|
set -euo pipefail
|
|
IFS=$'\n\t'
|
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
|
|
function main {
|
|
local all_zfs_datasets=$(zfs list -Hp -o 'name,mountpoint,canmount,ta:bemount,mounted')
|
|
local root_dataset=$(find_root_dataset "$all_zfs_datasets")
|
|
local datasets_to_mount=$(find_datasets_to_mount_for_boot_environment "$all_zfs_datasets" "$root_dataset")
|
|
if [ -n "$datasets_to_mount" ]; then
|
|
mount_datasets "$datasets_to_mount"
|
|
fi
|
|
}
|
|
|
|
function reverse_lines {
|
|
sed '1!x;H;1h;$!d;g'
|
|
}
|
|
|
|
function find_dataset {
|
|
local all_zfs_datasets="$1"
|
|
local dataset_name="$2"
|
|
while read dataset; do
|
|
local ds_name=$(awk '{print $1}'<<<"$dataset")
|
|
if [ "$ds_name" = "$dataset_name" ]; then
|
|
echo "$dataset"
|
|
return
|
|
fi
|
|
done<<<"$all_zfs_datasets"
|
|
}
|
|
|
|
function find_root_dataset {
|
|
local all_zfs_datasets="$1"
|
|
while read dataset; do
|
|
local ds_name=$(awk '{print $1}'<<<"$dataset")
|
|
local ds_mountpoint=$(awk '{print $2}'<<<"$dataset")
|
|
# local ds_canmount=$(awk '{print $3}'<<<"$dataset")
|
|
# local ds_bemount=$(awk '{print $4}'<<<"$dataset")
|
|
local ds_mounted=$(awk '{print $5}'<<<"$dataset")
|
|
if [ "$ds_mounted" = "yes" ] && [ "$ds_mountpoint" = "/" ]; then
|
|
echo "$ds_name"
|
|
return
|
|
fi
|
|
done<<<"$all_zfs_datasets"
|
|
}
|
|
|
|
function find_datasets_to_mount_for_boot_environment {
|
|
local all_zfs_datasets="$1"
|
|
local root_dataset="$2"
|
|
# This is a consequence of my layout for zfs datasets. I should
|
|
# make this more robust. Perhaps a zfs property like search up
|
|
# from dataset mounted at / until you find a dataset with property
|
|
# ta:bemountroot="on"?
|
|
local be_root_name="${root_dataset%/*/*}"
|
|
local be_root_dataset=$(find_dataset "$all_zfs_datasets" "$be_root_name")
|
|
|
|
while read dataset; do
|
|
local ds_name=$(awk '{print $1}'<<<"$dataset")
|
|
# local ds_mountpoint=$(awk '{print $2}'<<<"$dataset")
|
|
local ds_canmount=$(awk '{print $3}'<<<"$dataset")
|
|
local ds_bemount=$(awk '{print $4}'<<<"$dataset")
|
|
local ds_mounted=$(awk '{print $5}'<<<"$dataset")
|
|
|
|
case "$ds_name" in
|
|
"${be_root_name}/"*) ;;
|
|
*) continue ;;
|
|
esac
|
|
|
|
if [ "$ds_bemount" != "on" ]; then
|
|
continue
|
|
fi
|
|
|
|
if [ "$ds_mounted" != "no" ]; then
|
|
continue
|
|
fi
|
|
|
|
if [ "$ds_canmount" != "noauto" ]; then
|
|
continue
|
|
fi
|
|
echo "$dataset"
|
|
|
|
done<<<"$all_zfs_datasets"
|
|
}
|
|
|
|
function mount_datasets {
|
|
local datasets_to_mount=$(reverse_lines<<<"$1")
|
|
while read dataset; do
|
|
local ds_name=$(awk '{print $1}'<<<"$dataset")
|
|
local ds_mountpoint=$(awk '{print $2}'<<<"$dataset")
|
|
local ds_canmount=$(awk '{print $3}'<<<"$dataset")
|
|
local ds_bemount=$(awk '{print $4}'<<<"$dataset")
|
|
local ds_mounted=$(awk '{print $5}'<<<"$dataset")
|
|
|
|
mount -v -t zfs "$ds_name" "$ds_mountpoint"
|
|
|
|
done<<<"$datasets_to_mount"
|
|
}
|
|
|
|
main
|