#!/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) workdir=$(mktemp -d --tmpdir="$TMPDIR" lsinitcpio.XXXXXX) trap 'rm -rf "$workdir"' EXIT # fallback in case tput failed us columns=${columns:-80} zsize=$(stat -c %s "$image") # calculate compression ratio TIMEFORMAT=%R decomptime=$({ time decomp "$image" >/dev/null; } 2>&1 ) if [[ $compress ]]; then fullsize=$(decomp "$image" | bsdtar xOf - | wc -c) ratio=.$(( zsize * 1000 / fullsize % 1000 )) fi # decompress the image since we need to read from it multiple times decomp "$image" | bsdtar -C "$workdir" -xf - # collect stats kernver=("$workdir"/usr/lib/modules/*/) kernver=${kernver%/} kernver=${kernver##*/} modules=("$workdir/usr/lib/modules/$kernver"/kernel/*.ko*) if [[ -f ${modules[0]} ]]; then modules=("${modules[@]##*/}") modules=("${modules[@]%.ko*}") else unset modules fi foundhooks=("$workdir"/hooks/*) [[ -f ${foundhooks[0]} ]] && foundhooks=("${foundhooks[@]##*/}") || unset foundhooks mapfile -t binaries < <(find "$workdir/usr/bin" -type f -printf %f\\n) read -r version < "$workdir/VERSION" # source and read config . "$workdir/config" explicitmod=($MODULES) # 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" fi msg2 'Estimated extraction time: %ss' "$decomptime" 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 [[ $EARLYHOOKS ]]; then msg 'Early hook run order:' printf ' %s\n' $EARLYHOOKS printf '\n' fi if [[ $HOOKS ]]; then msg 'Hook run order:' printf ' %s\n' $HOOKS printf '\n' fi if [[ $LATEHOOKS ]]; then msg 'Late hook run order:' printf ' %s\n' $LATEHOOKS printf '\n' fi if [[ $CLEANUPHOOKS ]]; then msg 'Cleanup hook run order:' printf ' %s\n' $CLEANUPHOOKS printf '\n' fi else decomp "$image" | bsdcpio -i --quiet $verbose $list fi # vim: set ft=sh ts=4 sw=4 et: