#!/bin/sh

__path=`dirname $0`
bt_load=$__path/__bt_load
bt_read=$__path/__bt_read
bt_disym=$__path/__bt_disym
module_dir=$__path/../module
relfs_mod=$module_dir/relayfs.module-2.6.14.3/relayfs.ko
djprobe_mod=$module_dir/djprobe-20060125/mod_djprobe.ko
on_off_mod=$module_dir/bt_on_off_mod.ko

usage() {
	local cmd
	cmd=`basename $0`
cat << EOF
$cmd [option] [-p pid ...] [-m mnt_dir] -d log_dir
    mnt_dir: relayfs mount directory (default: /mnt/relay)
    log_dir: log write directory
    option is described below
      -S bts_size:       BTS buffer size
      -s size:           buffer size
      -n number:         buffer number
      -N number:         target process sleep threshold of relayfs buffers
      --start symbol:    log collection start symbol
      --stop  symbol:    log collection stop symbol
      --START addr,size: log collection start address and size
      --STOP  addr,size: log collection stop address and size
                         (only one can be specified either --start or --stop)
EOF
}

terminate() {
	cat /proc/modules|grep '^bt_on_off_mod' > /dev/null
	if [ $? -eq 0 ]; then
		rmmod bt_on_off_mod
	fi
	cat /proc/modules|grep '^bt_mod' > /dev/null
	if [ $? -eq 0 ]; then
		rmmod bt_mod
	fi
	cat /proc/modules|grep '^relayfs' > /dev/null
	if [ $? -eq 0 ]; then
		umount $1
		rmmod relayfs
	fi
	cat /proc/modules|grep '^mod_djprobe' > /dev/null
	if [ $? -eq 0 ]; then
		rmmod mod_djprobe
	fi
}

wait_for_all_cpus_full() {
	proc_dir=/proc/bts
	n_subbufs=`cat /proc/bts/n_subbufs`
	n_subbufs=`expr $n_subbufs - 1`
	buff_full_cpus=0
	cpus=`ls /proc/bts/cpu*.produced|wc -l`
	while [ $buff_full_cpus -ne $cpus ]; do
		buff_full_cpus=0
		for produced in /proc/bts/cpu*.produced; do
			if [ `od -A n -l $produced` -eq $n_subbufs ]; then
				buff_full_cpus=`expr $buff_full_cpus + 1`
			fi
		done
		sleep 1
	done
}

wait_for_bts_disable() {
	while [ `cat /proc/bts/enable` -eq 1 ]; do
		sleep 1
	done
}

chk_next() {
	if [ $# -lt 2 ]; then
		usage
		exit 1
	fi
}

parse_addr_and_size() {
	echo $2|grep ',' > /dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo ""
		return
	fi
	addr=`echo "${2%%,*}"`
	size=`echo "${2##*,}"`
	if [ "$addr" = "" ] || [ "$size" = "" ]; then
		echo ""
	else
		printf "%s_addr=%s %s_size=%s" $1 $addr $1 $size
	fi
}

#-------- check parameters --------
logdir=""
pids=""
mod_param=""
relay_mnt_point=/mnt/relay
start=""
stop=""

while [ $# -gt 0 ]; do
	case $1 in
	-p)
		shift
		while [ $# -gt 0 ] && [ `echo $1|cut -c1` != "-" ]; do
			pids=`echo $pids $1`
			shift
		done
		continue
		;;
	-m)
		chk_next $*
		relay_mnt_point=$2
		;;
	-d)
		chk_next $*
		logdir=$2
		;;
	-S)
		chk_next $*
		mod_param=`echo $mod_param btsbuf_size=$2`
		;;
	-s)
		chk_next $*
		mod_param=`echo $mod_param subbuf_size=$2`
		;;
	-n)
		chk_next $*
		mod_param=`echo $mod_param subbuf_num=$2`
		;;
	-N)
		chk_next $*
		mod_param=`echo $mod_param subbuf_sleep_threshold=$2`
		;;
	--start)
		chk_next $*
		start=`$bt_disym on $2`
		if [ "$start" = "" ]; then
			echo "symbol '$2' not found"
			exit 1
		fi
		mod_param=`echo $mod_param do_not_overwrite=1`
		;;
	--stop)
		chk_next $*
		stop=`$bt_disym off $2`
		if [ "$stop" = "" ]; then
			echo "symbol '$2' not found"
			exit 1
		fi
		;;
	--START)
		chk_next $*
		start=`parse_addr_and_size "on" $2`
		if [ "$start" = "" ]; then
			echo "'$2' format error"
			exit 1
		fi
		mod_param=`echo $mod_param do_not_overwrite=1`
		;;
	--STOP)
		chk_next $*
		stop=`parse_addr_and_size "off" $2`
		if [ "$stop" = "" ]; then
			echo "'$2' format error"
			exit 1
		fi
		;;
	*)
		usage
		exit 1
	esac
	shift 2
done
if [ "$logdir" = "" ] || ([ "$start" ] && [ "$stop" ]); then
	usage
	exit 1
fi
#echo logdir $logdir
#echo pids $pids

#-------- check module and proc file existance --------
if [ ! -f $relfs_mod ]; then
	echo "relayfs module not found"
	exit 1
fi
if [ ! -d $relay_mnt_point ]; then
	echo "relayfs mount point" $relay_mnt_point "is not directory"
	exit 1
fi
if [ ! -f $djprobe_mod ]; then
	echo "djprobe module not found"
	exit 1
fi
if ([ "$start" ] || [ "$stop" ]) && [ ! -f $on_off_mod ]; then
	echo "btrax on/off module not found"
	exit 1
fi
if [ ! -f /proc/modules ]; then
	echo "/proc/modules not found"
	exit 1
fi
if [ ! -f /proc/kallsyms ]; then
	echo "/proc/kallsyms not found"
	exit 1
fi

#-------- load module --------
insmod $relfs_mod
mount -t relayfs relayfs $relay_mnt_point
insmod $djprobe_mod
$bt_load $mod_param
if [ $? -ne 0 ]; then
	terminate $relay_mnt_point
	exit 1
fi

#-------- copy maps/modules files --------
mkdir -p $logdir
cp /proc/modules $logdir/modules
cp /proc/kallsyms $logdir/kallsyms
if [ "$pids" != "" ]; then
	echo "$pids" | sed -e 's/ /,/g' > /proc/bts/pid
	for pid in $pids; do
		cp /proc/$pid/maps $logdir/$pid.maps
	done
fi

#-------- ready for user-termination --------
trap '
	echo 0 > /proc/bts/enable
	sync; sync; sync
	# kill $kill_pid
	cp /proc/bts/dropped $logdir/dropped
	terminate $relay_mnt_point
	exit 0
' HUP INT QUIT TERM

#-------- start log collect --------
if [ "$start" ]; then
	insmod $on_off_mod $start
	wait_for_all_cpus_full
	echo 0 > /proc/bts/enable
	$bt_read $relay_mnt_point/bts $logdir &
	wait $!
	cp /proc/bts/dropped $logdir/dropped
	terminate $relay_mnt_point
elif [ "$stop" ]; then
	insmod $on_off_mod $stop
	echo 1 > /proc/bts/enable
	wait_for_bts_disable
	$bt_read $relay_mnt_point/bts $logdir &
	wait $!
	cp /proc/bts/dropped $logdir/dropped
	terminate $relay_mnt_point
else
	$bt_read $relay_mnt_point/bts $logdir &
	kill_pid=$!
	sleep 1
	ps aux|grep $kill_pid|grep -v 'grep' > /dev/null
	if [ $? -ne 0 ]; then
		terminate $relay_mnt_point
		exit 1
	fi
	echo 1 > /proc/bts/enable
	while : ; do
		sleep 1
	done
fi
exit 0
