* Name the install medium when pacstrap rejects a package off it A failed install showed "Omarchy installation stopped", the pacstrap error, a log tail, and a link to Discord. Somewhere in that tail was the whole answer -- pacman rejecting a package as corrupt -- and nothing on the screen connected it to the USB stick it came off. Nothing else can put it there. The offline mirror is bind-mounted onto the target's package cache for the duration of pacstrap, so a package rejected under that path was read straight off the medium; nothing else ever writes there. That is worth saying in the words that name the fix rather than leaving it as a package name nobody recognises. Which way the medium failed is a separate question, and usually unanswerable after the fact: pacstrap runs with --noconfirm, which answers yes to pacman's "delete it?", so the evidence is unlinked through the bind mount before anything can weigh it. The usual verdict therefore names the medium and gives both remedies in the order worth trying -- verify the download first, because it is cheap and rules out the common case. When the package does survive, the sha256 repo-add recorded at build time separates a bad write from a bad read, and the wording follows. Co-Authored-By: Codex XHigh <codex@openai.com> * Keep the media diagnosis whole and print it once Two things only visible by looking at the rendered screen. The diagnosis was recorded in the support log before the failure screen was drawn, and the log tail on that screen reads the same file -- so the verdict appeared twice, once as the banner and again eight lines below it. The same finding printed twice reads as two findings. It is recorded after the render now, and the tail carries the installer's own output the way it did before. The package name shared a line with the sentence explaining it, and the screen is only as wide as the logo. npth's name already pushed the mismatch wording past the edge, and a firmware package would have taken the whole sentence with it. Every verdict puts the name on a line of its own, and the test walks all three with a sixty-three character package name to keep them there. Co-Authored-By: Codex XHigh <codex@openai.com> * Break the media diagnosis between what happened and what to do The package name and the remedy beneath it ran together as one block, so the line telling someone to verify their download read as another clause about the package rather than the first thing to go and do. A blank line separates them in all three verdicts. The renderer dropped blank lines, on the assumption that any it saw were slack rather than shape, so the break is drawn now instead of skipped. * Give the log tail back the rows the diagnosis spends The tail sizes itself from the terminal height less a constant for everything drawn above it, and the diagnosis is seven rows that constant never knew about. On a forty-row console the failure screen came to forty-one and scrolled its own logo off the top. The tail is the part that should give way, so it is told what was spent above it. The test that came with this first asserted the logo was still on screen, which it cannot: it reads the output stream, and the stream keeps every row ever emitted whether or not it stayed visible. It passed with the fix reverted. It checks the mechanism instead -- a tail that reaches fewer lines of the log when a diagnosis is present -- against two logs identical line for line but for the one path that decides whether there is a diagnosis at all. --------- Co-authored-by: Codex XHigh <codex@openai.com>
125 lines
4.8 KiB
Bash
Executable File
125 lines
4.8 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Say whether an install failure was the install medium, and say it in words
|
|
# that name the fix.
|
|
#
|
|
# The ISO's offline mirror is bind-mounted onto the target's package cache for
|
|
# the duration of pacstrap (see _mount_offline_package_cache), so a package
|
|
# pacman calls corrupt under that path is a byte that came off the medium --
|
|
# nothing else ever writes there. That much is certain, and it is the part
|
|
# worth saying out loud, because the failure screen otherwise ends at "get help
|
|
# at discord" with the word USB nowhere on it.
|
|
#
|
|
# What is not certain is which way the medium failed. Bytes written wrong and
|
|
# bytes read wrong produce the same checksum mismatch, and pacstrap runs with
|
|
# --noconfirm, which answers yes to pacman's "delete it?" and unlinks the
|
|
# package through the bind mount before anything here can weigh it. So the
|
|
# usual verdict names the medium and gives both remedies in the order worth
|
|
# trying. When the package does survive, its checksum in the mirror's database
|
|
# tells the two apart, and then this says which.
|
|
#
|
|
# Prints the diagnosis on stdout, one line per line, headline first. Exits 1
|
|
# with no output when there is nothing here to diagnose, so the caller can ask
|
|
# unconditionally.
|
|
|
|
set -uo pipefail
|
|
|
|
TARGET_PACKAGE_CACHE="${OMARCHY_TARGET_PACKAGE_CACHE:-/mnt/var/cache/pacman/pkg}"
|
|
OFFLINE_MIRROR="${OMARCHY_OFFLINE_MIRROR:-/var/cache/omarchy/mirror/offline}"
|
|
|
|
if (( $# == 0 )); then
|
|
echo "Usage: omarchy-install-diagnose-media <log-file>..." >&2
|
|
exit 2
|
|
fi
|
|
|
|
# Only packages under the target cache count. A corrupt package anywhere else
|
|
# was not read off this ISO, and guessing wrong here sends someone to buy a USB
|
|
# stick they did not need.
|
|
corrupt_package() {
|
|
local log match package=""
|
|
|
|
for log in "$@"; do
|
|
[[ -f $log ]] || continue
|
|
match=$(sed -n "s|.*${TARGET_PACKAGE_CACHE}/\([^ ]*\) is corrupted.*|\1|p" "$log" | tail -n 1)
|
|
[[ -n $match ]] && package="$match"
|
|
done
|
|
|
|
printf '%s' "$package"
|
|
}
|
|
|
|
expected_checksum() {
|
|
local package="$1" reader
|
|
|
|
[[ -f $OFFLINE_MIRROR/offline.db ]] || return 1
|
|
|
|
if command -v bsdtar >/dev/null 2>&1; then
|
|
reader=(bsdtar -xOf "$OFFLINE_MIRROR/offline.db")
|
|
else
|
|
reader=(tar -xOzf "$OFFLINE_MIRROR/offline.db")
|
|
fi
|
|
|
|
# repo-add writes %FILENAME% before %SHA256SUM% in every desc record, so the
|
|
# name in hand when a checksum arrives is the name it belongs to. The wanted
|
|
# name comes through the environment rather than -v, which would read a
|
|
# backslash in a package version as an escape sequence.
|
|
"${reader[@]}" 2>/dev/null | want="$package" awk '
|
|
BEGIN { want = ENVIRON["want"] }
|
|
$0 == "%FILENAME%" { getline name; next }
|
|
$0 == "%SHA256SUM%" { getline sha; if (name == want) { print sha; exit } }
|
|
'
|
|
}
|
|
|
|
actual_checksum() {
|
|
local package="$1" sum
|
|
|
|
[[ -f $OFFLINE_MIRROR/$package ]] || return 1
|
|
sum=$(sha256sum "$OFFLINE_MIRROR/$package" 2>/dev/null) || return 1
|
|
printf '%s' "${sum%% *}"
|
|
}
|
|
|
|
package=$(corrupt_package "$@")
|
|
if [[ -z $package ]]; then
|
|
exit 1
|
|
fi
|
|
|
|
# The name reaches a terminal, and a package version may legally hold a
|
|
# backslash that the renderer would read as an escape. Strip anything a package
|
|
# filename has no business containing before printing it.
|
|
display_package="${package//[^A-Za-z0-9._+:@%-]/}"
|
|
|
|
expected=$(expected_checksum "$package")
|
|
actual=$(actual_checksum "$package")
|
|
|
|
# The package name goes on a line of its own throughout. Names run past fifty
|
|
# characters and the screen is only as wide as the logo, so a name sharing a
|
|
# line with the sentence that explains it truncates the explanation away. The
|
|
# blank line after it separates what happened from what to do about it.
|
|
if [[ -n $expected && -n $actual ]]; then
|
|
if [[ $expected == "$actual" ]]; then
|
|
# Intact now, so the bytes were misread rather than written wrong, and
|
|
# re-downloading fixes neither of the things that could have done it.
|
|
echo "The install medium was misread"
|
|
echo "This package is intact on this ISO, so the download and the write were fine:"
|
|
echo "$display_package"
|
|
echo
|
|
echo "Try another USB port or another stick, and test this machine's memory"
|
|
else
|
|
echo "The install medium is damaged"
|
|
echo "This package no longer matches the checksum it was built with:"
|
|
echo "$display_package"
|
|
echo
|
|
echo "Re-download the ISO, verify it with sha256sum, and write the USB again"
|
|
echo "If a verified ISO fails here too, the USB stick itself is the problem"
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
# The usual case: pacman deleted the package it rejected, so the medium is the
|
|
# answer but the manner of its failure is not recoverable from here.
|
|
echo "The install medium is damaged or misread"
|
|
echo "pacman rejected this package, read straight off this ISO:"
|
|
echo "$display_package"
|
|
echo
|
|
echo "Verify your download with sha256sum, then write the USB again"
|
|
echo "If the download verifies, the stick or this machine's memory is at fault"
|