diff --git a/zfsbootmenu/bin/zsnapshots b/zfsbootmenu/bin/zsnapshots index 377beda81..8cde47c91 100755 --- a/zfsbootmenu/bin/zsnapshots +++ b/zfsbootmenu/bin/zsnapshots @@ -1,4 +1,5 @@ #!/bin/bash +# vim: softtabstop=2 shiftwidth=2 expandtab sources=( /lib/profiling-lib.sh @@ -24,13 +25,37 @@ global_header() { echo -n -e "\\033[1;33m[ Recover from snapshot ]" } -if [ $# -ne 1 ] ; then - echo "Usage: $0 filesystem" - exit -fi +fs_header() { + echo -n -e "\\033[1;33m[ Select a filesystem ]" +} fs="${1}" +if [ -z "${fs}" ]; then + if ! candidates="$( find_be_candidates 2>/dev/null )"; then + zerror "no root candidates found; specify a filesystem manually" + exit 1 + fi + + header="$( column_wrap "^[RETURN] select:[ESCAPE] cancel" )" + + if ! fs="$( + fzf --header="${header}" --prompt "Filesystem > " \ + ${HAS_BORDER:+--border-label="$( fs_header )"} \ + ${HAS_BORDER:+--preview-label-pos=2:bottom} \ + --preview-window="up:${PREVIEW_HEIGHT}${HAS_BORDER:+,border-sharp}" \ + --preview="/libexec/zfsbootmenu-preview {} '${BOOTFS}'" <<< "${candidates}" + )"; then + tput clear + exit 0; + fi +fi + +if [ -z "${fs}" ]; then + zerror "a filesystem must be selected to browse snapshots" + exit 1 +fi + if ! is_zfs_filesystem "${fs}" ; then zerror "'${fs}' is not a ZFS filesystem" exit 1 diff --git a/zfsbootmenu/lib/zfsbootmenu-ui.sh b/zfsbootmenu/lib/zfsbootmenu-ui.sh index 54e6f074b..63b859357 100755 --- a/zfsbootmenu/lib/zfsbootmenu-ui.sh +++ b/zfsbootmenu/lib/zfsbootmenu-ui.sh @@ -582,26 +582,17 @@ get_sort_key() { echo -n "${sort_key:-name}" } -# arg1: path to BE list -# prints: nothing -# returns: 0 iff at least one valid BE was found +# prints: potential boot environments, one per line +# returns: 0 if any candidate was found, 1 otherwise -populate_be_list() { - local be_list fs canmount mnt active candidates ret sort_key - - be_list="${1}" - if [ -z "${be_list}" ]; then - zerror "be_list is undefined" - return 1 - fi - zdebug "be_list set to ${be_list}" +find_be_candidates() { + local fs mnt active ret sort_key list_fields have_bootfs + list_fields="name,canmount,mountpoint,org.zfsbootmenu:active" sort_key="$( get_sort_key )" - # Truncate the list to avoid stale entries - : > "${be_list}" - - # Find valid BEs + ret=1 + have_bootfs= while IFS=$'\t' read -r fs canmount mnt active; do if [ "${mnt}" = "/" ]; then # When mountpoint=/, BE is a candidate unless org.zfsbootmenu:active=off @@ -613,8 +604,10 @@ populate_be_list() { # All other datasets are ignored continue fi + + # If BOOTFS is defined, we'll manually append it to the array if [ "${BOOTFS}" = "${fs}" ] ; then - # If BOOTFS is defined, we'll manually append it to the array + have_bootfs="yes" continue fi @@ -623,14 +616,34 @@ populate_be_list() { zwarn "canmount=on set for '${fs}', should be canmount=noauto" fi - candidates+=( "${fs}" ) - done <<< "$(zfs list -H -o name,canmount,mountpoint,org.zfsbootmenu:active -S "${sort_key}")" + echo "${fs}" + ret=0 + done <<< "$( zfs list -H -o "${list_fields}" -S "${sort_key}" )" + + # put bootfs at the end + [ -n "${BOOTFS}" ] && [ -n "${have_bootfs}" ] && echo "${BOOTFS}" + return "${ret}" +} - # put bootfs on the end, so it is shown first with --tac - [ -n "${BOOTFS}" ] && candidates+=( "${BOOTFS}" ) +# arg1: path to BE list +# prints: nothing +# returns: 0 iff at least one valid BE was found + +populate_be_list() { + local be_list fs ret + + be_list="${1}" + if [ -z "${be_list}" ]; then + zerror "be_list is undefined" + return 1 + fi + zdebug "be_list set to ${be_list}" + + # Truncate the list to avoid stale entries + : > "${be_list}" ret=1 - for fs in "${candidates[@]}"; do + while read -r fs; do # Remove any existing cmdline cache rm -f "$( be_location "${fs}" )/cmdline" @@ -642,6 +655,6 @@ populate_be_list() { echo "${fs}" >> "${be_list}" ret=0 fi - done + done <<< "$( find_be_candidates 2>/dev/null )" return $ret }