#!/bin/bash # firmware downloader & unpacker script # # download: # Downloads all files mathing pattern '*.image' from ftp.avm.de # The filename based on the whole directory (s!/!--!). # unpack: # Removes unpacked/ folder, unpacks all downloaded firmware # files to corresponding folder. # Output: Either the count of files or something else on error. # unpack : # Unpacks given files to subdir of current folder (${file%.image}). # # don't run as root ;-) # # # cuma, 19.11.2012 DL_DIR=~/fw-avm download() { mkdir -p $DL_DIR cd $DL_DIR rm -rf ftp.avm.de 2>/dev/null # BETA/Labor/LabRC if [ -n "$1" -a "$1" != "stable" -a "$1" != "s" ]; then for url in ftp://ftp.avm.de/fritzbox/beta/{frisch-aus-der-entwicklung,wartung}; do wget -nv -m -A '*.zip' $url ( cd ${url#ftp://} for i in $(find . -type f -iname '*.zip'); do unzip -q -o -j $i done # remove all files with no beta|labor in name find . -type f -regextype posix-egrep ! -iregex '.*(beta|labor|labrc).*[.]image' -exec rm -f {} '+' 2>/dev/null ) done fi # stable if [ -z "$1" -o "$1" == "stable" -o "$1" == "s" ]; then for url in ftp://ftp.avm.de/fritzbox/ ftp://ftp.avm.de/archive/fritz.box/; do wget -nv -m -A '*.image' -R '*Powerline*,*powerline*,*Repeater*,*repeater*,*VoIP-Gateway*' $url find ${url#ftp://} -type f ! -name '*.image' -exec rm -f {} '+' 2>/dev/null done fi for file in $(find ftp.avm.de service.avm.de -type f); do mv -f $file $(echo $file | sed -r -e 's,(ftp[.]avm[.]de/fritzbox/|ftp[.]avm[.]de/archive/fritz[.]box/|service[.]avm[.]de/|firmware/),,g;s,/,--,g') done rm -rf ftp.avm.de service.avm.de 2>/dev/null } unpack() { [ ! -d $DL_DIR ] && echo "no $DL_DIR dir with images" cd $DL_DIR rm -rf unpacked 2>/dev/null mkdir -p unpacked [ -f _failed.log ] && rm _failed.log for file in *.image; do image $file unpacked/ done if [ -e _failed.log ]; then echo FAILED: cat _failed.log fi } # $1 is expected to be NMI-vector-removed and kernel-filesystem-splitted unfs_probe() { { { $FTOOLS/blkid -O 256 "$1" 2>/dev/null | grep -q 'TYPE="ext2"'; } \ && dd if="$1" of="$1.ext2" bs=256 skip=1 conv=sync >/dev/null 2>&1 \ && { mkdir -p "squashfs-root"; echo "rdump / squashfs-root" | $FTOOLS/debugfs "$1.ext2"; } } \ || $FTOOLS/unsquashfs4-avm-be "$1" \ || $FTOOLS/unsquashfs4-avm-le "$1" } image() { local img=$1 local dst=$2 [ -n "${dst}" -a "${dst: -1: 1}" != "/" ] && dst="${dst}/" # add trailing slash if missing local imgID=$(basename "${img}") imgID=${imgID%.*} declare -A probeDirs=( [mips]=var/tmp [arm]=var/remote/var/tmp [atom]=var/remote/var/tmp/x86 ) if [ ! -e $img ]; then echo -e "~~~~\t$img" | tee -a _failed.log return 1 fi rm -rf var if [ "$img" != "${img%.exe}" ]; then $FTOOLS/extract-images $img >/dev/null mkdir -p var/tmp mv ${img##*/}.unp/*.image var/tmp/ rm -rf ${img##*/}.unp else tar -xif $img \ $(printf " --wildcards ./%s/*.image" "${probeDirs[@]}") \ $(printf " --wildcards ./%s/plugins.update" "${probeDirs[@]}") \ >/dev/null 2>&1 fi if [ ! -d var ]; then echo -e "NULL\t$img" return 1 fi for d in "${probeDirs[@]}" no_kernel_image_found; do if [ -s ${d}/kernel.image ]; then break; fi if [ "${d}" == "no_kernel_image_found" ]; then echo -e "----\t$img" | tee -a _failed.log rm -rf var return 1 fi done # The following cases for kernel/filesystem layout are known/supported: # # 1. kernel.image contains the kernel followed by the (complete) root-filesystem # filesystem.image is empty # Examples: 7170, 7270, 7390 # # 2. kernel.image contains the kernel followed by the initial part of the root-filesystem # filesystem.image contains the remaining part of the root-filesystem # Examples: very old boxes like Fritz!Box SL, 7050en, 2030 # # 3. kernel.image contains just the kernel (and nothing else) # filesystem.image contains just the root-filesystem (and nothing else) # Examples: 7490 for arch in "${!probeDirs[@]}"; do d="${probeDirs[$arch]}" if [ ! -s ${d}/kernel.image ]; then continue; fi # remove TI checksum and concatenate kernel & filesystem images for f in ${d}/kernel.image ${d}/filesystem.image; do if [ -s "$f" ]; then $FTOOLS/tichksum -r "$f" >/dev/null 2>&1 cat "$f" | dd bs=256 conv=sync 2>/dev/null; fi done > kf.image rm -f ${d}/kernel.image ${d}/filesystem.image # strip NMI vector if any ($FTOOLS/remove-nmi-vector kf.image kf.image.no-nmi 2>&1 && mv kf.image.no-nmi kf.image 2>/dev/null) | sed -r -n -e 's,(.*NMI vector.*),\t\1,p' # and split them again... now at the right bounds (s. case 2 above) $FTOOLS/find-squashfs kf.image >/dev/null 2>&1 rm -f kf.image kernel.raw # unpack it unfs_probe kernelsquashfs.raw >/dev/null 2>&1 || echo FALSE ${img}-${arch} rm -f kernelsquashfs.raw kernelsquashfs.raw.ext2 # unpack the inner / the outer root-filesystem if found if [ -e squashfs-root/filesystem_core.squashfs ]; then mv squashfs-root filesystem.outer unfs_probe filesystem.outer/filesystem_core.squashfs >/dev/null 2>&1 rm -f filesystem.outer/filesystem_core.squashfs [ -d squashfs-root ] && mv filesystem.outer squashfs-root/ || rm -rf filesystem.outer fi if [ -d squashfs-root ]; then local numberOfFiles=$(find squashfs-root -type f \! -path '*filesystem.outer*' | wc -l) echo -e "${numberOfFiles}\t${imgID}-${arch}" mv squashfs-root "${dst}${imgID}-${arch}" fi if [ -e ${d}/plugins.update ]; then pluginsTmpDir="${imgID}.plugins-${arch}.tmp" mkdir -p "${pluginsTmpDir}" tar -xif "${d}/plugins.update" \ -C "${pluginsTmpDir}" \ --wildcards "./var/*.image" \ >/dev/null 2>&1 numberOfPlugins=0 for pluginImage in $(find "${pluginsTmpDir}/var" -type f -name "*.image"); do pluginID=$(basename "${pluginImage}"); pluginID=${pluginID%.*} unfs_probe "$pluginImage" >/dev/null 2>&1 if [ -d squashfs-root ]; then ((numberOfPlugins++)) mv squashfs-root "${pluginsTmpDir}/${pluginID}" fi done rm -rf "${pluginsTmpDir}/var" if [ "$numberOfPlugins" -eq 0 ]; then rm -rf "${pluginsTmpDir}" else if [ -d "${dst}${imgID}-${arch}" ]; then mv "${pluginsTmpDir}" "${dst}${imgID}-${arch}/plugins" else mv "${pluginsTmpDir}" "${dst}${imgID}.plugins-${arch}" fi fi fi if [ ! -e "${dst}${imgID}-${arch}" -a ! -e "${dst}${imgID}.plugins-${arch}" ]; then echo -e "====\t${img}-${arch}" | tee -a _failed.log fi done rm -rf var } # check args while [ $# -gt 0 ]; do case $1 in d|download) download=y case $2 in s|l|b|a|stable|labor|beta|all) dl_arg="$2" shift ;; u|unpack|"") ;; *) echo "Unknown argument: $2" exit 1 ;; esac ;; u|unpack) unpack=y ;; *) image="$image $1" ;; esac shift done if [ "$download" != "y" -a "$unpack" != "y" ]; then echo "usage: ${0##*/} " exit 1 fi # check tools if [ "$unpack" == "y" ]; then FTOOLS="$(dirname $(readlink -f ${0}))" if [ ! -e $FTOOLS/find-squashfs ]; then echo "You have to run 'make tools' first." exit 1 fi fi # main [ "$download" == "y" ] && download $dl_arg if [ "$unpack" == "y" ]; then [ -z "$image" ] && unpack for imgfile in $image; do image $imgfile done fi