#!/bin/bash # # lsinitcpio - dump the contents of an initramfs image # shopt -s extglob _list='--list' _optcolor=1 _optverbose=0 _f_functions=functions usage() { cat< Actions: -a, --analyze analyze contents of image -c, --config show configuration file image was built with -l, --list list contents of the image (default) -x, --extract extract image to disk Options: -h, --help display this help -n, --nocolor disable colorized output -v, --verbose more verbose output USAGE } decomp() { ${_compress:-cat} ${_compress:+-cd} "$@" } . "$_f_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]) }' } analyze_image() { local -a binaries explicitmod modules foundhooks hooks local kernver ratio columns=$(tput cols) image=$1 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. we # have to pass this through decomp() since the image might be lzop which # bsdtar can't read. 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 } _opt_short='achlnvx' _opt_long=('analyze' 'help' 'list' 'nocolor' 'showconfig' '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) _optanalyze=1 ;; -c|--config) _optshowconfig=1 ;; -h|--help) usage exit 0 ;; -l|--list) _optlistcontents=1 ;; -n|--nocolor) _optcolor=0 ;; -v|--verbose) _optverbose='--verbose' ;; -x|--extract) unset _list ;; --) shift break 2 ;; esac shift done _image=$1 if [[ -t 1 ]] && (( _optcolor )); then # prefer terminal safe colored and bold text when tput is supported if tput setaf 0 &>/dev/null; then _color_none="$(tput sgr0)" _color_bold="$(tput bold)" _color_blue="$_color_bold$(tput setaf 4)" _color_green="$_color_bold$(tput setaf 2)" _color_red="$_color_bold$(tput setaf 1)" _color_yellow="$_color_bold$(tput setaf 3)" else _color_none="\e[1;0m" _color_bold="\e[1;1m" _color_blue="$_color_bold\e[1;34m" _color_green="$_color_bold\e[1;32m" _color_red="$_color_bold\e[1;31m" _color_yellow="$_color_bold\e[1;33m" fi fi [[ $_image ]] || die "No image specified (use -h for help)" [[ -f $_image ]] || die "No such file: %s" "$_image" case $(( _optanalyze + _optlistcontents + _optshowconfig )) in 0) # default action when none specified _optlistcontents=1 ;; [!1]) die "Only one action may be specified at a time" ;; esac # 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 (( _optanalyze )); then analyze_image "$_image" elif (( _optshowconfig )); then decomp "$_image" | bsdtar xOf - buildconfig 2>/dev/null || die 'Failed to extract config from image (mkinitcpio too old?)' else decomp "$_image" | bsdcpio -i --quiet $_optverbose $_list fi # vim: set ft=sh ts=4 sw=4 et: