#!/bin/sh
#
# xfertest -- test transfer speeds of ftp, samba and rcp.
#
Program='Samba'
Verbose=0
Filesize=0
Debug=0
#JUNK='2>&1' # make output appear for debugging.
JUNK='>/dev/null 2>&1'


main() {
	while [ "$1" != "" ]; do
		case "$1" in
		-s)	Program='Samba';;
		-f)	Program='Ftp';;
		-r)	Program='Rcp';;
		-n)	Program='Nfs';;
		-v)	Verbose=1;;
		-d)	Debug=1; Verbose=1;;
		*)	break;;
		esac
		shift
	done
	if [ $# -lt 2 ]; then
		say "xfertest: you must provide a host and a test file."
		say "Usage: $0 [-sfr -v] host file"
		exit 1
	fi


	host="$1"
	file="$2"

	if [ ! -f "$file" ]; then
		say "$0: $file not found, halting."
		exit 1
	else
		Filesize=`ls -l $file | awk '{print $5}'`
	fi
	cp $file /tmp
	cd /tmp
	$Program $host $file
}

#
# Rcp -- time Remote CoPy
#
Rcp() {
	host="$1"
	file="$2"

	if [ "$Verbose" -eq 1 ]; then
		say "benchmarking rcp on $host with file $file"
		say "getting $file 5 times"
	fi
	rcp $host:$file . # Prime the pump
	for i in 1 2 3 4 5; do
		time rcp $host:$file .
	done 2>&1 | timeStats "rcp get $Filesize"

	if [ "$Verbose" -eq 1 ]; then
		say "putting $file 5 times"
	fi
	f=`basename $file`
	rcp $f $host:$file 
 
	for i in 1 2 3 4 5; do
		time rcp $f $host:$file
	done 2>&1 | timeStats "rcp put $Filesize"
}



#
# Nfs -- time nfs via timing cp. "host" will be ignored.
#
Nfs() {
	host="$1"
	file="$2"

	if [ "$file" != "" ]; then
		:
	else
		say "you must supply a host (which is then ingored)"
		exit 1
	fi

	if [ "$Verbose" -eq 1 ]; then
		say "benchmarking nfs (cp) on $host with file $file"
		say "getting $file 5 times"
	fi
	cp $file . # Prime the pump
	for i in 1 2 3 4 5; do
		time cp $file ./junk
	done 2>&1 | timeStats "nfs get $Filesize"

	if [ "$Verbose" -eq 1 ]; then
		say "putting $file 5 times"
	fi
	f=`basename $file`
	cp $f $file 
 
	for i in 1 2 3 4 5; do
		time cp $f $file
	done 2>&1 | timeStats "nfs put $Filesize"
}


#
# timeStats -- summarize stats from /bin/time, used for nfs/cp and rcp
#
timeStats() {
	nawk '
	BEGIN {
		avg=0.0;
	}
	/.*/ { 
		if (debug) {
			print "#", $0; 
		}
	}

	/real/ {
		avg += $2;
		if (verbose) {
			print $2;
		}
		next;
	}
	/user|sys|^[ 	]*$/ {
		next;
	}
	/.*/ {
		print $0;
	}
	END {
		if (verbose) {
			print "#pg op  size time kb/sec";
		}
		if (avg == 0.0 ) {
			printf("%s 0.0 N/A\n",description);
		}
		else {
			time = avg / 5;
			printf("%s %.2f %.2f\n",description,\
				 time, (size/time) /1000);
		}
	}
' description="$1" verbose=$Verbose size=$Filesize debug=$Debug
}


#
# ftp -- time File Transfer Program
#
Ftp() {
	host="$1"
	file="$2"

	if [ "$Verbose" -eq 1 ]; then
		say "benchmarking ftp on $host with file $file"
	fi
	say "Warning: this will temporarily overwrite your .netrc password"
	say "$0: enter password to use for ftp"
	read password

	trap '' 1 2 3 4 5 6 7 8 9 # Disable ^C et all.
	if [ -f $HOME/.netrc ]; then
		mv $HOME/.netrc $HOME/saved.netrc
	fi
	cat >$HOME/.netrc <<!
machine $host
login `whoami`
password $password
!
	chmod 700 $HOME/.netrc

	if [ "$Verbose" -eq 1 ]; then
		say "getting $file 5 times"
	fi
	# Prime the punp.
	ftp $host >/dev/null 2>&1 <<!
get $file junk
quit
!

	# Do the test
	ftp -v $host >/tmp/$$ 2>&1 <<!
get $file junk
get $file junk
get $file junk
get $file junk
get $file junk
quit
!
	cat /tmp/$$ | timeFtp "ftp get $Filesize"
	rm /tmp/$$

	if [ "$Verbose" -eq 1 ]; then
		say "putting $file 5 times"
	fi
	# Prime
	ftp $host >/dev/null 2>&1 <<!
put $file junk
quit
!

	# Test
ftp -v $host >/tmp/$$ 2>&1 <<!
put $file junk
put $file junk
put $file junk
put $file junk
put $file junk
quit
!
	cat /tmp/$$ | timeFtp "ftp put $Filesize"
	rm /tmp/$$

	rm $HOME/.netrc
	if [ -f $HOME/saved.netrc ]; then
		mv $HOME/saved.netrc $HOME/.netrc
	fi

}

#
# timeFtp 
#
timeFtp() {

	nawk '
	BEGIN {
		avg = 0.0;
	}
	/.*/ { 
		if (debug) {
			print "#", $0; 
		}
	}
	/.* bytes .* in/ {
		avg += $5
		if (verbose) {
			print $0;
		}
		next;
	}
	/[0-9]*/ {
		next;
	}
	/.*/ {
		print $0;
	}
	END {
		if (verbose) {
			print "#pg op  size time kb/sec";
		}
		if (avg == 0.0 ) {
			printf("%s 0.0 N/A\n",description);
		}
		else {
			time = avg / 5;
			printf("%s %.2f %.2f\n",description, time, (size/time) /1000);
		}
	}
' description="$1" verbose=$Verbose size=$Filesize  debug=$Debug
}


#
# Samba -- time Smbclient get/put, "host" parameter must be a service,
#	"file" a file relative to it
#
Samba() {
	host="$1"
	file="$2"

	if [ "$Verbose" -eq 1 ]; then
		say "benchmarking Samba's smbclient on $host with file $file"
	fi
	say "$0: enter password to use for samba"
	read password

	trap '' 1 2 3 4 5 6 7 8 9 # Disable ^C et all.
	if [ "$Verbose" -eq 1 ]; then
		say "getting $file 5 times"
	fi
	smbclient $host $password  >/dev/null 2>&1 <<!
get $file junk
quit
!
	smbclient $host $password >/tmp/$$ 2>&1 <<!
get $file junk
get $file junk
get $file junk
get $file junk
get $file junk
quit
!
	cat /tmp/$$ | timeSamba "smb get $Filesize"
	rm /tmp/$$

	if [ "$Verbose" -eq 1 ]; then
		say "putting $file 5 times"
	fi
	smbclient $host $password  >/dev/null 2>&1 <<!
put $file junk
quit
!

	smbclient $host $password >/tmp/$$ 2>&1 <<!
put $file junk
put $file junk
put $file junk
put $file junk
put $file junk
quit
!

	cat /tmp/$$ | timeSamba "smb put $Filesize"
	rm /tmp/$$

}

#
# timeSamba -- summarize stats from Samba
#
timeSamba() {
	nawk '
	BEGIN {
		avg=0.0;
	}
	/.*/ { 
		if (debug) {
			print "#", $0; 
		}
	}
	/^\(/ {
		sub("[(]", "", $1);
		avg += size/($1*1000)
		if (verbose) {
			print size/($1*1000), "sec, ", $1, "kb/sec";
		}
		next;
	}
	/^putting/ {
		sub("[(]", "", $10);
		avg += size/($10*1000)
                if (verbose) {
                        print size/($10*1000), "sec, ", $10, "kb/sec";
                }
                next;
	}		
	END {
		if (verbose) {
			print "#pg op  size time kb/sec";
		}
		if (avg == 0.0 ) {
			printf("%s 0.0 N/A\n",description);
		}
		else {
			time = avg / 5;
			printf("%s %.2f %.2f\n",description, time, (size/time) /1000);
		}
	}
' description="$1" verbose=$Verbose size=$Filesize  debug=$Debug
}


	
say() {
	echo "$*" 1>&2
}

main "$@"

