On nodes with autoupdate disabled the cmdline parameter '-f' has no effect. But using the autoupdater for manual updates is quite handy.
		
			
				
	
	
		
			188 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/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"/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
 | |
| 
 |