1eda14cbcSMatt Macy# ZFS boot stub for initramfs-tools. 2eda14cbcSMatt Macy# 3eda14cbcSMatt Macy# In the initramfs environment, the /init script sources this stub to 4eda14cbcSMatt Macy# override the default functions in the /scripts/local script. 5eda14cbcSMatt Macy# 6eda14cbcSMatt Macy# Enable this by passing boot=zfs on the kernel command line. 7eda14cbcSMatt Macy# 8*16038816SMartin Matuska# $quiet, $root, $rpool, $bootfs come from the cmdline: 9*16038816SMartin Matuska# shellcheck disable=SC2154 10eda14cbcSMatt Macy 11eda14cbcSMatt Macy# Source the common functions 12eda14cbcSMatt Macy. /etc/zfs/zfs-functions 13eda14cbcSMatt Macy 14eda14cbcSMatt Macy# Start interactive shell. 15eda14cbcSMatt Macy# Use debian's panic() if defined, because it allows to prevent shell access 16eda14cbcSMatt Macy# by setting panic in cmdline (e.g. panic=0 or panic=15). 17eda14cbcSMatt Macy# See "4.5 Disable root prompt on the initramfs" of Securing Debian Manual: 18eda14cbcSMatt Macy# https://www.debian.org/doc/manuals/securing-debian-howto/ch4.en.html 19eda14cbcSMatt Macyshell() { 20c40487d4SMatt Macy if command -v panic > /dev/null 2>&1; then 21c40487d4SMatt Macy panic 22eda14cbcSMatt Macy else 23eda14cbcSMatt Macy /bin/sh 24eda14cbcSMatt Macy fi 25eda14cbcSMatt Macy} 26eda14cbcSMatt Macy 27eda14cbcSMatt Macy# This runs any scripts that should run before we start importing 28eda14cbcSMatt Macy# pools and mounting any filesystems. 29eda14cbcSMatt Macypre_mountroot() 30eda14cbcSMatt Macy{ 31c40487d4SMatt Macy if command -v run_scripts > /dev/null 2>&1 32c40487d4SMatt Macy then 33c40487d4SMatt Macy if [ -f "/scripts/local-top" ] || [ -d "/scripts/local-top" ] 34eda14cbcSMatt Macy then 35eda14cbcSMatt Macy [ "$quiet" != "y" ] && \ 36eda14cbcSMatt Macy zfs_log_begin_msg "Running /scripts/local-top" 37eda14cbcSMatt Macy run_scripts /scripts/local-top 38eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 39eda14cbcSMatt Macy fi 40eda14cbcSMatt Macy 41c40487d4SMatt Macy if [ -f "/scripts/local-premount" ] || [ -d "/scripts/local-premount" ] 42eda14cbcSMatt Macy then 43eda14cbcSMatt Macy [ "$quiet" != "y" ] && \ 44eda14cbcSMatt Macy zfs_log_begin_msg "Running /scripts/local-premount" 45eda14cbcSMatt Macy run_scripts /scripts/local-premount 46eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 47eda14cbcSMatt Macy fi 48c40487d4SMatt Macy fi 49eda14cbcSMatt Macy} 50eda14cbcSMatt Macy 51eda14cbcSMatt Macy# If plymouth is available, hide the splash image. 52eda14cbcSMatt Macydisable_plymouth() 53eda14cbcSMatt Macy{ 54eda14cbcSMatt Macy if [ -x /bin/plymouth ] && /bin/plymouth --ping 55eda14cbcSMatt Macy then 56eda14cbcSMatt Macy /bin/plymouth hide-splash >/dev/null 2>&1 57eda14cbcSMatt Macy fi 58eda14cbcSMatt Macy} 59eda14cbcSMatt Macy 60eda14cbcSMatt Macy# Get a ZFS filesystem property value. 61eda14cbcSMatt Macyget_fs_value() 62eda14cbcSMatt Macy{ 63c40487d4SMatt Macy fs="$1" 64c40487d4SMatt Macy value=$2 65eda14cbcSMatt Macy 66c40487d4SMatt Macy "${ZFS}" get -H -ovalue "$value" "$fs" 2> /dev/null 67eda14cbcSMatt Macy} 68eda14cbcSMatt Macy 69eda14cbcSMatt Macy# Find the 'bootfs' property on pool $1. 70eda14cbcSMatt Macy# If the property does not contain '/', then ignore this 71eda14cbcSMatt Macy# pool by exporting it again. 72eda14cbcSMatt Macyfind_rootfs() 73eda14cbcSMatt Macy{ 74c40487d4SMatt Macy pool="$1" 75eda14cbcSMatt Macy 76eda14cbcSMatt Macy # If 'POOL_IMPORTED' isn't set, no pool imported and therefore 77eda14cbcSMatt Macy # we won't be able to find a root fs. 78eda14cbcSMatt Macy [ -z "${POOL_IMPORTED}" ] && return 1 79eda14cbcSMatt Macy 80eda14cbcSMatt Macy # If it's already specified, just keep it mounted and exit 81eda14cbcSMatt Macy # User (kernel command line) must be correct. 82eda14cbcSMatt Macy [ -n "${ZFS_BOOTFS}" ] && return 0 83eda14cbcSMatt Macy 84eda14cbcSMatt Macy # Not set, try to find it in the 'bootfs' property of the pool. 85eda14cbcSMatt Macy # NOTE: zpool does not support 'get -H -ovalue bootfs'... 86eda14cbcSMatt Macy ZFS_BOOTFS=$("${ZPOOL}" list -H -obootfs "$pool") 87eda14cbcSMatt Macy 88eda14cbcSMatt Macy # Make sure it's not '-' and that it starts with /. 89eda14cbcSMatt Macy if [ "${ZFS_BOOTFS}" != "-" ] && \ 90c40487d4SMatt Macy get_fs_value "${ZFS_BOOTFS}" mountpoint | grep -q '^/$' 91eda14cbcSMatt Macy then 92eda14cbcSMatt Macy # Keep it mounted 93eda14cbcSMatt Macy POOL_IMPORTED=1 94eda14cbcSMatt Macy return 0 95eda14cbcSMatt Macy fi 96eda14cbcSMatt Macy 97eda14cbcSMatt Macy # Not boot fs here, export it and later try again.. 98eda14cbcSMatt Macy "${ZPOOL}" export "$pool" 99*16038816SMartin Matuska POOL_IMPORTED= 100*16038816SMartin Matuska ZFS_BOOTFS= 101eda14cbcSMatt Macy return 1 102eda14cbcSMatt Macy} 103eda14cbcSMatt Macy 104eda14cbcSMatt Macy# Support function to get a list of all pools, separated with ';' 105eda14cbcSMatt Macyfind_pools() 106eda14cbcSMatt Macy{ 107*16038816SMartin Matuska pools=$("$@" 2> /dev/null | \ 108eda14cbcSMatt Macy grep -E "pool:|^[a-zA-Z0-9]" | \ 109eda14cbcSMatt Macy sed 's@.*: @@' | \ 110*16038816SMartin Matuska tr '\n' ';') 111eda14cbcSMatt Macy 112eda14cbcSMatt Macy echo "${pools%%;}" # Return without the last ';'. 113eda14cbcSMatt Macy} 114eda14cbcSMatt Macy 115eda14cbcSMatt Macy# Get a list of all available pools 116eda14cbcSMatt Macyget_pools() 117eda14cbcSMatt Macy{ 118eda14cbcSMatt Macy if [ -n "${ZFS_POOL_IMPORT}" ]; then 119eda14cbcSMatt Macy echo "$ZFS_POOL_IMPORT" 120eda14cbcSMatt Macy return 0 121eda14cbcSMatt Macy fi 122eda14cbcSMatt Macy 123eda14cbcSMatt Macy # Get the base list of available pools. 124eda14cbcSMatt Macy available_pools=$(find_pools "$ZPOOL" import) 125eda14cbcSMatt Macy 126eda14cbcSMatt Macy # Just in case - seen it happen (that a pool isn't visible/found 127eda14cbcSMatt Macy # with a simple "zpool import" but only when using the "-d" 128eda14cbcSMatt Macy # option or setting ZPOOL_IMPORT_PATH). 129eda14cbcSMatt Macy if [ -d "/dev/disk/by-id" ] 130eda14cbcSMatt Macy then 131eda14cbcSMatt Macy npools=$(find_pools "$ZPOOL" import -d /dev/disk/by-id) 132eda14cbcSMatt Macy if [ -n "$npools" ] 133eda14cbcSMatt Macy then 134eda14cbcSMatt Macy # Because we have found extra pool(s) here, which wasn't 135eda14cbcSMatt Macy # found 'normally', we need to force USE_DISK_BY_ID to 136eda14cbcSMatt Macy # make sure we're able to actually import it/them later. 137eda14cbcSMatt Macy USE_DISK_BY_ID='yes' 138eda14cbcSMatt Macy 139eda14cbcSMatt Macy if [ -n "$available_pools" ] 140eda14cbcSMatt Macy then 141eda14cbcSMatt Macy # Filter out duplicates (pools found with the simple 142eda14cbcSMatt Macy # "zpool import" but which is also found with the 143eda14cbcSMatt Macy # "zpool import -d ..."). 144eda14cbcSMatt Macy npools=$(echo "$npools" | sed "s,$available_pools,,") 145eda14cbcSMatt Macy 146eda14cbcSMatt Macy # Add the list to the existing list of 147eda14cbcSMatt Macy # available pools 148eda14cbcSMatt Macy available_pools="$available_pools;$npools" 149eda14cbcSMatt Macy else 150eda14cbcSMatt Macy available_pools="$npools" 151eda14cbcSMatt Macy fi 152eda14cbcSMatt Macy fi 153eda14cbcSMatt Macy fi 154eda14cbcSMatt Macy 155eda14cbcSMatt Macy # Filter out any exceptions... 156eda14cbcSMatt Macy if [ -n "$ZFS_POOL_EXCEPTIONS" ] 157eda14cbcSMatt Macy then 158c40487d4SMatt Macy found="" 159c40487d4SMatt Macy apools="" 160eda14cbcSMatt Macy OLD_IFS="$IFS" ; IFS=";" 161eda14cbcSMatt Macy 162eda14cbcSMatt Macy for pool in $available_pools 163eda14cbcSMatt Macy do 164eda14cbcSMatt Macy for exception in $ZFS_POOL_EXCEPTIONS 165eda14cbcSMatt Macy do 166eda14cbcSMatt Macy [ "$pool" = "$exception" ] && continue 2 167eda14cbcSMatt Macy found="$pool" 168eda14cbcSMatt Macy done 169eda14cbcSMatt Macy 170eda14cbcSMatt Macy if [ -n "$found" ] 171eda14cbcSMatt Macy then 172eda14cbcSMatt Macy if [ -n "$apools" ] 173eda14cbcSMatt Macy then 174eda14cbcSMatt Macy apools="$apools;$pool" 175eda14cbcSMatt Macy else 176eda14cbcSMatt Macy apools="$pool" 177eda14cbcSMatt Macy fi 178eda14cbcSMatt Macy fi 179eda14cbcSMatt Macy done 180eda14cbcSMatt Macy 181eda14cbcSMatt Macy IFS="$OLD_IFS" 182eda14cbcSMatt Macy available_pools="$apools" 183eda14cbcSMatt Macy fi 184eda14cbcSMatt Macy 185eda14cbcSMatt Macy # Return list of available pools. 186eda14cbcSMatt Macy echo "$available_pools" 187eda14cbcSMatt Macy} 188eda14cbcSMatt Macy 189eda14cbcSMatt Macy# Import given pool $1 190eda14cbcSMatt Macyimport_pool() 191eda14cbcSMatt Macy{ 192c40487d4SMatt Macy pool="$1" 193eda14cbcSMatt Macy 194eda14cbcSMatt Macy # Verify that the pool isn't already imported 195eda14cbcSMatt Macy # Make as sure as we can to not require '-f' to import. 196eda14cbcSMatt Macy "${ZPOOL}" get name,guid -o value -H 2>/dev/null | grep -Fxq "$pool" && return 0 197eda14cbcSMatt Macy 198eda14cbcSMatt Macy # For backwards compatibility, make sure that ZPOOL_IMPORT_PATH is set 199eda14cbcSMatt Macy # to something we can use later with the real import(s). We want to 200eda14cbcSMatt Macy # make sure we find all by* dirs, BUT by-vdev should be first (if it 201eda14cbcSMatt Macy # exists). 202c40487d4SMatt Macy if [ -n "$USE_DISK_BY_ID" ] && [ -z "$ZPOOL_IMPORT_PATH" ] 203eda14cbcSMatt Macy then 204*16038816SMartin Matuska dirs="$(for dir in /dev/disk/by-* 205eda14cbcSMatt Macy do 206eda14cbcSMatt Macy # Ignore by-vdev here - we want it first! 207eda14cbcSMatt Macy echo "$dir" | grep -q /by-vdev && continue 208eda14cbcSMatt Macy [ ! -d "$dir" ] && continue 209eda14cbcSMatt Macy 210c40487d4SMatt Macy printf "%s" "$dir:" 211eda14cbcSMatt Macy done | sed 's,:$,,g')" 212eda14cbcSMatt Macy 213eda14cbcSMatt Macy if [ -d "/dev/disk/by-vdev" ] 214eda14cbcSMatt Macy then 215eda14cbcSMatt Macy # Add by-vdev at the beginning. 216eda14cbcSMatt Macy ZPOOL_IMPORT_PATH="/dev/disk/by-vdev:" 217eda14cbcSMatt Macy fi 218eda14cbcSMatt Macy 219eda14cbcSMatt Macy # ... and /dev at the very end, just for good measure. 220eda14cbcSMatt Macy ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH$dirs:/dev" 221eda14cbcSMatt Macy fi 222eda14cbcSMatt Macy 223eda14cbcSMatt Macy # Needs to be exported for "zpool" to catch it. 224eda14cbcSMatt Macy [ -n "$ZPOOL_IMPORT_PATH" ] && export ZPOOL_IMPORT_PATH 225eda14cbcSMatt Macy 226eda14cbcSMatt Macy 227eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_begin_msg \ 228eda14cbcSMatt Macy "Importing pool '${pool}' using defaults" 229eda14cbcSMatt Macy 230eda14cbcSMatt Macy ZFS_CMD="${ZPOOL} import -N ${ZPOOL_FORCE} ${ZPOOL_IMPORT_OPTS}" 231eda14cbcSMatt Macy ZFS_STDERR="$($ZFS_CMD "$pool" 2>&1)" 232eda14cbcSMatt Macy ZFS_ERROR="$?" 233eda14cbcSMatt Macy if [ "${ZFS_ERROR}" != 0 ] 234eda14cbcSMatt Macy then 235eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" 236eda14cbcSMatt Macy 237eda14cbcSMatt Macy if [ -f "${ZPOOL_CACHE}" ] 238eda14cbcSMatt Macy then 239eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_begin_msg \ 240eda14cbcSMatt Macy "Importing pool '${pool}' using cachefile." 241eda14cbcSMatt Macy 242eda14cbcSMatt Macy ZFS_CMD="${ZPOOL} import -c ${ZPOOL_CACHE} -N ${ZPOOL_FORCE} ${ZPOOL_IMPORT_OPTS}" 243eda14cbcSMatt Macy ZFS_STDERR="$($ZFS_CMD "$pool" 2>&1)" 244eda14cbcSMatt Macy ZFS_ERROR="$?" 245eda14cbcSMatt Macy fi 246eda14cbcSMatt Macy 247eda14cbcSMatt Macy if [ "${ZFS_ERROR}" != 0 ] 248eda14cbcSMatt Macy then 249eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" 250eda14cbcSMatt Macy 251eda14cbcSMatt Macy disable_plymouth 252eda14cbcSMatt Macy echo "" 253eda14cbcSMatt Macy echo "Command: ${ZFS_CMD} '$pool'" 254eda14cbcSMatt Macy echo "Message: $ZFS_STDERR" 255eda14cbcSMatt Macy echo "Error: $ZFS_ERROR" 256eda14cbcSMatt Macy echo "" 257eda14cbcSMatt Macy echo "Failed to import pool '$pool'." 258eda14cbcSMatt Macy echo "Manually import the pool and exit." 259eda14cbcSMatt Macy shell 260eda14cbcSMatt Macy fi 261eda14cbcSMatt Macy fi 262eda14cbcSMatt Macy 263eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 264eda14cbcSMatt Macy 265eda14cbcSMatt Macy POOL_IMPORTED=1 266eda14cbcSMatt Macy return 0 267eda14cbcSMatt Macy} 268eda14cbcSMatt Macy 269eda14cbcSMatt Macy# Load ZFS modules 270eda14cbcSMatt Macy# Loading a module in a initrd require a slightly different approach, 271eda14cbcSMatt Macy# with more logging etc. 272eda14cbcSMatt Macyload_module_initrd() 273eda14cbcSMatt Macy{ 274*16038816SMartin Matuska [ -n "$ROOTDELAY" ] && ZFS_INITRD_PRE_MOUNTROOT_SLEEP="$ROOTDELAY" 275*16038816SMartin Matuska 276c40487d4SMatt Macy if [ "$ZFS_INITRD_PRE_MOUNTROOT_SLEEP" -gt 0 ] 2>/dev/null 277eda14cbcSMatt Macy then 278eda14cbcSMatt Macy if [ "$quiet" != "y" ]; then 279eda14cbcSMatt Macy zfs_log_begin_msg "Sleeping for" \ 280eda14cbcSMatt Macy "$ZFS_INITRD_PRE_MOUNTROOT_SLEEP seconds..." 281eda14cbcSMatt Macy fi 282eda14cbcSMatt Macy sleep "$ZFS_INITRD_PRE_MOUNTROOT_SLEEP" 283eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 284eda14cbcSMatt Macy fi 285eda14cbcSMatt Macy 286eda14cbcSMatt Macy # Wait for all of the /dev/{hd,sd}[a-z] device nodes to appear. 287c40487d4SMatt Macy if command -v wait_for_udev > /dev/null 2>&1 ; then 288eda14cbcSMatt Macy wait_for_udev 10 289c40487d4SMatt Macy elif command -v wait_for_dev > /dev/null 2>&1 ; then 290eda14cbcSMatt Macy wait_for_dev 291eda14cbcSMatt Macy fi 292eda14cbcSMatt Macy 293eda14cbcSMatt Macy # zpool import refuse to import without a valid /proc/self/mounts 294eda14cbcSMatt Macy [ ! -f /proc/self/mounts ] && mount proc /proc 295eda14cbcSMatt Macy 296eda14cbcSMatt Macy # Load the module 297eda14cbcSMatt Macy load_module "zfs" || return 1 298eda14cbcSMatt Macy 299c40487d4SMatt Macy if [ "$ZFS_INITRD_POST_MODPROBE_SLEEP" -gt 0 ] 2>/dev/null 300eda14cbcSMatt Macy then 301eda14cbcSMatt Macy if [ "$quiet" != "y" ]; then 302eda14cbcSMatt Macy zfs_log_begin_msg "Sleeping for" \ 303eda14cbcSMatt Macy "$ZFS_INITRD_POST_MODPROBE_SLEEP seconds..." 304eda14cbcSMatt Macy fi 305eda14cbcSMatt Macy sleep "$ZFS_INITRD_POST_MODPROBE_SLEEP" 306eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 307eda14cbcSMatt Macy fi 308eda14cbcSMatt Macy 309eda14cbcSMatt Macy return 0 310eda14cbcSMatt Macy} 311eda14cbcSMatt Macy 312eda14cbcSMatt Macy# Mount a given filesystem 313eda14cbcSMatt Macymount_fs() 314eda14cbcSMatt Macy{ 315c40487d4SMatt Macy fs="$1" 316eda14cbcSMatt Macy 317eda14cbcSMatt Macy # Check that the filesystem exists 318c40487d4SMatt Macy "${ZFS}" list -oname -tfilesystem -H "${fs}" > /dev/null 2>&1 || return 1 319eda14cbcSMatt Macy 320eda14cbcSMatt Macy # Skip filesystems with canmount=off. The root fs should not have 321eda14cbcSMatt Macy # canmount=off, but ignore it for backwards compatibility just in case. 322eda14cbcSMatt Macy if [ "$fs" != "${ZFS_BOOTFS}" ] 323eda14cbcSMatt Macy then 324eda14cbcSMatt Macy canmount=$(get_fs_value "$fs" canmount) 325eda14cbcSMatt Macy [ "$canmount" = "off" ] && return 0 326eda14cbcSMatt Macy fi 327eda14cbcSMatt Macy 328eda14cbcSMatt Macy # Need the _original_ datasets mountpoint! 329eda14cbcSMatt Macy mountpoint=$(get_fs_value "$fs" mountpoint) 330*16038816SMartin Matuska ZFS_CMD="mount -o zfsutil -t zfs" 331c40487d4SMatt Macy if [ "$mountpoint" = "legacy" ] || [ "$mountpoint" = "none" ]; then 332eda14cbcSMatt Macy # Can't use the mountpoint property. Might be one of our 333eda14cbcSMatt Macy # clones. Check the 'org.zol:mountpoint' property set in 334eda14cbcSMatt Macy # clone_snap() if that's usable. 335eda14cbcSMatt Macy mountpoint=$(get_fs_value "$fs" org.zol:mountpoint) 336c40487d4SMatt Macy if [ "$mountpoint" = "legacy" ] || 337c40487d4SMatt Macy [ "$mountpoint" = "none" ] || 338c40487d4SMatt Macy [ "$mountpoint" = "-" ] 339eda14cbcSMatt Macy then 340eda14cbcSMatt Macy if [ "$fs" != "${ZFS_BOOTFS}" ]; then 341eda14cbcSMatt Macy # We don't have a proper mountpoint and this 342eda14cbcSMatt Macy # isn't the root fs. 343eda14cbcSMatt Macy return 0 344eda14cbcSMatt Macy else 345eda14cbcSMatt Macy # Last hail-mary: Hope 'rootmnt' is set! 346eda14cbcSMatt Macy mountpoint="" 347eda14cbcSMatt Macy fi 348eda14cbcSMatt Macy fi 349eda14cbcSMatt Macy 350eda14cbcSMatt Macy # If it's not a legacy filesystem, it can only be a 351eda14cbcSMatt Macy # native one... 352*16038816SMartin Matuska if [ "$mountpoint" = "legacy" ]; then 353*16038816SMartin Matuska ZFS_CMD="mount -t zfs" 354eda14cbcSMatt Macy fi 355eda14cbcSMatt Macy fi 356eda14cbcSMatt Macy 357eda14cbcSMatt Macy # Possibly decrypt a filesystem using native encryption. 358eda14cbcSMatt Macy decrypt_fs "$fs" 359eda14cbcSMatt Macy 360eda14cbcSMatt Macy [ "$quiet" != "y" ] && \ 361eda14cbcSMatt Macy zfs_log_begin_msg "Mounting '${fs}' on '${rootmnt}/${mountpoint}'" 362eda14cbcSMatt Macy [ -n "${ZFS_DEBUG}" ] && \ 363eda14cbcSMatt Macy zfs_log_begin_msg "CMD: '$ZFS_CMD ${fs} ${rootmnt}/${mountpoint}'" 364eda14cbcSMatt Macy 365eda14cbcSMatt Macy ZFS_STDERR=$(${ZFS_CMD} "${fs}" "${rootmnt}/${mountpoint}" 2>&1) 366eda14cbcSMatt Macy ZFS_ERROR=$? 367eda14cbcSMatt Macy if [ "${ZFS_ERROR}" != 0 ] 368eda14cbcSMatt Macy then 369eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" 370eda14cbcSMatt Macy 371eda14cbcSMatt Macy disable_plymouth 372eda14cbcSMatt Macy echo "" 373eda14cbcSMatt Macy echo "Command: ${ZFS_CMD} ${fs} ${rootmnt}/${mountpoint}" 374eda14cbcSMatt Macy echo "Message: $ZFS_STDERR" 375eda14cbcSMatt Macy echo "Error: $ZFS_ERROR" 376eda14cbcSMatt Macy echo "" 377eda14cbcSMatt Macy echo "Failed to mount ${fs} on ${rootmnt}/${mountpoint}." 378eda14cbcSMatt Macy echo "Manually mount the filesystem and exit." 379eda14cbcSMatt Macy shell 380eda14cbcSMatt Macy else 381eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 382eda14cbcSMatt Macy fi 383eda14cbcSMatt Macy 384eda14cbcSMatt Macy return 0 385eda14cbcSMatt Macy} 386eda14cbcSMatt Macy 387eda14cbcSMatt Macy# Unlock a ZFS native encrypted filesystem. 388eda14cbcSMatt Macydecrypt_fs() 389eda14cbcSMatt Macy{ 390c40487d4SMatt Macy fs="$1" 391eda14cbcSMatt Macy 392eda14cbcSMatt Macy # If pool encryption is active and the zfs command understands '-o encryption' 393*16038816SMartin Matuska if [ "$(zpool list -H -o feature@encryption "${fs%%/*}")" = 'active' ]; then 394eda14cbcSMatt Macy 395eda14cbcSMatt Macy # Determine dataset that holds key for root dataset 396eda14cbcSMatt Macy ENCRYPTIONROOT="$(get_fs_value "${fs}" encryptionroot)" 397eda14cbcSMatt Macy KEYLOCATION="$(get_fs_value "${ENCRYPTIONROOT}" keylocation)" 398eda14cbcSMatt Macy 399eda14cbcSMatt Macy echo "${ENCRYPTIONROOT}" > /run/zfs_fs_name 400eda14cbcSMatt Macy 401eda14cbcSMatt Macy # If root dataset is encrypted... 402eda14cbcSMatt Macy if ! [ "${ENCRYPTIONROOT}" = "-" ]; then 403eda14cbcSMatt Macy KEYSTATUS="$(get_fs_value "${ENCRYPTIONROOT}" keystatus)" 404eda14cbcSMatt Macy # Continue only if the key needs to be loaded 405eda14cbcSMatt Macy [ "$KEYSTATUS" = "unavailable" ] || return 0 406eda14cbcSMatt Macy 407*16038816SMartin Matuska # Do not prompt if key is stored noninteractively, 408eda14cbcSMatt Macy if ! [ "${KEYLOCATION}" = "prompt" ]; then 409eda14cbcSMatt Macy $ZFS load-key "${ENCRYPTIONROOT}" 410eda14cbcSMatt Macy 411eda14cbcSMatt Macy # Prompt with plymouth, if active 412*16038816SMartin Matuska elif /bin/plymouth --ping 2>/dev/null; then 413eda14cbcSMatt Macy echo "plymouth" > /run/zfs_console_askpwd_cmd 414*16038816SMartin Matuska for _ in 1 2 3; do 415eda14cbcSMatt Macy plymouth ask-for-password --prompt "Encrypted ZFS password for ${ENCRYPTIONROOT}" | \ 416eda14cbcSMatt Macy $ZFS load-key "${ENCRYPTIONROOT}" && break 417eda14cbcSMatt Macy done 418eda14cbcSMatt Macy 419eda14cbcSMatt Macy # Prompt with systemd, if active 420eda14cbcSMatt Macy elif [ -e /run/systemd/system ]; then 421eda14cbcSMatt Macy echo "systemd-ask-password" > /run/zfs_console_askpwd_cmd 422*16038816SMartin Matuska for _ in 1 2 3; do 423eda14cbcSMatt Macy systemd-ask-password "Encrypted ZFS password for ${ENCRYPTIONROOT}" --no-tty | \ 424eda14cbcSMatt Macy $ZFS load-key "${ENCRYPTIONROOT}" && break 425eda14cbcSMatt Macy done 426eda14cbcSMatt Macy 427eda14cbcSMatt Macy # Prompt with ZFS tty, otherwise 428eda14cbcSMatt Macy else 429eda14cbcSMatt Macy # Temporarily setting "printk" to "7" allows the prompt to appear even when the "quiet" kernel option has been used 430eda14cbcSMatt Macy echo "load-key" > /run/zfs_console_askpwd_cmd 431eda14cbcSMatt Macy storeprintk="$(awk '{print $1}' /proc/sys/kernel/printk)" 432eda14cbcSMatt Macy echo 7 > /proc/sys/kernel/printk 433eda14cbcSMatt Macy $ZFS load-key "${ENCRYPTIONROOT}" 434eda14cbcSMatt Macy echo "$storeprintk" > /proc/sys/kernel/printk 435eda14cbcSMatt Macy fi 436eda14cbcSMatt Macy fi 437eda14cbcSMatt Macy fi 438eda14cbcSMatt Macy 439eda14cbcSMatt Macy return 0 440eda14cbcSMatt Macy} 441eda14cbcSMatt Macy 442eda14cbcSMatt Macy# Destroy a given filesystem. 443eda14cbcSMatt Macydestroy_fs() 444eda14cbcSMatt Macy{ 445c40487d4SMatt Macy fs="$1" 446eda14cbcSMatt Macy 447eda14cbcSMatt Macy [ "$quiet" != "y" ] && \ 448eda14cbcSMatt Macy zfs_log_begin_msg "Destroying '$fs'" 449eda14cbcSMatt Macy 450eda14cbcSMatt Macy ZFS_CMD="${ZFS} destroy $fs" 451eda14cbcSMatt Macy ZFS_STDERR="$(${ZFS_CMD} 2>&1)" 452eda14cbcSMatt Macy ZFS_ERROR="$?" 453eda14cbcSMatt Macy if [ "${ZFS_ERROR}" != 0 ] 454eda14cbcSMatt Macy then 455eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" 456eda14cbcSMatt Macy 457eda14cbcSMatt Macy disable_plymouth 458eda14cbcSMatt Macy echo "" 459eda14cbcSMatt Macy echo "Command: $ZFS_CMD" 460eda14cbcSMatt Macy echo "Message: $ZFS_STDERR" 461eda14cbcSMatt Macy echo "Error: $ZFS_ERROR" 462eda14cbcSMatt Macy echo "" 463eda14cbcSMatt Macy echo "Failed to destroy '$fs'. Please make sure that '$fs' is not available." 464eda14cbcSMatt Macy echo "Hint: Try: zfs destroy -Rfn $fs" 465eda14cbcSMatt Macy echo "If this dryrun looks good, then remove the 'n' from '-Rfn' and try again." 466eda14cbcSMatt Macy shell 467eda14cbcSMatt Macy else 468eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 469eda14cbcSMatt Macy fi 470eda14cbcSMatt Macy 471eda14cbcSMatt Macy return 0 472eda14cbcSMatt Macy} 473eda14cbcSMatt Macy 474eda14cbcSMatt Macy# Clone snapshot $1 to destination filesystem $2 475eda14cbcSMatt Macy# Set 'canmount=noauto' and 'mountpoint=none' so that we get to keep 476eda14cbcSMatt Macy# manual control over it's mounting (i.e., make sure it's not automatically 477eda14cbcSMatt Macy# mounted with a 'zfs mount -a' in the init/systemd scripts). 478eda14cbcSMatt Macyclone_snap() 479eda14cbcSMatt Macy{ 480c40487d4SMatt Macy snap="$1" 481c40487d4SMatt Macy destfs="$2" 482c40487d4SMatt Macy mountpoint="$3" 483eda14cbcSMatt Macy 484eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_begin_msg "Cloning '$snap' to '$destfs'" 485eda14cbcSMatt Macy 486eda14cbcSMatt Macy # Clone the snapshot into a dataset we can boot from 487eda14cbcSMatt Macy # + We don't want this filesystem to be automatically mounted, we 488eda14cbcSMatt Macy # want control over this here and nowhere else. 489eda14cbcSMatt Macy # + We don't need any mountpoint set for the same reason. 490eda14cbcSMatt Macy # We use the 'org.zol:mountpoint' property to remember the mountpoint. 491eda14cbcSMatt Macy ZFS_CMD="${ZFS} clone -o canmount=noauto -o mountpoint=none" 492eda14cbcSMatt Macy ZFS_CMD="${ZFS_CMD} -o org.zol:mountpoint=${mountpoint}" 493eda14cbcSMatt Macy ZFS_CMD="${ZFS_CMD} $snap $destfs" 494eda14cbcSMatt Macy ZFS_STDERR="$(${ZFS_CMD} 2>&1)" 495eda14cbcSMatt Macy ZFS_ERROR="$?" 496eda14cbcSMatt Macy if [ "${ZFS_ERROR}" != 0 ] 497eda14cbcSMatt Macy then 498eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" 499eda14cbcSMatt Macy 500eda14cbcSMatt Macy disable_plymouth 501eda14cbcSMatt Macy echo "" 502eda14cbcSMatt Macy echo "Command: $ZFS_CMD" 503eda14cbcSMatt Macy echo "Message: $ZFS_STDERR" 504eda14cbcSMatt Macy echo "Error: $ZFS_ERROR" 505eda14cbcSMatt Macy echo "" 506eda14cbcSMatt Macy echo "Failed to clone snapshot." 507eda14cbcSMatt Macy echo "Make sure that the any problems are corrected and then make sure" 508eda14cbcSMatt Macy echo "that the dataset '$destfs' exists and is bootable." 509eda14cbcSMatt Macy shell 510eda14cbcSMatt Macy else 511eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 512eda14cbcSMatt Macy fi 513eda14cbcSMatt Macy 514eda14cbcSMatt Macy return 0 515eda14cbcSMatt Macy} 516eda14cbcSMatt Macy 517eda14cbcSMatt Macy# Rollback a given snapshot. 518eda14cbcSMatt Macyrollback_snap() 519eda14cbcSMatt Macy{ 520c40487d4SMatt Macy snap="$1" 521eda14cbcSMatt Macy 522eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_begin_msg "Rollback $snap" 523eda14cbcSMatt Macy 524eda14cbcSMatt Macy ZFS_CMD="${ZFS} rollback -Rf $snap" 525eda14cbcSMatt Macy ZFS_STDERR="$(${ZFS_CMD} 2>&1)" 526eda14cbcSMatt Macy ZFS_ERROR="$?" 527eda14cbcSMatt Macy if [ "${ZFS_ERROR}" != 0 ] 528eda14cbcSMatt Macy then 529eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" 530eda14cbcSMatt Macy 531eda14cbcSMatt Macy disable_plymouth 532eda14cbcSMatt Macy echo "" 533eda14cbcSMatt Macy echo "Command: $ZFS_CMD" 534eda14cbcSMatt Macy echo "Message: $ZFS_STDERR" 535eda14cbcSMatt Macy echo "Error: $ZFS_ERROR" 536eda14cbcSMatt Macy echo "" 537eda14cbcSMatt Macy echo "Failed to rollback snapshot." 538eda14cbcSMatt Macy shell 539eda14cbcSMatt Macy else 540eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 541eda14cbcSMatt Macy fi 542eda14cbcSMatt Macy 543eda14cbcSMatt Macy return 0 544eda14cbcSMatt Macy} 545eda14cbcSMatt Macy 546eda14cbcSMatt Macy# Get a list of snapshots, give them as a numbered list 547eda14cbcSMatt Macy# to the user to choose from. 548eda14cbcSMatt Macyask_user_snap() 549eda14cbcSMatt Macy{ 550c40487d4SMatt Macy fs="$1" 551eda14cbcSMatt Macy 552eda14cbcSMatt Macy # We need to temporarily disable debugging. Set 'debug' so we 553eda14cbcSMatt Macy # remember to enabled it again. 554eda14cbcSMatt Macy if [ -n "${ZFS_DEBUG}" ]; then 555eda14cbcSMatt Macy unset ZFS_DEBUG 556eda14cbcSMatt Macy set +x 557eda14cbcSMatt Macy debug=1 558eda14cbcSMatt Macy fi 559eda14cbcSMatt Macy 560eda14cbcSMatt Macy # Because we need the resulting snapshot, which is sent on 561eda14cbcSMatt Macy # stdout to the caller, we use stderr for our questions. 562eda14cbcSMatt Macy echo "What snapshot do you want to boot from?" > /dev/stderr 563*16038816SMartin Matuska # shellcheck disable=SC2046 564*16038816SMartin Matuska IFS=" 565*16038816SMartin Matuska" set -- $("${ZFS}" list -H -oname -tsnapshot -r "${fs}") 566eda14cbcSMatt Macy 567*16038816SMartin Matuska i=1 568*16038816SMartin Matuska for snap in "$@"; do 569*16038816SMartin Matuska echo " $i: $snap" 570*16038816SMartin Matuska i=$((i + 1)) 571*16038816SMartin Matuska done > /dev/stderr 572*16038816SMartin Matuska 573*16038816SMartin Matuska # expr instead of test here because [ a -lt 0 ] errors out, 574*16038816SMartin Matuska # but expr falls back to lexicographical, which works out right 575*16038816SMartin Matuska snapnr=0 576*16038816SMartin Matuska while expr "$snapnr" "<" 1 > /dev/null || 577*16038816SMartin Matuska expr "$snapnr" ">" "$#" > /dev/null 578*16038816SMartin Matuska do 579*16038816SMartin Matuska printf "%s" "Snap nr [1-$#]? " > /dev/stderr 580c40487d4SMatt Macy read -r snapnr 581*16038816SMartin Matuska done 582eda14cbcSMatt Macy 583eda14cbcSMatt Macy # Re-enable debugging. 584eda14cbcSMatt Macy if [ -n "${debug}" ]; then 585eda14cbcSMatt Macy ZFS_DEBUG=1 586eda14cbcSMatt Macy set -x 587eda14cbcSMatt Macy fi 588eda14cbcSMatt Macy 589*16038816SMartin Matuska eval echo '$'"$snapnr" 590eda14cbcSMatt Macy} 591eda14cbcSMatt Macy 592eda14cbcSMatt Macysetup_snapshot_booting() 593eda14cbcSMatt Macy{ 594c40487d4SMatt Macy snap="$1" 595c40487d4SMatt Macy retval=0 596eda14cbcSMatt Macy 597c40487d4SMatt Macy # Make sure that the snapshot specified actually exists. 598c40487d4SMatt Macy if [ ! "$(get_fs_value "${snap}" type)" ] 599eda14cbcSMatt Macy then 600eda14cbcSMatt Macy # Snapshot does not exist (...@<null> ?) 601eda14cbcSMatt Macy # ask the user for a snapshot to use. 602eda14cbcSMatt Macy snap="$(ask_user_snap "${snap%%@*}")" 603eda14cbcSMatt Macy fi 604eda14cbcSMatt Macy 605eda14cbcSMatt Macy # Separate the full snapshot ('$snap') into it's filesystem and 606eda14cbcSMatt Macy # snapshot names. Would have been nice with a split() function.. 607eda14cbcSMatt Macy rootfs="${snap%%@*}" 608eda14cbcSMatt Macy snapname="${snap##*@}" 609eda14cbcSMatt Macy ZFS_BOOTFS="${rootfs}_${snapname}" 610eda14cbcSMatt Macy 611eda14cbcSMatt Macy if ! grep -qiE '(^|[^\\](\\\\)* )(rollback)=(on|yes|1)( |$)' /proc/cmdline 612eda14cbcSMatt Macy then 613eda14cbcSMatt Macy # If the destination dataset for the clone 614eda14cbcSMatt Macy # already exists, destroy it. Recursively 615c40487d4SMatt Macy if [ "$(get_fs_value "${rootfs}_${snapname}" type)" ]; then 616eda14cbcSMatt Macy filesystems=$("${ZFS}" list -oname -tfilesystem -H \ 617eda14cbcSMatt Macy -r -Sname "${ZFS_BOOTFS}") 618eda14cbcSMatt Macy for fs in $filesystems; do 619eda14cbcSMatt Macy destroy_fs "${fs}" 620eda14cbcSMatt Macy done 621eda14cbcSMatt Macy fi 622eda14cbcSMatt Macy fi 623eda14cbcSMatt Macy 624eda14cbcSMatt Macy # Get all snapshots, recursively (might need to clone /usr, /var etc 625eda14cbcSMatt Macy # as well). 626eda14cbcSMatt Macy for s in $("${ZFS}" list -H -oname -tsnapshot -r "${rootfs}" | \ 627eda14cbcSMatt Macy grep "${snapname}") 628eda14cbcSMatt Macy do 629eda14cbcSMatt Macy if grep -qiE '(^|[^\\](\\\\)* )(rollback)=(on|yes|1)( |$)' /proc/cmdline 630eda14cbcSMatt Macy then 631eda14cbcSMatt Macy # Rollback snapshot 632eda14cbcSMatt Macy rollback_snap "$s" || retval=$((retval + 1)) 633eda14cbcSMatt Macy else 634eda14cbcSMatt Macy # Setup a destination filesystem name. 635eda14cbcSMatt Macy # Ex: Called with 'rpool/ROOT/debian@snap2' 636eda14cbcSMatt Macy # rpool/ROOT/debian@snap2 => rpool/ROOT/debian_snap2 637eda14cbcSMatt Macy # rpool/ROOT/debian/boot@snap2 => rpool/ROOT/debian_snap2/boot 638eda14cbcSMatt Macy # rpool/ROOT/debian/usr@snap2 => rpool/ROOT/debian_snap2/usr 639eda14cbcSMatt Macy # rpool/ROOT/debian/var@snap2 => rpool/ROOT/debian_snap2/var 640eda14cbcSMatt Macy subfs="${s##$rootfs}" 641eda14cbcSMatt Macy subfs="${subfs%%@$snapname}" 642eda14cbcSMatt Macy 643eda14cbcSMatt Macy destfs="${rootfs}_${snapname}" # base fs. 644eda14cbcSMatt Macy [ -n "$subfs" ] && destfs="${destfs}$subfs" # + sub fs. 645eda14cbcSMatt Macy 646eda14cbcSMatt Macy # Get the mountpoint of the filesystem, to be used 647eda14cbcSMatt Macy # with clone_snap(). If legacy or none, then use 648eda14cbcSMatt Macy # the sub fs value. 649eda14cbcSMatt Macy mountpoint=$(get_fs_value "${s%%@*}" mountpoint) 650c40487d4SMatt Macy if [ "$mountpoint" = "legacy" ] || \ 651c40487d4SMatt Macy [ "$mountpoint" = "none" ] 652eda14cbcSMatt Macy then 653eda14cbcSMatt Macy if [ -n "${subfs}" ]; then 654eda14cbcSMatt Macy mountpoint="${subfs}" 655eda14cbcSMatt Macy else 656eda14cbcSMatt Macy mountpoint="/" 657eda14cbcSMatt Macy fi 658eda14cbcSMatt Macy fi 659eda14cbcSMatt Macy 660eda14cbcSMatt Macy # Clone the snapshot into its own 661eda14cbcSMatt Macy # filesystem 662eda14cbcSMatt Macy clone_snap "$s" "${destfs}" "${mountpoint}" || \ 663eda14cbcSMatt Macy retval=$((retval + 1)) 664eda14cbcSMatt Macy fi 665eda14cbcSMatt Macy done 666eda14cbcSMatt Macy 667eda14cbcSMatt Macy # If we haven't return yet, we have a problem... 668eda14cbcSMatt Macy return "${retval}" 669eda14cbcSMatt Macy} 670eda14cbcSMatt Macy 671eda14cbcSMatt Macy# ================================================================ 672eda14cbcSMatt Macy 673eda14cbcSMatt Macy# This is the main function. 674eda14cbcSMatt Macymountroot() 675eda14cbcSMatt Macy{ 676eda14cbcSMatt Macy # ---------------------------------------------------------------- 677eda14cbcSMatt Macy # I N I T I A L S E T U P 678eda14cbcSMatt Macy 679eda14cbcSMatt Macy # ------------ 680eda14cbcSMatt Macy # Run the pre-mount scripts from /scripts/local-top. 681eda14cbcSMatt Macy pre_mountroot 682eda14cbcSMatt Macy 683eda14cbcSMatt Macy # ------------ 684eda14cbcSMatt Macy # Source the default setup variables. 685eda14cbcSMatt Macy [ -r '/etc/default/zfs' ] && . /etc/default/zfs 686eda14cbcSMatt Macy 687eda14cbcSMatt Macy # ------------ 688eda14cbcSMatt Macy # Support debug option 689eda14cbcSMatt Macy if grep -qiE '(^|[^\\](\\\\)* )(zfs_debug|zfs\.debug|zfsdebug)=(on|yes|1)( |$)' /proc/cmdline 690eda14cbcSMatt Macy then 691eda14cbcSMatt Macy ZFS_DEBUG=1 692eda14cbcSMatt Macy mkdir /var/log 693eda14cbcSMatt Macy #exec 2> /var/log/boot.debug 694eda14cbcSMatt Macy set -x 695eda14cbcSMatt Macy fi 696eda14cbcSMatt Macy 697eda14cbcSMatt Macy # ------------ 698eda14cbcSMatt Macy # Load ZFS module etc. 699eda14cbcSMatt Macy if ! load_module_initrd; then 700eda14cbcSMatt Macy disable_plymouth 701eda14cbcSMatt Macy echo "" 702eda14cbcSMatt Macy echo "Failed to load ZFS modules." 703eda14cbcSMatt Macy echo "Manually load the modules and exit." 704eda14cbcSMatt Macy shell 705eda14cbcSMatt Macy fi 706eda14cbcSMatt Macy 707eda14cbcSMatt Macy # ------------ 708eda14cbcSMatt Macy # Look for the cache file (if any). 709*16038816SMartin Matuska [ -f "${ZPOOL_CACHE}" ] || unset ZPOOL_CACHE 710*16038816SMartin Matuska [ -s "${ZPOOL_CACHE}" ] || unset ZPOOL_CACHE 711eda14cbcSMatt Macy 712eda14cbcSMatt Macy # ------------ 713eda14cbcSMatt Macy # Compatibility: 'ROOT' is for Debian GNU/Linux (etc), 714eda14cbcSMatt Macy # 'root' is for Redhat/Fedora (etc), 715eda14cbcSMatt Macy # 'REAL_ROOT' is for Gentoo 716eda14cbcSMatt Macy if [ -z "$ROOT" ] 717eda14cbcSMatt Macy then 718eda14cbcSMatt Macy [ -n "$root" ] && ROOT=${root} 719eda14cbcSMatt Macy 720eda14cbcSMatt Macy [ -n "$REAL_ROOT" ] && ROOT=${REAL_ROOT} 721eda14cbcSMatt Macy fi 722eda14cbcSMatt Macy 723eda14cbcSMatt Macy # ------------ 724eda14cbcSMatt Macy # Where to mount the root fs in the initrd - set outside this script 725eda14cbcSMatt Macy # Compatibility: 'rootmnt' is for Debian GNU/Linux (etc), 726eda14cbcSMatt Macy # 'NEWROOT' is for RedHat/Fedora (etc), 727eda14cbcSMatt Macy # 'NEW_ROOT' is for Gentoo 728eda14cbcSMatt Macy if [ -z "$rootmnt" ] 729eda14cbcSMatt Macy then 730eda14cbcSMatt Macy [ -n "$NEWROOT" ] && rootmnt=${NEWROOT} 731eda14cbcSMatt Macy 732eda14cbcSMatt Macy [ -n "$NEW_ROOT" ] && rootmnt=${NEW_ROOT} 733eda14cbcSMatt Macy fi 734eda14cbcSMatt Macy 735eda14cbcSMatt Macy # ------------ 736eda14cbcSMatt Macy # No longer set in the defaults file, but it could have been set in 737eda14cbcSMatt Macy # get_pools() in some circumstances. If it's something, but not 'yes', 738eda14cbcSMatt Macy # it's no good to us. 739c40487d4SMatt Macy [ -n "$USE_DISK_BY_ID" ] && [ "$USE_DISK_BY_ID" != 'yes' ] && \ 740eda14cbcSMatt Macy unset USE_DISK_BY_ID 741eda14cbcSMatt Macy 742eda14cbcSMatt Macy # ---------------------------------------------------------------- 743eda14cbcSMatt Macy # P A R S E C O M M A N D L I N E O P T I O N S 744eda14cbcSMatt Macy 745eda14cbcSMatt Macy # This part is the really ugly part - there's so many options and permutations 746eda14cbcSMatt Macy # 'out there', and if we should make this the 'primary' source for ZFS initrd 747eda14cbcSMatt Macy # scripting, we need/should support them all. 748eda14cbcSMatt Macy # 749eda14cbcSMatt Macy # Supports the following kernel command line argument combinations 750eda14cbcSMatt Macy # (in this order - first match win): 751eda14cbcSMatt Macy # 752eda14cbcSMatt Macy # rpool=<pool> (tries to finds bootfs automatically) 753eda14cbcSMatt Macy # bootfs=<pool>/<dataset> (uses this for rpool - first part) 754eda14cbcSMatt Macy # rpool=<pool> bootfs=<pool>/<dataset> 755eda14cbcSMatt Macy # -B zfs-bootfs=<pool>/<fs> (uses this for rpool - first part) 756eda14cbcSMatt Macy # rpool=rpool (default if none of the above is used) 757eda14cbcSMatt Macy # root=<pool>/<dataset> (uses this for rpool - first part) 758eda14cbcSMatt Macy # root=ZFS=<pool>/<dataset> (uses this for rpool - first part, without 'ZFS=') 759eda14cbcSMatt Macy # root=zfs:AUTO (tries to detect both pool and rootfs 760eda14cbcSMatt Macy # root=zfs:<pool>/<dataset> (uses this for rpool - first part, without 'zfs:') 761eda14cbcSMatt Macy # 762eda14cbcSMatt Macy # Option <dataset> could also be <snapshot> 763eda14cbcSMatt Macy # Option <pool> could also be <guid> 764eda14cbcSMatt Macy 765eda14cbcSMatt Macy # ------------ 766eda14cbcSMatt Macy # Support force option 767eda14cbcSMatt Macy # In addition, setting one of zfs_force, zfs.force or zfsforce to 768eda14cbcSMatt Macy # 'yes', 'on' or '1' will make sure we force import the pool. 769eda14cbcSMatt Macy # This should (almost) never be needed, but it's here for 770eda14cbcSMatt Macy # completeness. 771eda14cbcSMatt Macy ZPOOL_FORCE="" 772eda14cbcSMatt Macy if grep -qiE '(^|[^\\](\\\\)* )(zfs_force|zfs\.force|zfsforce)=(on|yes|1)( |$)' /proc/cmdline 773eda14cbcSMatt Macy then 774eda14cbcSMatt Macy ZPOOL_FORCE="-f" 775eda14cbcSMatt Macy fi 776eda14cbcSMatt Macy 777eda14cbcSMatt Macy # ------------ 778eda14cbcSMatt Macy # Look for 'rpool' and 'bootfs' parameter 779eda14cbcSMatt Macy [ -n "$rpool" ] && ZFS_RPOOL="${rpool#rpool=}" 780eda14cbcSMatt Macy [ -n "$bootfs" ] && ZFS_BOOTFS="${bootfs#bootfs=}" 781eda14cbcSMatt Macy 782eda14cbcSMatt Macy # ------------ 783eda14cbcSMatt Macy # If we have 'ROOT' (see above), but not 'ZFS_BOOTFS', then use 784eda14cbcSMatt Macy # 'ROOT' 785c40487d4SMatt Macy [ -n "$ROOT" ] && [ -z "${ZFS_BOOTFS}" ] && ZFS_BOOTFS="$ROOT" 786eda14cbcSMatt Macy 787eda14cbcSMatt Macy # ------------ 788eda14cbcSMatt Macy # Check for the `-B zfs-bootfs=%s/%u,...` kind of parameter. 789eda14cbcSMatt Macy # NOTE: Only use the pool name and dataset. The rest is not 790c40487d4SMatt Macy # supported by OpenZFS (whatever it's for). 791eda14cbcSMatt Macy if [ -z "$ZFS_RPOOL" ] 792eda14cbcSMatt Macy then 793eda14cbcSMatt Macy # The ${zfs-bootfs} variable is set at the kernel command 794eda14cbcSMatt Macy # line, usually by GRUB, but it cannot be referenced here 795eda14cbcSMatt Macy # directly because bourne variable names cannot contain a 796eda14cbcSMatt Macy # hyphen. 797eda14cbcSMatt Macy # 798eda14cbcSMatt Macy # Reassign the variable by dumping the environment and 799eda14cbcSMatt Macy # stripping the zfs-bootfs= prefix. Let the shell handle 800*16038816SMartin Matuska # quoting through the eval command: 801*16038816SMartin Matuska # shellcheck disable=SC2046 802eda14cbcSMatt Macy eval ZFS_RPOOL=$(set | sed -n -e 's,^zfs-bootfs=,,p') 803eda14cbcSMatt Macy fi 804eda14cbcSMatt Macy 805eda14cbcSMatt Macy # ------------ 806eda14cbcSMatt Macy # No root fs or pool specified - do auto detect. 807c40487d4SMatt Macy if [ -z "$ZFS_RPOOL" ] && [ -z "${ZFS_BOOTFS}" ] 808eda14cbcSMatt Macy then 809eda14cbcSMatt Macy # Do auto detect. Do this by 'cheating' - set 'root=zfs:AUTO' 810eda14cbcSMatt Macy # which will be caught later 811c40487d4SMatt Macy ROOT='zfs:AUTO' 812eda14cbcSMatt Macy fi 813eda14cbcSMatt Macy 814eda14cbcSMatt Macy # ---------------------------------------------------------------- 815eda14cbcSMatt Macy # F I N D A N D I M P O R T C O R R E C T P O O L 816eda14cbcSMatt Macy 817eda14cbcSMatt Macy # ------------ 818eda14cbcSMatt Macy if [ "$ROOT" = "zfs:AUTO" ] 819eda14cbcSMatt Macy then 820eda14cbcSMatt Macy # Try to detect both pool and root fs. 821eda14cbcSMatt Macy 822*16038816SMartin Matuska # If we got here, that means we don't have a hint so as to 823*16038816SMartin Matuska # the root dataset, but with root=zfs:AUTO on cmdline, 824*16038816SMartin Matuska # this says "zfs:AUTO" here and interferes with checks later 825*16038816SMartin Matuska ZFS_BOOTFS= 826*16038816SMartin Matuska 827eda14cbcSMatt Macy [ "$quiet" != "y" ] && \ 828eda14cbcSMatt Macy zfs_log_begin_msg "Attempting to import additional pools." 829eda14cbcSMatt Macy 830eda14cbcSMatt Macy # Get a list of pools available for import 831eda14cbcSMatt Macy if [ -n "$ZFS_RPOOL" ] 832eda14cbcSMatt Macy then 833eda14cbcSMatt Macy # We've specified a pool - check only that 834eda14cbcSMatt Macy POOLS=$ZFS_RPOOL 835eda14cbcSMatt Macy else 836eda14cbcSMatt Macy POOLS=$(get_pools) 837eda14cbcSMatt Macy fi 838eda14cbcSMatt Macy 839eda14cbcSMatt Macy OLD_IFS="$IFS" ; IFS=";" 840eda14cbcSMatt Macy for pool in $POOLS 841eda14cbcSMatt Macy do 842eda14cbcSMatt Macy [ -z "$pool" ] && continue 843eda14cbcSMatt Macy 844*16038816SMartin Matuska IFS="$OLD_IFS" import_pool "$pool" 845*16038816SMartin Matuska IFS="$OLD_IFS" find_rootfs "$pool" && break 846eda14cbcSMatt Macy done 847eda14cbcSMatt Macy IFS="$OLD_IFS" 848eda14cbcSMatt Macy 849eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg $ZFS_ERROR 850eda14cbcSMatt Macy else 851eda14cbcSMatt Macy # No auto - use value from the command line option. 852eda14cbcSMatt Macy 853eda14cbcSMatt Macy # Strip 'zfs:' and 'ZFS='. 854eda14cbcSMatt Macy ZFS_BOOTFS="${ROOT#*[:=]}" 855eda14cbcSMatt Macy 856eda14cbcSMatt Macy # Strip everything after the first slash. 857eda14cbcSMatt Macy ZFS_RPOOL="${ZFS_BOOTFS%%/*}" 858eda14cbcSMatt Macy fi 859eda14cbcSMatt Macy 860eda14cbcSMatt Macy # Import the pool (if not already done so in the AUTO check above). 861c40487d4SMatt Macy if [ -n "$ZFS_RPOOL" ] && [ -z "${POOL_IMPORTED}" ] 862eda14cbcSMatt Macy then 863eda14cbcSMatt Macy [ "$quiet" != "y" ] && \ 864eda14cbcSMatt Macy zfs_log_begin_msg "Importing ZFS root pool '$ZFS_RPOOL'" 865eda14cbcSMatt Macy 866eda14cbcSMatt Macy import_pool "${ZFS_RPOOL}" 867eda14cbcSMatt Macy find_rootfs "${ZFS_RPOOL}" 868eda14cbcSMatt Macy 869eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 870eda14cbcSMatt Macy fi 871eda14cbcSMatt Macy 872eda14cbcSMatt Macy if [ -z "${POOL_IMPORTED}" ] 873eda14cbcSMatt Macy then 874eda14cbcSMatt Macy # No pool imported, this is serious! 875eda14cbcSMatt Macy disable_plymouth 876eda14cbcSMatt Macy echo "" 877eda14cbcSMatt Macy echo "Command: $ZFS_CMD" 878eda14cbcSMatt Macy echo "Message: $ZFS_STDERR" 879eda14cbcSMatt Macy echo "Error: $ZFS_ERROR" 880eda14cbcSMatt Macy echo "" 881eda14cbcSMatt Macy echo "No pool imported. Manually import the root pool" 882eda14cbcSMatt Macy echo "at the command prompt and then exit." 883*16038816SMartin Matuska echo "Hint: Try: zpool import -N ${ZFS_RPOOL}" 884eda14cbcSMatt Macy shell 885eda14cbcSMatt Macy fi 886eda14cbcSMatt Macy 887eda14cbcSMatt Macy # In case the pool was specified as guid, resolve guid to name 888eda14cbcSMatt Macy pool="$("${ZPOOL}" get name,guid -o name,value -H | \ 889eda14cbcSMatt Macy awk -v pool="${ZFS_RPOOL}" '$2 == pool { print $1 }')" 890eda14cbcSMatt Macy if [ -n "$pool" ]; then 891eda14cbcSMatt Macy # If $ZFS_BOOTFS contains guid, replace the guid portion with $pool 892eda14cbcSMatt Macy ZFS_BOOTFS=$(echo "$ZFS_BOOTFS" | \ 893eda14cbcSMatt Macy sed -e "s/$("${ZPOOL}" get guid -o value "$pool" -H)/$pool/g") 894eda14cbcSMatt Macy ZFS_RPOOL="${pool}" 895eda14cbcSMatt Macy fi 896eda14cbcSMatt Macy 897eda14cbcSMatt Macy 898eda14cbcSMatt Macy # ---------------------------------------------------------------- 899eda14cbcSMatt Macy # P R E P A R E R O O T F I L E S Y S T E M 900eda14cbcSMatt Macy 901eda14cbcSMatt Macy if [ -n "${ZFS_BOOTFS}" ] 902eda14cbcSMatt Macy then 903eda14cbcSMatt Macy # Booting from a snapshot? 904eda14cbcSMatt Macy # Will overwrite the ZFS_BOOTFS variable like so: 905eda14cbcSMatt Macy # rpool/ROOT/debian@snap2 => rpool/ROOT/debian_snap2 906eda14cbcSMatt Macy echo "${ZFS_BOOTFS}" | grep -q '@' && \ 907eda14cbcSMatt Macy setup_snapshot_booting "${ZFS_BOOTFS}" 908eda14cbcSMatt Macy fi 909eda14cbcSMatt Macy 910eda14cbcSMatt Macy if [ -z "${ZFS_BOOTFS}" ] 911eda14cbcSMatt Macy then 912eda14cbcSMatt Macy # Still nothing! Let the user sort this out. 913eda14cbcSMatt Macy disable_plymouth 914eda14cbcSMatt Macy echo "" 915eda14cbcSMatt Macy echo "Error: Unknown root filesystem - no 'bootfs' pool property and" 916eda14cbcSMatt Macy echo " not specified on the kernel command line." 917eda14cbcSMatt Macy echo "" 918eda14cbcSMatt Macy echo "Manually mount the root filesystem on $rootmnt and then exit." 919eda14cbcSMatt Macy echo "Hint: Try: mount -o zfsutil -t zfs ${ZFS_RPOOL-rpool}/ROOT/system $rootmnt" 920eda14cbcSMatt Macy shell 921eda14cbcSMatt Macy fi 922eda14cbcSMatt Macy 923eda14cbcSMatt Macy # ---------------------------------------------------------------- 924eda14cbcSMatt Macy # M O U N T F I L E S Y S T E M S 925eda14cbcSMatt Macy 926eda14cbcSMatt Macy # * Ideally, the root filesystem would be mounted like this: 927eda14cbcSMatt Macy # 928eda14cbcSMatt Macy # zpool import -R "$rootmnt" -N "$ZFS_RPOOL" 929eda14cbcSMatt Macy # zfs mount -o mountpoint=/ "${ZFS_BOOTFS}" 930eda14cbcSMatt Macy # 931eda14cbcSMatt Macy # but the MOUNTPOINT prefix is preserved on descendent filesystem 932eda14cbcSMatt Macy # after the pivot into the regular root, which later breaks things 933eda14cbcSMatt Macy # like `zfs mount -a` and the /proc/self/mounts refresh. 934eda14cbcSMatt Macy # 935eda14cbcSMatt Macy # * Mount additional filesystems required 936eda14cbcSMatt Macy # Such as /usr, /var, /usr/local etc. 937eda14cbcSMatt Macy # NOTE: Mounted in the order specified in the 938eda14cbcSMatt Macy # ZFS_INITRD_ADDITIONAL_DATASETS variable so take care! 939eda14cbcSMatt Macy 940eda14cbcSMatt Macy # Go through the complete list (recursively) of all filesystems below 941eda14cbcSMatt Macy # the real root dataset 942*16038816SMartin Matuska filesystems="$("${ZFS}" list -oname -tfilesystem -H -r "${ZFS_BOOTFS}")" 943*16038816SMartin Matuska OLD_IFS="$IFS" ; IFS=" 944*16038816SMartin Matuska" 945*16038816SMartin Matuska for fs in $filesystems; do 946*16038816SMartin Matuska IFS="$OLD_IFS" mount_fs "$fs" 947*16038816SMartin Matuska done 948*16038816SMartin Matuska IFS="$OLD_IFS" 949*16038816SMartin Matuska for fs in $ZFS_INITRD_ADDITIONAL_DATASETS; do 950eda14cbcSMatt Macy mount_fs "$fs" 951eda14cbcSMatt Macy done 952eda14cbcSMatt Macy 953eda14cbcSMatt Macy touch /run/zfs_unlock_complete 954eda14cbcSMatt Macy if [ -e /run/zfs_unlock_complete_notify ]; then 955*16038816SMartin Matuska read -r < /run/zfs_unlock_complete_notify 956eda14cbcSMatt Macy fi 957eda14cbcSMatt Macy 958eda14cbcSMatt Macy # ------------ 959eda14cbcSMatt Macy # Debugging information 960eda14cbcSMatt Macy if [ -n "${ZFS_DEBUG}" ] 961eda14cbcSMatt Macy then 962eda14cbcSMatt Macy #exec 2>&1- 963eda14cbcSMatt Macy 964eda14cbcSMatt Macy echo "DEBUG: imported pools:" 965eda14cbcSMatt Macy "${ZPOOL}" list -H 966eda14cbcSMatt Macy echo 967eda14cbcSMatt Macy 968eda14cbcSMatt Macy echo "DEBUG: mounted ZFS filesystems:" 969eda14cbcSMatt Macy mount | grep zfs 970eda14cbcSMatt Macy echo 971eda14cbcSMatt Macy 972eda14cbcSMatt Macy echo "=> waiting for ENTER before continuing because of 'zfsdebug=1'. " 973c40487d4SMatt Macy printf "%s" " 'c' for shell, 'r' for reboot, 'ENTER' to continue. " 974c40487d4SMatt Macy read -r b 975eda14cbcSMatt Macy 976eda14cbcSMatt Macy [ "$b" = "c" ] && /bin/sh 977eda14cbcSMatt Macy [ "$b" = "r" ] && reboot -f 978eda14cbcSMatt Macy 979eda14cbcSMatt Macy set +x 980eda14cbcSMatt Macy fi 981eda14cbcSMatt Macy 982eda14cbcSMatt Macy # ------------ 983eda14cbcSMatt Macy # Run local bottom script 984c40487d4SMatt Macy if command -v run_scripts > /dev/null 2>&1 985c40487d4SMatt Macy then 986c40487d4SMatt Macy if [ -f "/scripts/local-bottom" ] || [ -d "/scripts/local-bottom" ] 987eda14cbcSMatt Macy then 988eda14cbcSMatt Macy [ "$quiet" != "y" ] && \ 989eda14cbcSMatt Macy zfs_log_begin_msg "Running /scripts/local-bottom" 990eda14cbcSMatt Macy run_scripts /scripts/local-bottom 991eda14cbcSMatt Macy [ "$quiet" != "y" ] && zfs_log_end_msg 992eda14cbcSMatt Macy fi 993c40487d4SMatt Macy fi 994eda14cbcSMatt Macy} 995