#!/bin/sh
#
# Find missing firmware files requested by the kernel, and install the
# binary packages with the files.  Fetch them the from the non-free section
# if that is needed.
#
# This script was copied from auto-addfirmware from the debian-edu-config
# package and extended here.

dist=$(lsb_release -cs)
if [ "n/a" = "$dist" ] ; then
    dist=testing
fi
arch=$(dpkg --print-architecture)
mirror=http://http.debian.net/debian
aptsourcelist=/etc/apt/sources.list.d/isenkram-autoinstall-firmware.list

loginfo() {
    echo "info: $@" 1>&2
}

add_contrib_nonfree() {
    cat <<EOF > $aptsourcelist
deb $mirror $dist contrib non-free
deb-src $mirror $dist contrib non-free
EOF
    chmod a+r $aptsourcelist
}

# Find firmware files requested by loaded kernel drivers.
for fwfile in $(for module in $(awk '{print $1}' /proc/modules) ; do modinfo $module 2>/dev/null |awk '/^firmware:/ {print $2}'; done|sort -u); do
    if [ ! -e /lib/firmware/$fwfile ] ; then
	fwfiles="${fwfiles:+$fwfiles }$fwfile"
    fi
done

# Also look in dmesg for requested firmware for modules that refuse to
# load without their firmware.  See also bug #725714.
for fwfile in $(dmesg | sed -rn 's/^(\[[^]]*\] )?([^ ]+) [^ ]+: firmware: failed to load ([^ ]+) .*/\3/p'); do
    loginfo "looking for firmware file $fwfile requested by kernel"
    if [ ! -e /lib/firmware/$fwfile ] ; then
        fwfiles="${fwfiles:+$fwfiles }$fwfile"
    fi
done

if [ -z "$fwfiles" ] ; then
    loginfo "did not find any firmware files requested by loaded kernel modules.  exiting"
    exit 1
fi
loginfo "some kernel driver requested extra firmware files:" $fwfiles

tmpdir=$(mktemp -d)
cd $tmpdir || exit 1

cleanup() {
    cd /
    rm -rf $tmpdir
}

# Try to fetch updated data, but use local copy too just in case this
# fail.

for section in "main" "contrib" "non-free"; do
    # "" is main in Wheezy.
    if [  main = "$section" ] && [ wheezy = "$dist" ]; then
	url="$mirror/dists/$dist/Contents-$arch.gz"
    else
	url="$mirror/dists/$dist/$section/Contents-$arch.gz"
    fi
    loginfo "fetching $url"
    GET $url | gunzip | grep ^lib/firmware > Fw-Contents-$arch-$dist-$section
done

datafiles=""
for f in Fw-Contents-$arch-$dist-* \
    /usr/share/isenkram/Fw-Contents-$arch-$dist-* ; do
    if [ -s "$f" ] ; then
	datafiles="$datafiles $f"
    fi
done

if [ "$datafiles" ] ; then
    loginfo "locating packages with the requested firmware files"
    binpkginfos=""
    binpkgs=""
    for fwfile in $fwfiles ; do
	fwfilere=$(echo $fwfile | sed -e 's%/%\\/%g' -e 's/\./\\./g')
	binpkginfo="$(awk "/^lib\/firmware\/$fwfilere/ {print \$2}" $datafiles)"
	if [ -z "$binpkginfo" ] ; then
	# Special case for b43 where the firmware is undistributable
	# by Debian.
	    case "$fwfile" in
		b43/*)
		    add_contrib_nonfree
		    binpkgs="${binpkgs:+$binpkgs }firmware-b43-installer"
		    ;;
	    esac
	else
	    binpkginfos="$binpkginfos $binpkginfo"
	fi
    done
else
    loginfo "unable to find any firmware info for dist $dist"
fi

binpkgs="${binpkgs:+$binpkgs }$(
for binpkginfo in $binpkginfos ; do
    echo $binpkginfo |  while IFS=/ read section srcpkg binpkg ; do
        echo $binpkg
# Enable the non-free section if it is needed
	if LC_ALL=C apt-cache show $binpkg 2>&1 | \
               grep -q 'E: No packages found' \
           && ( [ non-free = "$section" ] \
               || [ contrib = "$section" ] ) ; then 
	    add_contrib_nonfree
	fi
    done
done)"

if [ -e $aptsourcelist ] ; then
    # Fetch updated package lists
    loginfo "Updating APT sources after adding non-free APT source"
    apt-get -qq update
fi

if [ "$binpkgs" ] ; then
    if [ "-l" = "$1" ] ; then
	echo $binpkgs | tr " " "\n" | sort -u
    else
        # Install firmware packages
	loginfo "trying to install $binpkgs"
	apt-get -qq install -y $binpkgs
    fi
else
    loginfo "No new firmware package with requested firmware detected."
fi
cleanup
