#!/bin/sh

# Unload unused modules after a modprobe run

set -e

# policy
#  minimal - cleanup modules we loaded, but only if modprobe failed
#            (i.e., dependencies of the failed module)
#  restricted - only cleanup modules we loaded
#  aggressive - try and remove all unused modules - use with caution,
#               this could very well remove drivers for in-use devices

policy="minimal"
modprobe=/sbin/modprobe

is_cleanable() {
	mod=$1

	if [ "$policy" = "aggressive" ]; then
		return 0
	elif [ -f /tmp/modules.$$ ] && ! grep -q "^${mod} " /tmp/modules.$$; then
		return 0
	fi

	return 1
}


if [ -f /proc/modules ]; then
	cp /proc/modules /tmp/modules.$$
fi

if ! $modprobe $* || [ "$policy" = "aggressive" ] || \
   [ "$policy" = "restricted" ]; 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"
		while read mod size refcount tail; do
			mod=$(printf "$mod" | tr '-' '_')
			if is_cleanable $mod && [ "$refcount" = "0" ]; then
				modprobe -r $mod || /bin/true
				# /proc/modules was altered; need to re-read
				progressing="true"
				safety=$(expr $safety + 1)
				break
			fi
		done < /proc/modules ## should we process a static copy instead?
	done
fi

rm -f /tmp/modules.$$
