Merge pull request #15 from zdykstra/cleaner-mount
Core update/feature bump
This commit is contained in:
commit
f2a8856a6f
|
@ -80,6 +80,7 @@ install() {
|
|||
dracut_install /usr/bin/tail
|
||||
dracut_install /usr/lib/udev/zvol_id
|
||||
inst_simple "${moddir}/zfsbootmenu-lib.sh" "/lib/zfsbootmenu-lib.sh"
|
||||
inst_simple "${moddir}/zfsbootmenu-preview.sh" "/bin/zfsbootmenu-preview.sh"
|
||||
inst_hook cmdline 95 "${moddir}/zfsbootmenu-parse-commandline.sh"
|
||||
inst_hook pre-mount 90 "${moddir}/zfsbootmenu.sh"
|
||||
|
||||
|
|
|
@ -2,26 +2,6 @@
|
|||
|
||||
# ZFS boot menu functions
|
||||
|
||||
# arg1: zroot/ROOT/bootenvironment
|
||||
# prints: zroot_ROOT_bootenvironment
|
||||
# returns: No return value
|
||||
|
||||
underscore() {
|
||||
local bepath
|
||||
bepath="${1}"
|
||||
echo ${bepath} | sed 's,/,_,g'
|
||||
}
|
||||
|
||||
# arg1: zroot_ROOT_bootenvironment
|
||||
# prints: zroot/ROOT/bootenvironment
|
||||
# returns: No return value
|
||||
|
||||
slash() {
|
||||
local bepath
|
||||
bepath="${1}"
|
||||
echo ${bepath} | sed 's,_,/,g'
|
||||
}
|
||||
|
||||
# arg1: ZFS filesystem name
|
||||
# arg2: mountpoint
|
||||
# prints: No output
|
||||
|
@ -31,31 +11,18 @@ mount_zfs() {
|
|||
local fs mnt ret
|
||||
|
||||
fs="${1}"
|
||||
mnt="${2}"
|
||||
|
||||
test -d ${mnt} || return 1
|
||||
mount -o zfsutil -t zfs ${fs} ${mnt}
|
||||
mnt="${BASE}/${fs}/mnt"
|
||||
test -d "${mnt}" || mkdir -p "${mnt}"
|
||||
|
||||
mount -o zfsutil -t zfs "${fs}" "${mnt}"
|
||||
ret=$?
|
||||
|
||||
echo "${mnt}"
|
||||
return ${ret}
|
||||
}
|
||||
|
||||
# arg1: mount point
|
||||
# prints: No output
|
||||
# returns: 0 on success
|
||||
|
||||
umount_zfs() {
|
||||
local mnt ret
|
||||
|
||||
mnt="${1}"
|
||||
umount ${mnt}
|
||||
ret=$?
|
||||
|
||||
return ${ret}
|
||||
}
|
||||
|
||||
# arg1: Path to file with header/options text
|
||||
# arg2: Path to file with detected boot environments, 1 per line
|
||||
# arg1: Path to file with detected boot environments, 1 per line
|
||||
# prints: key pressed, boot environment
|
||||
# returns: 130 on error, 0 otherwise
|
||||
|
||||
|
@ -63,13 +30,14 @@ draw_be() {
|
|||
local env header selected ret
|
||||
|
||||
env="${1}"
|
||||
header="${2}"
|
||||
|
||||
test -f ${env} || return 130
|
||||
test -f ${header} || return 130
|
||||
|
||||
selected="$( cat ${header} ${env} | fzf -0 --prompt "BE > " \
|
||||
--header-lines=2 --expect=alt-k,alt-s,alt-a,alt-r )"
|
||||
selected="$( cat ${env} | fzf -0 --prompt "BE > " \
|
||||
--expect=alt-k,alt-s,alt-a,alt-r,alt-d \
|
||||
--preview-window=up:2 \
|
||||
--header="[ENTER] boot [ALT+K] kernel [ALT+D] set bootfs [ALT+S] snapshots" \
|
||||
--preview="zfsbootmenu-preview.sh ${BASE} {} ${BOOTFS}")"
|
||||
ret=$?
|
||||
while read -r line; do
|
||||
if [ -z "$line" ]; then
|
||||
|
@ -90,13 +58,8 @@ draw_kernel() {
|
|||
|
||||
benv="${1}"
|
||||
|
||||
# Set a pretty benv for our prompt
|
||||
pretty="$( slash ${benv})"
|
||||
pretty="${pretty#${BASE}/}"
|
||||
|
||||
selected="$( cat ${benv} | fzf --prompt "${pretty} > " --tac \
|
||||
--with-nth=2 --header="[ENTER] boot
|
||||
[ESC] back")"
|
||||
selected="$( cat ${BASE}/${benv}/kernels | fzf --prompt "${benv} > " --tac \
|
||||
--with-nth=2 --header="[ENTER] boot [ESC] back")"
|
||||
|
||||
ret=$?
|
||||
echo "${selected}"
|
||||
|
@ -113,8 +76,7 @@ draw_snapshots() {
|
|||
benv="${1}"
|
||||
|
||||
selected="$( zfs list -t snapshot -H -o name ${benv} | fzf --prompt "Snapshot > " --tac \
|
||||
--header="[ENTER] clone
|
||||
[ESC] back" )"
|
||||
--header="[ENTER] clone [ESC] back" )"
|
||||
ret=$?
|
||||
echo "${selected}"
|
||||
return ${ret}
|
||||
|
@ -136,19 +98,23 @@ kexec_kernel() {
|
|||
# initramfs
|
||||
IFS=' ' read fs kernel initramfs <<<"${selected}"
|
||||
|
||||
mount_zfs ${fs} ${BASE_MOUNT}
|
||||
mnt="$( mount_zfs "${fs}" )"
|
||||
|
||||
ret=$?
|
||||
if [ $ret != 0 ]; then
|
||||
emergency_shell "unable to mount ${fs}"
|
||||
fi
|
||||
|
||||
test -e ${BASE_MOUNT}/etc/default/grub && . ${BASE_MOUNT}/etc/default/grub
|
||||
while IFS= read -r line
|
||||
do
|
||||
cli_args="${line}"
|
||||
done < "${BASE}/${fs}/default_args"
|
||||
|
||||
kexec -l ${BASE_MOUNT}${kernel} \
|
||||
--initrd=${BASE_MOUNT}/${initramfs} \
|
||||
--command-line="root=zfs:${fs} ${GRUB_CMDLINE_LINUX_DEFAULT}"
|
||||
kexec -l ${mnt}${kernel} \
|
||||
--initrd=${mnt}/${initramfs} \
|
||||
--command-line="root=zfs:${fs} ${cli_args}"
|
||||
|
||||
umount_zfs ${fs}
|
||||
umount ${mnt}
|
||||
|
||||
# Export if read-write, to ensure a clean pool
|
||||
pool="${selected%%/*}"
|
||||
|
@ -170,7 +136,7 @@ clone_snapshot() {
|
|||
|
||||
pool="${selected%%/*}"
|
||||
|
||||
# If the pool is read-only, flip the import arg off and, export then import
|
||||
# If the pool is read-only, flip the arg off then export and import
|
||||
if [ "$( zpool get -H -o value readonly ${pool} )" = "on" ]; then
|
||||
export_pool "${pool}"
|
||||
import_args="${import_args/readonly=on/readonly=off}"
|
||||
|
@ -179,6 +145,16 @@ clone_snapshot() {
|
|||
|
||||
target="${selected/@/_}"
|
||||
|
||||
if $( zfs list -H -o name | grep -q ${target} ); then
|
||||
last_env="$( zfs list -H -o name | grep ${target} | tail -1 )"
|
||||
index="${last_env##${target}_}"
|
||||
index="$(( ${index} + 1 ))"
|
||||
else
|
||||
index="0"
|
||||
fi
|
||||
|
||||
target="$( printf "%s_%0.3d" ${target} ${index} )"
|
||||
|
||||
zfs clone -o mountpoint=/ \
|
||||
-o canmount=noauto \
|
||||
${selected} ${target}
|
||||
|
@ -187,7 +163,7 @@ clone_snapshot() {
|
|||
if [ $ret -eq 0 ]; then
|
||||
key_wrapper "${target}"
|
||||
if [ $? -eq 0 ]; then
|
||||
if output=$( find_be_kernels "${target}" "${BASE_MOUNT}" ); then
|
||||
if output=$( find_be_kernels "${target}" ); then
|
||||
echo "${target}" >> ${BASE}/env
|
||||
return 0
|
||||
else
|
||||
|
@ -204,33 +180,47 @@ clone_snapshot() {
|
|||
fi
|
||||
}
|
||||
|
||||
set_default_env() {
|
||||
local selected
|
||||
selected="${1}"
|
||||
|
||||
pool="${selected%%/*}"
|
||||
|
||||
# If the pool is read-only, flip the arg off then export and import
|
||||
if [ "$( zpool get -H -o value readonly ${pool} )" = "on" ]; then
|
||||
export_pool "${pool}"
|
||||
import_args="${import_args/readonly=on/readonly=off}"
|
||||
import_pool "${pool}"
|
||||
key_wrapper "${pool}"
|
||||
fi
|
||||
|
||||
if output="$( zpool set bootfs=${selected} ${pool} )"; then
|
||||
BOOTFS="${selected}"
|
||||
fi
|
||||
}
|
||||
|
||||
# arg1: ZFS filesystem
|
||||
# arg2: mountpoint
|
||||
# prints: nothing
|
||||
# returns: number of kernels found
|
||||
# returns: 0 if kernels were found
|
||||
|
||||
find_be_kernels() {
|
||||
local fs mnt
|
||||
fs="${1}"
|
||||
mnt="${2}"
|
||||
|
||||
local sane kernel version pairs
|
||||
|
||||
local sane kernel version kernel_records
|
||||
pairs=()
|
||||
|
||||
# Check if /boot even exists in the environment
|
||||
mount_zfs "${fs}" "${mnt}"
|
||||
mnt="$( mount_zfs "${fs}" )"
|
||||
kernel_records="${mnt/mnt/kernels}"
|
||||
|
||||
if [ ! -d "${mnt}/boot" ]; then
|
||||
umount_zfs "${fs}"
|
||||
return
|
||||
umount "${mnt}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Create a filename with out /'s
|
||||
sane="$( underscore ${fs} )"
|
||||
|
||||
# Remove this file if it already exists
|
||||
test -f ${BASE}/${sane} && rm ${BASE}/${sane}
|
||||
|
||||
for kernel in $( ls ${mnt}/boot/vmlinux-* \
|
||||
${mnt}/boot/vmlinuz-* \
|
||||
${mnt}/boot/kernel-* \
|
||||
|
@ -243,16 +233,26 @@ find_be_kernels() {
|
|||
"initrd-${version}" "initramfs-${version}.img"; do
|
||||
|
||||
if test -e "${mnt}/boot/${i}" ; then
|
||||
echo "${fs} ${kernel} /boot/${i}" >> ${BASE}/${sane}
|
||||
echo "${fs} ${kernel} /boot/${i}" >> "${kernel_records}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
umount_zfs "${fs}"
|
||||
defaults="$( select_kernel "${fs}" )"
|
||||
IFS=' ' read def_fs def_kernel def_initramfs <<<"${defaults}"
|
||||
def_kernel="$( basename "${def_kernel}" )"
|
||||
def_version=$( echo $def_kernel | sed -e "s,^[^0-9]*-,,g" )
|
||||
|
||||
# Return the number of kernels found
|
||||
return "${#pairs[@]}"
|
||||
def_kernel_file="${mnt/mnt/default_kernel}"
|
||||
echo "${def_version}" > "${def_kernel_file}"
|
||||
|
||||
def_args="$( find_kernel_args "${mnt}" )"
|
||||
def_args_file="${mnt/mnt/default_args}"
|
||||
echo "${def_args}" > "${def_args_file}"
|
||||
|
||||
umount "${mnt}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# arg1: ZFS filesystem
|
||||
|
@ -264,13 +264,12 @@ select_kernel() {
|
|||
zfsbe="${1}"
|
||||
|
||||
local sane specific_kernel kexec_args
|
||||
sane="$( underscore ${zfsbe} )"
|
||||
|
||||
specific_kernel="$( zfs get -H -o value org.zfsbootmenu:kernel ${zfsbe} )"
|
||||
|
||||
# No value set, pick the last kernel entry
|
||||
if [ "${specific_kernel}" = "-" ]; then
|
||||
kexec_args="$( tail -1 ${BASE}/${sane} )"
|
||||
kexec_args="$( tail -1 ${BASE}/${zfsbe}/kernels )"
|
||||
else
|
||||
while read -r kexec_args; do
|
||||
local fs kernel initramfs
|
||||
|
@ -278,12 +277,30 @@ select_kernel() {
|
|||
if [[ "${kernel}" =~ "${specific_kernel}" ]]; then
|
||||
break
|
||||
fi
|
||||
done <<<"$( cat ${BASE}/${sane} )"
|
||||
done <<<"$( cat ${BASE}/${zfsbe}/kernels )"
|
||||
fi
|
||||
|
||||
echo "${kexec_args}"
|
||||
}
|
||||
|
||||
find_kernel_args() {
|
||||
local zfsbe
|
||||
zfsbe="${1}"
|
||||
|
||||
local arguments
|
||||
|
||||
if [ -f "${zfsbe}/etc/default/grub" ]; then
|
||||
echo "$(
|
||||
. "${zfsbe}/etc/default/grub" ;
|
||||
echo "${GRUB_CMDLINE_LINUX_DEFAULT}"
|
||||
)"
|
||||
return
|
||||
fi
|
||||
|
||||
# No arguments found, return something generic
|
||||
echo "quiet loglevel=3"
|
||||
}
|
||||
|
||||
# no arguments
|
||||
# prints: nothing
|
||||
# returns: number of pools that can be imported
|
||||
|
|
|
@ -40,6 +40,10 @@ else
|
|||
menu_timeout=10
|
||||
fi
|
||||
|
||||
if getargbool 1 die_on_import_failure ; then
|
||||
info "ZFSBootMenu: Disabling die on import failure"
|
||||
fi
|
||||
|
||||
wait_for_zfs=0
|
||||
case "${root}" in
|
||||
""|zfsbootmenu|zfsbootmenu:)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
|
||||
BASE="${1}"
|
||||
ENV="${2}"
|
||||
BOOTFS="${3}"
|
||||
|
||||
BLUE='\033[0;34m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
while IFS= read -r line
|
||||
do
|
||||
selected_kernel="${line}"
|
||||
done < "${BASE}/${ENV}/default_kernel"
|
||||
|
||||
while IFS= read -r line
|
||||
do
|
||||
selected_arguments="${line}"
|
||||
done < "${BASE}/${ENV}/default_args"
|
||||
|
||||
if [[ "${BOOTFS}" =~ "${ENV}" ]]; then
|
||||
selected_env_str="${ENV} (default) - ${selected_kernel}"
|
||||
else
|
||||
selected_env_str="${ENV} - ${selected_kernel}"
|
||||
fi
|
||||
|
||||
# Left pad the strings to center them based on the preview width
|
||||
selected_env_str="$( printf "%*s\n" $(( (${#selected_env_str} + FZF_PREVIEW_COLUMNS) / 2)) "${selected_env_str}" )"
|
||||
selected_arguments="$( printf "%*s\n" $(( (${#selected_arguments} + FZF_PREVIEW_COLUMNS) / 2)) "${selected_arguments}" )"
|
||||
|
||||
echo -e "${GREEN}${selected_env_str}${NC}"
|
||||
echo "${selected_arguments}"
|
|
@ -1,6 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
. /lib/zfsbootmenu-lib.sh
|
||||
test -f /lib/zfsbootmenu-lib.sh && source /lib/zfsbootmenu-lib.sh
|
||||
test -f zfsbootmenu-lib.sh && source zfsbootmenu-lib.sh
|
||||
|
||||
|
||||
echo "Loading boot menu ..."
|
||||
TERM=linux
|
||||
|
@ -11,15 +13,7 @@ OLDIFS="$IFS"
|
|||
export FZF_DEFAULT_OPTS="--layout=reverse-list --cycle \
|
||||
--inline-info --tac"
|
||||
|
||||
BE_SELECTED=0
|
||||
KERNEL_SELECTED=0
|
||||
|
||||
BASE="$( mktemp -d /tmp/zfs.XXXX )"
|
||||
BASE_MOUNT="${BASE}/be"
|
||||
mkdir ${BASE_MOUNT}
|
||||
|
||||
ENV_HEADER="[ALT+K] select kernel [ENTER] boot\n[ALT+A] all snapshots [ALT+S] BE snapshots"
|
||||
echo -e ${ENV_HEADER} > ${BASE}/env_header
|
||||
|
||||
# I should probably just modprobe zfs right off the bat
|
||||
# rootok is always 1 here, otherwise we wouldn't be here ...
|
||||
|
@ -46,7 +40,10 @@ if [ $ret -gt 0 ]; then
|
|||
emergency_shell "unable to successfully import a pool"
|
||||
fi
|
||||
else
|
||||
emergency_shell "no pools available to import"
|
||||
if [ ${die_on_import_failure} -eq 1 ]; then
|
||||
emergency_shell "no pools available to import"
|
||||
exit;
|
||||
fi
|
||||
fi
|
||||
|
||||
# Prefer a specific pool when checking for a bootfs value
|
||||
|
@ -129,7 +126,7 @@ if [[ ! -z "${BOOTFS}" ]]; then
|
|||
fi
|
||||
|
||||
# Generate a list of valid kernels for our bootfs
|
||||
if output=$( find_be_kernels "${BOOTFS}" "${BASE_MOUNT}" ); then
|
||||
if output=$( find_be_kernels "${BOOTFS}" ); then
|
||||
# Automatically select a kernel and boot it
|
||||
kexec_kernel "$( select_kernel "${BOOTFS}" )"
|
||||
fi
|
||||
|
@ -150,7 +147,7 @@ for FS in $( zfs list -H -o name,mountpoint | grep -E "/$" | cut -f1 ); do
|
|||
fi
|
||||
|
||||
# Check for kernels under the mountpoint, add to our BE list
|
||||
if output=$( find_be_kernels "${FS}" "${BASE_MOUNT}" ); then
|
||||
if output="$( find_be_kernels "${FS}" )" ; then
|
||||
echo ${FS} >> ${BASE}/env
|
||||
fi
|
||||
done
|
||||
|
@ -160,9 +157,12 @@ if [ ! -f ${BASE}/env ]; then
|
|||
fi
|
||||
|
||||
# This is the actual menuing system
|
||||
BE_SELECTED=0
|
||||
tput civis
|
||||
|
||||
while true; do
|
||||
if [ ${BE_SELECTED} -eq 0 ]; then
|
||||
bootenv="$( draw_be "${BASE}/env" "${BASE}/env_header")"
|
||||
bootenv="$( draw_be "${BASE}/env" )"
|
||||
ret=$?
|
||||
|
||||
# key press
|
||||
|
@ -181,7 +181,7 @@ while true; do
|
|||
exit
|
||||
;;
|
||||
"alt-k")
|
||||
selected_kernel="$( draw_kernel ${BASE}/$( underscore ${selected_be} ) )"
|
||||
selected_kernel="$( draw_kernel "${selected_be}" )"
|
||||
ret=$?
|
||||
|
||||
if [ $ret -eq 130 ]; then
|
||||
|
@ -191,6 +191,10 @@ while true; do
|
|||
exit
|
||||
fi
|
||||
;;
|
||||
"alt-d")
|
||||
set_default_env "${selected_be}"
|
||||
BE_SELECTED=0
|
||||
;;
|
||||
"alt-s")
|
||||
selected_snap="$( draw_snapshots ${selected_be} )"
|
||||
ret=$?
|
||||
|
|
Loading…
Reference in New Issue