mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 16:34:06 +01:00
check_file_length.sh required a dot in the filename, so every
extensionless executable was silently uncapped. is_source_file() now
reads the first two bytes and accepts a shebang, which catches real
scripts while still skipping data files like i3/config.
That immediately surfaced boot_recovery/boot-repair at 756 lines --
three times the largest capped shell file in the repo, uncapped purely
because its name has no dot in it. Split along its own section markers
into lib/{discovery,repair_fs,repair_kernel,modes}.sh, leaving the entry
script at 218.
The report block stays inline on purpose. It is top-level code with exit
calls rather than function definitions, and sourcing it changed control
flow: 30 of 42 tests failed. That is recorded in the lib headers so the
next reader does not retry it.
No vmbox pass for this one, deliberately. boot-repair is UEFI/ESP tooling
and the guest is BIOS/GRUB, so a sandbox green would be actively
misleading -- the vmbox skill says so itself. The evidence is the fixture
suite, which drives the real script against synthetic root trees: 42
passed before, 42 passed after.
verify_shell_split.sh reports 31 of 32 functions byte-identical. The one
difference is clean_shadow_files, where quoting $ESP_MOUNTPOINT fixed a
genuine SC2086 that only became visible once the function left the
monolith -- shellcheck could no longer see the readonly declaration and
stopped assuming the expansion was safe.
lib/tests/run_all.sh delegates to that same suite rather than standing up
a second, weaker harness: these libraries need the entry script's strict
mode and globals, so testing them in isolation would test a fiction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
155 lines
4.2 KiB
Bash
Executable File
155 lines
4.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Repair steps that operate on the kernel: depmod, the kernel image, the
|
|
# initramfs, and the pacman parallel-download check.
|
|
#
|
|
# Sourced by boot-repair, not executed. Split out of it verbatim to bring the
|
|
# entry script under the 250-line cap; it inherits the caller's strict mode,
|
|
# its $ROOT/$MODE globals and the output helpers defined there.
|
|
#
|
|
# shellcheck shell=bash
|
|
# shellcheck source=../boot-repair
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# depmod output is what modprobe consults; the same skipped-hook bug that
|
|
# leaves the ESP stale also leaves modules.dep missing for the new kernel.
|
|
ensure_depmod() {
|
|
local kver dep
|
|
kver="$1"
|
|
dep="$(rpath "/usr/lib/modules/${kver}/modules.dep")"
|
|
if [[ -f $dep ]]; then
|
|
ok "modules.dep present for $kver"
|
|
return 0
|
|
fi
|
|
problem "modules.dep missing for $kver"
|
|
if ! acting; then
|
|
would "run depmod $kver"
|
|
return 1
|
|
fi
|
|
if is_live; then
|
|
depmod "$kver" || {
|
|
problem "depmod $kver failed"
|
|
return 1
|
|
}
|
|
else
|
|
depmod -b "${ROOT%/}" "$kver" || {
|
|
problem "depmod failed"
|
|
return 1
|
|
}
|
|
fi
|
|
repaired "generated modules.dep for $kver"
|
|
return 0
|
|
}
|
|
|
|
# The core repair: make the ESP's kernel image match the installed module tree.
|
|
sync_kernel_image() {
|
|
local kver src dest have
|
|
kver="$1"
|
|
src="$(rpath "/usr/lib/modules/${kver}/vmlinuz")"
|
|
dest="$(rpath "${ESP_MOUNTPOINT}/vmlinuz-linux")"
|
|
|
|
[[ -f $src ]] || {
|
|
problem "no kernel image at $src"
|
|
return 1
|
|
}
|
|
|
|
if [[ -f $dest ]]; then
|
|
have="$(kernel_image_version "$dest" || true)"
|
|
if [[ $have == "$kver" ]]; then
|
|
ok "ESP kernel matches installed tree ($kver)"
|
|
return 0
|
|
fi
|
|
problem "ESP kernel is ${have:-unreadable} but installed tree is $kver"
|
|
else
|
|
problem "no kernel image on the ESP"
|
|
fi
|
|
|
|
if ! acting; then
|
|
would "install $kver to $dest"
|
|
return 1
|
|
fi
|
|
install -Dm644 "$src" "$dest"
|
|
repaired "installed kernel $kver to the ESP"
|
|
return 0
|
|
}
|
|
|
|
# Which kernel an initramfs was built for. Prefers lsinitcpio, but falls back
|
|
# to scanning the image directly — lsinitcpio is not guaranteed to be present
|
|
# in a degraded emergency shell.
|
|
initramfs_version() {
|
|
local img="$1" v=""
|
|
[[ -r $img ]] || return 1
|
|
if command -v lsinitcpio >/dev/null 2>&1; then
|
|
v="$(lsinitcpio "$img" 2>/dev/null |
|
|
grep -oE 'modules/[0-9]+\.[0-9]+\.[0-9]+-arch[0-9]+-[0-9]+' |
|
|
head -1 | cut -d/ -f2 || true)"
|
|
fi
|
|
if [[ -z $v ]]; then
|
|
v="$(grep -aoE 'modules/[0-9]+\.[0-9]+\.[0-9]+-arch[0-9]+-[0-9]+' "$img" 2>/dev/null |
|
|
head -1 | cut -d/ -f2 || true)"
|
|
fi
|
|
[[ -n $v ]] || return 1
|
|
printf '%s' "$v"
|
|
}
|
|
|
|
# Rebuild every preset so the initramfs matches the kernel we just installed.
|
|
rebuild_initramfs() {
|
|
local kver img have
|
|
kver="$1"
|
|
img="$(rpath "${ESP_MOUNTPOINT}/initramfs-linux.img")"
|
|
|
|
have="$(initramfs_version "$img" || true)"
|
|
|
|
if [[ -n $have && $have == "$kver" ]]; then
|
|
ok "initramfs matches $kver"
|
|
return 0
|
|
fi
|
|
|
|
problem "initramfs is ${have:-missing/unknown}, expected $kver"
|
|
if ! acting; then
|
|
would "run mkinitcpio -P"
|
|
return 1
|
|
fi
|
|
is_live || {
|
|
warn "skipping mkinitcpio (--root given)"
|
|
return 1
|
|
}
|
|
command -v mkinitcpio >/dev/null 2>&1 || {
|
|
problem "mkinitcpio is not installed"
|
|
return 1
|
|
}
|
|
mkinitcpio -P || {
|
|
problem "mkinitcpio -P failed"
|
|
return 1
|
|
}
|
|
repaired "rebuilt initramfs for $kver"
|
|
return 0
|
|
}
|
|
|
|
# The actual root cause on this machine. With ParallelDownloads > 1, pacman-git
|
|
# segfaults every forked hook child, so mkinitcpio and depmod never run and the
|
|
# transaction still reports success.
|
|
check_parallel_downloads() {
|
|
local conf value
|
|
conf="$(rpath /etc/pacman.conf)"
|
|
[[ -r $conf ]] || return 0
|
|
value="$(grep -E '^[[:space:]]*ParallelDownloads[[:space:]]*=' "$conf" 2>/dev/null |
|
|
tail -1 | sed 's/.*=[[:space:]]*//' | tr -d '[:space:]')"
|
|
[[ -n $value ]] || {
|
|
ok "ParallelDownloads not set (pacman default is serial)"
|
|
return 0
|
|
}
|
|
if [[ $value == "1" ]]; then
|
|
ok "ParallelDownloads = 1"
|
|
return 0
|
|
fi
|
|
problem "ParallelDownloads = $value — forked alpm hooks segfault, silently skipping mkinitcpio"
|
|
if ! acting; then
|
|
would "set ParallelDownloads = 1 in $conf"
|
|
return 1
|
|
fi
|
|
cp -a "$conf" "${conf}.bak-$(date +%Y%m%d-%H%M%S)"
|
|
sed -i -E 's/^([[:space:]]*ParallelDownloads[[:space:]]*=[[:space:]]*).*/\11/' "$conf"
|
|
repaired "set ParallelDownloads = 1"
|
|
return 0
|
|
}
|