#!/bin/sh

# If a module fails to load, it may leave unused dependencies around.
# This wrapper attempts to clean up those orphans, reclaiming memory

set -e

modprobe=/sbin/modprobe
statefile=/tmp/modules.$$

save_state() {
	rm -f $statefile
	if [ -f /proc/modules ]; then
		cp /proc/modules $statefile
	fi
}

is_cleanable() {
	mod=$1

	if [ -f $statefile ] && ! grep -q "^${mod} " $statefile; then
		return 0
	fi

	return 1
}

clean() {
	if [ ! -f $statefile ]; then
		return 0
	fi

	while read mod size refcount tail; do
		if is_cleanable $mod && [ "$refcount" = "0" ]; then
			modprobe -r $mod || continue
			# /proc/modules was altered; need to restart
			return 0
		fi
	done < /proc/modules ## should we process a static copy instead?
	# nothing left to remove
	return 1
}

save_state

if ! $modprobe $*; then
	safety=0 # just in case we get stuck in an infinite loop somehow
	progressing=true
	while [ "$progressing" = "true" ] && [ $safety -lt 10 ]; do
		progressing="false"
		safety=$(expr $safety + 1)
		if clean; then
			progressing="true"
		fi
	done
fi

rm -f $statefile
