#!/bin/bash # # Script to modify AVM FRITZ!Box firmware images (Freetz) # # $Id$ # # Copyright (C) 2005-2006 Daniel Eiband # Copyright (C) 2006-2007 Oliver Metz, Alexander Kriegisch, Mikolas Bingemer, # Michael Hampicke and others # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # This script is based on Christian Volkmann's fritzbox mod-0.57. # Legacy URL: http://www.ip-phone-forum.de/showthread.php?t=65894 # # Special Thanks to Andreas Buehmann, Christian Volkmann, Enrik Berkhan, # SpeedyBZ and all members on ip-phone-forum.de who contributed to this mod SHELL=$BASH usage() { cat << 'EOF' Usage: fwmod [-u|-m|-p|-a] [-i ] [-d ] [] actions -u unpack firmware image -m modify previously unpacked image -p pack firmware image -a all: unpack, modify and pack firmware image (-u -m -p) input/output -i input file for configuration data (default: .config) -d build directory (default: .mod) original firmware name 2nd firmware name (e.g. for merging in web UI) EOF } # Print usage info to stdout (no error, just info) if [ $# -eq 0 ]; then usage exit 0 fi L1=' ' L2=' ' BOLD=$(echo -e '\033[1m') NORM=$(echo -e '\033[0m') # Default values FREETZ_VERBOSITY_LEVEL=0 DOT_CONFIG="$(dirname "$0")/.config" CMDLINE_OPTS="umpad:i:" # Default config override? # NOTE: Both 'getopts' must have an identical argument list! while getopts "$CMDLINE_OPTS" opt; do if [ "$opt" == "i" ]; then DOT_CONFIG="$OPTARG" echo $DOT_CCONFIG fi done DO_UNPACK=0 DO_MOD=0 DO_PACK=0 DIR='' _OPT=0 # Reset command line option counter OPTIND=0 # Get other options besides '-i ' # NOTE: Both 'getopts' must have an identical argument list! while getopts "$CMDLINE_OPTS" opt; do case "$opt" in u) DO_UNPACK=1 _OPT=1 ;; m) DO_MOD=1 _OPT=1 ;; p) DO_PACK=1 _OPT=1 ;; a) DO_UNPACK=1 DO_MOD=1 DO_PACK=1 _OPT=1 ;; d) DIR="$OPTARG" ;; i) # Do nothing, DOT_CONFIG has been assigned already ;; *) usage >&2 exit 1 ;; esac done shift $(($OPTIND - 1)) if [ $# -ne 1 -a $# -ne 2 ]; then usage >&2 exit 1 fi if [ "$_OPT" -eq 0 ]; then DO_UNPACK=1 DO_MOD=1 DO_PACK=1 fi FIRMWARE="$1" FIRMWARE2="$2" BASE_DIR="$(dirname "$0")" if [ -z "$DIR" ]; then DIR="${FIRMWARE}.mod" fi ABS_BASE_DIR="$BASE_DIR" if [[ "$ABS_BASE_DIR" != /* ]]; then ABS_BASE_DIR="$(pwd)/$ABS_BASE_DIR" fi TOOLS_SUBDIR="tools" SOURCE_SUBDIR="source" FIRMWARE_SUBDIR="firmware" FILESYSTEM_SUBDIR="filesystem" AVMPLUGINS_SUBDIR="plugins.image" EXTERNAL_SUBDIR="external" KERNEL_SUBDIR="kernel" VARTAR_SUBDIR="var.tar" KERNEL_IMAGE="var/tmp/kernel.image" AVMPLUGINS_FILE="var/tmp/plugins.update" RAW_KERNEL_FILE="kernel.raw" RAW_HIDDEN_FILE="kernelsquashfs.raw" VARTAR_FILE="var.tar" FINDSQUASHFS_TOOL="find-squashfs" TICHKSUM_TOOL="tichksum" RMTICHKSUM_TOOL="rmtichksum" MAKEDEVS_TOOL="makedevs" FAKEROOT_TOOL="fakeroot" UNSQUASHFS_TOOL="unsquashfs3-lzma" EXTERNAL_TOOL="external" MKSQUASHFS_OPTIONS="-le -noappend -all-root -info" UNSQUASHFS_OPTIONS="-no-progress" TAR_TOOL="tar" TOOLS_DIR="${ABS_BASE_DIR}/${TOOLS_SUBDIR}" EXTERNAL="${TOOLS_DIR}/${EXTERNAL_TOOL}" UNSQUASHFS="${TOOLS_DIR}/${UNSQUASHFS_TOOL}" FINDSQUASHFS="${TOOLS_DIR}/${FINDSQUASHFS_TOOL}" MKSQUASHFS="${TOOLS_DIR}/${MKSQUASHFS_TOOL}" TICHKSUM="${TOOLS_DIR}/${TICHKSUM_TOOL}" RMTICHKSUM="${TOOLS_DIR}/${RMTICHKSUM_TOOL}" MAKEDEVS="${TOOLS_DIR}/${MAKEDEVS_TOOL}" MAKEDEVS_FILE="${TOOLS_DIR}/device_table.txt" FAKEROOT="${TOOLS_DIR}/usr/bin/${FAKEROOT_TOOL}" TAR="${TOOLS_DIR}/${TAR_TOOL}" PACKAGES_DIR="${BASE_DIR}/packages" PATCHES_DIR="${BASE_DIR}/patches" ROOT_DIR="${BASE_DIR}/root" KERNEL_REP_DIR="${BASE_DIR}/kernel" ADDON_DIR="${BASE_DIR}/addon" FAVICON_DIR="${BASE_DIR}/favicon" STATIC_PACKAGES_FILE="${BASE_DIR}/.static" DYNAMIC_PACKAGES_FILE="${BASE_DIR}/.dynamic" STATIC_ADDON_FILE="${ADDON_DIR}/static.pkg" DYNAMIC_ADDON_FILE="${ADDON_DIR}/dynamic.pkg" # Config file readable? if [ ! -r "$DOT_CONFIG" ]; then echo -e "ERROR: not configured" 1>&2 exit 1 fi # Load config . "$DOT_CONFIG" if [ "$FREETZ_REPLACE_KERNEL" == "y" ] || [ "$FREETZ_KERNEL_VERSION_2_6_19_2" ]; then MKSQUASHFS_TOOL="mksquashfs3-lzma" MKSQUASHFS_OPTIONS+=" -no-progress -no-exports -no-sparse" else MKSQUASHFS_TOOL="mksquashfs-lzma" fi # Dot-include 'modpatch' shell function . "${TOOLS_DIR}/freetz_patch" # Dot-include some helper shell function (isFreetzType, rm_files) . "${TOOLS_DIR}/freetz_functions" # Dont run this script as root if [ $UID -eq 0 ]; then error 1 "running this script as root is prohibited" fi if [ -z "$FIRMWARE" ]; then error 1 "no firmware filename supplied" fi # Does the firmware image exist ? if [ -n "$FIRMWARE" -a ! -r "$FIRMWARE" ]; then error 1 "firmware image $(basename "$FIRMWARE") not found" fi if [ -n "$FIRMWARE2" -a ! -r "$FIRMWARE2" ]; then error 1 "firmware image $(basename "$FIRMWARE2") not found" fi if [ ! -e "$DIR" ]; then mkdir -p "$DIR" fi ############################################ ## Unpack and unsquash the firmware image ## ############################################ ORG_DIR="${DIR}/original" FIRMWARE_DIR="${ORG_DIR}/${FIRMWARE_SUBDIR}" FILESYSTEM_DIR="${ORG_DIR}/${FILESYSTEM_SUBDIR}" KERNEL_DIR="${ORG_DIR}/${KERNEL_SUBDIR}" AVMPLUGINS_DIR="${KERNEL_DIR}/${AVMPLUGINS_SUBDIR}" VARTAR_DIR="${KERNEL_DIR}/${VARTAR_SUBDIR}" KERNEL="${FIRMWARE_DIR}/${KERNEL_IMAGE}" RAW_KERNEL="${KERNEL_DIR}/${RAW_KERNEL_FILE}" FILESYSTEM="${KERNEL_DIR}/${RAW_HIDDEN_FILE}" AVMPLUGINS="${FIRMWARE_DIR}/${AVMPLUGINS_FILE}" VARTAR="${FILESYSTEM_DIR}/${VARTAR_FILE}" if [ "$DO_UNPACK" -gt 0 ]; then echo "${BOLD}STEP 1: UNPACK${NORM}" rm -rf "$ORG_DIR" mkdir "$ORG_DIR" echo "unpacking firmware image" mkdir "$FIRMWARE_DIR" "$TAR" -xif "$FIRMWARE" -C "$FIRMWARE_DIR" || exit 1 # Do the images exist ? if [ ! -r "${FIRMWARE_DIR}/${KERNEL_IMAGE}" ]; then error 1 "cannot find kernel.image" fi # Do we have the tool ? if [ ! -x "$RMTICHKSUM" ]; then error 1 "cannot find the tool $RMTICHKSUM_TOOL" fi if [ ! -x "$UNSQUASHFS" ]; then error 1 "cannot find the tool $UNSQUASHFS_TOOL" fi if [ ! -x "$FINDSQUASHFS" ]; then error 1 "cannot find the very useful tool $FINDSQUASHFS_TOOL" fi "$RMTICHKSUM" -f "${FIRMWARE_DIR}/${KERNEL_IMAGE}" > /dev/null echo "splitting kernel image" mkdir "$KERNEL_DIR" ( cd "$KERNEL_DIR" && "${TOOLS_DIR}/${FINDSQUASHFS_TOOL}" "../${FIRMWARE_SUBDIR}/${KERNEL_IMAGE}" > /dev/null 2>&1 ) if [ ! -r "$RAW_KERNEL" -o ! -r "$FILESYSTEM" ]; then error 1 "kernel splitting failed" fi echo "unpacking filesystem image" modunsqfs "$FILESYSTEM_DIR" "$FILESYSTEM" chmod -R +w "$FILESYSTEM_DIR" if [ -r "$AVMPLUGINS" ]; then echo "unpacking AVM plugins" mkdir -p "$AVMPLUGINS_DIR" "$TAR" -xif "$AVMPLUGINS" -C "$AVMPLUGINS_DIR" || exit 1 for i in "${AVMPLUGINS_DIR}/var/"*.image; do AVMPLUGIN="${i##*/plugin-}" AVMPLUGIN="${AVMPLUGIN%\.image}" echo1 "$AVMPLUGIN image" modunsqfs "$AVMPLUGINS_DIR/plugin-${AVMPLUGIN}" "$i" > /dev/null done chmod -R +w "$AVMPLUGINS_DIR" fi if [ ! -r "$FILESYSTEM_DIR/var" ]; then error 1 "could not unpack the filesystem image" fi if [ ! -r "$VARTAR" ]; then error 1 "no var.tar found" fi echo "unpacking var.tar" mkdir "$VARTAR_DIR" "$TAR" -xif "$VARTAR" -C "$VARTAR_DIR" || exit 1 # Unpacking second firmware image if [ -n "$FIRMWARE2" ]; then echo "unpacking tk image" rm -rf "${DIR}/.tk" "$0" -u -d "${DIR}/.tk" "$FIRMWARE2" > /dev/null fi touch "${DIR}/.unpacked" echo "done." echo fi ############################################### # Lets copy and modify the unpacked firmware ## ############################################### MOD_DIR="${DIR}/modified" FIRMWARE_MOD_DIR="${MOD_DIR}/${FIRMWARE_SUBDIR}" FILESYSTEM_MOD_DIR="${MOD_DIR}/${FILESYSTEM_SUBDIR}" EXTERNAL_MOD_DIR="${MOD_DIR}/${EXTERNAL_SUBDIR}" KERNEL_MOD_DIR="${MOD_DIR}/${KERNEL_SUBDIR}" AVMPLUGINS_MOD_DIR="${KERNEL_MOD_DIR}/${AVMPLUGINS_SUBDIR}" AVMPLUGINS_FILESYSTEM_MOD_DIR="${FILESYSTEM_MOD_DIR}/usr/share/avmplugins" VARTAR_MOD_DIR="${KERNEL_MOD_DIR}/${VARTAR_SUBDIR}" KERNEL_MOD="${FIRMWARE_MOD_DIR}/${KERNEL_IMAGE}" RAW_KERNEL_MOD="${KERNEL_MOD_DIR}/${RAW_KERNEL_FILE}" FILESYSTEM_MOD="${KERNEL_MOD_DIR}/${RAW_HIDDEN_FILE}" VARTAR_MOD="${FILESYSTEM_MOD_DIR}/${VARTAR_FILE}" HTML_MOD_DIR="${FILESYSTEM_MOD_DIR}/usr/www" # HTML_LANG_MOD_DIR can't be defined here MODULES_DIR="${FILESYSTEM_MOD_DIR}/lib/modules/${FREETZ_KERNEL_VERSION}" if [ "$DO_MOD" -gt 0 ]; then echo "${BOLD}STEP 2: MODIFY${NORM}" # Check if firmware is unpacked if [ ! -r "${DIR}/.unpacked" ]; then error 1 "firmware image has to be unpacked before modifying" fi rm -rf "$MOD_DIR" rm -f "${DIR}/.modified" # Copy the unpacked directory mkdir -p "$MOD_DIR" "$TAR" -c -C "$ORG_DIR" --exclude=dev . | "$TAR" -x -C "$MOD_DIR" || exit 1 if [ -d "${FILESYSTEM_MOD_DIR}/usr/www/avm" ]; then echo1 "Applying symlinks, deleting additional webinterfaces" mv ${FILESYSTEM_MOD_DIR}/usr/www/avm ${FILESYSTEM_MOD_DIR}/usr/www/all oems="$(grep 'for i in avm' "${FIRMWARE_MOD_DIR}/var/install" | head -n 1 | sed -e 's/^.*for i in\(.*\); do.*$/\1/')" for i in $oems; do rm -rf ${FILESYSTEM_MOD_DIR}/usr/www/$i ln -s all ${FILESYSTEM_MOD_DIR}/usr/www/$i done fi echo "applying patches" echo1 "applying patches (${FREETZ_TYPE_STRING}-${FREETZ_TYPE_LANG_STRING})" # Apply patches if [ ! -d "${PATCHES_DIR}/${FREETZ_TYPE_STRING}" ]; then error 1 "missing ${PATCHES_DIR}/${FREETZ_TYPE_STRING}" fi # Execute version specific patch scripts for i in "${PATCHES_DIR}/${FREETZ_TYPE_STRING}/"*.sh; do [ -r "$i" ] || continue echo2 "applying patch file $i" . $i done # Now we are in place to check html directory for i in all avme/en avme; do if [ -d "${HTML_MOD_DIR}/$i" ]; then HTML_LANG_MOD_DIR="${HTML_MOD_DIR}/$i" break fi done [ -z "$HTML_LANG_MOD_DIR" ] && error 1 "No HTML directory given." # Apply (general, version specific, language specific) patches for i in "${PATCHES_DIR}/"*.patch \ "${PATCHES_DIR}/${FREETZ_TYPE_STRING}/"*.patch \ "${PATCHES_DIR}/${FREETZ_TYPE_STRING}/${FREETZ_TYPE_LANG_STRING}/"*.patch do modpatch "$FILESYSTEM_MOD_DIR" "$i" done echo1 "creating symlinks /tmp, /mod and /home" [ -e "$FILESYSTEM_MOD_DIR"/tmp ] && rm -rf "$FILESYSTEM_MOD_DIR"/tmp ln -s var/{tmp,mod} "$FILESYSTEM_MOD_DIR"/ ln -s var/mod/home "$FILESYSTEM_MOD_DIR"/ # Set version and options SUBVERSION_FILE="${BASE_DIR}/.version" FIRMWAREVERSION_FILE="${FILESYSTEM_MOD_DIR}/etc/.version" FIRMWAREVERSION="$(cat $FIRMWAREVERSION_FILE)" PACKAGES_LIST_FILE="${BASE_DIR}/.packages" if [ ! -r "$SUBVERSION_FILE" ]; then error 1 "cannot determine version" fi if [ "$FREETZ_DEVELOPER_VERSION_STRING" == "y" ]; then # be compatible: older versions of svnversion need WC_PATH if SVN_VERSION="$(svnversion . | tr ":" "_")"; then [ "${SVN_VERSION:0:6}" == "export" ] && SVN_VERSION="" [ "$SVN_VERSION" != "" ] && SVN_VERSION="-$SVN_VERSION" fi fi SUBVERSION="$(cat $SUBVERSION_FILE)${SVN_VERSION}" #delete .packages file rm -f "${PACKAGES_LIST_FILE}" for i in $(set|grep -i "^FREETZ_REMOVE_.*=y$"|sed -e "s/^.\{14\}//;s/=.*//"|tr [A-Z] [a-z]|sort); do OPTIONS+=" -$i" done OPTIONS_ADD=" +busybox" for i in $(set|grep -i "^FREETZ_PATCH_.*=y$"|sed -e "s/^.\{13\}//;s/=.*//"|tr [A-Z] [a-z]); do OPTIONS_ADD+=" +$i" done for pkg in $(static_packages) $(static_addons); do OPTIONS_ADD+=" +$pkg" echo "$pkg" >> "${PACKAGES_LIST_FILE}" done if [ "$FREETZ_REPLACE_KERNEL" == "y" ] && [ "$FWMOD_PATCH_TEST" != "y" ]; then KERNEL_SUBVERSION_FILE="${KERNEL_REP_DIR}/.version-${FREETZ_KERNEL_REF}-${FREETZ_AVM_VERSION_STRING}" if [ ! -r "$KERNEL_SUBVERSION_FILE" ]; then error 1 "cannot determine kernel version" fi KERNEL_SUBVERSION="$(cat $KERNEL_SUBVERSION_FILE)" OPTIONS_ADD+=" +kernel ($KERNEL_SUBVERSION)" fi for i in $(echo ${OPTIONS_ADD}|sed -e's: +:\n+:g'|sort); do OPTIONS+=" $i" done echo1 "setting freetz-version '${SUBVERSION}'" echo "$SUBVERSION" > "${FILESYSTEM_MOD_DIR}/etc/.freetz-version" if [ "$FREETZ_SUBVERSION_STRING" == "y" ]; then echo1 "setting subversion '${SUBVERSION}'" echo "$SUBVERSION" > "${FILESYSTEM_MOD_DIR}/etc/.subversion" sed -i -e "s/\export\ FIRMWARE_SUBVERSION=.*\$/export\ FIRMWARE_SUBVERSION=\"${SUBVERSION}\"/g" "${FILESYSTEM_MOD_DIR}/etc/version" if [ ! -e "${FILESYSTEM_MOD_DIR}/etc/init.d/rc.init" ]; then AVM_SUBVERSION=`grep "SUBVERSION=" "${FILESYSTEM_MOD_DIR}/etc/init.d/rc.conf" | sed -e "s/[^-0-9]//g"` sed -i -e "s/SUBVERSION=\"$AVM_SUBVERSION\"/SUBVERSION=\"$SUBVERSION\"/" "${FILESYSTEM_MOD_DIR}/etc/init.d/rc.conf" fi fi sed -i -e "s//${SUBVERSION}/g" "${FILESYSTEM_MOD_DIR}/usr/bin/system_status" sed -i -e "s//${OPTIONS}/g" "${FILESYSTEM_MOD_DIR}/usr/bin/system_status" # Execute general patch scripts for i in "${PATCHES_DIR}/"*.sh; do [ -r "$i" ] || continue echo2 "applying patch file $i" . $i done # stop execution if in patch test mode if [ "$FWMOD_PATCH_TEST" == "y" ]; then echo "${BOLD}Patch test mode: exiting without error.${NORM}" exit fi # remove oems [ "$FREETZ_VERBOSITY_LEVEL" -ge 1 ] && echo -n "${L1}removing oem:" oem_removed=0 oem_kept=0 oem_list= oems=$(grep -E 'for i in (avm|tcom)' "${FIRMWARE_MOD_DIR}/var/install" | head -n 1 | sed -e 's/^.*for i in\(.*\); do.*$/\1/') if [ -z "$oems" ]; then error 1 "no oems found" fi ln -sf /usr/www/cgi-bin/freetz_status "${HTML_LANG_MOD_DIR}/cgi-bin/freetz_status" ln -sf /usr/www/cgi-bin/freetz_wol "${HTML_LANG_MOD_DIR}/cgi-bin/freetz_wol" for i in $oems; do if [ "$(eval "echo \"\$FREETZ_REMOVE_BRANDING_${i}\"")" == "y" ]; then [ "$FREETZ_VERBOSITY_LEVEL" -ge 1 ] && echo -n " $i" rm -rf "${FILESYSTEM_MOD_DIR}/usr/www/${i}" rm -rf "${FILESYSTEM_MOD_DIR}/etc/default."*"/${i}" oem_removed=1 else oem_list+=" $i" oem_kept=1 fi done if [ "$FREETZ_VERBOSITY_LEVEL" -ge 1 ]; then [ "$oem_removed" -eq 0 ] && echo -n " none" echo fi if isFreetzType W501V; then oem_list="tcom avm" fi sed -i -r -e 's/for i in (avm|tcom).*; do/for i in '"$oem_list"' ; do/g' "${FIRMWARE_MOD_DIR}/var/install" if [ "$oem_kept" -eq 0 ]; then error 1 "please choose at least one OEM (branding) in menuconfig: AVM, 1&1, Freenet etc." fi # Copy selected avmplugins into the firmware if [ "$FREETZ_AVMPLUGINS_ENABLED" == "y" ]; then echo "installing AVM plugins" echo "#" > ${FILESYSTEM_MOD_DIR}/sbin/start_plugin.sh rm -rf ${FIRMWARE_MOD_DIR}/${AVMPLUGINS_FILE} mkdir "${AVMPLUGINS_FILESYSTEM_MOD_DIR}" for i in `find "${AVMPLUGINS_MOD_DIR}" -maxdepth 1 -type d -name var -prune -false , -type d -name "plugin-*"`; do AVMPLUGIN="${i##*plugin-}" if [ "$(eval "echo \"\$FREETZ_AVMPLUGINS_$(echo "$AVMPLUGIN" | tr [:lower:] [:upper:])\"")" == "y" ]; then echo1 "$AVMPLUGIN plugin" cp -a "${AVMPLUGINS_MOD_DIR}/plugin-${AVMPLUGIN}" "${AVMPLUGINS_FILESYSTEM_MOD_DIR}/plugin-${AVMPLUGIN}" ln -s "/usr/share/avmplugins/plugin-${AVMPLUGIN}" "${VARTAR_MOD_DIR}/var/plugin-${AVMPLUGIN}" for module in `cd "${AVMPLUGINS_FILESYSTEM_MOD_DIR}/plugin-${AVMPLUGIN}";find -type f -name "*.ko"`; do echo2 "moving ${module##*/} to standard modules dir" mv "${AVMPLUGINS_FILESYSTEM_MOD_DIR}/plugin-${AVMPLUGIN}/$module" "${FILESYSTEM_MOD_DIR}/$module" done fi done fi if [ "$FREETZ_INSTALL_BASE" == "y" ]; then echo "installing mod base" echo1 "copying files" "$TAR" -c -C "$ROOT_DIR" --exclude=lib --exclude=usr/lib --exclude=usr/share/terminfo \ $([ -r "${BASE_DIR}/.exclude" ] && echo "--exclude-from=${BASE_DIR}/.exclude") \ . | "$TAR" -x -C "$FILESYSTEM_MOD_DIR" || exit 1 "$TAR" -c -C "$ROOT_DIR" \ $([ -r "${BASE_DIR}/.exclude" ] && echo "--exclude-from=${BASE_DIR}/.exclude") \ ./usr/lib/cgi-bin | "$TAR" -x -C "$FILESYSTEM_MOD_DIR" || exit 1 mkdir -p "${FILESYSTEM_MOD_DIR}/usr/lib" cp "${ROOT_DIR}/usr/lib/lib"*.sh "${FILESYSTEM_MOD_DIR}/usr/lib/" # Emergency stop switch for execution of debug.cfg sed -i -r 's#(\. /var/flash/debug\.cfg)#[ "$dbg_off" == "y" ] || \1#g' "${FILESYSTEM_MOD_DIR}/etc/init.d/rc.S" # Emergency stop switch for execution of Freetz as a whole echo '[ "$ds_off" == "y" ] || . /etc/init.d/rc.mod 2>&1 | tee /var/log/mod.log' >> "${FILESYSTEM_MOD_DIR}/etc/init.d/rc.S" MOD_CRON="${VARTAR_MOD_DIR}/var/spool/cron/crontabs" MOD_ROOT="${VARTAR_MOD_DIR}/var/mod" mkdir -p "$MOD_CRON" mkdir -p "${MOD_ROOT}/pkg" "${MOD_ROOT}/home" "${MOD_ROOT}/lib" mkdir -p "${MOD_ROOT}/bin" "${MOD_ROOT}/sbin" mkdir -p "${MOD_ROOT}/var/cache" mkdir -p "${MOD_ROOT}/usr/bin" "${MOD_ROOT}/usr/sbin" "${MOD_ROOT}/usr/share" \ "${MOD_ROOT}/usr/lib" "${MOD_ROOT}/usr/lib/cgi-bin" mkdir -p "${MOD_ROOT}/etc/conf" "${MOD_ROOT}/etc/init.d" "${MOD_ROOT}/etc/reg" # AVM compatibility symlink ln -s ../sys "${VARTAR_MOD_DIR}/var/sysfs" echo "root:x:0:0:root:/mod/root:/bin/sh" > "${VARTAR_MOD_DIR}/var/tmp/passwd" echo 'root:$1$$zO6d3zi9DefdWLMB.OHaO.:12332:0:99999:7:::' > "${VARTAR_MOD_DIR}/var/tmp/shadow" echo "root:x:0:" > "${VARTAR_MOD_DIR}/var/tmp/group" echo "users:x:1:" >> "${VARTAR_MOD_DIR}/var/tmp/group" touch "${VARTAR_MOD_DIR}/var/tmp/ethers" touch "${VARTAR_MOD_DIR}/var/tmp/exports" touch "${VARTAR_MOD_DIR}/var/tmp/gshadow" chmod 644 "${VARTAR_MOD_DIR}/var/tmp/passwd" "${VARTAR_MOD_DIR}/var/tmp/group" chmod 600 "${VARTAR_MOD_DIR}/var/tmp/shadow" "${VARTAR_MOD_DIR}/var/tmp/gshadow" touch "${VARTAR_MOD_DIR}/var/tmp/onlinechanged" chmod +x "${VARTAR_MOD_DIR}/var/tmp/onlinechanged" ln -s ../var/tmp/ethers "${FILESYSTEM_MOD_DIR}/etc/ethers" ln -s ../var/tmp/exports "${FILESYSTEM_MOD_DIR}/etc/exports" ln -s ../var/tmp/gshadow "${FILESYSTEM_MOD_DIR}/etc/gshadow" echo1 "installing libs" for i in $(set | grep ^FREETZ_LIB_.*=y ); do found=0 conf=${i%%=*} bn=${conf#FREETZ_LIB_} fn=${bn//_/[-+._]} echo2 "$bn" for dn in lib usr/lib usr/lib/xtables; do files=$(shopt -s nullglob; echo ${ROOT_DIR}/$dn/$fn[-.]*so*) if [ -z "$files" ]; then continue; fi found=1 [ -d "${FILESYSTEM_MOD_DIR}/${dn}" ] || mkdir -p "${FILESYSTEM_MOD_DIR}/${dn}" cp -a $files "${FILESYSTEM_MOD_DIR}/${dn}/" done if [ "$found" = 0 ]; then warn "Library $bn selected, but no files found" fi done [ "$FREETZ_LIB_libuClibc" == "y" ] && cp -a "${ROOT_DIR}/lib/libc.so.0" "${FILESYSTEM_MOD_DIR}/lib/" if [ "$FREETZ_SHARE_terminfo" == "y" ]; then echo1 "installing terminfos" for i in $(set | grep ^FREETZ_SHARE_terminfo_.*=y |grep -v '^FREETZ_SHARE_terminfo_showall=' ); do dn=usr/share/terminfo conf=${i%%=*} bn=${conf#FREETZ_SHARE_terminfo_} fn=$(echo "$bn" | sed 's/MINUS/-/g;s/PLUS/+/g;s/\DOT/./g') echo2 "$fn" fn="${fn:0:1}/$fn" file="${ROOT_DIR}/$dn/$fn" if [ ! -e "$file" ]; then warn "Terminfo $bn selected, but no file found" continue; fi dest="${FILESYSTEM_MOD_DIR}/$dn/${fn:0:1}" [ -d "$dest" ] || mkdir -p "$dest" cp -a $file "$dest/" done fi if [ "$FREETZ_FAVICON_STRING" != "none" ]; then echo1 "adding favicons (${FREETZ_FAVICON_STRING})" cp "${FAVICON_DIR}/${FREETZ_FAVICON_STRING}/freetz.ico" "${FILESYSTEM_MOD_DIR}/usr/share/favicon.ico" ln -s "../share/favicon.ico" "${FILESYSTEM_MOD_DIR}/usr/mww/favicon.ico" cp "${FAVICON_DIR}/${FREETZ_FAVICON_STRING}/box.ico" "${HTML_LANG_MOD_DIR}/html/favicon.ico" ln -fs "./html/favicon.ico" "${HTML_LANG_MOD_DIR}/favicon.ico" fi if [ "$FREETZ_STATUS_STYLE" == "y" ]; then echo1 "patching bar-style and cache-usage" modpatch "$FILESYSTEM_MOD_DIR" "${PATCHES_DIR}/cond/bar-style_n_cache-usage.patch" fi modlang "${BASE_DIR}/.language" "${FILESYSTEM_MOD_DIR}" else error 1 "installation of base system is mandatory" fi if [ "$FREETZ_REPLACE_BUSYBOX" == "y" ]; then echo "replacing busybox" echo1 "replacing busybox-${FREETZ_TARGET_REF}" if [ ! -r "${BASE_DIR}/busybox/busybox-${FREETZ_TARGET_REF}" ]; then error 1 "cannot find busybox replacement" fi # Replace busybox cp -f "${BASE_DIR}/busybox/busybox-${FREETZ_TARGET_REF}" "${FILESYSTEM_MOD_DIR}/bin/busybox" echo1 "installing symlinks" if [ ! -r "${BASE_DIR}/busybox/busybox-${FREETZ_TARGET_REF}.links" ]; then error 1 "cannot find busybox links" fi # Remove old busybox links # be compatible: do not use -delete (not found in older versions of find) find "$FILESYSTEM_MOD_DIR" \( -lname "busybox" -or -lname "*/busybox" \) -print0 | xargs -0 rm # Install new busybox links for link in $(cat "${BASE_DIR}/busybox/busybox-${FREETZ_TARGET_REF}.links"); do LINK_DIR="$(dirname "$link")" LINK_NAME="$(basename "$link")" case "$LINK_DIR" in /) BUSYBOX_PATH="bin/busybox" ;; /bin) BUSYBOX_PATH="busybox" ;; /sbin) BUSYBOX_PATH="../bin/busybox" ;; /usr/bin|/usr/sbin) BUSYBOX_PATH="../../bin/busybox" ;; *) error 1 "unknown installation directory: $link" ;; esac ln -sf "$BUSYBOX_PATH" "${FILESYSTEM_MOD_DIR}${LINK_DIR}/$LINK_NAME" || error 1 "could not create link for $link" done || exit 1 else error 1 "installation of busybox replacement is mandatory" fi if [ "$FREETZ_REPLACE_KERNEL" == "y" ]; then echo "replacing kernel" if [ ! -r "${KERNEL_REP_DIR}/kernel-${FREETZ_KERNEL_REF}-${FREETZ_AVM_VERSION_STRING}.bin" ]; then error 1 "can't find kernel for ref ${FREETZ_KERNEL_REF}-${FREETZ_AVM_VERSION_STRING}" fi echo1 "replacing kernel-${FREETZ_KERNEL_REF}-${FREETZ_AVM_VERSION_STRING} (${KERNEL_SUBVERSION})" cp "${KERNEL_REP_DIR}/kernel-${FREETZ_KERNEL_REF}-${FREETZ_AVM_VERSION_STRING}.bin" "$RAW_KERNEL_MOD" fi echo1 "installing modules" for i in \ $( \ cd "${KERNEL_REP_DIR}/modules-${FREETZ_KERNEL_REF}-${FREETZ_AVM_VERSION_STRING}" && \ find . -type d -name .svn -prune -false , -type f \( -name modules.dep -o -name "*.ko" \) \ ) do bn="$(basename "$i")" mod="${bn%\.ko}" if [ "$FREETZ_MODULES_ALL" = "y" -o \ "$(eval "echo \"\$FREETZ_MODULE_$(echo "$mod" | tr '\-+' '_x')\"")" == "y" ] then echo2 "${bn}" dn="$(dirname "$i")" [ -d "${FILESYSTEM_MOD_DIR}/${dn}" ] || mkdir -p "${FILESYSTEM_MOD_DIR}/${dn}" cp "${KERNEL_REP_DIR}/modules-${FREETZ_KERNEL_REF}-${FREETZ_AVM_VERSION_STRING}/${i}" "${FILESYSTEM_MOD_DIR}/${dn}/" chmod +x "${FILESYSTEM_MOD_DIR}/${i}" fi done echo1 "generating modules.dep" # 7270 modules dir is 2.6.19.2 not 2.6.19.2-ur8 [ ! -e "$MODULES_DIR" ] && MODULES_DIR="$MODULES_DIR-${FREETZ_KERNEL_LAYOUT}" ${TOOLS_SUBDIR}/depmod.pl -b "$MODULES_DIR" \ -F ${KERNEL_REP_DIR}/System-${FREETZ_KERNEL_REF}-${FREETZ_AVM_VERSION_STRING}.map 2> /dev/null echo "installing packages" for pkg in $(static_packages); do echo1 "${pkg}" pkg_name=$(pkg_name "$pkg") "$TAR" -c -C "${PACKAGES_DIR}/${pkg}/root" \ $( [ -r "${PACKAGES_DIR}/${pkg}/.exclude" ] \ && echo "--exclude-from=${PACKAGES_DIR}/${pkg}/.exclude" ) . | \ "$TAR" -x -C "$FILESYSTEM_MOD_DIR" || exit 1 [ -r "${PACKAGES_DIR}/${pkg}/.language" ] && \ modlang "${PACKAGES_DIR}/${pkg}/.language" "${FILESYSTEM_MOD_DIR}" grep -q "^$pkg_name$" "${FILESYSTEM_MOD_DIR}/etc/static.pkg" >/dev/null 2>&1 || ( echo "$pkg_name" >> "${FILESYSTEM_MOD_DIR}/etc/static.pkg" ) done for pkg in $(static_addons); do echo1 "${pkg} (addon)" pkg_name=$(pkg_name "$pkg") if [ -e "${ADDON_DIR}/${pkg}/etc/init.d/rc.${pkg_name}" ]; then echo "NOTICE: addon '$pkg' is in old-style format (no language support)." 1>&2 "$TAR" -c -C "${ADDON_DIR}/${pkg}" . | "$TAR" -x -C "$FILESYSTEM_MOD_DIR" || exit 1 else "$TAR" -c -C "${ADDON_DIR}/${pkg}/root" \ $( [ -r "${ADDON_DIR}/${pkg}/.exclude" ] \ && echo "--exclude-from=${ADDON_DIR}/${pkg}/.exclude" \ ) . | \ "$TAR" -x -C "$FILESYSTEM_MOD_DIR" || exit 1 [ -r "${ADDON_DIR}/${pkg}/.language" ] && \ modlang "${ADDON_DIR}/${pkg}/.language" "${FILESYSTEM_MOD_DIR}" fi grep -q "^$pkg_name$" "${FILESYSTEM_MOD_DIR}/etc/static.pkg" >/dev/null 2>&1 || ( echo "$pkg_name" >> "${FILESYSTEM_MOD_DIR}/etc/static.pkg" ) done if [ -x "${BASE_DIR}/fwmod_custom" ]; then echo "invoking custom script" # syntax check $SHELL -n "${BASE_DIR}/fwmod_custom" if [ $? -ne 0 ]; then error 1 "syntax error in custom script" fi ( cd "$MOD_DIR" && ../../fwmod_custom all ) || exit 1 if [ $? -ne 0 ]; then error 1 "custom script returned error" fi fi if [ "$FREETZ_STRIP_LIBRARIES" == "y" ]; then echo "shrink shared libs" TARGET_TOOLCHAIN_STAGING_DIR="${ABS_BASE_DIR}/toolchain/target" # TODO: replace the next 3 lines with code that replaces all # absolute sym links... to make mklibs.py happy ln -sf libcapi20.so.3.0.4 "${FILESYSTEM_MOD_DIR}/lib/libcapi20.so" ln -sf libcapi20.so.3.0.4 "${FILESYSTEM_MOD_DIR}/lib/libcapi20.so.3" ln -sf libfwsign.so "${FILESYSTEM_MOD_DIR}/lib/libfwsign.so.0" # move shared libs from /lib and /usr/lib to libs_to_reduce folder # this is fundamental for mklibs.py !! # all needed lib are copied by mklibs.py to dest path (mklibs.py -d param) CUR=`pwd` rm -rf libs_to_reduce mkdir libs_to_reduce for SODIR in ${FILESYSTEM_MOD_DIR}/lib ${FILESYSTEM_MOD_DIR}/usr/lib; do cd $CUR/$SODIR for i in `find -maxdepth 1 -name "*.so*"`; do mv $i $CUR/libs_to_reduce/$i; done done cd $CUR # when mklibs.py breaks with errors like "X unresolved non weak symbols: ...." # you should search with grep, mc, readelf -s which binary needs this symbols # and which lib provides this symbol ... you get some debug output when you " # add some -v -v -v to mklibs.py call # get_UserAgentTransport is referenced by libfon.so but not provided by # any shared lib or binary # __cxa_pure_virtual is referenced at some places.. UNNEEDED_SYMBOLS="-u get_UserAgentTransport -u __cxa_pure_virtual" # some more referenced symbols not provided on 3170, this box does not have tr069 # but this should not break compatibility for other boxes UNNEEDED_SYMBOLS+=" -u __cxa_atexit -u add_node -u add_object -u get_ctlmgr_value -u set_ctlmgr_value" if [ "$FREETZ_REMOVE_TR069" == "y" ]; then # ignore some symbols provided by libtr069.so and referenced at # some places e.g. in libfon.so libwlan.so UNNEEDED_SYMBOLS+=" -u get_ctlmgr_value -u _ZN14ModuleRegistry12ApplyChangesEv \ -u get_UIModule -u getNode -u cm_create_node -u GetContext \ -u _Z23TR069_SOAPEnvelope_FreeP18TR069_SOAPEnvelope -u findRefNodeOfName \ -u TR069_Helper_Parse_SOAP -u _ZN14ModuleRegistry19TransactionRollbackEv \ -u Unregister_VOIP_1und1_Assi -u _ZN14ModuleRegistry17TransactionCommitEv \ -u Register_VOIP_1und1_Assi -u get_NumberOfEntries -u _fLog -u remove_node \ -u _Z20Get_g_pParamRegistryv -u _ZN14ModuleRegistry17SetParameterValueEPcS0_ \ -u get_ExternalIPAddress -u _ZN14ModuleRegistry16TransactionBeginEv" else # set_PPPoEServiceName is referenced by libtr069.so but not # provided by and shared lib or binary UNNEEDED_SYMBOLS+=" -u set_PPPoEServiceName" fi #find all executables which uses parts of shared objects find "${FILESYSTEM_MOD_DIR}" -type f -perm +100 -exec \ file -r -N -F '' {} + | \ awk ' /executable.*dynamically/ { print $1 }; /shared object/ {print $1} ' > "${FILESYSTEM_MOD_DIR}/mklibs-progs" #we need the rest of shared objects in mod dir too #iptables shared libs... ctlrmg shared libs for i in `find "${FILESYSTEM_MOD_DIR}" -type f -name "*.so"`; do echo $i >> "${FILESYSTEM_MOD_DIR}/mklibs-progs" done PATH=${TARGET_TOOLCHAIN_STAGING_DIR}/bin:$PATH tools/mklibs.py -v \ --target mipsel-linux-uclibc \ --ldlib ld-uClibc.so.0 \ --root ${FILESYSTEM_MOD_DIR} \ -d ${FILESYSTEM_MOD_DIR}/lib \ -D \ -L ${CUR}/libs_to_reduce \ -L ${TARGET_TOOLCHAIN_STAGING_DIR}/lib \ ${UNNEEDED_SYMBOLS} \ `cat "${FILESYSTEM_MOD_DIR}/mklibs-progs"` > "${DIR}/modified/mklibs.log" 2>&1 rm -rf libs_to_reduce rm -f ${FILESYSTEM_MOD_DIR}/mklibs-progs fi # external should run after modifying and stripping and so on # only run, if packaging is enabled if [ "$DO_PACK" -gt 0 ]; then if [ "$EXTERNAL_ENABLED" == "y" ]; then echo "processing external" [ ! -x "$EXTERNAL" ] && error 1 "cannot find the tool $EXTERNAL_TOOL" . "${EXTERNAL}" fi fi touch "${DIR}/.modified" echo "done." echo fi ################################ ## Pack the modified firmware ## ################################ if [ "$DO_PACK" -gt 0 ]; then echo "${BOLD}STEP 3: PACK${NORM}" if [ ! "$DO_MOD" -gt 0 ]; then echo "WARNING: Modifications (STEP 2) and this step should never" 1>&2 echo " ever be run with different configurations!" 1>&2 echo " This can result in invalid images!!!" 1>&2 fi # Check if firmware is unpacked if [ ! -r "${DIR}/.unpacked" ]; then error 1 "firmware image has to be unpacked before packing" fi # Check if firmware is modified by the script if [ ! -r "${DIR}/.modified" ]; then warn "firmware does not seem to be modified by the script" if [ ! -d "$MOD_DIR" ]; then # Copy the unpacked directory cp -r "$ORG_DIR" "$MOD_DIR" fi fi # Remove left over Subversion directories echo1 "Checking for left over Subversion directories" find "$MOD_DIR" -type d -name .svn | xargs rm -rf # Delete all files that we are going to re-create now rm -f "$VARTAR_MOD" rm -f "$KERNEL_MOD" rm -f "$FILESYSTEM_MOD" rm -f "${DIR}/*.image" if [ "$FREETZ_SQUASHFS_BLOCKSIZE_ORIG" == "y" ]; then FILESYSTEM_BLOCKSIZE="$((1<<$(od -i -N 1 -j 34 "$FILESYSTEM" | sed -n -e '1s#.* ##' -e 1p)))" else FILESYSTEM_BLOCKSIZE=$(set | sed -rn 's/FREETZ_SQUASHFS_BLOCKSIZE_([^=]+)=y/\1/p') fi if [ "$FREETZ_VERBOSITY_LEVEL" -ge 1 ]; then echo "squashfs blocksize" echo "${L1}root filesystem: $FILESYSTEM_BLOCKSIZE" fi # Pack var.tar (use old tar for compatibility) echo "packing var.tar" "$TAR" -c --owner=0 --group=0 --mode=0755 --format=oldgnu -C "$VARTAR_MOD_DIR" . > "$VARTAR_MOD" || exit 1 if [ ! -s "$VARTAR_MOD" ]; then error 1 "packing of var.tar failed" fi # Do we have the tool ? if [ ! -x "$MKSQUASHFS" ]; then error 1 "cannot find $MKSQUASHFS_TOOL" fi echo "creating filesystem image" "$FAKEROOT" -s fakechroot.save -- $MAKEDEVS -d $MAKEDEVS_FILE $FILESYSTEM_MOD_DIR > $MOD_DIR/filesystem.log 2>&1 # Possible race condition: save file must become available in file system. # This can take an instant, so wait if necessary. until [ -r fakechroot.save ]; do sleep 0.1; done "$FAKEROOT" -i fakechroot.save -- $TOOLS_DIR/$MKSQUASHFS_TOOL $FILESYSTEM_MOD_DIR/* $ABS_BASE_DIR/$FILESYSTEM_MOD $MKSQUASHFS_OPTIONS -b $FILESYSTEM_BLOCKSIZE >> $MOD_DIR/filesystem.log 2>&1 rm -f fakechroot.save if [ ! -s "$FILESYSTEM_MOD" ]; then error 1 "creation of filesystem failed" fi echo "merging kernel image" dd if="$RAW_KERNEL_MOD" of="$KERNEL_MOD" bs=256 conv=sync 2> /dev/null cat "$FILESYSTEM_MOD" >> "$KERNEL_MOD" if [ ! -s "$KERNEL_MOD" ]; then error 1 "kernel merging failed" fi # Check size of kernel image let KERNEL_LIMIT="$FREETZ_KERNEL_MTD_SIZE*65536" let KERNEL_SIZE="$(wc -c < "$KERNEL_MOD")" let DIFF="KERNEL_SIZE-KERNEL_LIMIT" echo1 "kernel image size: $KERNEL_SIZE (max: $KERNEL_LIMIT, free: $((-DIFF)))" if [ "$KERNEL_SIZE" -eq 0 ]; then error 1 "kernel image is empty" fi if [ "$KERNEL_SIZE" -gt "$KERNEL_LIMIT" ]; then error 1 "kernel image is $DIFF bytes too big. See http://trac.freetz.org/wiki/FAQ#Filesystemimagetoobig for details" fi if [ "$FREETZ_VERBOSITY_LEVEL" -ge 1 ]; then if [ "$FREETZ_HAS_TAM" = "y" ]; then # Calculate aproximately free space in seconds for the answering machine FREE_BYTE_JFFS2=$((($KERNEL_LIMIT - $KERNEL_SIZE - 233472))) FREE_MINUTES=$((($FREE_BYTE_JFFS2 / 2017 / 60))) if [ "$FREE_BYTE_JFFS2" -gt 0 ]; then echo "${L1}Aproximately free time for the answering machine: $((($FREE_BYTE_JFFS2 / 2017)))s (${FREE_MINUTES}min $((($FREE_BYTE_JFFS2 / 2017 - $FREE_MINUTES * 60)))s)" else echo "${L1}WARNING: Not enough free flash space for answering machine!" fi fi fi # Do we have the tool ? if [ ! -x "$TICHKSUM" ]; then error 1 "cannot find wonderful tool $TICHKSUM_TOOL" fi # Write checksum "$TICHKSUM" "$KERNEL_MOD" > "${MOD_DIR}/kernelchksum.log" # Consistency check if [ -s "${FIRMWARE_DIR}/${KERNEL_IMAGE}" -a ! -s "${FIRMWARE_MOD_DIR}/${KERNEL_IMAGE}" ] || \ [ ! -s "${FIRMWARE_DIR}/${KERNEL_IMAGE}" -a -s "${FIRMWARE_MOD_DIR}/${KERNEL_IMAGE}" ] then error 1 "inconsistency comparing size of old and new kernel.image" fi # Last, but not least, include .config and addon/static.pkg into firmware # image for further reference, e.g. user support [ -r "$DOT_CONFIG" ] && cp "$DOT_CONFIG" "$FIRMWARE_MOD_DIR/var" [ -r "$STATIC_ADDON_FILE" ] && cp "$STATIC_ADDON_FILE" "$FIRMWARE_MOD_DIR/var" [ -r "$PACKAGES_LIST_FILE" ] && cp "$PACKAGES_LIST_FILE" "$FIRMWARE_MOD_DIR/var" modmakedate=$(date +%Y%m%d-%H%M%S) modimage="${FREETZ_TYPE_STRING2}${FREETZ_TYPE_STRING}_${FIRMWAREVERSION}${SUBVERSION}.${FREETZ_TYPE_LANG_STRING}_$modmakedate.image" # Pack firmware image (use old tar for compatibility) echo "packing ${modimage}" "$TAR" -c --owner=0 --group=0 --mode=0755 --format=oldgnu -C "$FIRMWARE_MOD_DIR" . > "${DIR}/${modimage}" || exit 1 if [ ! -s "${DIR}/${modimage}" ]; then rm -f "${DIR}/${modimage}" error 1 "packing of firmware image failed" fi if [ "$EXTERNAL_CREATEPAK" == "y" ]; then modexternal="${FREETZ_TYPE_STRING2}${FREETZ_TYPE_STRING}_${FIRMWAREVERSION}${SUBVERSION}.${FREETZ_TYPE_LANG_STRING}_${modmakedate}.external" echo "packing ${modexternal}" "$TAR" -c --owner=0 --group=0 --mode=0755 --format=oldgnu -C "$EXTERNAL_MOD_DIR" . > "${DIR}/${modexternal}" || exit 1 if [ ! -s "${DIR}/${modexternal}" ]; then rm -f "${DIR}/${modexternal}" error 1 "packing of external tar failed" fi fi if [ -s "${DIR}/${modimage}" ]; then echo "Image files can be found in the ./${FW_IMAGES_DIR}/ subfolder" [ "$FREETZ_LIB_libcrypto" == "y" -o "$FREETZ_LIB_libssl" == "y" ] && echo "Caution: Replacing libcrypto or libssl may cause an unusable image. See http://trac.freetz.org/wiki/FAQ#NachdemFlashenistdasAVM-Webinterfacenichtmehrerreichbar for details." fi echo "done." echo echo "${BOLD}FINISHED${NORM}" fi exit 0