#!/bin/bash
#
#   Script to modify AVM FRITZ!Box firmware images (Freetz)
#
#   $Id: fwmod 3247 2009-04-06 15:54:02Z oliver $
#
#   Copyright (C) 2005-2006 Daniel Eiband <eiband@online.de>
#   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 Bhmann, 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 <cfg>] [-d <dir>] <orig_fw> [<tk_fw>]
  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 <cfg>   input file for configuration data (default: .config)
    -d <dir>   build directory (default: <orig_firmware>.mod)
    <orig_fw>  original firmware name
    <tk_fw>    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='    '
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

# 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 <file>'
# 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"

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}"
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"

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"

# little helper function used by many patches (maybe this should be sourced out)
rm_files()
{
        for file in "$@"; do
        echo2 "rm $file"
        rm -rf "$file"
        done
}

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 <lang> <file>
	#   Substitutes all $(lang de:"Deutscher Text" en:"English text" ...) occurrences
	#   in <file> with <text> of the corresponding <lang>:"<text>" 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 <key> <file>
	#   Get <content> of a <key> { <content> } section in <file>

	s='[\t\r\n ]'

	sed -n -e ":n;N;\$!bn;s/^.*${1}${s}\+{${s}*\([^}]*\)${s}*}.*$/\1/p" "$2"
}

modlang()
{
	# modlang <conffile> <dir>

	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
}

# list of static packages, sorted by start level
static_packages()
{
	if [ -r "$STATIC_PACKAGES_FILE" ]; then
		sort "$STATIC_PACKAGES_FILE" \
		  | sed -e 's/^[\ \t]*//' -e 's/[\ \t]*$//' -e 's/^S[0-9]*//' \
		  | grep -v '^#' | grep -v '^$'
	fi
}

static_addons()
{
	if [ -r "$STATIC_ADDON_FILE" ]; then
		cat "$STATIC_ADDON_FILE" \
		  | sed -e 's/^[\ \t]*//' -e 's/[\ \t]*$//' \
		  | grep -v '^#' | grep -v '^$'
	fi
}

pkg_name() 
{
	local name=$1
	echo "$name" | sed -e 's/-BETA$//' -e 's/-[0-9][^-]*$//' -e 's/-cgi$//'
}

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

	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}"
	OPTIONS="+busybox"
	#delete .packages file
	rm -f "${PACKAGES_LIST_FILE}"
	
	[ "$FREETZ_REMOVE_ASSISTANT" == "y" ]		&& OPTIONS+=" -assistant"
	[ "$FREETZ_REMOVE_HELP" == "y" ]		&& OPTIONS+=" -help"
	[ "$FREETZ_REMOVE_CDROM_ISO" == "y" ]		&& OPTIONS+=" -cdrom.iso"
	[ "$FREETZ_PATCH_ATA" == "y" ]			&& OPTIONS+=" +ata"
	[ "$FREETZ_PATCH_DSL_EXPERT" == "y" ]		&& OPTIONS+=" +dslexpert"
	[ "$FREETZ_PATCH_ENUM" == "y" ]			&& OPTIONS+=" +enum"
	[ "$FREETZ_PATCH_GETCONS" == "y" ]		&& OPTIONS+=" +getcons"
	[ "$FREETZ_PATCH_INTERNATIONAL" == "y" ]	&& OPTIONS+=" +international"
	[ "$FREETZ_PATCH_MAXDEVCOUNT" == "y" ]		&& OPTIONS+=" +maxdevcount"
	[ "$FREETZ_PATCH_VCC" == "y" ]			&& OPTIONS+=" +vcc"
	[ "$FREETZ_PATCH_SIGNED" == "y" ]		&& OPTIONS+=" +signed"
	[ "$FREETZ_PATCH_USBSTORAGE" == "y" ]		&& 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+=" +kernel ($KERNEL_SUBVERSION)"
	fi

	for pkg in $(static_packages) $(static_addons); do
		OPTIONS+=" +$pkg"
		echo "$pkg" >> "${PACKAGES_LIST_FILE}"
	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>/${SUBVERSION}/g" "${FILESYSTEM_MOD_DIR}/usr/bin/system_status"
	sed -i -e "s/<options>/${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 [ "$FREETZ_TYPE_SPEEDPORT_W501V" == "y" ] || \
		[ "$FREETZ_TYPE_SPEEDPORT_W701V" == "y" ] || \
		[ "$FREETZ_TYPE_SPEEDPORT_W900V" == "y" ]
	then
		oem_list="tcom congstar 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}"
			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 }' > "${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"
	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"
	fi

	echo "done."
	echo

	echo "${BOLD}FINISHED${NORM}"
fi

exit 0
