summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Reisner <dreisner@archlinux.org>2013-01-04 06:11:30 +0100
committerDave Reisner <dreisner@archlinux.org>2013-01-12 19:13:00 +0100
commitf8ee357b280161e7d3e04fdf9d3f73643ccfdddb (patch)
tree258f6eb8e6be7fc3d16a2b440ea9970b402a4ed1
parent7a470f977f8aa2ce245e79795acaebd5b334b257 (diff)
downloadmkinitcpio-f8ee357b280161e7d3e04fdf9d3f73643ccfdddb.tar.gz
mkinitcpio-f8ee357b280161e7d3e04fdf9d3f73643ccfdddb.tar.xz
mkinitcpio: avoid using 'file' to get kernel versions
The kernel defines an offset at a fixed location within the bzImage which we can use to find the kernel version string. Since this is fairly important, reimplement the algorithm (which file almost surely uses) using low level tools to avoid the possibility that file may break or change its output, critically wounding mkinitcpio. Note that this change leaves 'file' in use for lsinitcpio compression detection. Signed-off-by: Dave Reisner <dreisner@archlinux.org>
-rw-r--r--bash-completion24
-rwxr-xr-xmkinitcpio19
2 files changed, 33 insertions, 10 deletions
diff --git a/bash-completion b/bash-completion
index aa6efbb..597eab2 100644
--- a/bash-completion
+++ b/bash-completion
@@ -1,6 +1,14 @@
#!/bin/bash
# mkinitcpio bash completion by Seblu <seblu@seblu.net>
+detect_kver() {
+ local kver_validator='^[[:digit:]]+(\.[[:digit:]]+)+'
+ offset=$(hexdump -s 526 -n 2 -e '"%0d"' "$1" 2>/dev/null) || return 1
+ read kver _ < \
+ <(dd if="$1" bs=1 count=127 skip=$(( offset + 0x200 )) 2>/dev/null)
+ [[ $kver =~ $kver_validator ]] && printf "$kver"
+}
+
_lsinitcpio() {
local cur opts
opts=(-a --analyze -c --config -h --help -l --list
@@ -18,14 +26,14 @@ _lsinitcpio() {
_find_kernel_versions() {
local -a matches
- local dir regex
-
- # add completions from kernels in /boot
- regex="Linux kernel.*version"
- while IFS=':' read -r file metadata; do
- [[ $metadata =~ $regex ]] || continue
- matches+=("$file")
- done < <(file -e ascii /boot/*)
+ local dir f
+
+ for f in /boot/*; do
+ # only match regular files which pass validation
+ if [[ ! -L $f && -f $f ]] && kver=$(detect_kver "$f"); then
+ matches+=("$f")
+ fi
+ done
# add completions based on kernel versions in /lib/modules
for dir in /lib/modules/*/kernel; do
diff --git a/mkinitcpio b/mkinitcpio
index 013bc46..752107b 100755
--- a/mkinitcpio
+++ b/mkinitcpio
@@ -82,7 +82,13 @@ cleanup() {
}
resolve_kernver() {
- local kernel=$1
+ local kernel=$1 offset 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_validator='^[[:digit:]]+(\.[[:digit:]]+)+'
if [[ -z $kernel ]]; then
uname -r
@@ -99,7 +105,16 @@ resolve_kernver() {
return 1
fi
- if file -Lb "$kernel" | grep -oP '(?<=version )[^ ]+'; then
+ # 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.
+ offset=$(hexdump -s 526 -n 2 -e '"%0d"' "$kernel")
+ read kver _ < \
+ <(dd if="$kernel" bs=1 count=127 skip=$(( offset + 0x200 )) 2>/dev/null)
+
+ if [[ $kver =~ $kver_validator ]]; then
+ printf '%s' "$kver"
return 0
fi