#!/bin/sh BRANCH=$(uci get autoupdater.settings.branch) PROBABILITY=$(uci get autoupdater.${BRANCH}.probability) if test "a$1" != "a-f"; then if test $(uci get autoupdater.settings.enabled) != 1; then echo "autoupdater is disabled" exit 0 fi # 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}/${BRANCH}.manifest" || 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 my_model="$(lua -e 'print(require("platform_info").get_image_name())')" 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