diff --git a/contrib/initramfs/scripts/zfs b/contrib/initramfs/scripts/zfs index 170ccd8e8451..5e7f373b5206 100644 --- a/contrib/initramfs/scripts/zfs +++ b/contrib/initramfs/scripts/zfs @@ -16,6 +16,10 @@ ZPOOL="/sbin/zpool" ZPOOL_CACHE="/etc/zfs/zpool.cache" export ZFS ZPOOL ZPOOL_CACHE +# Needs to be set for rest of the code to work. +[ -z "${ZFS_INITRD_PRE_MOUNTROOT_SLEEP}" ] && ZFS_INITRD_PRE_MOUNTROOT_SLEEP=0 +[ -z "${ZFS_INITRD_POST_MODPROBE_SLEEP}" ] && ZFS_INITRD_POST_MODPROBE_SLEEP=0 + # This runs any scripts that should run before we start importing # pools and mounting any filesystems. pre_mountroot() @@ -23,19 +27,19 @@ pre_mountroot() if type run_scripts > /dev/null 2>&1 && \ [ -f "/scripts/local-top" -o -d "/scripts/local-top" ] then - [ "$quiet" != "y" ] && \ + [ "${quiet}" != "y" ] && \ zfs_log_begin_msg "Running /scripts/local-top" run_scripts /scripts/local-top - [ "$quiet" != "y" ] && zfs_log_end_msg + [ "${quiet}" != "y" ] && zfs_log_end_msg fi if type run_scripts > /dev/null 2>&1 && \ [ -f "/scripts/local-premount" -o -d "/scripts/local-premount" ] then - [ "$quiet" != "y" ] && \ + [ "${quiet}" != "y" ] && \ zfs_log_begin_msg "Running /scripts/local-premount" run_scripts /scripts/local-premount - [ "$quiet" != "y" ] && zfs_log_end_msg + [ "${quiet}" != "y" ] && zfs_log_end_msg fi } @@ -53,14 +57,14 @@ disable_plymouth() # with more logging etc. load_module_initrd() { - if [ "$ZFS_INITRD_PRE_MOUNTROOT_SLEEP" > 0 ] + if [ "${ZFS_INITRD_PRE_MOUNTROOT_SLEEP}" -gt 0 ] then - if [ "$quiet" != "y" ]; then + if [ "${quiet}" != "y" ]; then zfs_log_begin_msg "Sleeping for" \ - "$ZFS_INITRD_PRE_MOUNTROOT_SLEEP seconds..." + "${ZFS_INITRD_PRE_MOUNTROOT_SLEEP} seconds..." fi - sleep "$ZFS_INITRD_PRE_MOUNTROOT_SLEEP" - [ "$quiet" != "y" ] && zfs_log_end_msg + sleep "${ZFS_INITRD_PRE_MOUNTROOT_SLEEP}" + [ "${quiet}" != "y" ] && zfs_log_end_msg fi # Wait for all of the /dev/{hd,sd}[a-z] device nodes to appear. @@ -77,14 +81,14 @@ load_module_initrd() # Load the module load_module "zfs" || return 1 - if [ "$ZFS_INITRD_POST_MODPROBE_SLEEP" > 0 ] + if [ "${ZFS_INITRD_POST_MODPROBE_SLEEP}" -gt 0 ] then - if [ "$quiet" != "y" ]; then + if [ "${quiet}" != "y" ]; then zfs_log_begin_msg "Sleeping for" \ - "$ZFS_INITRD_POST_MODPROBE_SLEEP seconds..." + "${ZFS_INITRD_POST_MODPROBE_SLEEP} seconds..." fi - sleep "$ZFS_INITRD_POST_MODPROBE_SLEEP" - [ "$quiet" != "y" ] && zfs_log_end_msg + sleep "${ZFS_INITRD_POST_MODPROBE_SLEEP}" + [ "${quiet}" != "y" ] && zfs_log_end_msg fi return 0 @@ -95,9 +99,7 @@ load_module_initrd() # This is the main function. mountroot() { - local snaporig - local snapsub - local destfs + local snaporig snapsub destfs pool POOLS # ---------------------------------------------------------------- # I N I T I A L S E T U P @@ -112,7 +114,7 @@ mountroot() # ------------ # Support debug option - if grep -qiE '(^|[^\\](\\\\)* )(zfs_debug|zfs\.debug|zfsdebug)=(on|yes|1)( |$)' /proc/cmdline + if check_zfs_debug then ZFS_DEBUG=1 mkdir /var/log @@ -138,11 +140,11 @@ mountroot() # Compatibility: 'ROOT' is for Debian GNU/Linux (etc), # 'root' is for Redhat/Fedora (etc), # 'REAL_ROOT' is for Gentoo - if [ -z "$ROOT" ] + if [ -z "${ROOT}" ] then - [ -n "$root" ] && ROOT=${root} + [ -n "${root}" ] && ROOT=${root} - [ -n "$REAL_ROOT" ] && ROOT=${REAL_ROOT} + [ -n "${REAL_ROOT}" ] && ROOT=${REAL_ROOT} fi # ------------ @@ -150,18 +152,18 @@ mountroot() # Compatibility: 'rootmnt' is for Debian GNU/Linux (etc), # 'NEWROOT' is for RedHat/Fedora (etc), # 'NEW_ROOT' is for Gentoo - if [ -z "$rootmnt" ] + if [ -z "${rootmnt}" ] then - [ -n "$NEWROOT" ] && rootmnt=${NEWROOT} + [ -n "${NEWROOT}" ] && rootmnt=${NEWROOT} - [ -n "$NEW_ROOT" ] && rootmnt=${NEW_ROOT} + [ -n "${NEW_ROOT}" ] && rootmnt=${NEW_ROOT} fi # ------------ # No longer set in the defaults file, but it could have been set in # get_pools() in some circumstances. If it's something, but not 'yes', # it's no good to us. - [ -n "$USE_DISK_BY_ID" -a "$USE_DISK_BY_ID" != 'yes' ] && \ + [ -n "${USE_DISK_BY_ID}" -a "${USE_DISK_BY_ID}" != 'yes' ] && \ unset USE_DISK_BY_ID # ---------------------------------------------------------------- @@ -200,19 +202,19 @@ mountroot() # ------------ # Look for 'rpool' and 'bootfs' parameter - [ -n "$rpool" ] && ZFS_RPOOL="${rpool#rpool=}" - [ -n "$bootfs" ] && ZFS_BOOTFS="${bootfs#bootfs=}" + [ -n "${rpool}" ] && ZFS_RPOOL="${rpool#rpool=}" + [ -n "${bootfs}" ] && ZFS_BOOTFS="${bootfs#bootfs=}" # ------------ # If we have 'ROOT' (see above), but not 'ZFS_BOOTFS', then use # 'ROOT' - [ -n "$ROOT" -a -z "${ZFS_BOOTFS}" ] && ZFS_BOOTFS="$ROOT" + [ -n "${ROOT}" -a -z "${ZFS_BOOTFS}" ] && ZFS_BOOTFS="${ROOT}" # ------------ # Check for the `-B zfs-bootfs=%s/%u,...` kind of parameter. # NOTE: Only use the pool name and dataset. The rest is not # supported by ZoL (whatever it's for). - if [ -z "$ZFS_RPOOL" ] + if [ -z "${ZFS_RPOOL}" ] then # The ${zfs-bootfs} variable is set at the kernel commmand # line, usually by GRUB, but it cannot be referenced here @@ -227,7 +229,7 @@ mountroot() # ------------ # No root fs or pool specified - do auto detect. - if [ -z "$ZFS_RPOOL" -a -z "${ZFS_BOOTFS}" ] + if [ -z "${ZFS_RPOOL}" -a -z "${ZFS_BOOTFS}" ] then # Do auto detect. Do this by 'cheating' - set 'root=zfs:AUTO' # which will be caught later @@ -238,33 +240,33 @@ mountroot() # F I N D A N D I M P O R T C O R R E C T P O O L # ------------ - if [ "$ROOT" = "zfs:AUTO" ] + if [ "${ROOT}" = "zfs:AUTO" ] then # Try to detect both pool and root fs. - [ "$quiet" != "y" ] && \ + [ "${quiet}" != "y" ] && \ zfs_log_begin_msg "Attempting to import additional pools." # Get a list of pools available for import - if [ -n "$ZFS_RPOOL" ] + if [ -n "${ZFS_RPOOL}" ] then # We've specified a pool - check only that - POOLS=$ZFS_RPOOL + POOLS=${ZFS_RPOOL} else POOLS=$(get_pools) fi OLD_IFS="$IFS" ; IFS=";" - for pool in $POOLS + for pool in ${POOLS} do - [ -z "$pool" ] && continue + [ -z "${pool}" ] && continue - import_pool "$pool" - find_rootfs "$pool" + import_pool "${pool}" + find_rootfs "${pool}" done IFS="$OLD_IFS" - [ "$quiet" != "y" ] && zfs_log_end_msg $ZFS_ERROR + [ "${quiet}" != "y" ] && zfs_log_end_msg $ZFS_ERROR else # No auto - use value from the command line option. @@ -276,15 +278,10 @@ mountroot() fi # Import the pool (if not already done so in the AUTO check above). - if [ -n "$ZFS_RPOOL" -a -z "${POOL_IMPORTED}" ] + if [ -n "${ZFS_RPOOL}" -a -z "${POOL_IMPORTED}" ] then - [ "$quiet" != "y" ] && \ - zfs_log_begin_msg "Importing ZFS root pool '$ZFS_RPOOL'" - import_pool "${ZFS_RPOOL}" find_rootfs "${ZFS_RPOOL}" - - [ "$quiet" != "y" ] && zfs_log_end_msg fi if [ -z "${POOL_IMPORTED}" ] @@ -322,8 +319,8 @@ mountroot() echo "Error: Unknown root filesystem - no 'bootfs' pool property and" echo " not specified on the kernel command line." echo "" - echo "Manually mount the root filesystem on $rootmnt and then exit." - echo "Hint: Try: mount -o zfsutil -t zfs ${ZFS_RPOOL-rpool}/ROOT/system $rootmnt" + echo "Manually mount the root filesystem on ${rootmnt} and then exit." + echo "Hint: Try: mount -o zfsutil -t zfs ${ZFS_RPOOL-rpool}/ROOT/system ${rootmnt}" emergency_shell fi @@ -332,7 +329,7 @@ mountroot() # * Ideally, the root filesystem would be mounted like this: # - # zpool import -R "$rootmnt" -N "$ZFS_RPOOL" + # zpool import -R "${rootmnt}" -N "${ZFS_RPOOL}" # zfs mount -o mountpoint=/ "${ZFS_BOOTFS}" # # but the MOUNTPOINT prefix is preserved on descendent filesystem @@ -343,20 +340,28 @@ mountroot() # Such as /usr, /var, /usr/local etc. # NOTE: Mounted in the order specified in the # ZFS_INITRD_ADDITIONAL_DATASETS variable so take care! - - # Go through the complete list (recursivly) of all filesystems below - # the real root dataset - filesystems=$("${ZFS}" list -oname -tfilesystem -H -r "${ZFS_BOOTFS}") - for fs in $filesystems $ZFS_INITRD_ADDITIONAL_DATASETS - do - mount_fs "$fs" - done + recursive_mount_filesystems "Using ${ZFS_BOOTFS} as root." "${ZFS_BOOTFS}" + if [ "${ZFS_ERROR}" != 0 ] + then + disable_plymouth + echo "" + echo "Command: ${ZFS_CMD}" + echo "Message: ${ZFS_STDERR}" + echo "Error: ${ZFS_ERROR}" + echo "" + echo "Error: Failed to mount root filesystem '${ZFS_BOOTFS}'." + echo "" + echo "Manually mount the filesystem and exit." + echo "Hint: Try: mount -o zfsutil -t zfs ${ZFS_BOOTFS} ${rootmnt}" + emergency_shell + fi # ------------ # Debugging information if [ -n "${ZFS_DEBUG}" ] then #exec 2>&1- + set +x echo "DEBUG: imported pools:" "${ZPOOL}" list -H @@ -370,10 +375,8 @@ mountroot() echo -n " 'c' for shell, 'r' for reboot, 'ENTER' to continue. " read b - [ "$b" = "c" ] && emergency_shell - [ "$b" = "r" ] && reboot -f - - set +x + [ "${b}" = "c" ] && emergency_shell + [ "${b}" = "r" ] && reboot -f fi # ------------ @@ -381,9 +384,9 @@ mountroot() if type run_scripts > /dev/null 2>&1 && \ [ -f "/scripts/local-bottom" -o -d "/scripts/local-bottom" ] then - [ "$quiet" != "y" ] && \ + [ "${quiet}" != "y" ] && \ zfs_log_begin_msg "Running /scripts/local-bottom" run_scripts /scripts/local-bottom - [ "$quiet" != "y" ] && zfs_log_end_msg + [ "${quiet}" != "y" ] && zfs_log_end_msg fi } diff --git a/contrib/shell-common/zfs-functions.in b/contrib/shell-common/zfs-functions.in index ae29dc84585f..619ef2b01490 100644 --- a/contrib/shell-common/zfs-functions.in +++ b/contrib/shell-common/zfs-functions.in @@ -11,6 +11,9 @@ # https://github.com/zfsonlinux/pkg-zfs/commit/80a3ae582b59c0250d7912ba794dca9e669e605a PATH=/sbin:/bin:/usr/bin:/usr/sbin +OLD_IFS="${IFS}" +NEWLINE=" +" # Source function library if [ -f /etc/rc.d/init.d/functions ]; then @@ -37,20 +40,20 @@ elif type success > /dev/null 2>&1 ; then # Fedora/RedHat functions zfs_log_begin_msg() { echo -n "$1 "; } zfs_log_end_msg() { - zfs_set_ifs "$OLD_IFS" + zfs_set_ifs "${OLD_IFS}" if [ "$1" -eq 0 ]; then success else failure fi echo - zfs_set_ifs "$TMP_IFS" + zfs_set_ifs "${TMP_IFS}" } zfs_log_failure_msg() { - zfs_set_ifs "$OLD_IFS" + zfs_set_ifs "${OLD_IFS}" failure echo - zfs_set_ifs "$TMP_IFS" + zfs_set_ifs "${TMP_IFS}" } zfs_log_progress_msg() { echo -n $"$1"; } elif type einfo > /dev/null 2>&1 ; then @@ -64,13 +67,13 @@ else # Unknown - simple substitues. zfs_log_begin_msg() { echo -n "$1"; } zfs_log_end_msg() { - ret=$1 - if [ "$ret" -ge 1 ]; then + ret="$1" + if [ "${ret}" -ge 1 ]; then echo " failed!" else echo " success" fi - return "$ret" + return "${ret}" } zfs_log_failure_msg() { echo "$1"; } zfs_log_progress_msg() { echo -n "$1"; } @@ -107,6 +110,26 @@ fi # ---------------------------------------------------- +# Run a command, capture STDOUT, STDERR and exit code. +# Sets the global variables ZFS_STDERR and ZFS_ERROR +# with this information. +# +# For some reason, some functions in the library have a problem +# with a changed IFS, so make sure we reset this while running +# the command. +# +zfs_run_cmd() +{ + ZFS_CMD="$*" + + zfs_set_ifs "${OLD_IFS}" + ZFS_STDERR="$(${ZFS_CMD} 2>&1)" + ZFS_ERROR="$?" + zfs_set_ifs "${TMP_IFS}" + + return "${ZFS_ERROR}" +} + # Run a command, output a message if quiet != 'y' OR if running # with debugging enabled. # @@ -116,20 +139,21 @@ fi # zfs_action() { + zfs_set_ifs " " local MSG="$1"; shift local CMD="$*" - local ret - zfs_log_begin_msg "$MSG " - $CMD - ret=$? - if [ "$ret" -eq 0 ]; then - zfs_log_end_msg $ret + ([ "${quiet}" != "y" ] || check_zfs_debug) && zfs_log_begin_msg "${MSG} " + zfs_run_cmd ${CMD} + if [ "${ZFS_ERROR}" -eq 0 ]; then + ([ "${quiet}" != "y" ] || check_zfs_debug) && \ + zfs_log_end_msg "${ZFS_ERROR}" else - zfs_log_failure_msg $ret + ([ "${quiet}" != "y" ] || check_zfs_debug) && \ + zfs_log_failure_msg "${ZFS_ERROR}" fi - return $ret + return "${ZFS_ERROR}" } # Returns @@ -146,24 +170,24 @@ zfs_daemon_start() if type start-stop-daemon > /dev/null 2>&1 ; then # LSB functions - start-stop-daemon --start --quiet --pidfile "$PIDFILE" \ - --exec "$DAEMON_BIN" --test > /dev/null || return 1 + start-stop-daemon --start --quiet --pidfile "${PIDFILE}" \ + --exec "${DAEMON_BIN}" --test > /dev/null || return 1 - start-stop-daemon --start --quiet --exec "$DAEMON_BIN" -- \ - $DAEMON_ARGS || return 2 + start-stop-daemon --start --quiet --exec "${DAEMON_BIN}" -- \ + ${DAEMON_ARGS} || return 2 # On Debian GNU/Linux, there's a 'sendsigs' script that will # kill basically everything quite early and zed is stopped # much later than that. We don't want zed to be among them, # so add the zed pid to list of pids to ignore. - if [ -f "$PIDFILE" -a -d /run/sendsigs.omit.d ] + if [ -f "${PIDFILE}" -a -d /run/sendsigs.omit.d ] then ln -sf "$PIDFILE" /run/sendsigs.omit.d/zed fi elif type daemon > /dev/null 2>&1 ; then # Fedora/RedHat functions - daemon --pidfile "$PIDFILE" "$DAEMON_BIN" $DAEMON_ARGS - return $? + daemon --pidfile "${PIDFILE}" "${DAEMON_BIN}" ${DAEMON_ARGS} + return "$?" else # Unsupported return 3 @@ -187,16 +211,16 @@ zfs_daemon_stop() if type start-stop-daemon > /dev/null 2>&1 ; then # LSB functions start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \ - --pidfile "$PIDFILE" --name "$DAEMON_NAME" - [ "$?" = 0 ] && rm -f "$PIDFILE" + --pidfile "${PIDFILE}" --name "${DAEMON_NAME}" + [ "$?" = 0 ] && rm -f "${PIDFILE}" - return $? + return "$?" elif type killproc > /dev/null 2>&1 ; then # Fedora/RedHat functions - killproc -p "$PIDFILE" "$DAEMON_NAME" - [ "$?" = 0 ] && rm -f "$PIDFILE" + killproc -p "${PIDFILE}" "${DAEMON_NAME}" + [ "$?" = 0 ] && rm -f "${PIDFILE}" - return $? + return "$?" else # Unsupported return 3 @@ -214,12 +238,12 @@ zfs_daemon_status() if type status_of_proc > /dev/null 2>&1 ; then # LSB functions - status_of_proc "$DAEMON_NAME" "$DAEMON_BIN" - return $? + status_of_proc "${DAEMON_NAME}" "${DAEMON_BIN}" + return "$?" elif type status > /dev/null 2>&1 ; then # Fedora/RedHat functions - status -p "$PIDFILE" "$DAEMON_NAME" - return $? + status -p "${PIDFILE}" "${DAEMON_NAME}" + return "$?" else # Unsupported return 3 @@ -236,12 +260,12 @@ zfs_daemon_reload() if type start-stop-daemon > /dev/null 2>&1 ; then # LSB functions start-stop-daemon --stop -signal 1 --quiet \ - --pidfile "$PIDFILE" --name "$DAEMON_NAME" - return $? + --pidfile "${PIDFILE}" --name "${DAEMON_NAME}" + return "$?" elif type killproc > /dev/null 2>&1 ; then # Fedora/RedHat functions - killproc -p "$PIDFILE" "$DAEMON_NAME" -HUP - return $? + killproc -p "${PIDFILE}" "${DAEMON_NAME}" -HUP + return "$?" else # Unsupported return 3 @@ -254,20 +278,20 @@ zfs_daemon_reload() # Will catch a problem with libraries as well. zfs_installed() { - if [ ! -x "$ZPOOL" ]; then + if [ ! -x "${ZPOOL}" ]; then return 1 else # Test if it works (will catch missing/broken libs etc) - "$ZPOOL" -? > /dev/null 2>&1 - return $? + "${ZPOOL}" -? > /dev/null 2>&1 + return "$?" fi - if [ ! -x "$ZFS" ]; then + if [ ! -x "${ZFS}" ]; then return 2 else # Test if it works (will catch missing/broken libs etc) - "$ZFS" -? > /dev/null 2>&1 - return $? + "${ZFS}" -? > /dev/null 2>&1 + return "$?" fi return 0 @@ -295,7 +319,7 @@ checksystem() # HOWEVER, only do this if we're called at the boot up # (from init), not if we're running interactivly (as in # from the shell - we know what we're doing). - [ -n "$init" ] && exit 3 + [ -n "${init}" ] && exit 3 fi # Check if ZFS is installed. @@ -322,10 +346,29 @@ get_root_pool() [ "$5" = "zfs" ] && echo "${1%%/*}" } +# Check if a variable is 'yes' (any case) or '1' +# Returns TRUE if set. +check_boolean() +{ + local var="$1" + + echo "$var" | grep -Eiq "^yes$|^1$" && return 0 || return 1 +} + +# Check to see if we're running in debug mode +# Returns +# 0 if debugging enabled +# 1 if debugging disabled +check_zfs_debug() +{ + grep -qiE '(^|[^\\](\\\\)* )(zfs_debug|zfs\.debug|zfsdebug)=(on|yes|[0-9])( |$)' \ + /proc/cmdline +} + # Check if the specified module is loaded. check_module_loaded() { - module="$1" + local module="$1" [ -r "/sys/module/${module}/version" ] && return 0 || return 1 } @@ -333,17 +376,45 @@ check_module_loaded() # Load specified module. load_module() { - module="$1" + local module="$1" # Load the zfs module stack - if ! check_module_loaded "$module"; then - if ! /sbin/modprobe "$module"; then + if ! check_module_loaded "${module}"; then + if ! /sbin/modprobe "${module}"; then return 5 fi fi return 0 } +# Recursivly mount all filesystems, including any additional filesystems, +# below the specified filesystem. +recursive_mount_filesystems() +{ + local msg="$1" + local fs="$2" + local filesystems f + + # Fail here if the first fs (the root fs) fails to mount. + zfs_action "${msg}" mount_fs "${fs}" || return 1 + + # Go through the complete list (recursivly) of all filesystems + # below the first (root) dataset. + filesystems=$("${ZFS}" list -oname -tfilesystem -H -r "${fs}") + for f in ${filesystems} ${ZFS_INITRD_ADDITIONAL_DATASETS} + do + # Ignore the first (root) fs. Should already be + # mounted, but is still included in the 'zfs list' + # above. + [ "${f}" = "${fs}" ] && continue + + zfs_action "Mounting filesystem ${f}" mount_fs "${f}" || \ + return 1 + done + + return 0 +} + # Load the list of all mounted filsystems, recording filesystem, mountpint # etc for later use in in_mtab(). # First parameter is a regular expression that filters mtab @@ -356,7 +427,8 @@ read_mtab() unset $(env | grep ^MTAB_ | sed 's,=.*,,') while read -r fs mntpnt fstype opts rest; do - if echo "$fs $mntpnt $fstype $opts" | grep -qE "$match"; then + if echo "${fs} ${mntpnt} ${fstype} ${opts}" | grep -qE "${match}" + then # * Fix problems (!?) in the mounts file. It will record # 'rpool 1' as 'rpool\0401' instead of 'rpool\00401' # which seems to be the correct (at least as far as @@ -364,16 +436,16 @@ read_mtab() # * We need to use the external echo, because the # internal one would interpret the backslash code # (incorrectly), giving us a  instead. - mntpnt=$(/bin/echo "$mntpnt" | sed "s,\\\0,\\\00,") - fs=$(/bin/echo "$fs" | sed "s,\\\0,\\\00,") + mntpnt="$(/bin/echo "${mntpnt}" | sed "s,\\\0,\\\00,g")" + fs="$(/bin/echo "${fs}" | sed "s,\\\0,\\\00,")" # Replace 'unwanted' characters with underscore. - mntpnt=$(printf '%b\n' "$mntpnt" | sed -e 's,/,_,g' \ - -e 's,-,_,g' -e 's,\.,_,g' -e 's, ,_,g') - fs=$(printf '%b\n' "$fs") + mntpnt="$(printf '%b\n' "${mntpnt}" | sed -e 's,/,,g' \ + -e 's,-,,g' -e 's,\.,,g' -e 's, ,,g')" + fs="$(printf '%b\n' "${fs}")" # Set the variable. - eval export MTAB_$mntpnt=\"$fs\" + eval export MTAB_${mntpnt}=\"${fs}\" fi done < /proc/mounts } @@ -384,8 +456,8 @@ in_mtab() local fs="$(echo "$1" | sed 's,/,_,g')" local var - var="$(eval echo MTAB_$fs)" - [ "$(eval echo "$""$var")" != "" ] + var="$(eval echo MTAB_${fs})" + [ "$(eval echo "$""${var}")" != "" ] return "$?" } @@ -403,14 +475,15 @@ read_fstab() i=0 while read -r fs mntpnt fstype opts; do - echo "$fs" | egrep -qE '^#|^$' && continue + echo "${fs}" | egrep -qE '^#|^$' && continue - if echo "$fs $mntpnt $fstype $opts" | grep -qE "$match"; then - eval export FSTAB_dev_$i="$fs" - fs=$(printf '%b\n' "$fs" | sed 's,/,_,g') - eval export FSTAB_$i="$mntpnt" + if echo "${fs} ${mntpnt} ${fstype} ${opts}" | grep -qE "${match}" + then + eval export FSTAB_dev_${i}="${fs}" + fs="$(printf '%b\n' "${fs}" | sed 's,/,_,g')" + eval export FSTAB_${i}="${mntpnt}" - i=$((i + 1)) + i="$((i + 1))" fi done < /etc/fstab } @@ -422,7 +495,7 @@ in_fstab() var="$(eval echo FSTAB_$1)" [ "${var}" != "" ] - return $? + return "$?" } # Check if specified mountpoint is mounted. @@ -433,9 +506,7 @@ is_mounted() mount | \ while read line; do - if echo "$line" | grep -q " on $mntpt "; then - return 0 - fi + echo "${line}" | grep -q " on ${mntpt} " && return 0 done return 1 @@ -445,9 +516,9 @@ is_mounted() get_fs_value() { local fs="$1" - local value=$2 + local value="$2" - "${ZFS}" get -H -ovalue $value "$fs" 2> /dev/null + "${ZFS}" get -H -ovalue ${value} "${fs}" 2> /dev/null } # Find the 'bootfs' property on pool $1. @@ -458,16 +529,16 @@ find_rootfs() local pool="$1" # If 'POOL_IMPORTED' isn't set, no pool imported and therefor - # we won't be able to find a root fs. + # no root fs could be found. [ -z "${POOL_IMPORTED}" ] && return 1 - # If it's already specified, just keep it mounted and exit - # User (kernel command line) must be correct. + # If it's already specified, just keep it mounted and exit + # User (kernel command line) must be correct. [ -n "${ZFS_BOOTFS}" ] && return 0 # Not set, try to find it in the 'bootfs' property of the pool. # NOTE: zpool does not support 'get -H -ovalue bootfs'... - ZFS_BOOTFS=$("${ZPOOL}" list -H -obootfs "$pool") + ZFS_BOOTFS="$("${ZPOOL}" list -H -obootfs "${pool}")" # Make sure it's not '-' and that it starts with /. if [ "${ZFS_BOOTFS}" != "-" ] && \ @@ -479,7 +550,7 @@ find_rootfs() fi # Not boot fs here, export it and later try again.. - "${ZPOOL}" export "$pool" + "${ZPOOL}" export "${pool}" POOL_IMPORTED="" return 1 @@ -489,15 +560,14 @@ find_rootfs() find_pools() { local CMD="$*" - local pools + local pool pools - pools=$($CMD 2> /dev/null | \ + pools="$(${CMD} 2> /dev/null | \ grep -E "pool:|^[a-zA-Z0-9]" | \ sed 's@.*: @@' | \ - sort | \ while read pool; do \ - echo -n "$pool;" - done) + echo -n "${pool};" + done)" echo "${pools%%;}" # Return without the last ';'. } @@ -508,95 +578,98 @@ get_pools() local available_pools npools # Get the base list of availible pools. - available_pools=$(find_pools "$ZPOOL" import) + available_pools="$(find_pools "${ZPOOL}" import)" # Just in case - seen it happen (that a pool isn't visable/found # with a simple "zpool import" but only when using the "-d" # option or setting ZPOOL_IMPORT_PATH). if [ -d "/dev/disk/by-id" ] then - npools=$(find_pools "$ZPOOL" import -d /dev/disk/by-id) - if [ -n "$npools" ] + npools="$(find_pools "${ZPOOL}" import -d /dev/disk/by-id)" + if [ -n "${npools}" ] then # Because we have found extra pool(s) here, which wasn't # found 'normaly', we need to force USE_DISK_BY_ID to # make sure we're able to actually import it/them later. USE_DISK_BY_ID='yes' - if [ -n "$available_pools" ] + if [ -n "${available_pools}" ] then # Filter out duplicates (pools found with the simple # "zpool import" but which is also found with the # "zpool import -d ..."). - npools=$(echo "$npools" | sed "s,$available_pools,,") + npools="$(echo "${npools}" | sed "s,${available_pools},,")" # Add the list to the existing list of # available pools - available_pools="$available_pools;$npools" + available_pools="${available_pools};${npools}" else - available_pools="$npools" + available_pools="${npools}" fi fi fi # Filter out any exceptions... - if [ -n "$ZFS_POOL_EXCEPTIONS" ] + if [ -n "${ZFS_POOL_EXCEPTIONS}" ] then local found="" local apools="" local pool exception - OLD_IFS="$IFS" ; IFS=";" + OLD_IFS="${IFS}" ; IFS=";" - for pool in $available_pools + for pool in ${available_pools} do - for exception in $ZFS_POOL_EXCEPTIONS + for exception in ${ZFS_POOL_EXCEPTIONS} do - [ "$pool" = "$exception" ] && continue 2 - found="$pool" + [ "${pool}" = "${exception}" ] && continue 2 + found="${pool}" done - if [ -n "$found" ] + if [ -n "${found}" ] then - if [ -n "$apools" ] + if [ -n "${apools}" ] then - apools="$apools;$pool" + apools="${apools};${pool}" else - apools="$pool" + apools="${pool}" fi fi done - IFS="$OLD_IFS" - available_pools="$apools" + IFS="${OLD_IFS}" + available_pools="${apools}" fi # Return list of availible pools. - echo "$available_pools" + echo "${available_pools}" } # Import given pool $1 import_pool() { local pool="$1" - local dirs dir ZFS_CMD ZFS_STDERR ZFS_ERROR + local dirs dir # Verify that the pool isn't already imported # Make as sure as we can to not require '-f' to import. - "${ZPOOL}" status "$pool" > /dev/null 2>&1 && return 0 + "${ZPOOL}" status "${pool}" > /dev/null 2>&1 && return 0 + + # Check that the pool exists + "${ZPOOL}" list -oname -H "${pool}" > /dev/null 2>&1 && return 1 # For backwards compability, make sure that ZPOOL_IMPORT_PATH is set # to something we can use later with the real import(s). We want to # make sure we find all by* dirs, BUT by-vdev should be first (if it # exists). - if [ -n "$USE_DISK_BY_ID" -a -z "$ZPOOL_IMPORT_PATH" ] + if [ -n "${USE_DISK_BY_ID}" -a -z "${ZPOOL_IMPORT_PATH}" ] then dirs="$(for dir in $(echo /dev/disk/by-*) do # Ignore by-vdev here - we want it first! - echo "$dir" | grep -q /by-vdev && continue - [ ! -d "$dir" ] && continue + echo "${dir}" | grep -q /by-vdev && continue + [ ! -d "${dir}" ] && continue - echo -n "$dir:" + echo -n "${dir}:" done | sed 's,:$,,g')" if [ -d "/dev/disk/by-vdev" ] @@ -606,51 +679,42 @@ import_pool() fi # ... and /dev at the very end, just for good measure. - ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH$dirs:/dev" + ZPOOL_IMPORT_PATH="${ZPOOL_IMPORT_PATH}${dir}s:/dev" fi # Needs to be exported for "zpool" to catch it. - [ -n "$ZPOOL_IMPORT_PATH" ] && export ZPOOL_IMPORT_PATH - + [ -n "${ZPOOL_IMPORT_PATH}" ] && export ZPOOL_IMPORT_PATH - [ "$quiet" != "y" ] && zfs_log_begin_msg \ - "Importing pool '${pool}' using defaults" - ZFS_CMD="${ZPOOL} import -N ${ZPOOL_FORCE}" - ZFS_STDERR="$($ZFS_CMD "$pool" 2>&1)" - ZFS_ERROR="$?" + zfs_action "Importing pool '${pool}' using defaults" \ + "${ZPOOL}" import -N ${ZPOOL_FORCE} ${ZPOOL_IMPORT_OPTS} "${pool}" if [ "${ZFS_ERROR}" != 0 ] then - [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" - if [ -f "${ZPOOL_CACHE}" ] then - [ "$quiet" != "y" ] && zfs_log_begin_msg \ - "Importing pool '${pool}' using cachefile." - - ZFS_CMD="${ZPOOL} import -c ${ZPOOL_CACHE} -N ${ZPOOL_FORCE}" - ZFS_STDERR="$($ZFS_CMD "$pool" 2>&1)" - ZFS_ERROR="$?" + zfs_action "Importing pool '${pool}' using cachefile." \ + "${ZPOOL}" import -c "${ZPOOL_CACHE}" \ + -N ${ZPOOL_FORCE} ${ZPOOL_IMPORT_OPTS} "${pool}" fi if [ "${ZFS_ERROR}" != 0 ] then - [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" - disable_plymouth - echo "" - echo "Command: ${ZFS_CMD} '$pool'" - echo "Message: $ZFS_STDERR" - echo "Error: $ZFS_ERROR" - echo "" - echo "Failed to import pool '$pool'." - echo "Manually import the pool and exit." - emergency_shell + if [ "$?" != 999 ]; then + echo "" + echo "Command: ${ZFS_CMD}" + echo "Message: ${ZFS_STDERR}" + echo "Error: ${ZFS_ERROR}" + echo "" + echo "Failed to import pool '${pool}'." + echo "Manually import the pool and exit." + emergency_shell + else + return 1 + fi fi fi - [ "$quiet" != "y" ] && zfs_log_end_msg - POOL_IMPORTED=1 return 0 } @@ -659,20 +723,25 @@ import_pool() mount_fs() { local fs="$1" - local mountpoint ZFS_CMD ZFS_STDERR ZFS_ERROR + local mountpoint cmd + + # Check that the filesystem exists + "${ZFS}" list -oname -tfilesystem -H "${fs}" > /dev/null 2>&1 + [ "$?" -ne 0 ] && return 1 # Need the _original_ datasets mountpoint! - mountpoint=$(get_fs_value "$fs" mountpoint) - if [ "$mountpoint" = "legacy" -o "$mountpoint" = "none" ]; then + mountpoint="$(get_fs_value "${fs}" mountpoint)" + if [ "${mountpoint}" = "legacy" -o "${mountpoint}" = "none" ] + then # Can't use the mountpoint property. Might be one of our # clones. Check the 'org.zol:mountpoint' property set in # clone_snap() if that's usable. - mountpoint=$(get_fs_value "$fs" org.zol:mountpoint) - if [ "$mountpoint" = "legacy" -o \ - "$mountpoint" = "none" -o \ - "$mountpoint" = "-" ] + mountpoint="$(get_fs_value "${fs}" org.zol:mountpoint)" + if [ "${mountpoint}" = "legacy" -o \ + "${mountpoint}" = "none" -o \ + "${mountpoint}" = "-" ] then - if [ "$fs" != "${ZFS_BOOTFS}" ]; then + if [ "${fs}" != "${ZFS_BOOTFS}" ]; then # We don't have a proper mountpoint, this # isn't the root fs. So extract the root fs # value from the filesystem, and we should @@ -684,42 +753,40 @@ mount_fs() fi fi - if [ "$mountpoint" = "legacy" ]; then - ZFS_CMD="mount -t zfs" + if [ "${mountpoint}" = "legacy" ]; then + cmd="mount -t zfs" else # If it's not a legacy filesystem, it can only be a # native one... - ZFS_CMD="mount -o zfsutil -t zfs" + cmd="mount -o zfsutil -t zfs" fi else - ZFS_CMD="mount -o zfsutil -t zfs" + cmd="mount -o zfsutil -t zfs" fi # Possibly decrypt a filesystem using native encryption. - decrypt_fs "$fs" + zfs_action "Decrypting ${fs}" decrypt_fs "${fs}" - [ "$quiet" != "y" ] && \ - zfs_log_begin_msg "Mounting '${fs}' on '${rootmnt}/${mountpoint}'" [ -n "${ZFS_DEBUG}" ] && \ - zfs_log_begin_msg "CMD: '$ZFS_CMD ${fs} ${rootmnt}/${mountpoint}'" + zfs_log_begin_msg "CMD: '${cmd} ${fs} ${rootmnt}/${mountpoint}'" - ZFS_STDERR=$(${ZFS_CMD} "${fs}" "${rootmnt}/${mountpoint}" 2>&1) - ZFS_ERROR=$? + zfs_action "Mounting '${fs}' on '${rootmnt}/${mountpoint}'" \ + "${cmd}" "${fs}" "${rootmnt}/${mountpoint}" if [ "${ZFS_ERROR}" != 0 ] then - [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" - disable_plymouth - echo "" - echo "Command: ${ZFS_CMD} ${fs} ${rootmnt}/${mountpoint}" - echo "Message: $ZFS_STDERR" - echo "Error: $ZFS_ERROR" - echo "" - echo "Failed to mount ${fs} on ${rootmnt}/${mountpoint}." - echo "Manually mount the filesystem and exit." - emergency_shell - else - [ "$quiet" != "y" ] && zfs_log_end_msg + if [ "$?" != 999 ]; then + echo "" + echo "Command: ${ZFS_CMD}" + echo "Message: ${ZFS_STDERR}" + echo "Error: ${ZFS_ERROR}" + echo "" + echo "Failed to mount ${fs} on ${rootmnt}/${mountpoint}." + echo "Manually mount the filesystem and exit." + emergency_shell + else + return 1 + fi fi return 0 @@ -729,68 +796,57 @@ mount_fs() decrypt_fs() { local fs="$1" - local ZFS_CMD ZFS_STDERR ZFS_ERROR # If the 'zfs key' command isn't availible, exit right here. "${ZFS}" 2>&1 | grep -q 'key -l ' || return 0 # Check if filesystem is encrypted. If not, exit right here. - [ "$(get_fs_value "$fs" encryption)" != "off" ] || return 0 - - [ "$quiet" != "y" ] && \ - zfs_log_begin_msg "Loading crypto wrapper key for $fs" + [ "$(get_fs_value "${fs}" encryption)" != "off" ] || return 0 # Just make sure that ALL crypto modules module is loaded. # Simplest just to load all... for mod in sun-ccm sun-gcm sun-ctr do - [ "$quiet" != "y" ] && zfs_log_progress_msg "${mod} " - - ZFS_CMD="load_module $mod" - ZFS_STDERR="$(${ZFS_CMD} 2>&1)" - ZFS_ERROR="$?" - + zfs_action "Loading module ${mod}" load_module "${mod}" if [ "${ZFS_ERROR}" != 0 ] then - [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" - disable_plymouth - echo "" - echo "Command: $ZFS_CMD" - echo "Message: $ZFS_STDERR" - echo "Error: $ZFS_ERROR" - echo "" - echo "Failed to load $mod module." - echo "Please verify that it is availible on the initrd image" - echo "(without it it won't be possible to unlock the filesystem)" - echo "and rerun: $ZFS_CMD" - emergency_shell - else - [ "$quiet" != "y" ] && zfs_log_end_msg + if [ "$?" != 999 ]; then + echo "" + echo "Command: ${ZFS_CMD}" + echo "Message: ${ZFS_STDERR}" + echo "Error: ${ZFS_ERROR}" + echo "" + echo "Failed to load ${mod} module." + echo "Please verify that it is availible on the initrd image" + echo "(without it it won't be possible to unlock the filesystem)" + echo "and rerun: ${ZFS_CMD}" + emergency_shell + else + return 1 + fi fi done # If the key isn't availible, then this will fail! - ZFS_CMD="${ZFS} key -l -r $fs" - ZFS_STDERR="$(${ZFS_CMD} 2>&1)" - ZFS_ERROR="$?" - + zfs_action "Loading crypto wrapper key for ${fs}" \ + "${ZFS}" key -l -r "${fs}" if [ "${ZFS_ERROR}" != 0 ] then - [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" - disable_plymouth - echo "" - echo "Command: $ZFS_CMD" - echo "Message: $ZFS_STDERR" - echo "Error: $ZFS_ERROR" - echo "" - echo "Failed to load zfs encryption wrapper key (s)." - echo "Please verify dataset property 'keysource' for datasets" - echo "and rerun: $ZFS_CMD" - emergency_shell - else - [ "$quiet" != "y" ] && zfs_log_end_msg + if [ "$?" != 999 ]; then + echo "" + echo "Command: ${ZFS_CMD}" + echo "Message: ${ZFS_STDERR}" + echo "Error: ${ZFS_ERROR}" + echo "" + echo "Failed to load zfs encryption wrapper key (s)." + echo "Please verify dataset property 'keysource' for datasets" + echo "and rerun: ${ZFS_CMD}" + emergency_shell + else + return 1 + fi fi return 0 @@ -800,30 +856,24 @@ decrypt_fs() destroy_fs() { local fs="$1" - local ZFS_CMD ZFS_STDERR ZFS_ERROR - [ "$quiet" != "y" ] && \ - zfs_log_begin_msg "Destroying '$fs'" - - ZFS_CMD="${ZFS} destroy $fs" - ZFS_STDERR="$(${ZFS_CMD} 2>&1)" - ZFS_ERROR="$?" + zfs_action "Destroying '${fs}'" "${ZFS}" destroy "${fs}" if [ "${ZFS_ERROR}" != 0 ] then - [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" - disable_plymouth - echo "" - echo "Command: $ZFS_CMD" - echo "Message: $ZFS_STDERR" - echo "Error: $ZFS_ERROR" - echo "" - echo "Failed to destroy '$fs'. Please make sure that '$fs' is not availible." - echo "Hint: Try: zfs destroy -Rfn $fs" - echo "If this dryrun looks good, then remove the 'n' from '-Rfn' and try again." - emergency_shell - else - [ "$quiet" != "y" ] && zfs_log_end_msg + if [ "$?" != 999 ]; then + echo "" + echo "Command: ${ZFS_CMD}" + echo "Message: ${ZFS_STDERR}" + echo "Error: ${ZFS_ERROR}" + echo "" + echo "Failed to destroy '${fs}'. Please make sure that '${fs}' is not availible." + echo "Hint: Try: zfs destroy -Rfn ${fs}" + echo "If this dryrun looks good, then remove the 'n' from '-Rfn' and try again." + emergency_shell + else + return 1 + fi fi return 0 @@ -838,36 +888,32 @@ clone_snap() local snap="$1" local destfs="$2" local mountpoint="$3" - local ZFS_CMD ZFS_STDERR ZFS_ERROR - - [ "$quiet" != "y" ] && zfs_log_begin_msg "Cloning '$snap' to '$destfs'" # Clone the snapshot into a dataset we can boot from # + We don't want this filesystem to be automatically mounted, we # want controll over this here and nowhere else. # + We don't need any mountpoint set for the same reason. # We use the 'org.zol:mountpoint' property to remember the mountpoint. - ZFS_CMD="${ZFS} clone -o canmount=noauto -o mountpoint=none" - ZFS_CMD="${ZFS_CMD} -o org.zol:mountpoint=${mountpoint}" - ZFS_CMD="${ZFS_CMD} $snap $destfs" - ZFS_STDERR="$(${ZFS_CMD} 2>&1)" - ZFS_ERROR="$?" + zfs_action "Cloning '${snap}' to '${destfs}'" \ + "${ZFS}" clone -o canmount=noauto -o mountpoint=none \ + -o org.zol:mountpoint="${mountpoint}" \ + "${snap}" "${destfs}" if [ "${ZFS_ERROR}" != 0 ] then - [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" - disable_plymouth - echo "" - echo "Command: $ZFS_CMD" - echo "Message: $ZFS_STDERR" - echo "Error: $ZFS_ERROR" - echo "" - echo "Failed to clone snapshot." - echo "Make sure that the any problems are corrected and then make sure" - echo "that the dataset '$destfs' exists and is bootable." - emergency_shell - else - [ "$quiet" != "y" ] && zfs_log_end_msg + if [ "$?" != 999 ]; then + echo "" + echo "Command: ${ZFS_CMD}" + echo "Message: ${ZFS_STDERR}" + echo "Error: ${ZFS_ERROR}" + echo "" + echo "Failed to clone snapshot." + echo "Make sure that the any problems are corrected and then make sure" + echo "that the dataset '${destfs}' exists and is bootable." + emergency_shell + else + return 1 + fi fi return 0 @@ -877,27 +923,22 @@ clone_snap() rollback_snap() { local snap="$1" - local ZFS_CMD ZFS_STDERR ZFS_ERROR - - [ "$quiet" != "y" ] && zfs_log_begin_msg "Rollback $snap" - ZFS_CMD="${ZFS} rollback -Rf $snap" - ZFS_STDERR="$(${ZFS_CMD} 2>&1)" - ZFS_ERROR="$?" + zfs_action "Rollback snapshot '${snap}'" "${ZFS}" rollback -Rf "${snap}" if [ "${ZFS_ERROR}" != 0 ] then - [ "$quiet" != "y" ] && zfs_log_failure_msg "${ZFS_ERROR}" - disable_plymouth - echo "" - echo "Command: $ZFS_CMD" - echo "Message: $ZFS_STDERR" - echo "Error: $ZFS_ERROR" - echo "" - echo "Failed to rollback snapshot." - emergency_shell - else - [ "$quiet" != "y" ] && zfs_log_end_msg + if [ "$?" != 999 ]; then + echo "" + echo "Command: ${ZFS_CMD}" + echo "Message: ${ZFS_STDERR}" + echo "Error: ${ZFS_ERROR}" + echo "" + echo "Failed to rollback snapshot." + emergency_shell + else + return 1 + fi fi return 0 @@ -923,9 +964,9 @@ ask_user_snap() # stdout to the caller, we use stderr for our questions. echo "What snapshot do you want to boot from?" > /dev/stderr while read snap; do - echo " $i: ${snap}" > /dev/stderr - eval `echo SNAP_$i=$snap` - i=$((i + 1)) + echo " ${i}: ${snap}" > /dev/stderr + eval `echo SNAP_${i}=${snap}` + i="$((i + 1))" done <