#!/bin/bash
# Extract gzip-compressed initial RAM disk images which may have a microcode cpio archive pre-pended
# Copyright 2015 TJ <ubuntu@iam.tj>
# Licenced on the terms of the GNU General Public Licence version 2, or later

function set_type_handler()
{
  local TYPE
  TYPE=$(/usr/bin/file --brief "$1" )
  RESULT=0
  INDEX=0
  for MATCH in 'cpio archive' 'gzip compressed'; do
    let INDEX=$((INDEX + 1))
    if echo ${TYPE} | /bin/grep -q "${MATCH}"; then
      RESULT=${INDEX}
    fi
  done
  echo ${RESULT}
}

function extract_one()
{
  INITRD="$1"
  VER=$( /bin/echo ${INITRD} | /bin/sed 's/^.*initrd.img-\(.*\)$/\1/' )
  CMD="/bin/cat \"${INITRD}\""
  while true; do
    STAT_SIZE=$( /usr/bin/stat -c %s "${INITRD}" )
    echo "Processing ${STAT_SIZE} bytes of ${INITRD}"
    TYPE=$( set_type_handler "${INITRD}" )
    if [ ${TYPE} -eq 1 ]; then # CPIO Archive
      CPIO_SIZE=$( /bin/cpio -t < "${INITRD}" |& /usr/bin/awk '/blocks/{print $1*512}' )
      if [ ${STAT_SIZE} -gt ${CPIO_SIZE} ]; then # pre-pended cpio to the main image
        echo "Skipping ${CPIO_SIZE} bytes pre-pended early initramfs image (possibly CPU microcode)"
        TMP="/tmp/initrd.img.${RANDOM}"
        echo "Creating ${TMP} for remaining $((STAT_SIZE - CPIO_SIZE)) bytes"
        /bin/dd "if=${INITRD}" bs=${CPIO_SIZE} skip=1 > "${TMP}" 2>/dev/null
        CMD="/bin/cat \"${TMP}\" "
        INITRD=${TMP}
        continue
      else # only a cpio archive nothing left to unwrap
        CMD="/bin/cat \"${INITRD}\" "
        break
      fi
    fi
    if [ ${TYPE} -eq 2 ]; then # GZIP Compressed
      CMD="${CMD} | /bin/zcat"
      break
    fi
  done
  CMD="${CMD} | /bin/cpio --extract --make-directories"
  /bin/mkdir -p /tmp/initrd/${VER}
  pushd /tmp/initrd/${VER} >/dev/null
  echo "Executing ${CMD}"
  eval ${CMD}
  popd > /dev/null
  if [ -n "${TMP}" ]; then
    rm -f "${TMP}"
  fi
  QTY=$(find /tmp/initrd/${VER} -type f | wc -l)
  echo  "Extracted ${QTY} files to /tmp/initrd/${VER}/"
  ls --color -a /tmp/initrd/${VER}/
}

function extract_all()
{
while read INITRD; do
  extract_one "${INITRD}"
done < <( echo $1 )
}

INITRD_LIST=$( find /boot -maxdepth 1  -name 'initrd.img*' )

if [ -z "$1" ]; then
  extract_all "${INITRD_LIST}"
else
  if [ ! -r "$1" ]; then
    echo "Error: Cannot read $1"
    exit 1
  fi
  extract_one "$1"
fi

exit 0

