#!/bin/bash # # lsinitcpio - dump the contents of an initramfs image # shopt -s extglob declare verbose= declare list='--list' declare -i color=1 declare NC= BOLD= BLUE= GREEN= RED= YELLOW= declare FUNCTIONS=functions usage() { cat< Options: -a, --analyze analyze contents -h, --help display this help -n, --nocolor disable colorized output -v, --verbose more verbose output -x, --extract extract image to disk USAGE } decomp() { ${compress:-cat} ${compress:+-cd} "$@" } . "$FUNCTIONS" # override the die method from functions die() { error "$@" exit 1 } size_to_human() { awk -v size="$1" ' BEGIN { suffix[1] = "B" suffix[2] = "KiB" suffix[3] = "MiB" suffix[4] = "GiB" suffix[5] = "TiB" count = 1 while (size > 1024) { size /= 1024 count++ } sizestr = sprintf("%.2f", size) sub(/\.?0+$/, "", sizestr) printf("%s %s", sizestr, suffix[count]) }' } OPT_SHORT='ahnvx' OPT_LONG=('analyze' 'help' 'nocolor' 'verbose' 'extract') if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then exit 1 fi set -- "${OPTRET[@]}" unset OPT_SHORT OPT_LONG OPTRET while :; do case $1 in -a|--analyze) analyze=1 ;; -h|--help) usage exit 0 ;; -n|--nocolor) color=0 ;; -v|--verbose) verbose='--verbose' ;; -x|--extract) unset list ;; --) shift break 2 ;; esac shift done declare image=$1 if [[ -t 1 ]] && (( color )); then # prefer terminal safe colored and bold text when tput is supported if tput setaf 0 &>/dev/null; then NC="$(tput sgr0)" BOLD="$(tput bold)" BLUE="$BOLD$(tput setaf 4)" GREEN="$BOLD$(tput setaf 2)" RED="$BOLD$(tput setaf 1)" YELLOW="$BOLD$(tput setaf 3)" else NC="\e[1;0m" BOLD="\e[1;1m" BLUE="$BOLD\e[1;34m" GREEN="$BOLD\e[1;32m" RED="$BOLD\e[1;31m" YELLOW="$BOLD\e[1;33m" fi fi readonly NC BOLD BLUE GREEN RED YELLOW [[ $image ]] || die "No image specified (use -h for help)" [[ -f $image ]] || die "No such file: $image" # read compression type case "$(file -Lb "$image")" in @(data|LZMA)*) compress=lzma ;; gzip*) compress=gzip ;; bzip2*) compress=bzip2 ;; lzop*) compress=lzop ;; XZ*) compress=xz ;; esac if (( analyze )); then declare -a binaries explicitmod modules foundhooks hooks declare kernver ratio columns=$(tput cols) # fallback in case tput failed us columns=${columns:-80} zsize=$(stat -c %s "$image") # calculate compression ratio if [[ $compress ]]; then TIMEFORMAT=%R decomptime=$({ time decomp "$image" >/dev/null; } 2>&1 ) fullsize=$(decomp "$image" | bsdtar xOf - | wc -c) ratio=.$(( zsize * 1000 / fullsize % 1000 )) fi # read contents of image while read -r line; do if [[ $line = *.ko?(.?z) ]]; then line=${line##*/} modules+=("${line%.ko?(.?z)}") elif [[ -z $kernver && $line =~ /lib/modules/([^/]+)/ ]]; then kernver=${BASH_REMATCH[1]} elif [[ $line = ./hooks/* ]]; then foundhooks+=("${line##*/}") elif [[ $line = *@(/?(s)bin/)* ]]; then binaries+=("${line##*/}") fi done < <(decomp "$image" | bsdtar tf -) read -r version < <(decomp "$image" | bsdtar xOf - VERSION 2>/dev/null) # source and read config . <(decomp "$image" | bsdtar xOf - config) explicitmod=($MODULES) for hook in $HOOKS; do in_array "$hook" "${foundhooks[@]}" && hooks+=("$hook") done # print results imagename=$image [[ -L $image ]] && imagename+=" -> $(readlink -e "$image")" msg 'Image: %s %s' "$imagename" [[ $version ]] && msg 'Created with mkinitcpio %s' "$version" msg 'Kernel: %s' "${kernver:-unknown}" msg 'Size: %s' "$(size_to_human "$zsize")" if [[ $compress ]]; then msg 'Compressed with: %s' "$compress" msg2 'Uncompressed size: %s (%s ratio)' "$(size_to_human "$fullsize")" "$ratio" msg2 'Estimated decompression time: %ss' "$decomptime" fi printf '\n' if (( ${#modules[*]} )); then msg 'Included modules:' for mod in "${modules[@]}"; do printf ' %s' "$mod" in_array "${mod//_/-}" "${explicitmod[@]//_/-}" && printf ' [explicit]' printf '\n' done | sort | column -c$columns printf '\n' fi msg 'Included binaries:' printf ' %s\n' "${binaries[@]}" | sort | column -c$columns printf '\n' if (( ${#hooks[*]} )); then msg 'Hook run order:' printf ' %s\n' "${hooks[@]}" printf '\n' fi else decomp "$image" | bsdcpio -i --quiet $verbose $list fi # vim: set ft=sh ts=4 sw=4 et: