#!/bin/sh
#
# Copy modules into the right directories in preparation for building udebs.
# This script is named after the its counterpart in the original
# kernel-image-di package by Joey Hess <joeyh@debian.org>.
#
# Copyright (c) 2001-2002 Herbert Xu <herbert@debian.org>
#
# Usage: copy-modules version flavour installedname

set -e

deplist() {
	local deps=$1
	local list=$2
	
	cp $list $tmpdir/work

	# recursively append external dependencies to $list
	while :; do

		# list external dependencies of $work
		join -o 2.2 $tmpdir/work $deps | sort -u | comm -23 - $list \
			> $tmpdir/work.new
		mv $tmpdir/work.new $tmpdir/work

		# exit if work is empty
		[ -s $tmpdir/work ] || break
      
		# append work to $list
		sort -um -o $list $list $tmpdir/work
	done
}

processmodules() {
	local list=$1
	local moddir=$2
	
	cp $list $tmpdir/work
	(
		while read module; do
			# Question mark suffixed modules are optional.
			# Support dash prefixing for backwards compatibility.
			if [ "${module#-}" != "$module" ] || \
			   [ "${module% \?}" != "$module" ]; then
				optional=1
				module=${module% \?}
				module=${module#-}
			else
				optional=0
			fi

			module=${module##*/} # remove path info
			module=${module%.*}  # remove extension
			
			# Prefer modules in the kernel subdir, but failing
			# that search the whole thing, to find third-party,
			# etc modules.
			match="$(find `ls -d $moddir/kernel 2>/dev/null` $moddir \
			            -name $module.o -or -name $module.ko \
				| head -n 1 | sed "s!$moddir/!!")"
			
			if [ -n "$match" ]; then
				echo $match
			else
				if [ "$optional" = 0 ]; then
					echo "missing module $module" >&2
					exit 1
				fi
			fi
		done
	) < $tmpdir/work > $list.new || exit $?
	sort < $list.new > $list
	rm -f $list.new
}

version=$1-$2
flavour=$2
installedname=$3
arch=$(dpkg-architecture -qDEB_HOST_ARCH)
os=$(dpkg-architecture -qDEB_HOST_ARCH_OS)
home=$PWD

trap 'rm -rf $tmpdir' EXIT
tmpdir=$(tempfile)
rm $tmpdir
mkdir $tmpdir

# SOURCEDIR may be set externally to control where to copy from.
if [ -n "$SOURCEDIR" ]; then
	moddir=$SOURCEDIR/lib/modules/$installedname
else
	moddir=/lib/modules/$installedname
fi

if [ ! -d $moddir ]; then
	exit 0
fi
	
# The directory of modules lists to use.
if [ -d modules/$arch-$flavour ]; then
	modlistdir=modules/$arch-$flavour
elif [ -d modules/$flavour ]; then
	modlistdir=modules/$flavour
else
	modlistdir=modules/$arch
fi

if [ "$os" = "linux" ] ; then
	if [ ! -e "$moddir/modules.dep" ]; then
		echo "no $moddir/modules.dep. This file is required by kernel-wedge" >&2
		exit 1
	fi

	# get module dependencies from modules.dep
	# sort it by field 2
	perl -lne '
		@words=split(" ");
		s!'/lib/modules/$installedname'/!! foreach (@words);
		if ($words[0] =~ /:$/) {
			$words[0]=~s/:$//;
			$module=shift @words;
		}
		foreach (@words) {
			print "$module\t$_" unless $_ eq "\\";
		}
	' $moddir/modules.dep | sort -k 2,2 > $tmpdir/deps
	
	if [ ! -s $tmpdir/deps ] && [ ! -e $home/no-modules ]; then
		echo "No module interdependencies found. This probably means your modules.dep is broken." >&2
		echo "If this is intentional, touch $home/no-modules" >&2
		exit 1
	fi
fi

mkdir $tmpdir/module-deps $tmpdir/module-list

# generate module interrelationships from package-list file
kernel-wedge gen-deps $flavour > $tmpdir/module-deps.packages

# loop over all udebs, sort that all dependent modules are processed first
for i in $(
	{
		find $modlistdir -maxdepth 1 \( -type f -or -type l \) -not -name '*.lnk' -printf "%f\t%f\n"
		cat $tmpdir/module-deps.packages
	} | tsort | tac
); do
	# write dependent (direct and indirect) udebs to exclude
	# write dependencies to module-deps/$i
	echo $i | join -o 2.2 - $tmpdir/module-deps.packages | { # dependent modules
		cd $tmpdir/module-deps
		xargs -r sh -c 'printf "%s\n" "$@"; cat "$@"' sh # direct and indirect deps
	} | sort -u | tee $tmpdir/module-deps/$i | {	# write deps
		cd $tmpdir/module-list
		xargs -r cat
	} | sort -u > $tmpdir/exclude			# modules to exclude
	
	# preprocess file, handle includes and excludes and sort so that
	# the joins work, no matter what the order of the input.
	kernel-wedge preprocess $home/$modlistdir/$i | sort > $tmpdir/module-list/$i

	# exclude modules in exclude from dependency list
	join -2 2 -v 2 $tmpdir/exclude $tmpdir/deps |
		sort -k 1,1 > $tmpdir/tmpdeps

	# deal with modules marked as optional and other transformations
	processmodules $tmpdir/module-list/$i $moddir

	# include dependent modules which are not in a
	# dependent udeb into module-list/$i
	deplist $tmpdir/tmpdeps $tmpdir/module-list/$i

	if [ -s $tmpdir/module-list/$i ] && dh_listpackages | grep -qx "$i-$version-di"; then
		# copy kernel modules to package build dir
		cd $moddir
		ret=$( ( (
			set +e
			tar cfT - $tmpdir/module-list/$i
			printf $? >&3
		) | (
			set +e
			dir=$home/debian/$i-$version-di/lib/modules/$installedname
			mkdir -p $dir
			cd $dir
			tar xf -
			printf $? >&3
		) ) 3>&1)
		if [ "$ret" != "00" ]; then
			echo "tar failed" >&2
			exit $ret
		fi
		cd $home
	fi
done
