#!/bin/sh
DIRS="foo foo-bound foo-bound-ro"
set -e

function do_umount
{
	echo -n unmounting...
	(
	 umount foo || true;
	 umount foo-bound || true;
	 umount foo-bound-ro || true;
	) 2> /dev/null
	echo done
	true
}

trap do_umount ERR
trap do_umount INT

# just in case the last invocation left them
do_umount

function should_fail
{
	eval "$@" > /dev/null 2>&1 \
	&& ( echo  BAD: unexpected success: "$@" ; false) \
	|| echo GOOD: expected failure: "$@";
}
function should_succeed
{
	eval "$@" > /dev/null 2>&1 2>&1 \
	&& echo GOOD: expected success: "$@" \
	|| ( echo \ BAD: unexpected failure: "$@"; false)
}
function should_fail_ro
{
	RO=$1
	shift
	if $RO; then
		should_fail "$@"
	else
		should_succeed "$@"
	fi
}
function testdir
{
	RO=$1
	shift;
	i=$1
	should_fail_ro $RO touch $i/$i-file
	should_fail_ro $RO echo foo '>' $i/$i-file
	should_fail_ro $RO echo foo '>>' $i/$i-file
	should_fail_ro $RO mkdir $i/$i-dir
	should_fail_ro $RO mknod $i/$i-null-chardev c 1 3 
	should_fail_ro $RO chmod 777 $i/$i-null-chardev
	chattrs $RO $i
}
function getattr
{
	lsattr -d -v "$1" | awk '{print $1, $2}'
}
function attr_changed
{
	[ "$2" != "$3" ]
}
CHECK_XATTRS=true;
function chattrs
{
	$CHECK_XATTRS || return 0
	RO="$1"
	file="$2"
	# chattr exits with a 0 code if the files
	# don't exist, so don't even bother running
	if ! [ -e "$file" ]; then
		return
	fi
	ORIG_ATTR="$(getattr "$file")"
	if [ -z "$ORIG_ATTR" ]; then
		echo invalid attributes: "'$ORIG_ATTR'"
		exit 1;
	fi
	( chattr -v 4 $file;
	  chattr +ADdiS $file ) > /dev/null 2>&1
	 # xfs does not support all of these:
	 # chattr +ADdijsSu $file ) > /dev/null 2>&1

	NEW_ATTR="$(getattr "$file")"
	should_fail_ro $RO attr_changed $file "'$ORIG_ATTR'" "'$NEW_ATTR'"
	chattr = $file > /dev/null 2>&1
}
			
for i in $DIRS; do
	rm -r ./$i > /dev/null 2>&1 || true
	mkdir -p $i;
done;

if [ -z "$*" ]; then
	FSTYPES="ext3"
else
	FSTYPES="$*"
fi
for fstype in $FSTYPES; do
	image=$fstype.img
	#echo creating image: $image...
	#dd if=/dev/zero of=$image bs=$((1<<20)) count=32 2>&1 | grep transferred
	OPTS="-F"
	MOUNT_OPTS="-o loop"
	MKFS="true"
	if [ "$fstype" == "reiserfs" ]; then
		OPTS="-f --journal-size 513 -q"
		MOUNT_OPTS="$MOUNT_OPTS,rw,noatime,nodiratime,user_xattr,attrs"
	elif [ "$fstype" == "jfs" ]; then
		OPTS="-f"
	elif [ "$fstype" == "ramfs" ]; then
		MKFS="false"
		OPTS=""
	elif [ "$fstype" == "nfs" ]; then
		MKFS="false"
		OPTS=""
		image="localhost:/home"
		MOUNT_OPTS=""
		CHECK_XATTRS=false;
	elif [ "$fstype" == "xfs" ]; then
		OPTS=""
	fi
	if $MKFS; then
		echo -n creating $fstype fs in image: $image...
		mkfs.$fstype $OPTS $image > /dev/null 2>&1
		echo done "($?)"
	fi
	echo mount -t $fstype $MOUNT_OPTS $image foo
	mount -t $fstype $MOUNT_OPTS $image foo

	mount --bind foo foo-bound/	 || exit
	mount --bind foo foo-bound-ro	 || exit
	mount -o remount,ro foo-bound-ro || exit

	testdir false foo
	testdir false foo-bound
	testdir true  foo-bound-ro
	if false; then
	should_succeed echo foo > foo-bound/foo-null-chardev
	should_succeed echo foo > foo-bound-ro/foo-null-chardev
	should_succeed echo foo >> foo-bound/foo-null-chardev
	should_succeed echo foo >> foo-bound-ro/foo-null-chardev

	for i in foo-bound-ro/foo-dir \
		 foo-bound-ro/foo-file ;
	do
		should_fail chmod 777 $i
		should_fail chown nobody $i
		should_succeed ls $i
		should_succeed cat $i \> /dev/null
		chattrs true $i
	done
	should_fail rmdir foo-bound-ro/foo-dir
	fi
	should_succeed mount -o remount,ro foo-bound/
	should_succeed umount foo-bound
	should_succeed umount foo-bound-ro
	should_succeed umount foo
done
