#! /bin/sh -e
#
# Set the XFS project quotas on specified directories
#
# Only directories without projects in /etc/projects and /etc/projid are set,
# existing project assignments and quotas are not touched.
#
# After removing from /etc/projects and /etc/projid, this script will set again
# the project assignments and quota.
#
# Check result:
#
# xfs_quota -xc 'report -ph'
#
# Check individual file project assignment (replace $DIR by path):
#
# xfs_io -c lsproj $DIR
#
# Clear project assignment (replace $DIR_OR_ID by project name or ID):
#
# xfs_quota -xc "project -C $DIR_OR_ID" /exports
# vim /etc/projects /etc/projid
#

PROG="$0"
SOFT=1024M
HARD=1152M
DISK_MOUNTPOINT=/exports
TARGET_PATH=/exports

usage() {
	cat << EOF
$PROG [OPTIONS]
OPTIONS are:
  -h,--help
  -n,--dry-run
  -i,--include REGEXP
  -e,--exclude REGEXP
  -s,--soft-quota QUOTA (default $SOFT)
  -q,--hard-quota QUOTA (default $HARD)
EOF
	return 0
}


TEMP=$(getopt -o 'i:e:s:q:hn' --long 'include:,exclude:,soft-quota:,hard-quota:,help,dry-run' -n 'xfs-quotas.sh' -- "$@") || exit $?
eval set -- "$TEMP"
unset TEMP

soft="$SOFT"
hard="$HARD"

truncate -s 0 /tmp/quota.list
while true; do
	case "$1" in
		-h|--help)
			usage
			shift
			exit 0
			;;
		-s|--soft-quota)
			soft="$2"
			shift 2
			continue
			;;
		-q|--hard-quota)
			hard="$2"
			shift 2
			continue
			;;
		-e|--exclude)
			grep -v "$2" /tmp/quota.list > /tmp/quota.list2
			mv /tmp/quota.list2 /tmp/quota.list
			shift 2
			continue
			;;
		-i|--include)
			find $TARGET_PATH -mindepth 1 -maxdepth 1 -type d | grep "$2" >> /tmp/quota.list
			shift 2
			continue
			;;
		-n|--dry-run)
			dry_run=1
			shift
			continue
			;;
		--)
			shift
			break
			;;
		*)
			usage
			exit 1
			;;
	esac
done

test -f /etc/projects || touch /etc/projects
test -f /etc/projid || touch /etc/projid

# all specified directories
sort /tmp/quota.list | uniq > /tmp/quota.list2
mv /tmp/quota.list2 /tmp/quota.list

# directories with quota
cut -d: -f1 /etc/projid 2>/dev/null | sort | uniq > /tmp/quota.xfs.list

lastid=0
lastid="$( (maxid=0; IFS=:; while read -r dir id; do if test "$id" -gt "$maxid"; then maxid="$id"; fi; done; echo "$maxid") < /etc/projid )"
cat <<EOF > /tmp/quota-cmd.sh
#! /bin/sh -e
cp -p /etc/projects /etc/projects.new
cp -p /etc/projid /etc/projid.new

EOF
diff /tmp/quota.list /tmp/quota.xfs.list | grep '^< ' | while read -r _ dir; do
	lastid=$((lastid+1))
	id="$lastid"
	cat <<EOF >> /tmp/quota-cmd.sh
echo "$id:$dir" >> /etc/projects.new
echo "$dir:$id" >> /etc/projid.new
xfs_quota -x -D /etc/projects.new -P /etc/projid.new -c "project -s $dir" $DISK_MOUNTPOINT >/dev/null
xfs_quota -x  -D /etc/projects.new -P /etc/projid.new -c "limit -p bsoft=$soft bhard=$hard $dir" $DISK_MOUNTPOINT

EOF
done
cat <<EOF >>/tmp/quota-cmd.sh
mv /etc/projects.new /etc/projects
mv /etc/projid.new /etc/projid
EOF

if test -z "$dry_run"; then
	sh -e /tmp/quota-cmd.sh
else
	cat /tmp/quota-cmd.sh
fi

rm -f /tmp/quota-cmd.sh /tmp/quota.list /tmp/quota.list2 /tmp/quota.xfs.list
