#!/bin/sh -e

Info()
{
	printf >&2 %s\\n "${0##*/}: $*"
}

Fatal()
{
	Info "$@"
	exit 1
}

#parse command line options
TEMP=`getopt -n "$0" -o k:,o:,p:,r: -l kernel:,output:,pattern:,root: -- "$@"` || exit 1
eval set -- "$TEMP"

kernel=
output=
pattern=
root=.

while :; do
	case "$1" in
		-k|--kernel-version)
			shift
			kernel="$1"
			;;
		-o|--output)
			shift
			output="$1"
			;;
		-p|--pattern*)
			shift
			pattern="$1"
			;;
		-r|--root)
			shift
			root="$1"
			;;
		--) shift; break
			;;
		*) Fatal "Unrecognized option: $1"
			;;
	esac
	shift
done

[ -n "$output" ] || Fatal 'Mandatory --output= option not specified.'
[ -n "$pattern" ] || Fatal 'Mandatory --pattern= option not specified.'
[ -n "$kernel" ] || kernel=`uname -r`

exit_handler()
{
	local rc=$?
	trap - EXIT
	[ $rc -eq 0 ] ||
		rm -f -- "$output.mar" "$output.dep" "$output.map"
	exit $rc
}

trap exit_handler HUP PIPE INT TERM QUIT EXIT

modpath="$(readlink -ev "$root/lib/modules/$kernel")"
deps="$modpath/modules.dep"
pcimap="$modpath/modules.pcimap"

modules_list()
{
	local dep mod path

	> "$output.dep"
	find "$modpath/" -type f | grep -w -f "$pattern" |
	while read path; do
		printf %s\\n "$path"
		if grep -qw "${path##*$root}: " "$deps"; then
			mod="${path##*/}"
			mod="${mod%.*}"
			echo -n "$mod:" >> "$output.dep"
			for dep in `grep -w "${path##*$root}: " $deps | sed 's|^[^:]\+:||'`; do
				dep="$(readlink -ev "$root/$dep")"
				printf %s\\n "$dep"
				dep="${dep##*/}"
				dep="${dep%.*}"
				printf ' %s' "$dep" >> "$output.dep"
			done
			echo >> "$output.dep"
		fi
	done | sort -u
}

# Scan $pcimap for ids corresponding to given module.
# Inspired by ListPciModules() code from mkinitrd.
grep_pcimap()
{
	local sample="$1" && shift
	local PCI_ANY="0xffffffff"

	while read module vendor device ignored; do
		[ "$sample" = "$module" ] || continue

		# skip wildcards
		[ "$device" != "$PCI_ANY" -a "$vendor" != "$PCI_ANY" ] ||
			continue

		printf '0x%04x 0x%04x %s\n' "$vendor" "$device" "$module"
	done < "$pcimap"
}

make_modules_map()
{
	local mod list
	list="$(mar -l "$output.mar" |sed 's/^[[:space:]]\+\([^\.]\+\)\.ko$/\1/')"
	for mod in ${list}; do
		grep_pcimap "$mod"
	done > "$output.map"
}

mar -c "$output.mar" $(modules_list)
make_modules_map
