#!/bin/sh

set -eu

MYNAME=${0##*/}

usage() {
	echo "Usage: $MYNAME [ -u | --unused SECTORS ] MOUNT-POINT"
}

help() {
	usage
	cat << EOF

Resizes the ext2/3/4 file-system at the specified MOUNT-POINT to the size of
the underlying block device, optionally leaving the specified number of
512-byte sectors unused at the end of the device. This is intended to make
later encapsulation of the file-system in LUKS easier to manage.

Typically this tool must be run as root.
EOF
}

main() {
	if ! parsed_args=$(getopt -n "$MYNAME" -o hu: --long help,unused: -- "$@"); then
		usage
		exit 1
	fi

	unused=0
	eval set -- "$parsed_args"
	while :; do
		case "$1" in
			-s | --unused)
				unused="$2"
				shift 2
				;;
			-h | --help)
				help
				exit 0
				;;
			--)
				shift
				break
				;;
			*)
				echo "Internal error: $1 unknown" >&2
				exit 63
				;;
		esac
	done
	if [ "$#" -ne 1 ]; then
		usage
		exit 1
	fi

	mount_point="$1"
	fstype=$(findmnt --output FSTYPE --noheadings "$mount_point")
	case "$fstype" in
		ext2|ext3|ext4)
			device=$(findmnt --output SOURCE --noheadings "$mount_point")
			device_size=$(blockdev --getsz "$device") # 512-byte sectors
			new_fs_size=$((device_size - unused))

			# dumpe2fs is required here as the "SIZE" reported by
			# findmnt is the total size of the file-system as
			# reported by the file-system driver. This excludes
			# blocks used by the file-system itself and hence isn't
			# accurate for our purposes
			fs_block_size=$(dumpe2fs -h "$device" 2>/dev/null | \
				awk -F: '/^Block size:/ {print $2}')
			old_fs_size=$(dumpe2fs -h "$device" 2>/dev/null | \
				awk -F: '/^Block count:/ {print $2}')
			# Convert from blocks to 512-byte sectors
			old_fs_size=$((old_fs_size * fs_block_size / 512))

			if [ "$old_fs_size" -lt "$new_fs_size" ]; then
				resize2fs "$device" "$new_fs_size"s
			else
				echo "Current fs size is at least requested size (already expanded?)" >&2
				exit 1
			fi
			;;
		*)
			echo "Specified mount is not an ext file-system" >&2
			exit 1
			;;
	esac
}

main "$@"
