Skip to content

Commit

Permalink
Add fallback kernel version scraper
Browse files Browse the repository at this point in the history
The kernel version scraper included in mkinitcpio works only on
x86 kernel images.
This commit implements kernel version scraping on a generic
architecture if an uncompressed image is provided.

Signed-off-by: Davide Depau <davide@depau.eu>
  • Loading branch information
depau committed Feb 11, 2021
1 parent 55e6ce3 commit 76bc391
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 14 deletions.
44 changes: 36 additions & 8 deletions functions
Original file line number Diff line number Diff line change
Expand Up @@ -133,23 +133,51 @@ parseopts() {
return 0
}

kver() {
# this is intentionally very loose. only ensure that we're
# dealing with some sort of string that starts with something
# resembling dotted decimal notation. remember that there's no
# requirement for CONFIG_LOCALVERSION to be set.
local kver re='^[[:digit:]]+(\.[[:digit:]]+)+'

kver_x86() {
# scrape the version out of the kernel image. locate the offset
# to the version string by reading 2 bytes out of image at at
# address 0x20E. this leads us to a string of, at most, 128 bytes.
# read the first word from this string as the kernel version.
local offset=$(hexdump -s 526 -n 2 -e '"%0d"' "$1")
local kver offset=$(hexdump -s 526 -n 2 -e '"%0d"' "$1")
[[ $offset = +([0-9]) ]] || return 1

read kver _ < \
<(dd if="$1" bs=1 count=127 skip=$(( offset + 0x200 )) 2>/dev/null)

printf '%s' "$kver"
}

kver_generic() {
# For unknown architectures, we can try to grep the uncompressed
# image for the boot banner.
# This should work at least for ARM when run on /boot/Image. On
# other architectures it may be worth trying rather than bailing,
# and inform the user if none was found.

# Loosely grep for `linux_banner`:
# https://elixir.bootlin.com/linux/v5.7.2/source/init/version.c#L46
# Banner ends with a new line so we can safely grep `.*`
local kver=

read _ _ kver _ < <(grep -m1 -aoE 'Linux version .(\.[-[:alnum:]]+)+' "$1")

printf '%s' "$kver"
}

kver() {
# this is intentionally very loose. only ensure that we're
# dealing with some sort of string that starts with something
# resembling dotted decimal notation. remember that there's no
# requirement for CONFIG_LOCALVERSION to be set.
local kver re='^[[:digit:]]+(\.[[:digit:]]+)+'

local arch=$(uname -m)
if [[ $arch == @(i?86|x86_64) ]]; then
kver=$(kver_x86 "$1")
else
kver=$(kver_generic "$1")
fi

[[ $kver =~ $re ]] || return 1

printf '%s' "$kver"
Expand Down
12 changes: 6 additions & 6 deletions mkinitcpio
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,6 @@ resolve_kernver() {
return 0
fi

arch=$(uname -m)
if [[ $arch != @(i?86|x86_64) ]]; then
error "kernel version extraction from image not supported for \`%s' architecture" "$arch"
return 1
fi

if [[ ! -e $kernel ]]; then
error "specified kernel image does not exist: \`%s'" "$kernel"
return 1
Expand All @@ -116,6 +110,12 @@ resolve_kernver() {

error "invalid kernel specified: \`%s'" "$1"

arch=$(uname -m)
if [[ $arch != @(i?86|x86_64) ]]; then
error "kernel version extraction from image not supported for \`%s' architecture" "$arch"
error "there's a chance the generic version extractor may work with a valid uncompressed kernel image"
fi

return 1
}

Expand Down

0 comments on commit 76bc391

Please sign in to comment.