home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2011 November
/
CHIP_2011_11.iso
/
Programy
/
Linux
/
Ubuntu_64-bit
/
ubuntu-11.04-desktop-amd64.iso
/
casper
/
filesystem.squashfs
/
bin
/
check-missing-firmware
< prev
next >
Wrap
Text File
|
2011-04-22
|
6KB
|
231 lines
#!/bin/sh
set -e
. /usr/share/debconf/confmodule
MISSING=/dev/.udev/firmware-missing
DENIED=/tmp/missing-firmware-denied
if [ "x$1" = "x-n" ]; then
NONINTERACTIVE=1
else
NONINTERACTIVE=""
fi
log () {
logger -t check-missing-firmware "$@"
}
# Not all drivers register themselves if firmware is missing; in that
# case determine the module via the device's modalias.
get_module () {
local devpath=$1
if [ -d $devpath/driver ]; then
# The realpath of the destination of the driver/module
# symlink should be something like "/sys/module/e100"
basename $(realpath $devpath/driver/module) || true
elif [ -e $devpath/modalias ]; then
modalias="$(cat $devpath/modalias)"
# Take the last module returned by modprobe
modprobe --show-depends "$modalias" 2>/dev/null | \
sed -n -e '$s#^.*/\([^.]*\)\.ko.*$#\1#p'
fi
}
check_missing () {
# Give modules some time to request firmware.
sleep 1
modules=""
files=""
if [ -d "$MISSING" ]; then
for file in $(find $MISSING -type l); do
# decode firmware filename as encoded by
# udev firmware.agent
fwfile="$(basename $file | sed -e 's#\\x2f#/#g')"
# strip probably nonexistant firmware subdirectory
devpath="$(readlink $file | sed 's/\/firmware\/.*//')"
# the symlink is supposed to point to the device in /sys
if ! echo "$devpath" | grep -q '^/sys/'; then
devpath="/sys$devpath"
fi
module=$(get_module "$devpath")
if [ -z "$module" ]; then
log "failed to determine module from $devpath"
continue
fi
rm -f "$file"
if grep -q "^$fwfile$" $DENIED 2>/dev/null; then
continue
fi
modules="$module${modules:+ $modules}"
files="$fwfile${files:+ $files}"
done
fi
if [ -n "$modules" ]; then
log "missing firmware files ($files) for $modules"
return 0
else
log "no missing firmware in $MISSING"
return 1
fi
}
# If found, copy firmware file; preserve subdirs.
try_copy () {
local fwfile=$1
local sdir file f target
sdir=$(dirname $fwfile | sed "s/^\.$//")
file=$(basename $fwfile)
for f in "/media/$fwfile" "/media/firmware/$fwfile" \
${sdir:+"/media/$file" "/media/firmware/$file"}; do
if [ -e "$f" ]; then
target="/lib/firmware${sdir:+/$sdir}"
log "copying loose file $file from '$(dirname $f)' to '$target'"
mkdir -p "$target"
rm -f "$target/$file"
cp -aL "$f" "$target" || true
break
fi
done
}
first_try=1
first_ask=1
ask_load_firmware () {
if [ "$first_try" ]; then
first_try=""
return 0
fi
if [ "$NONINTERACTIVE" ]; then
if [ ! "$first_ask" ]; then
return 1
else
first_ask=""
return 0
fi
fi
db_subst hw-detect/load_firmware FILES "$files"
if ! db_input high hw-detect/load_firmware; then
if [ ! "$first_ask" ]; then
exit 1;
else
first_ask=""
fi
fi
if ! db_go; then
exit 10 # back up
fi
db_get hw-detect/load_firmware
if [ "$RET" = true ]; then
return 0
else
echo "$files" | tr ' ' '\n' >> $DENIED
return 1
fi
}
list_deb_firmware () {
ar p "$1" data.tar.gz | tar zt \
| grep '^\./lib/firmware/' \
| sed -e 's!^\./lib/firmware/!!' \
| grep -v '^$'
}
check_deb_arch () {
arch=$(ar p "$1" control.tar.gz | tar zxO ./control | grep '^Architecture:' | sed -e 's/Architecture: *//')
[ "$arch" = all ] || [ "$arch" = "$(udpkg --print-architecture)" ]
}
# Remove non-accepted firmware package
remove_pkg() {
pkgname="$1"
# Remove all files listed in /var/lib/dpkg/info/$pkgname.md5sum
for file in $(cut -d" " -f 2- /var/lib/dpkg/info/$pkgname.md5sum) ; do
rm /$file
done
}
install_firmware_pkg () {
if echo "$1" | grep -q '\.deb$'; then
# cache deb for installation into /target later
mkdir -p /var/cache/firmware/
cp -aL "$1" /var/cache/firmware/ || true
filename="$(basename "$1")"
pkgname="$(echo $filename |cut -d_ -f1)"
udpkg --unpack "/var/cache/firmware/$filename"
if [ -f /var/lib/dpkg/info/$pkgname.preinst ] ; then
# Run preinst script to see if the firmware
# license is accepted Exit code of preinst
# decide if the package should be installed or
# not.
if /var/lib/dpkg/info/$pkgname.preinst ; then
:
else
remove_pkg "$pkgname"
rm "/var/cache/firmware/$filename"
fi
fi
else
udpkg --unpack "$1"
fi
}
# Try to load udebs (or debs) that contain the missing firmware.
# This does not use anna because debs can have arbitrary
# dependencies, which anna might try to install.
check_for_firmware() {
echo "$files" | sed -e 's/ /\n/g' >/tmp/grepfor
for filename in $@; do
if [ -f "$filename" ]; then
if check_deb_arch "$filename" && list_deb_firmware "$filename" | grep -qf /tmp/grepfor; then
log "installing firmware package $filename"
install_firmware_pkg "$filename" || true
fi
fi
done
rm -f /tmp/grepfor
}
while check_missing && ask_load_firmware; do
# first, check if needed firmware (u)debs are available on the
# PXE initrd or the installation CD.
if [ -d /firmware ]; then
check_for_firmware /firmware/*.deb /firmware/*.udeb
fi
if [ -d /cdrom/firmware ]; then
check_for_firmware /cdrom/firmware/*.deb /cdrom/firmware/*.udeb
fi
# second, look for loose firmware files on the media device.
if mountmedia; then
for file in $files; do
try_copy "$file"
done
umount /media || true
fi
# last, look for firmware (u)debs on the media device
if mountmedia driver; then
check_for_firmware /media/*.deb /media/*.udeb /media/*.ude /media/firmware/*.deb /media/firmware/*.udeb /media/firmware/*.ude
umount /media || true
fi
# remove and reload modules so they see the new firmware
# Sort to only reload a given module once if it ask for more
# than one firmware file (example iwlagn)
for module in $(echo $modules | tr " " "\n" | sort -u); do
modprobe -r $module || true
modprobe $module || true
done
done