gluon/package/gluon-autoupdater/files/usr/sbin/autoupdater
2014-03-11 20:32:58 +01:00

188 lines
4.2 KiB
Bash
Executable File

#!/bin/sh
if test $(uci get autoupdater.settings.enabled) != 1; then
echo "autoupdater is disabled"
exit 0
fi
BRANCH=$(uci get autoupdater.settings.branch)
PROBABILITY=$(uci get autoupdater.${BRANCH}.probability)
if test "a$1" != "a-f"; then
# get one random byte from /dev/urandom, convert it to decimal and check
# against update_probability*255
hexdump -n1 -e '/1 "%d"' /dev/urandom | awk "{exit \$1 > $PROBABILITY * 255}"
if test $? -ne 0; then
echo "No autoupdate this time. Use -f to override"
exit 0
fi
fi
BRANCH_NAME=$(uci get autoupdater.${BRANCH}.name)
MIRRORS=$(for mirror in $(uci get autoupdater.${BRANCH}.mirror); do \
hexdump -n1 -e '/1 "%d '"$mirror"'\n"' /dev/urandom; \
done | sort -n | cut -d' ' -f2)
PUBKEYS=$(uci get autoupdater.${BRANCH}.pubkey)
GOOD_SIGNATURES=$(uci get autoupdater.${BRANCH}.good_signatures)
VERSION_FILE=/lib/gluon/release
# returns 0 when $1 is a higher version number than $2
newer_than() {
# negate the return value as opkg returns 1 when the proposition is true
! opkg compare-versions "$1" '>>' "$2"
}
fetch_manifest() {
local MIRROR=$1
local manifest=$2
wget -O$manifest "$MIRROR"/manifest
if test $? -ne 0; then
echo "Couldn't fetch manifest from $MIRROR" >&2
return 1
fi
return 0
}
verify_manifest() {
local manifest=$1
local manifest_upper=$2
local manifest_lower=$(mktemp)
awk "BEGIN { sep=0 }
/^---\$/ { sep=1; next }
{ if(sep==0) print > \"$manifest_upper\";
else print > \"$manifest_lower\"}" \
$manifest
local signatures=""
while read sig; do
echo "$sig" | grep -q "^[0-9a-f]\{128\}$"
if test $? -ne 0; then
continue
fi
signatures="$signatures -s $sig"
done < $manifest_lower
local pubkeys=""
for key in $PUBKEYS; do
pubkeys="$pubkeys -p $key"
done
rm -f $manifest_lower
ecdsaverify -n $GOOD_SIGNATURES $pubkeys $signatures $manifest_upper
if test $? -ne 0; then
echo "Not enough valid signatures!" >&2
return 1
fi
return 0
}
analyse_manifest() {
local manifest_upper=$1
grep -q "^BRANCH=${BRANCH_NAME}$" $manifest_upper
if test $? -ne 0; then
echo "Wrong branch. We are on ${BRANCH_NAME}" >&2
return 1
fi
local my_firmware
my_firmware=$(grep "^${my_model} " $manifest_upper)
if test $? -ne 0; then
echo "No matching firmware found (model ${my_model})" >&2
return 1
fi
fw_version=$(echo "${my_firmware}"|cut -d' ' -f2)
fw_checksum=$(echo "${my_firmware}"|cut -d' ' -f3)
fw_file=$(echo "${my_firmware}"|cut -d' ' -f4)
return 0
}
fetch_firmware() {
local MIRROR=$1
local fw_image=$2
wget -O$fw_image "${MIRROR}/${fw_file}"
if test $? -ne 0; then
echo "Error downloading image from $MIRROR" >&2
return 1
fi
return 0
}
autoupdate() {
local MIRROR=$1
local manifest=$(mktemp)
fetch_manifest $MIRROR $manifest || { rm -f $manifest; return 1; }
local manifest_upper=$(mktemp)
verify_manifest $manifest $manifest_upper || { rm -f $manifest $manifest_upper; return 1; }
rm -f $manifest
analyse_manifest $manifest_upper || { rm -f $manifest_upper; return 1; }
rm -f $manifest_upper
if newer_than "$fw_version" "$my_version"; then
echo "New version available"
# drop caches to make room for firmware image
sync
sysctl -w vm.drop_caches=3
local fw_image=$(mktemp)
fetch_firmware $MIRROR $fw_image || { rm -f $fw_image; return 1; }
image_sha512=$(sha512sum "$fw_image" | awk '{print $1}')
image_md5=$(md5sum "$fw_image" | awk '{print $1}')
if [ "$image_sha512" != "$fw_checksum" -a "$image_md5" != "$fw_checksum" ]; then
echo "Invalid image checksum" >&2
rm -f $fw_image
return 1
fi
echo "Upgrading firmware."
sysupgrade "${fw_image}"
else
echo "No new firmware available"
fi
return 0
}
trap 'echo Signal ignored.' INT TERM PIPE
. /lib/gluon/functions/model.sh
my_model="$(get_model | tr '[A-Z]' '[a-z]' | sed -r 's/[^a-z0-9]+/-/g;s/-$//')"
if [ ! -f "$VERSION_FILE" ]; then
echo "Couldn't determine firmware version!" >&2
exit 1
fi
my_version="$(cat "$VERSION_FILE")"
for mirror in $MIRRORS; do
autoupdate $mirror && exit 0
unset fw_version
unset fw_checksum
unset fw_file
done