#!/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 Bühmann, Christian Volkmann, Enrik Berkhan, # SpeedyBZ and all members on ip-phone-forum.de who contributed to this mod 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 } # error exit-code error-message error() { if [ "$1" -gt 0 ]; then echo -e "ERROR: $2" 1>&2 exit $1 fi } # warn warn-message warn() { echo -e "WARNING: $1" 1>&2 } # Dont run this script as root if [ $UID -eq 0 ]; then error 1 "running this script as root is prohibited" fi # Print usage info to stdout (no error, just info) if [ $# -eq 0 ]; then usage exit 0 fi L1=' ' L2=' ' # 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 # Config file readable? if [ ! -r "$DOT_CONFIG" ]; then error 1 "not configured" fi # Load config . "$DOT_CONFIG" 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 [ "$(expr index "$ABS_BASE_DIR" "/")" -ne 1 ]; then ABS_BASE_DIR="$(pwd)/$ABS_BASE_DIR" fi TOOLS_SUBDIR="tools" SOURCE_SUBDIR="source" FIRMWARE_SUBDIR="firmware" FILESYSTEM_SUBDIR="filesystem" KERNEL_SUBDIR="kernel" VARTAR_SUBDIR="var.tar" KERNEL_IMAGE="var/tmp/kernel.image" 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" MKSQUASHFS_OPTIONS="-le -noappend -all-root -info" 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 TAR_TOOL="tar" TOOLS_DIR="${ABS_BASE_DIR}/${TOOLS_SUBDIR}" 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" echo0() { [ "$FREETZ_VERBOSITY_LEVEL" -ge 0 ] && echo -e "${L0}$1" } echo1() { [ "$FREETZ_VERBOSITY_LEVEL" -ge 1 ] && echo -e "${L1}$1" } echo2() { [ "$FREETZ_VERBOSITY_LEVEL" -ge 2 ] && echo -e "${L2}$1" } # Dot-include 'modpatch' shell function . "${TOOLS_DIR}/freetz_patch" modunsqfs() { local STATUS if [ "$FREETZ_VERBOSITY_LEVEL" -ge 1 ]; then "$FAKEROOT" "$UNSQUASHFS" -dest "$1" "$2" 2>&1 | grep -v "^$" | sed -e "s/^/${L1}/g" STATUS=${PIPESTATUS[0]} else "$FAKEROOT" "$UNSQUASHFS" -dest "$1" "$2" > /dev/null STATUS=$? fi if [ $STATUS -gt 0 ]; then error 1 "modunsqfs: Error in $2" fi } modlangsubst() { # modlangsubst # Substitutes all $(lang de:"Deutscher Text" en:"English text" ...) occurrences # in with of the corresponding :"" section. s='[\t\r\n ]' val='\(\([^"\\]*\(\\.\)*\)*\)' entry="\w\+:\"${val}\"" LC_ALL="" LC_CTYPE=C sed -i -e " :a s/\$(lang\(${s}\+${entry}\)*${s}\+${1}:\"${val}\"\(${s}\+${entry}\)*${s}*)/\$(lang:\"\5\")/g s/\$(lang\(${s}\+${entry}\)*${s}*)/*** error: language[${1}] not available ***/g :n s/\$(lang:\"\(\([^\"\\]\+\)\|[\\]\(.\)\)${val}\")/\2\3\$(lang:\"\4\")/g tn s/\$(lang:\"\")//g /\$(lang\(${s}\|\$\)/ {N; ba} " "$2" } modlangconf() { # modlangconf # Get of a { } section in s='[\t\r\n ]' sed -n -e ":n;N;\$!bn;s/^.*${1}${s}\+{${s}*\([^}]*\)${s}*}.*$/\1/p" "$2" } modlang() { # modlang avail="$(modlangconf "languages" "$1")" default="$FREETZ_LANG_STRING $(modlangconf "default" "$1") en de $avail" lang="" for i in $default; do for j in $avail; do if [ "$i" == "$j" ]; then lang="$j" break 2 fi done done if [ -z "$lang" ]; then error 1 "no language available" fi [ "$lang" == "$FREETZ_LANG_STRING" ] || \ echo "NOTICE: language $FREETZ_LANG_STRING not available; $lang chosen." 1>&2 for i in $(modlangconf "files" "$1"); do if [ -e "${2}/${i}" ]; then modlangsubst "$lang" "${2}/${i}" else warn "${2}/${i} not found" fi done } 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}" VARTAR_DIR="${KERNEL_DIR}/${VARTAR_SUBDIR}" KERNEL="${FIRMWARE_DIR}/${KERNEL_IMAGE}" RAW_KERNEL="${KERNEL_DIR}/${RAW_KERNEL_FILE}" FILESYSTEM="${KERNEL_DIR}/${RAW_HIDDEN_FILE}" VARTAR="${FILESYSTEM_DIR}/${VARTAR_FILE}" if [ "$DO_UNPACK" -gt 0 ]; then echo -e "\033[1mSTEP 1: UNPACK\033[0m" 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 "$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}" KERNEL_MOD_DIR="${MOD_DIR}/${KERNEL_SUBDIR}" 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" if [ "$FREETZ_TYPE_LANG_EN" == "y" ]; then HTML_LANG_MOD_DIR="${HTML_MOD_DIR}/avme/en" else HTML_LANG_MOD_DIR="${HTML_MOD_DIR}/all" fi MODULES_DIR="${FILESYSTEM_MOD_DIR}/lib/modules/${FREETZ_KERNEL_VERSION}" if [ "$DO_MOD" -gt 0 ]; then echo -e "\033[1mSTEP 2: MODIFY\033[0m" # 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 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 # 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" 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)" 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}" OPTIONS="+busybox" [ "$FREETZ_REMOVE_ASSISTANT" == "y" ] && OPTIONS="$OPTIONS -assistant" [ "$FREETZ_REMOVE_HELP" == "y" ] && OPTIONS="$OPTIONS -help" [ "$FREETZ_REMOVE_CDROM_ISO" == "y" ] && OPTIONS="$OPTIONS -cdrom.iso" [ "$FREETZ_PATCH_ATA" == "y" ] && OPTIONS="$OPTIONS +ata" [ "$FREETZ_PATCH_ENUM" == "y" ] && OPTIONS="$OPTIONS +enum" [ "$FREETZ_PATCH_INTERNATIONAL" == "y" ] && OPTIONS="$OPTIONS +international" [ "$FREETZ_PATCH_PUSH" == "y" ] && OPTIONS="$OPTIONS +push" [ "$FREETZ_PATCH_WDS" == "y" ] && OPTIONS="$OPTIONS +wds" [ "$FREETZ_PATCH_SIGNED" == "y" ] && OPTIONS="$OPTIONS +signed" [ "$FREETZ_PATCH_USBSTORAGE" == "y" ] && OPTIONS="$OPTIONS +usbstorage" 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="$OPTIONS +kernel ($KERNEL_SUBVERSION)" fi if [ -r "$STATIC_PACKAGES_FILE" ]; then for pkg in \ $( \ cat "$STATIC_PACKAGES_FILE" \ | sed -e 's/^[\ \t]*//' -e 's/[\ \t]*$//' -e 's/^S[0-9]*//' \ | grep -v '^#' | grep -v '^$' \ ) do OPTIONS="$OPTIONS +$pkg" done fi if [ -r "$STATIC_ADDON_FILE" ]; then for pkg in \ $( \ cat "$STATIC_ADDON_FILE" \ | sed -e 's/^[\ \t]*//' -e 's/[\ \t]*$//' \ | grep -v '^#' | grep -v '^$' \ ) do OPTIONS="$OPTIONS +$pkg" done fi 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" 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" 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=\"$AVM_SUBVERSION-$SUBVERSION\"/" "${FILESYSTEM_MOD_DIR}/etc/init.d/rc.conf" fi # 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 -e "\033[1mPatch test mode: exiting without error.\033[0m" exit fi # remove oems [ "$FREETZ_VERBOSITY_LEVEL" -ge 1 ] && echo -n "${L1}removing oem:" oem_removed=0 oem_kept=0 oem_list= oems="$(grep 'for i in avm' "${FIRMWARE_MOD_DIR}/var/install" | head -n 1 | sed -e 's/^.*for i in\(.*\); do.*$/\1/')" if [ -z "$oems" ]; then oems="$(grep 'for i in tcom' "${FIRMWARE_MOD_DIR}/var/install" | head -n 1 | sed -e 's/^.*for i in\(.*\); do.*$/\1/')" fi 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_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="$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 [ "$FREETZ_TYPE_SPEEDPORT_W501V" == "y" ] || \ [ "$FREETZ_TYPE_SPEEDPORT_W701V" == "y" ] || \ [ "$FREETZ_TYPE_SPEEDPORT_W900V" == "y" ] then oem_list="tcom congstar avm" sed -i -e 's/for i in tcom.*; do/for i in '"$oem_list"' ; do/g' "${FIRMWARE_MOD_DIR}/var/install" else sed -i -e 's/for i in avm.*; do/for i in '"$oem_list"' ; do/g' "${FIRMWARE_MOD_DIR}/var/install" fi if [ "$oem_kept" -eq 0 ]; then error 1 "please choose at least one OEM (branding) in menuconfig: AVM, 1&1, Freenet etc." 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" ln -s ../var/tmp/onlinechanged "${FILESYSTEM_MOD_DIR}/bin/onlinechanged" if [ "$FREETZ_STRIP_LIBRARIES" != "y" ]; then echo1 "installing libs" for i in \ $( \ cd "${ROOT_DIR}" && \ find lib usr/lib -type d -name .svn -prune -false , -type f -name "*.so*" \ ) do bn="$(basename "$i")" lib="${bn%\.so*}" lib="$(echo "$lib" | sed -r 's/^libg(lib|object|module|thread)-2/libg\12-2/;s/-[0-9][\.0-9a-z]*$//')" if [ "$(eval "echo \"\$FREETZ_LIB_$(echo "$lib" | tr '\-+' '_x')\"")" == "y" ]; then echo2 "${bn}" dn="$(dirname "$i")" lib="$(echo "$lib" | sed -r 's/^libg(lib|object|module|thread)2/libg\1-2/')" [ -d "${FILESYSTEM_MOD_DIR}/${dn}" ] || mkdir -p "${FILESYSTEM_MOD_DIR}/${dn}" cp -a "${ROOT_DIR}/${dn}/${lib}"[-\|\.]*so* "${FILESYSTEM_MOD_DIR}/${dn}/" chmod +x "${FILESYSTEM_MOD_DIR}/${i}" fi done fi [ "$FREETZ_LIB_libuClibc" == "y" ] && cp -a "${ROOT_DIR}/lib/libc.so.0" "${FILESYSTEM_MOD_DIR}/lib/" if [ "$FREETZ_LIB_libterminfo" == "y" ]; then echo1 "installing terminfos" for i in \ $( \ cd "${ROOT_DIR}" && \ find usr/share/terminfo -type d -name .svn -prune -false , -type f \ ) do bn="$(basename "$i")" terminfo="${bn}" if [ "$(eval "echo \"\$FREETZ_LIB_libterminfo_$(echo "$terminfo" | sed 's/-/minus/g;s/+/plus/g;s/\./dot/g')\"")" == "y" ]; then echo2 "${bn}" dn="$(dirname "$i")" [ -d "${FILESYSTEM_MOD_DIR}/${dn}" ] || mkdir -p "${FILESYSTEM_MOD_DIR}/${dn}" cp -a "${ROOT_DIR}/${dn}/${terminfo}" "${FILESYSTEM_MOD_DIR}/${dn}/" fi 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 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" if [ -r "$STATIC_PACKAGES_FILE" ]; then for pkg in \ $( \ sort "$STATIC_PACKAGES_FILE" \ | sed -e 's/^[\ \t]*//' -e 's/[\ \t]*$//' -e 's/^S[0-9]*//' \ | grep -v '^#' | grep -v '^$' \ ) do echo1 "${pkg}" pkg_name="$(echo "$pkg" | sed -e 's/-BETA$//' -e 's/-[0-9][^-]*$//' -e 's/-cgi$//')" "$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}" echo "$pkg_name" >> "${FILESYSTEM_MOD_DIR}/etc/static.pkg" done fi if [ -r "$STATIC_ADDON_FILE" ]; then for pkg in \ $( \ cat "$STATIC_ADDON_FILE" \ | sed -e 's/^[\ \t]*//' -e 's/[\ \t]*$//' \ | grep -v '^#' | grep -v '^$' \ ) do echo1 "${pkg} (addon)" pkg_name="$(echo "$pkg" | sed -e 's/-BETA$//' -e 's/-[0-9][^-]*$//' -e 's/-cgi$//')" 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 echo "$pkg_name" >> "${FILESYSTEM_MOD_DIR}/etc/static.pkg" done fi 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" 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 # is this really a good idea to remove this lib ?!? ;-) # here it works... UNNEEDED_SYMBOLS+=" -u get_ctlmgr_value -u _ZN14ModuleRegistry12ApplyChangesEv \ -u add_node -u 'get_ctlmgr_value -u get_UIModule -u getNode \ -u _Z23TR069_SOAPEnvelope_FreeP18TR069_SOAPEnvelope -u findRefNodeOfName \ -u TR069_Helper_Parse_SOAP -u add_object -u _ZN14ModuleRegistry19TransactionRollbackEv \ -u Unregister_VOIP_1und1_Assi -u _ZN14ModuleRegistry17TransactionCommitEv -u GetContext \ -u Register_VOIP_1und1_Assi -u get_NumberOfEntries -u _fLog -u remove_node \ -u _Z20Get_g_pParamRegistryv -u _ZN14ModuleRegistry17SetParameterValueEPcS0_ \ -u get_ExternalIPAddress -u _ZN14ModuleRegistry16TransactionBeginEv -u set_ctlmgr_value \ -u cm_create_node" 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 }' > "${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 ${TARGET_TOOLCHAIN_STAGING_DIR}/lib \ -L ${CUR}/libs_to_reduce \ ${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 touch "${DIR}/.modified" echo "done." echo fi ################################ ## Pack the modified firmware ## ################################ if [ "$DO_PACK" -gt 0 ]; then echo -e "\033[1mSTEP 3: PACK\033[0m" 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 [ "$FREETZ_VERBOSITY_LEVEL" -ge 1 ]; then if [ "$FREETZ_TYPE_FON_7150" = "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))) 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)" fi fi 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" 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" modimage="${FREETZ_TYPE_STRING2}${FREETZ_TYPE_STRING}_${FIRMWAREVERSION}-${SUBVERSION}.${FREETZ_TYPE_LANG_STRING}_$(date +%Y%m%d-%H%M%S).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 echo "done." echo echo -e "\033[1mFINISHED\033[0m" fi exit 0