Blob Blame History Raw
#!/bin/bash
# 
# given a Module.base and modules.dep, generate list
# of base / supported / unsupported modules

set -e
export LC_COLLATE=C

usage()
{
	echo "Usage: ${0##*/} -b Module.base [-d dir] [-i] [-e] [-o outdir]"
	echo "  -i    Ignore supported.conf errors"
	echo "  -e    Create the -extra filelist (otherwise, treat all modules as supported)"
}

options=$(getopt -o b:d:o:ie -- "$@")
if test $? -ne 0; then
	usage >&2
	exit 1
fi
eval set -- "$options"
opt_builddir=
opt_out=.
opt_dir=.
opt_ignore_errors=false
opt_extra=false
while test $# -gt 0; do
	opt=$1
	shift
	case "$opt" in
	-b | -d | -o)
		arg=$1
		shift
	esac
	case "$opt" in
	-b)
		opt_builddir=$arg ;;
	-d)
		opt_dir=$arg ;;
	-o)
		opt_out=$arg ;;
	-i)
		opt_ignore_errors=true ;;
	-e)
		opt_extra=true ;;
	--)
		break ;;
	*)
		echo "Unknown option $opt" >&2
		exit 1
	esac
done
if test -z "$opt_builddir"; then
	usage >&2
	exit 1
fi

trap 'rm -rf "$tmp"' EXIT
tmp=$(mktemp -d)
mkdir "$tmp/empty"

find "$opt_dir" -type f -name '*.ko' -printf '/%P\n' | \
	awk -F/ '{ n=$NF; gsub(/-/, "_", n); sub(/\.ko$/, "", n); print n " " $0; }' | \
	sort >"$tmp/all"

err=false
while read mod path; do
	if $opt_extra; then
		support=$(/sbin/modinfo -F supported "$opt_dir/$path")
	else
		support=yes
	fi
	case "$support" in
	yes | external)
		echo "$mod"
		;;
	no)
		;;
	"")
		echo "warning: ${path#/lib/modules/*/kernel/} not listed in supported.conf" >&2
		;;
	*)
		echo "error: invalid support flag for $mod: $support" >&2
		err=true
		;;
	esac
done <"$tmp/all" | sort -u >"$tmp/supp"
if $err; then
	exit 1
fi

modules_dep=$(find "$opt_dir" -type f -name modules.dep)
if test -z "$modules_dep"; then
	echo "Cannot find modules.dep in $opt_dir" >&2
	exit 1
fi
(
	echo '%:
	@echo $@
ifdef EXPLAIN
	@for dep in $^; do echo "$$dep needed by $@"; done >> $(EXPLAIN)
endif
'
	sed -r 's:[^ ]*/([^/]*)\.ko\>:\1:g; y/-/_/' "$modules_dep"
) >"$tmp/dep"

add_dependent_modules()
{
	xargs -r make EXPLAIN=$1 -rRs -C "$tmp/empty" -f "$tmp/dep" | sort -u
}

# base
sed 'y/-/_/' <"$opt_builddir/Module.base" | add_dependent_modules >"$tmp/base"
join -j 1 -o 2.2 "$tmp/base" "$tmp/all" >"$opt_out/base-modules"

# base firmware
kver=$(make -s -C "$opt_builddir" kernelrelease)
if test -d "$opt_dir/lib/firmware/$kver"; then
	join <(/sbin/modinfo -F firmware \
		$(sed "s:^:$opt_dir:" "$opt_out/base-modules") | sort) \
	     <(find "$opt_dir/lib/firmware/$kver" -type f -printf '%P\n' | sort)
fi | sed "s:^:/lib/firmware/$kver/:" >"$opt_out/base-firmware"

# kmps
for f in "$opt_builddir"/Module.*-kmp; do
	kmp=${f##*/Module.}
	sed 'y/-/_/' <"$f" >"$tmp/$kmp"
	join -j 1 -o 2.2 "$tmp/$kmp" "$tmp/all" >"$opt_out/$kmp-modules"
	cat "$tmp/$kmp"
done | sort -u >"$tmp/kmp-all"
join -v1 "$tmp/supp" "$tmp/kmp-all" >"$tmp/supp-main"

# main
add_dependent_modules "$tmp/supp-explain" <"$tmp/supp-main" >"$tmp/supp-all"
if ! cmp -s "$tmp/supp-main" "$tmp/supp-all"; then
	# FIXME: Error message not accurate if a supported KMP module is
	# needed by a module in the main package
	echo "The following unsupported modules are used by supported modules:" >&2
	join -j1 -a2 <(sort "$tmp/supp-explain") \
		 <(join -v2 "$tmp/supp-main" "$tmp/supp-all") >&2
	echo "Please fix supported.conf." >&2
	if ! $opt_ignore_errors; then
		exit 1
	fi
fi
join -j 1 -o 2.2 "$tmp/supp-all" "$tmp/all" >"$opt_out/main-modules"

# unsupported
join -j 1 -v 2 -o 2.2 <(sort -u "$tmp/supp-all" "$tmp/kmp-all") "$tmp/all" >"$opt_out/unsupported-modules"

exit 0