Witajcie. Napisałem ostatnio sobie skrypcik w bashu do tworzenia datasetów i pooli zfs. Mam wrażenie że mój skrypt to czysty mess. Uczę się dopiero pisać w bashu, czerpię wiedzę z kursów videopoint. Bardzo mi zależy na solidnym code review skryptu, nie boję się krytyki ;-)
Kod
#!/usr/bin/env bash
set -o errexit
# set -o pipefail
set -o nounset
# set -o xtrace
die() {
local msg=$1
printf "Error: %s. Exiting...\n" "$msg" >&2
exit 1
}
log_info() {
local msg=$1
printf "[INFO] %s\n" "$msg"
}
require_binary() {
local binaries=( "$@" )
for binary in ${binaries[*]}; do
if ! command -v "${binary}" &> /dev/null; then
die "${binary} binary does not exist"
fi
done
}
require_binary "zpool" "zfs" "sgdisk"
readonly lockdir=/tmp/prepare_zfs.lock
if ! mkdir "$lockdir"; then
die "Lock file already exists"
fi
trap 'stty echo; rm -rf "${lockdir}"; exit $?' EXIT
display_usage() {
cat <<EOF
./prepare_zfs.sh - Setup ZFS layout
Usage:
./prepare_zfs.sh [ options ]
./prepare_zfs.sh --help
Options:
Specific to the target zfs_on_root:
--boot-mode legacy_bios|uefi (default: legacy_bios) - specify a boot mode
--distro|--distribution debian|gentoo|linux (default: linux) - specify a target linux distribution
--gnome - create gnome datasets
--libvirt - create libvirt datasets
--lxc - create lxc datasets
--docker - create docker datasets
--nfs - create nfs datasets
--webserver - create datasets for webservers
--mailserver - create datasets for mailservers
--snap - create datasets for snap packages
--systemd - create datasets for systemd
--rpool-name - specify a rootfs pool name
--bpool-name - specify a boot pool name
--zfs-swap - enable zfs swap partition
--swap-hibernate - enable if swap hibernation is used
-u|--username value (default: user) - specify username
Specific to the target home_dir:
-u|--username value (defaukt: user) - specify username
Target independent:
--ashift value (default: optimal, calculated by script) - overrides default ashift value
--raid none|raid0|raid1 (default: none) - specify raid type
--device|--devices paths - specify target devices
-m|--mnt path (default: /mnt) - specify ZFS pool mount path
--encrypt-zfs - specify if you want to encrypt ZFS pool
--key-type password|keyfile - encryption key type
--key-path path - path to the encryption keyfile
-c|--config path (default: ./zfs_layout.conf) - specify path to the config file
-t|--target data|home_dir|zfs_on_root - specify the target
-i|--interactive - enter into interactive mode
-h|--help - displays help
EOF
exit 0
}
while (( $# )); do
opt=$1
case $opt in
--ashift)
ZFS_POOL_ASHIFT=$2
shift 2
;;
--boot-mode)
BOOT_MODE=$2
shift 2
;;
--distro|--distribution)
TARGET_DISTRO=$2
shift 2
;;
--gnome)
ZFS_DATASET_GNOME="y"
shift 1
;;
--libvirt)
ZFS_DATASET_LIBVIRT="y"
shift 1
;;
--lxc)
ZFS_DATASET_LXC="y"
shift 1
;;
--docker)
ZFS_DATASET_DOCKER="y"
shift 1
;;
--nfs)
ZFS_DATASET_NFS="y"
shift 1
;;
--webserver)
ZFS_DATASET_WEBSERVER="y"
shift 1
;;
--mailserver)
ZFS_DATASET_MAILSERVER="y"
shift 1
;;
--snap)
ZFS_DATASET_SNAP="y"
shift 1
;;
--systemd)
ZFS_DATASET_SYSTEMD="y"
shift 1
;;
--encrypt-zfs)
ZFS_ENC_ENABLED="y"
shift 1
;;
--key-type)
ZFS_ENC_TYPE="$2"
shift 2
;;
--key-path)
ZFS_ENC_KEYPATH="$2"
shift 2
;;
--rpool-name)
ZFS_RPOOL="$2"
shift 2
;;
--bpool-name)
ZFS_BPOOL="$2"
shift 2
;;
--pool-name)
ZFS_POOL="$2"
shift 2
;;
--zfs-swap)
ZFS_CREATE_SWAP="y"
shift 1
;;
--swap-hibernate)
SWAP_HIBERNATE="y"
shift 1
;;
-t|--target)
ZFS_TARGET="$2"
shift 2
;;
--raid)
ZFS_RAID_TYPE="$2"
shift 2
;;
-u|--username)
ZFS_DATASET_USER="$2"
shift 2
;;
--device|--devices)
TARGET_DEV="$2"
shift 2
;;
-m|--mnt)
MNT_PATH="$2"
shift 2
;;
-c|--config)
CONFIG_FILE="$2"
shift 2
;;
-i|--interactive)
INTERACTIVE="y"
shift 1
;;
-h|--help)
display_usage
shift 1
;;
*)
printf "./prepare_zfs.sh: error: unrecognized arguments: %s" "$@"
display_usage
exit 1
;;
esac
done
ZFS_POOL_ASHIFT=${ZFS_POOL_ASHIFT:-}
BOOT_MODE=${BOOT_MODE:-"legacy_bios"}
TARGET_DISTRO=${TARGET_DISTRO:-"linux"}
ZFS_DATASET_GNOME=${ZFS_DATASET_GNOME:-}
ZFS_DATASET_LIBVIRT=${ZFS_DATASET_LIBVIRT:-}
ZFS_DATASET_LXC=${ZFS_DATASET_LXC:-}
ZFS_DATASET_DOCKER=${ZFS_DATASET_DOCKER:-}
ZFS_DATASET_NFS=${ZFS_DATASET_NFS:-}
ZFS_DATASET_WEBSERVER=${ZFS_DATASET_WEBSERVER:-}
ZFS_DATASET_MAILSERVER=${ZFS_DATASET_MAILSERVER:-}
ZFS_DATASET_SNAP=${ZFS_DATASET_SNAP:-}
ZFS_DATASET_SYSTEMD=${ZFS_DATASET_SYSTEMD:-}
ZFS_ENC_ENABLED=${ZFS_ENC_ENABLED:-}
ZFS_ENC_TYPE=${ZFS_ENC_TYPE:-}
ZFS_ENC_KEYPATH=${ZFS_ENC_KEYPATH:-}
ZFS_RPOOL=${ZFS_RPOOL:-"rpool"}
ZFS_BPOOL=${ZFS_BPOOL:-"bpool"}
ZFS_POOL=${ZFS_POOL:-}
ZFS_CREATE_SWAP=${ZFS_CREATE_SWAP:-}
SWAP_HIBERNATE=${SWAP_HIBERNATE:-}
ZFS_TARGET=${ZFS_TARGET:-}
ZFS_RAID_TYPE=${ZFS_RAID_TYPE:-"none"}
TARGET_DEV=${TARGET_DEV:-}
MNT_PATH=${MNT_PATH:-"/mnt"}
ZFS_DATASET_USER=${ZFS_DATASET_USER:-"user"}
CONFIG_FILE=${CONFIG_FILE:-"./zfs_layout.conf"}
INTERACTIVE=${INTERACTIVE:-}
# shellcheck disable=SC1090
[[ -f "${CONFIG_FILE}" ]] && source "${CONFIG_FILE}"
yesno() {
local question=$1
local -n answer=$2
while true; do
read -rp "$question (answer y or n)? " answer
case $answer in
y) answer=1; return;;
n) answer=""; return;;
*) printf "Error: invalid answer, valid choices are y and n.\n" >&2 ;;
esac
done
}
read_string() {
local question=$1
local -n answer=$2
local default=${3:-}
if [[ $default ]]; then
read -rp "$question (leave blank for $default): " answer
else
read -rp "$question: " answer
fi
answer=${answer:-$default}
}
read_num() {
local question=$1
local -n answer=$2
local default=${3:-}
if [[ $default ]]; then
question="$question (leave blank for $default): "
else
question="$question: "
fi
local re='^[0-9]+$'
until
read -rp "$question" answer
answer=${answer:-$default}
[[ "$answer" =~ $re ]]
do
printf "%s: not a number.\n" "$answer" >&2
done
}
read_device() {
local question=$1
local -n answer=$2
local default=${3:-}
if [[ $default ]]; then
question="$question (leave blank for $default): "
else
question="$question: "
fi
until
read -rp "$question" answer
answer=${answer:-$default}
[ -b "$answer" ]
do
printf "%s: not a device.\n" "$answer" >&2
done
}
read_devices() {
local question=$1
local -n devices=$2
local quit=false
until $quit; do
read_string "$question" devices
for device in $devices; do
if [ ! -b "$device" ]; then
printf "%s: not a device.\n" "$device" >&2
else
quit=true
fi
done
done
}
read_dir() {
local question=$1
local -n answer=$2
local default=${3:-}
if [[ $default ]]; then
question="$question (leave blank for $default): "
else
question="$question: "
fi
until
read -rp "$question" answer
answer=${answer:-$default}
[ -b "$answer}" ]
do
printf "%s: not a directory.\n" "$answer" >&2
done
}
read_mnt() {
local question=$1
local -n answer=$2
local default=${3:-}
if [[ $default ]]; then
question="$question (leave blank for $default): "
else
question="$question: "
fi
while
read -rp "$question" answer
answer=${answer:-$default}
[ "$(findmnt -M "$answer")" ]
do
printf "%s: already mounted.\n" "$answer" >&2
done
}
read_choice() {
local question=$1
local -n ans=$2
local choices=( "$@" )
choices=( "${choices[@]:2}" )
while true; do
printf "%s\n" "$question"
for (( i = 0; i < ${#choices[@]}; ++i )); do
printf "%d) %s\n" "$i" "${choices[$i]}"
done
read_num "Your choice" ans
if [ "$ans" -ge 0 ] && [ "$ans" -lt ${#choices[@]} ]; then
ans=${choices[$ans]}
break
else
printf "Invalid choice!\n\n"
fi
done
}
read_password() {
local -n answer=$1
local passwd confirm_passwd
until
stty -echo
read -rp "Password: " passwd
printf "\n"
read -rp "Confirm password: " confirm_passwd
printf "\n"
stty echo
[ "$passwd" == "$confirm_passwd" ]
do
printf "Error: passwords don't match.\n" >&2
done
answer="${passwd}"
}
find_device_id() {
local device=$1
local result
[[ ! -b ${device} ]] && die "${device}: not a block device"
result=$(find /dev/disk/by-id -lname "*$(lsblk --noheadings --output NAME -nl ${device} | head -n1 | awk '{print $1;}')" -printf "%p\n" | grep -v "wwn")
[[ -z "${result}" ]] && printf "%s" "${device}" || printf "%s" "${result}"
}
if [[ ${INTERACTIVE} ]]; then
if [[ -z ${TARGET_DEV[*]} ]]; then
if [[ ${ZFS_RAID_TYPE} != "none" ]]; then
read_devices "Enter target devices separated by spaces" TARGET_DEV
else
read_device "Enter target device path" TARGET_DEV
fi
fi
if [[ -z ${ZFS_TARGET} ]]; then
choices=( "zfs_on_root" "home_dir" "data" )
read_choice "Select target" ZFS_TARGET "${choices[@]}"
fi
[[ -z "${ZFS_ENC_ENABLED}" ]] && yesno "Do you want to use encryption" ZFS_ENC_ENABLED
if [[ ${ZFS_TARGET} == "zfs_on_root" ]]; then
if [[ -z ${BOOT_MODE} ]]; then
choices=( "legacy_bios" "uefi" )
read_choice "Select boot mode" BOOT_MODE "${choices[@]}"
fi
[[ -z "${MNT_PATH}" ]] && read_mnt "Enter mount path for rootfs" MNT_PATH "/mnt"
[[ -z "${ZFS_BPOOL}" ]] && read_string "Enter ZFS boot pool name" ZFS_BPOOL "bpool"
[[ -z "${ZFS_RPOOL}" ]] && read_string "Enter ZFS root pool name" ZFS_RPOOL "rpool"
if [[ -z "${TARGET_DISTRO}" ]]; then
choices=( "gentoo" "debian" "linux" )
read_choice "Choose target operating system" TARGET_DISTRO "${choices[@]}"
fi
[[ -z "${ZFS_DATASET_GNOME}" ]] && yesno "Will you be using GNOME" ZFS_DATASET_GNOME
[[ -z "${ZFS_DATASET_LIBVIRT}" ]] && yesno "Will you be using libvirt" ZFS_DATASET_LIBVIRT
[[ -z "${ZFS_DATASET_LXC}" ]] && yesno "Will you be using LXC" ZFS_DATASET_LXC
[[ -z "${ZFS_DATASET_DOCKER}" ]] && yesno "Will you be using Docker" ZFS_DATASET_DOCKER
[[ -z "${ZFS_DATASET_NFS}" ]] && yesno "Will you be using NFS" ZFS_DATASET_NFS
[[ -z "${ZFS_DATASET_WEBSERVER}" ]] && yesno "Will you be using web servers" ZFS_DATASET_WEBSERVER
[[ -z "${ZFS_DATASET_MAILSERVER}" ]] && yesno "Will you be using mail servers" ZFS_DATASET_MAILSERVER
[[ -z "${ZFS_DATASET_SNAP}" ]] && yesno "Will you be using snap packages" ZFS_DATASET_SNAP
[[ -z "${ZFS_DATASET_SYSTEMD}" ]] && yesno "Will you be using systemd" ZFS_DATASET_SYSTEMD
[[ -z "${ZFS_CREATE_SWAP}" ]] && yesno "Do you want to create swap dataset" ZFS_CREATE_SWAP
[[ $ZFS_CREATE_SWAP ]] && yesno "Will you hibernate device" SWAP_HIBERNATE
[[ -z "${ZFS_DATASET_USER}" ]] && read_string "Enter username" username "user"
[[ -z "${ZFS_ENC_ENABLED}" ]] && yesno "Do you want to use encryption" ZFS_ENC_ENABLED
fi
fi
IFS=" " read -r -a TARGET_DEV <<< "${TARGET_DEV}"
case ${BOOT_MODE} in
legacy_bios|uefi)
;;
*)
die "unsupported boot mode ${BOOT_MODE}"
;;
esac
case ${TARGET_DISTRO} in
gentoo|debian|linux)
;;
*)
die "unsupported operating system '${TARGET_DISTRO}'"
;;
esac
case ${ZFS_TARGET} in
data|home_dir|zfs_on_root)
;;
"")
die "target not specified"
;;
*)
die "invalid target '${ZFS_TARGET}'"
;;
esac
case ${ZFS_RAID_TYPE} in
none)
[[ ${#TARGET_DEV[@]} -gt 1 ]] && die "too many devices, specified raid type is 'none'"
;;
raid0|raid1)
[[ ${#TARGET_DEV[@]} -lt 2 ]] && die "required at least 2 devices, not a raid"
;;
*)
die "invalid raid type $2"
;;
esac
# if [[ ${ZFS_TARGET} != "zfs_on_root" ]]; then
# if [[ ${ZFS_DATASET_GNOME} || ${ZFS_DATASET_LIBVIRT} || ${ZFS_DATASET_LXC} || ${ZFS_DATASET_DOCKER} || ${ZFS_DATASET_NFS}\
# || ${ZFS_DATASET_WEBSERVER} || ${ZFS_DATASET_MAILSERVER} || ${ZFS_DATASET_SNAP} || ${ZFS_DATASET_SYSTEMD} || ${ZFS_RPOOL}\
# || ${ZFS_BPOOL} || ${ZFS_CREATE_SWAP} || ${SWAP_HIBERNATE} || ${ZFS_RAID_TYPE} ]]; then
# die "${ZFS_TARGET} target contains zfs_on_root specific argument"
# fi
# fi
if [[ ${ZFS_TARGET} == "data" && -n "${ZFS_DATASET_USER}" ]]; then
die "${ZFS_TARGET} target cannot contain username argument"
fi
# if [[ ${ZFS_POOL} ]]; then
# [[ ${ZFS_RPOOL} || ${ZFS_BPOOL} ]] && die "--bpool-name and --rpool-name arguments cannot be specified when --pool-name argument is specified"
# fi
for dev in "${TARGET_DEV[@]}"; do
if [ ! -b "${dev}" ]; then
die "${dev}: not a device"
fi
done
if [[ ! -d ${MNT_PATH} ]]; then
die "${MNT_PATH}: not a directory"
fi
if [[ "$(findmnt -M "${MNT_PATH}")" ]]; then
die "${MNT_PATH}: already mounted"
fi
PASSWORD=""
if [[ ${ZFS_ENC_ENABLED} ]]; then
choices=( "password" "keyfile" )
[[ -z ${ZFS_ENC_TYPE} ]] && read_choice "Do you want to use password or generate keyfile?" ZFS_ENC_TYPE "${choices[@]}"
case ${ZFS_ENC_TYPE} in
"password")
read_password PASSWORD
;;
"keyfile")
if [[ -z ${ZFS_ENC_KEYPATH} ]]; then
read_string "Enter path for generated keyfile" ZFS_ENC_KEYPATH "/usr/local/etc/keys/${ZFS_POOL}.key"
fi
;;
**)
die "invalid encryption type '${ZFS_ENC_TYPE}'"
;;
esac
fi
for (( i = 0; i < ${#TARGET_DEV[@]}; ++i )); do
TARGET_DEV[$i]=$(find_device_id "${TARGET_DEV[$i]}")
done
calculate_ashift() {
local device=$1
local zpool_ashift=""
local sector_size
sector_size=$(blockdev --getpbsz "${device}")
case $sector_size in
"512")
zpool_ashift=9
;;
"4096")
zpool_ashift=12
;;
"8192")
zpool_ashift=13
;;
esac
[[ -z ${ZFS_POOL_ASHIFT} ]] && printf "%d" $zpool_ashift || printf "%d" "${ZFS_POOL_ASHIFT}"
}
calculate_swap_size() {
local swap_size
local total_memory
total_memory=$(free -m | awk '/^Mem:/{print $2}')
if [[ $total_memory -le 2048 ]]; then
if [[ ${SWAP_HIBERNATE} ]]; then
swap_size=$(( 3 * total_memory ))
else
swap_size=$(( 2 * total_memory ))
fi
elif [[ $total_memory -gt 2048 && $total_memory -le 8192 ]]; then
if [[ ${SWAP_HIBERNATE} ]]; then
swap_size=$(( 2 * total_memory ))
else
swap_size=$total_memory
fi
elif [[ $total_memory -gt 8192 && $total_memory -le 65536 ]]; then
if [[ ${SWAP_HIBERNATE} ]]; then
swap_size=$(echo "1.5 * $total_memory" | bc -l)
else
swap_size=4096
fi
else
if [[ ${SWAP_HIBERNATE} ]]; then
die "operation not supported"
else
swap_size=4096
fi
fi
printf "%sM" $swap_size
}
create_partitions() {
log_info "Creating partitions"
for device in ${TARGET_DEV[*]}; do
sgdisk --zap-all "$device"
sgdisk -n 0:0:+1MiB -t 0:ef02 -c 0:grub "$device"
sgdisk -n 0:0:+1GiB -t 0:be00 -c 0:boot "$device"
sgdisk -n 0:0:0 -t 0:bf00 -c 0:root "$device"
done
sleep 3
}
create_swap() {
log_info "Creating swap dataset"
local swap_size
swap_size=$(calculate_swap_size "${SWAP_HIBERNATE}" "${ZFS_RPOOL}")
zfs create -V "$swap_size" -b 4096 -o logbias=throughput -o sync=always -o primarycache=metadata\
-o com.sun:auto-snapshot=false "${ZFS_RPOOL}/swap"
mkswap -f "/dev/zvol/${ZFS_RPOOL}/swap"
}
check_ashift() {
local partitions=$*
local zpool_ashift=""
local prev=""
for part in ${partitions[*]}; do
zpool_ashift=$(calculate_ashift "${part}")
if [[ ${prev} && ${zpool_ashift} != $(calculate_ashift "${prev}") ]]; then
die "device ashifts don't match"
fi
prev=${part}
done
printf "%d" "${zpool_ashift}"
}
generate_keyfile() {
local target=$1
tr -d '\n' < /dev/urandom | head -c 512 > "$target"
log_info "Successfully created encryption key"
}
create_bpool() {
log_info "Creating bpool"
local devices=( "$@" )
local bpool_ashift
bpool_ashift=$(check_ashift "${devices[@]}")
local bpool_args=(
"-d"
"-f"
"-o feature@allocation_classes=enabled"
"-o feature@async_destroy=enabled"
"-o feature@bookmarks=enabled"
"-o feature@embedded_data=enabled"
"-o feature@empty_bpobj=enabled"
"-o feature@enabled_txg=enabled"
"-o feature@extensible_dataset=enabled"
"-o feature@filesystem_limits=enabled"
"-o feature@hole_birth=enabled"
"-o feature@large_blocks=enabled"
"-o feature@lz4_compress=enabled"
"-o feature@project_quota=enabled"
"-o feature@resilver_defer=enabled"
"-o feature@spacemap_histogram=enabled"
"-o feature@spacemap_v2=enabled"
"-o feature@userobj_accounting=enabled"
"-o feature@zpool_checkpoint=enabled"
"-o ashift=${bpool_ashift}"
"-o cachefile=/etc/zfs/zpool.cache"
"-o autotrim=on"
"-O acltype=posixacl"
"-O canmount=off"
"-O compression=off"
"-O devices=off"
"-O normalization=formD"
"-O relatime=on"
"-O xattr=sa"
"-O mountpoint=/boot"
"-R ${MNT_PATH}"
)
case ${ZFS_RAID_TYPE} in
none)
zpool create ${bpool_args[*]} ${ZFS_BPOOL} ${devices[*]}
;;
raid0)
zpool create ${bpool_args[*]} ${ZFS_BPOOL} ${devices[*]}
;;
raid1)
zpool create ${bpool_args[*]} ${ZFS_BPOOL} mirror ${devices[*]}
;;
esac
zfs create -o canmount=off -o mountpoint=none ${ZFS_BPOOL}/BOOT
zfs create -o mountpoint=/boot ${ZFS_BPOOL}/BOOT/default
zpool export ${ZFS_BPOOL}
rmdir ${MNT_PATH}/boot || true
}
create_rpool() {
log_info "Creating rpool"
local devices=( "$@" )
local rpool_args=(
"-f"
"-o ashift=$(check_ashift "${devices[@]}")"
"-o cachefile=/etc/zfs/zpool.cache"
"-O acltype=posixacl"
"-O relatime=on"
"-O xattr=sa"
"-O dnodesize=legacy"
"-O normalization=formD"
"-O mountpoint=none"
"-O canmount=off"
"-O devices=off"
"-O compression=lz4"
"-m none"
"-R ${MNT_PATH}"
)
if [[ ${ZFS_ENC_ENABLED} ]]; then
rpool_args+=( "-O encryption=aes-256-gcm" "-O keyformat=passphrase" )
case ${ZFS_ENC_TYPE} in
"password")
rpool_args+=( "-O keylocation=prompt" )
;;
"keyfile")
mkdir -p "$(dirname "${ZFS_ENC_KEYPATH}")"
generate_keyfile "${ZFS_ENC_KEYPATH}"
rpool_args+=( "-O keylocation=file://${ZFS_ENC_KEYPATH}" )
;;
esac
fi
case ${ZFS_RAID_TYPE} in
none)
zpool create ${rpool_args[*]} ${ZFS_RPOOL} ${devices[*]} <<< "${PASSWORD}"
;;
raid0)
zpool create ${rpool_args[*]} ${ZFS_RPOOL} ${devices[*]} <<< "${PASSWORD}"
;;
raid1)
zpool create ${rpool_args[*]} ${ZFS_RPOOL} mirror ${devices[*]} <<< "${PASSWORD}"
;;
esac
zfs create -o mountpoint=none -o compression=lz4 ${ZFS_RPOOL}/ROOT
zfs create -o mountpoint=/ ${ZFS_RPOOL}/ROOT/default
zfs create -o canmount=off -o mountpoint=/var -o xattr=sa ${ZFS_RPOOL}/ROOT/var
zfs create -o canmount=off -o mountpoint=/var/lib ${ZFS_RPOOL}/ROOT/var/lib
if [[ ${TARGET_DISTRO} == "gentoo" ]]; then
# Create portage directories
zfs create -o mountpoint=/var/cache/distfiles ${ZFS_RPOOL}/ROOT/distfiles
# Create portage build directory
zfs create -o mountpoint=/var/tmp/portage -o compression=lz4 -o sync=disabled ${ZFS_RPOOL}/ROOT/build_dir
# Create optional packages directory
zfs create -o mountpoint=/var/cache/binpkgs ${ZFS_RPOOL}/ROOT/binpkgs
# Create optional ccache directory
zfs create -o mountpoint=/var/tmp/ccache -o compression=lz4 ${ZFS_RPOOL}/ROOT/ccache
fi
[[ ${ZFS_DATASET_GNOME} ]] && zfs create -o canmount=on -o mountpoint=/var/lib/AccountsService ${ZFS_RPOOL}/ROOT/var/lib/AccountsService
[[ ${ZFS_DATASET_LIBVIRT} ]] && zfs create -o canmount=on -o mountpoint=/var/lib/libvirt ${ZFS_RPOOL}/ROOT/var/lib/libvirt
[[ ${ZFS_DATASET_LXC} ]] && zfs create -o canmount=on -o mountpoint=/var/lib/lxc ${ZFS_RPOOL}/ROOT/var/lib/lxc
[[ ${ZFS_DATASET_DOCKER} ]] && zfs create -o canmount=on -o mountpoint=/var/lib/docker ${ZFS_RPOOL}/ROOT/var/lib/docker
[[ ${ZFS_DATASET_NFS} ]] && zfs create -o canmount=on -o mountpoint=/var/lib/nfs ${ZFS_RPOOL}/ROOT/var/lib/nfs
[[ ${ZFS_DATASET_WEBSERVER} ]] && zfs create -o canmount=on -o mountpoint=/var/www ${ZFS_RPOOL}/ROOT/var/www
[[ ${ZFS_DATASET_MAILSERVER} ]] && zfs create -o canmount=on -o mountpoint=/var/mail ${ZFS_RPOOL}/ROOT/var/mail
[[ ${ZFS_DATASET_SNAP} ]] && zfs create -o canmount=on -o mountpoint=/var/snap ${ZFS_RPOOL}/ROOT/var/snap
[[ ${ZFS_DATASET_SYSTEMD} ]] && zfs create -o canmount=off -o mountpoint=/var/lib/systemd ${ZFS_RPOOL}/ROOT/var/lib/systemd
zfs create -o canmount=off -o mountpoint=/usr ${ZFS_RPOOL}/ROOT/usr
zfs create -o mountpoint=/usr/local ${ZFS_RPOOL}/ROOT/usr/local
zfs create -o mountpoint=/opt ${ZFS_RPOOL}/ROOT/opt
[[ ${ZFS_DATASET_SYSTEMD} ]] && zfs create -o mountpoint=/var/lib/systemd/coredump ${ZFS_RPOOL}/ROOT/var/lib/systemd/coredump
zfs create -o mountpoint=/var/log ${ZFS_RPOOL}/ROOT/var/log
[[ ${ZFS_DATASET_SYSTEMD} ]] && zfs create -o acltype=posixacl -o mountpoint=/var/log/journal ${ZFS_RPOOL}/ROOT/var/log/journal
zfs create -o mountpoint=/home ${ZFS_RPOOL}/home
zfs create -o mountpoint=/root ${ZFS_RPOOL}/home/root
zfs create -o mountpoint=/home/${ZFS_DATASET_USER} ${ZFS_RPOOL}/home/${ZFS_DATASET_USER}
zpool set bootfs=${ZFS_RPOOL} ${ZFS_RPOOL}
zfs set relatime=on ${ZFS_RPOOL}
zfs set compression=lz4 ${ZFS_RPOOL}
[[ ${ZFS_CREATE_SWAP} ]] && create_swap ${SWAP_HIBERNATE} ${ZFS_RPOOL}
zpool export ${ZFS_RPOOL}
}
mount_rootfs() {
zpool import -R ${MNT_PATH} ${ZFS_RPOOL}
if [[ ${ZFS_ENC_ENABLED} ]]; then
zfs load-key ${ZFS_RPOOL} <<< "${PASSWORD}"
zfs mount -a
fi
zpool import -o cachefile=/etc/zfs/zpool.cache -R ${MNT_PATH} ${ZFS_BPOOL}
mkdir -p ${MNT_PATH}/etc/zfs
cp /etc/zfs/zpool.cache ${MNT_PATH}/etc/zfs/zpool.cache
log_info "Successfully mounted rootfs"
}
create_rootfs() {
local partitions=( )
for device in ${TARGET_DEV[*]}; do
if [[ ${device} == /dev/disk/by-id* ]]; then
partitions+=( "${device}-part2" )
else
partitions+=( "${device}2" )
fi
done
create_bpool "${partitions[@]}"
partitions=( )
for device in ${TARGET_DEV[*]}; do
if [[ ${device} == /dev/disk/by-id* ]]; then
partitions+=( "${device}-part3" )
else
partitions+=( "${device}3" )
fi
done
create_rpool "${partitions[@]}"
mount_rootfs
}
create_data_pool() {
local devices=( "$@" )
local zpool_args=(
"-f"
"-o ashift=$(check_ashift "${TARGET_DEV[@]}")"
"-o cachefile=/etc/zfs/zpool.cache"
"-O compression=lz4"
"-R ${MNT_PATH}"
)
if [[ ${ZFS_ENC_ENABLED} ]]; then
rpool_args+=( "-O encryption=aes-256-gcm" "-O keyformat=passphrase" )
case ${ZFS_ENC_TYPE} in
"password")
rpool_args+=( "-O keylocation=prompt" )
;;
"keyfile")
mkdir -p "$(dirname "${ZFS_ENC_KEYPATH}")"
generate_keyfile "${ZFS_ENC_KEYPATH}"
zpool_args+=( "-O keylocation=file://${ZFS_ENC_KEYPATH}" )
;;
esac
fi
case ${ZFS_RAID_TYPE} in
none)
zpool create ${rpool_args[*]} ${ZFS_POOL} ${devices[*]} <<< "${PASSWORD}"
;;
raid0)
zpool create ${rpool_args[*]} ${ZFS_POOL} ${devices[*]} <<< "${PASSWORD}"
;;
raid1)
zpool create ${rpool_args[*]} ${ZFS_POOL} mirror ${devices[*]} <<< "${PASSWORD}"
;;
esac
zfs create ${ZFS_POOL}/documents
zfs create ${ZFS_POOL}/downloads
zfs create ${ZFS_POOL}/ebooks
zfs create ${ZFS_POOL}/images
zfs create ${ZFS_POOL}/movies
zfs create ${ZFS_POOL}/music
zfs create ${ZFS_POOL}/operating_systems
zfs create ${ZFS_POOL}/websites
zfs create ${ZFS_POOL}/random_stuff
zpool export ${ZFS_POOL}
zpool import -R ${MNT_PATH} ${ZFS_POOL}
if [[ ${ZFS_ENC_ENABLED} ]]; then
zfs load-key ${ZFS_POOL} <<< "${PASSWORD}"
zfs mount -a
fi
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/documents
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/downloads
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/ebooks
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/images
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/movies
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/music
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/operating_systems
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/websites
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/random_stuff
chown -R ${ZFS_DATASET_USER}:users ${MNT_PATH}
}
create_home_dir_pool() {
local devices=( "$@" )
local pool_args=(
"-f"
"-o ashift=$(check_ashift "${devices[@]}")"
"-o cachefile=/etc/zfs/zpool.cache"
"-O compression=lz4"
"-O mountpoint=none"
"-R ${MNT_PATH}"
)
if [[ ${ZFS_ENC_ENABLED} ]]; then
pool_args+=( "-O encryption=aes-256-gcm" "-O keyformat=passphrase" )
case ${ZFS_ENC_TYPE} in
"password")
pool_args+=( "-O keylocation=prompt" )
;;
"keyfile")
mkdir -p "$(dirname "${ZFS_ENC_KEYPATH}")"
generate_keyfile "${ZFS_ENC_KEYPATH}"
pool_args+=( "-O keylocation=file://${ZFS_ENC_KEYPATH}" )
;;
esac
fi
case ${ZFS_RAID_TYPE} in
none)
zpool create ${pool_args[*]} ${ZFS_POOL} ${devices[*]} <<< "${PASSWORD}"
;;
raid0)
zpool create ${pool_args[*]} ${ZFS_POOL} ${devices[*]} <<< "${PASSWORD}"
;;
raid1)
zpool create ${pool_args[*]} ${ZFS_POOL} mirror ${devices[*]} <<< "${PASSWORD}"
;;
esac
zfs create -o mountpoint=/home/${ZFS_DATASET_USER}/Documents ${ZFS_POOL}/documents
zfs create -o mountpoint=/home/${ZFS_DATASET_USER}/Downloads ${ZFS_POOL}/downloads
zfs create -o mountpoint=/home/${ZFS_DATASET_USER}/Calibre\ Library ${ZFS_POOL}/ebooks
zfs create -o mountpoint=/home/${ZFS_DATASET_USER}/Pictures ${ZFS_POOL}/images
zfs create -o mountpoint=/home/${ZFS_DATASET_USER}/Videos ${ZFS_POOL}/movies
zfs create -o mountpoint=/home/${ZFS_DATASET_USER}/Music ${ZFS_POOL}/music
zfs create -o mountpoint=/home/${ZFS_DATASET_USER}/Operating\ systems ${ZFS_POOL}/operating_systems
zfs create -o mountpoint=/home/${ZFS_DATASET_USER}/websites ${ZFS_POOL}/websites
zpool export ${ZFS_POOL}
zpool import ${ZFS_POOL}
if [[ ${ZFS_ENC_ENABLED} ]]; then
zfs load-key ${ZFS_POOL} <<< "${PASSWORD}"
zfs mount -a
fi
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/documents
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/downloads
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/ebooks
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/images
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/movies
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/music
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/operating_systems
zfs allow ${ZFS_DATASET_USER} create,mount,mountpoint,snapshot ${ZFS_POOL}/websites
chown -R ${ZFS_DATASET_USER}:users /home/${ZFS_DATASET_USER}
}
case ${ZFS_TARGET} in
"data")
create_data_pool "${TARGET_DEV[@]}"
;;
"home_dir")
create_home_dir_pool "${TARGET_DEV[@]}"
;;
"zfs_on_root")
create_partitions
create_rootfs
;;
esac