#!/bin/sh

set -e

DESTDIR=$PWD/live
KVERS=${KVERS:-`uname -r`}
MODULES_DIR="$DESTDIR/lib/modules/$KVERS/misc"
XPP_SYNC=auto
AST_SCRIPT=/etc/init.d/asterisk
# Use this file to pass options to modules:
PERLLIBDIR=`perl -V:sitelib | cut -d "'" -f 2`

# Manual list of modules. They will be loaded by insmod.
# If reside in a subdir, add it explicitly.

MODULES_LOAD="zaptel"

# this one *is* resolved recusively. 
# the only reason to set a different value is if you use hpec / oslec,
# as Zaptel depends on them.
REMOVE_MODULES="zaptel"

if [ -r $DESTDIR/live.conf ]; then . $DESTDIR/live.conf; fi

# Give priority to our installed binaries:
PATH=$DESTDIR/sbin:$DESTDIR/usr/sbin:$PATH
export PATH

# TODO: If you already use PERL5DIR, please fix this part:
PERL5LIB="$DESTDIR/$PERLLIBDIR"
export PERL5LIB

# the same as xpp/utils/zaptel_drivers .
# With the remote mode, I can't rely on files in the source directory.
zaptel_drivers() {
	perl -MZaptel::Hardware -e '
		my $hardware = Zaptel::Hardware->scan;
		print join(" ", $hardware->drivers);
		'
}

# Detect the modules used in the system:
for mod in `zaptel_drivers`; do
	case "$mod" in
		xpp_usb) 
			MODULES_LOAD="$MODULES_LOAD xpp/xpp xpp/xpd_fxs"
			MODULES_LOAD="$MODULES_LOAD xpp/xpd_fxo xpp/xpd_pri" 
			MODULES_LOAD="$MODULES_LOAD xpp/xpp_usb"
			;;
		wctdm24xxp | wct4xxp | wcte12xp | wctc4xp)
			MODULES_LOAD="$MODULES_LOAD $mod/$mod"
			;;
		wanpipe)
			: # requires different handling
			;;
		*)
			MODULES_LOAD="$MODULES_LOAD $mod"
			;;
	esac
done

# Initialize the Xorcom Astribank (xpp/) using perl utiliites:
# intended to replace all the the three functions below if user has 
# installed the zaptel-perl utilities.
xpp_startup() {
	# do nothing if there are no astribank devices:
	if ! grep -q connected /proc/xpp/xbuses 2>/dev/null; then return 0; fi

	echo "Waiting for Astribank devices to initialize:"
	cat /proc/xpp/XBUS-[0-9]*/waitfor_xpds 2>/dev/null || true
	
	# overriding locales for the above two, as perl can be noisy
	# when locales are missing.
	# No register all the devices if they didn't auto-register:
	LC_ALL=C zt_registration on

	# this one could actually be run after ztcfg:
	LC_ALL=C xpp_sync "$XPP_SYNC"
}

# recursively unload a module and its dependencies, if possible.
# where's modprobe -r when you need it?
# inputs: module to unload.
# returns: the result from 
unload_module() {
	module="$1"
	line=`lsmod 2>/dev/null | grep "^$1 "`
	if [ "$line" = '' ]; then return; fi # module was not loaded

	set -- $line
	# $1: the original module, $2: size, $3: refcount, $4: deps list
	mods=`echo $4 | tr , ' '`
	# xpp_usb keeps the xpds below busy if an xpp hardware is
	# connected. Hence must be removed before them:
	case "$module" in xpd_*) mods="xpp_usb $mods";; esac
	for mod in $mods; do
		# run in a subshell, so it won't step over our vars:
		(unload_module $mod) 
		# TODO: the following is probably the error handling we want:
		# if [ $? != 0 ]; then return 1; fi
	done
	rmmod $module
}

usage() {
	me=`basename $0`
	echo "$me: Run Zaptel in a test environment"
	echo 'Version: $Id: live_zap 3851 2008-02-19 00:48:36Z tzafrir $'
	echo ''
	echo "Usage:           equivalent of:"
	echo "$me install    make install"
	echo "$me config     make config"
	echo "$me unload     /etc/init.d/zaptel stop"
	echo "$me load       /etc/init.d/zaptel start"
	echo "$me reload     /etc/init.d/zaptel restart"
	echo "$me rsync TARGET   (copies file to /tmp/live in TARGET)"
	echo "$me exec  COMMAND  (Runs COMMAND in 'live' environment)"
}

case "$1" in
install)
	shift
	make install DESTDIR=$DESTDIR DYNFS=yes "$@"
	;;
config)
	shift
	make config DESTDIR=$DESTDIR "$@"
	mkdir -p $DESTDIR/etc/asterisk
	;;
rsync)
	if [ $# -ne 2 ]; then
		echo >&2 "$0: Error: rsync requires a target parameter".
		exit 1
	fi
	# copy the script itself and the installed directory to the
	# target host:
	rsync -ai "$0" $DESTDIR "$2:/tmp/"
	;;
unload)
	$AST_SCRIPT stop
	for mod in $REMOVE_MODULES; do
		unload_module $mod
	done
	;;
load)
	# TODO: Find a way to use modprobe.
	# Or implement a way to pass arguments to modules here (yuck)
	for module in $MODULES_LOAD; do
		eval module_args="\$`basename ${module}`_ARGS"
		insmod $MODULES_DIR/$module.ko $module_args
	done
	xpp_startup
	ZAPTEL_BOOT_DEBIAN=$DESTDIR/live.conf \
	ZAPTEL_BOOT_FEDORA=$DESTDIR/live.conf \
	ZAPTEL_FILE=$DESTDIR/etc/zaptel.conf \
	ZAPATA_FILE=$DESTDIR/etc/asterisk/zapata-channels.conf \
		zapconf
	ztcfg -c $DESTDIR/etc/zaptel.conf
	# TODO: fxotune, hpec
	# or find a way to reuse init.d start sequence.

	# TODO: A local copy of Asterisk, configured with zapconf. 
	# doable, but trickier.
	$AST_SCRIPT start
	;;
reload)
	$0 unload
	$0 load
	;;
exec)
	if [ $# -lt 2 ]; then
		# No command given: start a subshell in the environemnt
		# of the "live" system:
		echo >&2 "$0: Error: exec requires a command to run"
		exit 1
	fi

	# Command given: run it:
	shift
	"$@"
	;;
help)
	usage
	;;
*)
	echo >&2 "$0: Error: incorrect command \"$1\". Aborting"
	usage
	exit 1
esac
