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