#!/bin/bash set -euo pipefail SCRIPT_ROOT=$(dirname "$0") # @TODO: Implement more soft-coding and interactivity to this script ZFS_POOL_NAME="medialib" ZFS_COMPAT="openzfs-2.1-linux" ZFS_KEY_LOC="file:///etc/zfs/keys/zroot.key" ZFS_KEY_FORMAT="passphrase" ZFS_COMPRESSION="zstd-3" create_zpool () { sudo zpool create \ -o ashift=12 \ -o autotrim=on \ -o compatibility="$3" \ -O encryption=on \ -O keylocation="$4" \ -O keyformat="$5" \ -O acltype=posixacl \ -O xattr=sa \ -O dnodesize=auto \ -O compression="$6" \ -O normalization=formD \ -O relatime=on \ -O canmount=off \ -O mountpoint=none \ "$2" \ /dev/disk/by-id/"${1}" } mkdataset () { mkdir -p "$1" sudo zfs create -v -o mountpoint="$1" "$2" } create_datasets () { read -r -p "Provide custom datasets? (y/n): " CUSTOMIZE_DATASETS if [[ "$CUSTOMIZE_DATASETS" =~ [Nn]* ]]; then DATASET=("${HOME}/Documents/.calibre" "${1}/LITERATURE") mkdataset "${DATASET[0]}" "${DATASET[1]}" DATASET=("${HOME}/Videos" "${1}/FILM") mkdataset "${DATASET[0]}" "${DATASET[1]}" DATASET=("${HOME}/.var/app/com.valvesoftware.Steam" "${1}/STEAMGAMES") mkdataset "${DATASET[0]}" "${DATASET[1]}" DATASET=("${HOME}/.var/app/org.libretro.RetroArch" "${1}/RARCHGAMES") mkdataset "${DATASET[0]}" "${DATASET[1]}" DATASET=("${HOME}/Games" "${1}/GAMES") mkdataset "${DATASET[0]}" "${DATASET[1]}" ln -s "${HOME}/.var/app/com.valvesoftware.Steam" "${DATASET[0]}/Steam" ln -s "${HOME}/.var/app/org.libretro.RetroArch" "${DATASET[0]}/libRetro" DATASET=("${HOME}/.var/app/org.libretro.RetroArch" "${1}/RARCHGAMES") mkdataset "${DATASET[0]}" "${DATASET[1]}" DATASET=("${HOME}/.XXX" "${1}/XXX") mkdir -p "${DATASET[0]}" sudo zfs create -o keylocation=prompt -o keyformat=passphrase -o mountpoint="${DATASET[0]}" "${DATASET[1]}" elif [[ "$CUSTOMIZE_DATASETS" =~ [Yy]* ]]; then while true; do read -r -a DATASET -p "Define a mount path and its corresponding dataset name or route, in that order: " if [ ${#DATASET[@]} -eq 2 ]; then mkdataset "${DATASET[0]}" "${1}"/"${DATASET[1]}" read -r -p "Create another ZFS dataset? (y/n): " ANOTHER_DATASET if [[ "$ANOTHER_DATASET" =~ [Yy]* ]]; then continue elif [[ "$ANOTHER_DATASET" =~ [Nn]* ]]; then break fi else printf "Error: must provide 2 arguments (i.e., mount path and dataset name or route)." read -r -p "Try again? (y/n): " RETRY_PROMPT if [[ "$RETRY_PROMPT" =~ [Yy]* ]]; then continue elif [[ "$RETRY_PROMPT" =~ [Nn]* ]]; then break fi fi done else exit 1 fi } print_menu () { printf "%s" "$(<"${SCRIPT_ROOT}"/zfs-media-drive.help)" } if [ -z "$1" ]; then printf "Subcommand must be provided" exit 1 fi if [ -n "$1" ] && [ "$1" == "init" ]; then shift while getopts "d:p:k:f:c:v:" opt; do case $opt in k) ZFS_KEY_LOC="${OPTARG}";; f) ZFS_KEY_FORMAT="${OPTARG}";; c) ZFS_COMPRESSION="${OPTARG}";; v) ZFS_COMPAT="${OPTARG}";; p) ZFS_POOL_NAME="${OPTARG}";; d) ZFS_TARGET_DRIVE="${OPTARG}";; *) exit 1; esac done if [ -z "$ZFS_TARGET_DRIVE" ]; then printf "Error: It is necessary to argue a -d option." exit 1 fi export ZFS_POOL_NAME create_zpool "$ZFS_TARGET_DRIVE" "$ZFS_POOL_NAME" "$ZFS_COMPAT" "$ZFS_KEY_LOC" "$ZFS_KEY_FORMAT" "$ZFS_COMPRESSION" printf "Following pool has been created: \n" zpool list -v | grep "$ZFS_POOL_NAME" create_datasets "$ZFS_POOL_NAME" printf "Following datasets have been created: \n" zfs list | grep "$ZFS_POOL_NAME" elif [ -n "$1" ] && [ "$1" == "enc" ]; then while true; do read -r -a DATASET -p "Define a mount path and its corresponding dataset name or route, in that order: " if [ ${#DATASET[@]} -eq 2 ]; then mkdir -p "${DATASET[0]}" sudo zfs create -v -o keylocation=prompt -o keyformat=passphrase -o mountpoint="${DATASET[0]}" "${ZFS_POOL_NAME}"/"${DATASET[1]}" read -r -p "Create another ZFS dataset? (y/n): " ANOTHER_DATASET if [[ "$ANOTHER_DATASET" =~ [Yy]* ]]; then continue elif [[ "$ANOTHER_DATASET" =~ [Nn]* ]]; then break fi else printf "Error: must provide 2 arguments (i.e., mount path and dataset name or route)." read -r -p "Try again? (y/n): " RETRY_PROMPT if [[ "$RETRY_PROMPT" =~ [Yy]* ]]; then continue elif [[ "$RETRY_PROMPT" =~ [Nn]* ]]; then break fi fi done elif [ -n "$1" ] && [ "$1" == "link" ]; then while true; do read -r -a LINKAGE -p "Define a symbolic link source path and destination dataset: " if [ ${#LINKAGE[@]} -eq 2 ]; then if ! [ -d "${LINKAGE[0]}" ]; then mkdir -p "${LINKAGE[0]}" fi ln -s "${LINKAGE[0]}" "${ZFS_POOL_NAME}"/"${LINKAGE[1]}" read -r -p "Create another symbolic link? (y/n): " ANOTHER_LINKAGE if [[ "$ANOTHER_LINKAGE" =~ [Yy]* ]]; then continue elif [[ "$ANOTHER_LINKAGE" =~ [Nn]* ]]; then break fi else printf "Error: must provide 2 arguments (i.e., source path and destination path)." read -r -p "Try again? (y/n): " RETRY_PROMPT if [[ "$RETRY_PROMPT" =~ [Yy]* ]]; then continue elif [[ "$RETRY_PROMPT" =~ [Nn]* ]]; then break fi fi done else while getopts "h" flag; do case "$flag" in h) print_menu;; *) exit 1;; esac done fi