Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zfsbootmenu: log errors for unimportable pools #461

Merged
merged 1 commit into from
Sep 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions zfsbootmenu/bin/zlogtail
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# shellcheck disable=SC1091
source /lib/zfsbootmenu-lib.sh >/dev/null 2>&1 || exit 1
source /lib/kmsg-log-lib.sh >/dev/null 2>&1 || exit 1

[ -f "${BASE}/have_errors" ] && rm "${BASE}/have_errors"
[ -f "${BASE}/have_warnings" ] && rm "${BASE}/have_warnings"
Expand Down Expand Up @@ -29,10 +30,4 @@ fi

export FZF_DEFAULT_OPTS="${fuzzy_default_options[*]}"

# Try to use feature flags found on dmesg from util-linux
if output="$( dmesg --notime -f user -l err,warn 2>/dev/null )" ; then
echo "${output}" | ${FUZZYSEL}
else
# fall back to manually parsing dmesg output; will show all ZBM generated logs up to zinfo level
dmesg | awk '/ZFSBootMenu:/{ for (i=3; i<=NF; i++){ printf("%s ", $i)}; printf "\n" }' | ${FUZZYSEL}
fi
print_kmsg_logs "err,warn" | ${FUZZYSEL}
55 changes: 55 additions & 0 deletions zfsbootmenu/lib/kmsg-log-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,58 @@ zerror() {
: > "${BASE}/have_errors"
echo "<3>ZFSBootMenu: $1" > /dev/kmsg
}

# arg1: comma-separated log levels to print
# prints: all logs at that level
# returns: nothing

print_kmsg_logs() {
local levels levels_array grep_args

levels="${1}"
if [ -z "${levels}" ]; then
zerror "levels is undefined"
return
fi

# Try to use feature flags found in dmesg from util-linux
if output="$( dmesg --notime -f user --color=always -l "${levels}" 2>/dev/null )" ; then
echo -e "${output}"
else
# Both util-linux and Busybox dmesg support the -r flag. However, the log level that is
# reported by Busybox dmesg is larger than that reported by util-linux dmesg. Busybox dmesg
# is too bare-bones to do much of anything, so we just need to grep for both integers at
# a given log level, then refly on matching ZFSBootMenu for info and lower, and ZBM for debug.

IFS=',' read -r -a levels_array <<<"${levels}"
for level in "${levels_array[@]}"; do
case "${level}" in
err)
grep_args+=( "-e" "^<11>" "-e" "^<3>" )
;;
warn)
grep_args+=( "-e" "^<12>" "-e" "^<4>" )
;;
notice)
grep_args+=( "-e" "^<13>" "-e" "^<5>" )
;;
info)
grep_args+=( "-e" "^<14>" "-e" "^<6>" )
;;
debug)
grep_args+=( "-e" "^<15>" "-e" "^<7>" )
;;
*)
grep_args+=( "-e" "." )
;;
esac
done

dmesg -r | grep "${grep_args[@]}" \
| awk '
/ZFSBootMenu:/{ for (i=3; i<=NF; i++){ printf("%s ", $i)}; printf "\n" }
/ZBM:/{ for (i=3; i<=NF; i++){ printf("%s ", $i)}; printf "\n" }
'
fi
}

39 changes: 38 additions & 1 deletion zfsbootmenu/lib/zfsbootmenu-core.sh
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,38 @@ match_hostid() {
return 1
}

# args: no arguments
# prints: nothing
# returns: nothing

log_unimportable() {
local pool id state line error_line

while read -r line; do
case "${line}" in
pool*)
pool="${line#pool: }"
;;
id*)
id="${line#id: }"
;;
state*)
state="${line#state: }"
if [ "${state}" == "UNAVAIL" ]; then
while read -r error_line; do
zerror "${error_line}"
done <<<"$( zpool import -N "${id}" 2>&1 )"
fi
state=
pool=
id=
;;
*)
;;
esac
done <<<"$( zpool import )"
}

# args: none
# prints: nothing
# returns: 0 if at least one pool is available
Expand Down Expand Up @@ -1813,7 +1845,12 @@ emergency_shell() {

EOF

command -v efibootmgr >/dev/null 2>&1 && mount_efivarfs "rw"
if [ -f "${BASE}/have_errors" ]; then
print_kmsg_logs "err"
echo ""
fi

command -v efibootmgr >/dev/null 2>&1 && mount_efivarfs "rw"

# -i (interactive) mode will source $HOME/.bashrc
/bin/bash -i
Expand Down
2 changes: 2 additions & 0 deletions zfsbootmenu/libexec/zfsbootmenu-init
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ fi
# If a boot pool is specified, that will be tried first
try_pool="${boot_pool}"
zbm_import_attempt=0

while true; do
if [ -n "${try_pool}" ]; then
zdebug "attempting to import preferred pool ${try_pool}"
Expand Down Expand Up @@ -173,6 +174,7 @@ while true; do
continue
fi

log_unimportable
# Allow the user to attempt recovery
emergency_shell "unable to successfully import a pool"
done
Expand Down