How to extract the linux version from a `.img` backup

disk-imagekernel

In short:

How to extract the VERSION, SUBVERSION and PATCHLEVEl numbers from a system backup .img? ideally without root permissions.

Extended:

From the following page:

https://www.raspberrypi.org/downloads/raspbian/

It is provided a Debian zip extracted as .img, which represents a full system backup of a Debian/Raspian system for arm architecture.

For the generation of a custom kernel, it is required to know the VERSION, SUBVERSION and PATCHLEVEL of the system, equivalent to what is provided by the typical

$ uname -r
4.9.0-3-amd64

The easiest way is to load the system directly and run the command, but that is not applicable in this case.

Goal:

The kernel of the image need to be patched and cross-compiled. My intention is to create a script for this process, so it may be "easily" applied further when kernel updates come.

Best Answer

This seems to work on the 2017-09-07-raspbian-stretch-lite.img image at that site:

$ sudo kpartx -rva 2017-09-07-raspbian-stretch-lite.img
add map loop0p1 (252:19): 0 85622 linear 7:0 8192
add map loop0p2 (252:20): 0 3528040 linear 7:0 94208
$ sudo mount -r /dev/mapper/loop0p1 mnt
$ LC_ALL=C gawk -v RS='\37\213\10\0' 'NR==2{printf "%s", RS $0; exit}
  ' < mnt/kernel.img | gunzip | grep -aPom1 'Linux version \S+'
Linux version 4.9.41+

(where \37\213\10\0 identifies the start of gzipped data).

As non-root, and assuming the first partition is always 4MiB within the image, using the GNU mtools to extract the kernel.img from that vfat partition:

$ MTOOLS_SKIP_CHECK=1 mtype -i 2017-09-07-raspbian-stretch-lite.img@@4M ::kernel.img|
  LC_ALL=C gawk -v RS='\37\213\10\0' 'NR==2{printf "%s", RS $0; exit}' |
  gunzip | grep -aPom1 'Linux version \K\S+'
4.9.41+

If not, on systems with /dev/fd support (and GNU grep):

MTOOLS_SKIP_CHECK=1 MTOOLSRC=/dev/fd/3 mtype z:kernel.img \
  3<< EOF 4< 2017-09-07-raspbian-stretch-lite.img |
drive z:
  file="/dev/fd/4"
  partition=1

EOF
  LC_ALL=C gawk -v RS='\37\213\10\0' 'NR==2{printf "%s", RS $0; exit}' |
  gunzip | grep -aPom1 'Linux version \K\S+'

(on other systems, use file="2017-09-07-raspbian-stretch-lite.img", the /dev/fd/4 is just for making it easier to adapt to arbitrary file names)

From, the zip file, you should be able to get away without extracting the whole image, just the first partition with:

#! /bin/zsh -
zip=${1?zip file missing}

MTOOLS_SKIP_CHECK=1 mtype -i =(
    unzip -p -- "$zip" | perl -ne '
      BEGIN{$/=\512}
      if ($. == 1) {
        ($offset, $size) = unpack("x454L<2",$_)
      } elsif ($. > $offset) {
        print;
        if ($. == $offset + $size - 1) {exit}
      }') ::kernel.img |
  LC_ALL=C gawk -v RS='\37\213\10\0' 'NR==2{printf "%s", RS $0; exit}' |
  gunzip | grep -aPom1 'Linux version \K\S+'
Related Question