274 lines
7.9 KiB
Bash
Executable File
274 lines
7.9 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# RESUME DOWNLOAD DETAILS
|
|
# swupdate can retry and resume a broken download. See -t and -r arguments
|
|
# in do_swupdate call at end of this file.
|
|
#
|
|
# Implementation in swupdate:
|
|
# https://github.com/sbabic/swupdate/blob/master/corelib/downloader.c
|
|
#
|
|
# Note that it only resumes the download when kept running: after the
|
|
# swupdate process has stopped, for example because of a reboot, it will
|
|
# restart. Improving this, without adding an intermediate scratchpad on disk,
|
|
# is not straightforward: the download is streamed straight into ubifs on the
|
|
# CCGX, and re-opening an unfinished ubifs volume is not a good idea.
|
|
#
|
|
# Resuming while online file has changed:
|
|
# When a new version is made available, the venus-swu-[machine].swu file on
|
|
# the webserver is replaced with the newer one. Devices busy starting a
|
|
# resume after that should not accidentally resume the download with the new
|
|
# file. A waste of bandwidth and possible leads to installing and booting
|
|
# into a corrupt rootfs. (What type of CRC or hash does swupdate on the swu
|
|
# file after download?)
|
|
#
|
|
# This is prevented this by dowloading the file that contains its version
|
|
# in the name. Therefore the webserver should always have the latest file
|
|
# available under two names:
|
|
# venus-swu-[machine].swu
|
|
# venus-swu-[machine]-[build-date-time].swu
|
|
#
|
|
# Best sequence of installing the files on the webserver is:
|
|
# 1. venus-swu-[machine]-[build-date-time].swu
|
|
# 2. venus-swu-[machine].swu
|
|
# 3. rename or remove the old build-date-time file: force the running
|
|
# downloads to cancel.
|
|
|
|
. $(dirname $0)/functions.sh
|
|
|
|
get_setting() {
|
|
dbus-send --print-reply=literal --system --type=method_call \
|
|
--dest=com.victronenergy.settings \
|
|
"/Settings/System/$1" \
|
|
com.victronenergy.BusItem.GetValue |
|
|
awk '{ print $3 }'
|
|
}
|
|
|
|
get_swu_version() {
|
|
if [ -f "$1" ]; then
|
|
# local file
|
|
cmd="head -n 10"
|
|
else
|
|
# url, probably
|
|
cmd="curl -s -r 0-999 -m 30 --retry 3"
|
|
fi
|
|
|
|
$cmd "$1" |
|
|
cpio --quiet -i --to-stdout sw-description 2>/dev/null |
|
|
sed -n '/venus-version/ {
|
|
s/.*"\(.*\)".*/\1/
|
|
p
|
|
q
|
|
}'
|
|
}
|
|
|
|
swu_status() {
|
|
printf '%s\n' "$1" ${offline:+""} "$2" >$status_file
|
|
}
|
|
|
|
status_file=/var/run/swupdate-status
|
|
|
|
start_log
|
|
|
|
echo "*** Checking for updates ***"
|
|
echo "arguments: $@"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-auto)
|
|
update=auto
|
|
auto=1
|
|
;;
|
|
-check) update=2 ;;
|
|
-update) update=1 ;;
|
|
-delay) delay=y ;;
|
|
-force) force=y ;;
|
|
-swu)
|
|
shift
|
|
force=y
|
|
forceswu="$1"
|
|
update="1"
|
|
;;
|
|
-swubase)
|
|
shift
|
|
swubase="$1"
|
|
;;
|
|
-offline)offline=y ;;
|
|
-help) help=y ;;
|
|
*) echo "Invalid option $arg"
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [ "$help" = y ]; then
|
|
echo "check-updates.sh: wrapper script around swupdate"
|
|
echo
|
|
echo "Arguments:"
|
|
echo "-auto script will check automatic update setting in localsettings."
|
|
echo " use this when calling from cron or after boot."
|
|
echo "-delay sleep for a random delay before starting the download of"
|
|
echo " new image (to prevent thousands of units starting the"
|
|
echo " download at the same time)."
|
|
echo " use this when calling from cron or after boot."
|
|
echo "-check (only) check if there is a new version available."
|
|
echo "-update check and, when necessary, update."
|
|
echo "-force force downloading and installing the new image, even if its"
|
|
echo " version is older or same as already installed version."
|
|
echo "-swu url forcefully install the swu from given url"
|
|
echo "-swubase url use given url as a base, rather than the default:"
|
|
echo " https://updates.victronenergy.com/feeds/venus/[feed]/"
|
|
echo "-offline search for updates on removable storage devices"
|
|
echo "-help this help"
|
|
echo
|
|
echo "Behaviour when called without any arguments is same as -update"
|
|
exit
|
|
fi
|
|
|
|
if [ "${update:-auto}" = auto ]; then
|
|
update=$(get_setting AutoUpdate)
|
|
case $update in
|
|
0) echo "Auto-update disabled, exit."
|
|
exit
|
|
;;
|
|
1) ;;
|
|
2) ;;
|
|
*) echo "Invalid AutoUpdate value $update, exit."
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
if [ "$delay" = y ]; then
|
|
DELAY=$[ $RANDOM % 3600 ]
|
|
echo "Sleeping for $DELAY seconds"
|
|
sleep $DELAY
|
|
fi
|
|
|
|
machine=$(cat /etc/venus/machine)
|
|
swu_name=$(cat /etc/venus/swu-name)
|
|
swu_base=${swu_name}-${machine}
|
|
|
|
if [[ $forceswu ]]; then
|
|
echo "Updating to $forceswu"
|
|
SWU="$forceswu"
|
|
# The version is not known, since the stream might not support seeking,
|
|
# like stdin for example. So as a best effort, use the url instead.
|
|
swu_version="$forceswu"
|
|
elif [ "$offline" = y ]; then
|
|
echo "Searching for update on SD/USB..."
|
|
|
|
for dev in /media/*; do
|
|
# reverse order gives preference to an unversioned file
|
|
# followed by that with the most recent timestamp if
|
|
# multiple files exist
|
|
#
|
|
# MIND IT: There are ccgx and venusgx around which only check for
|
|
# venus-swu-${machine}*.swu so don't make an incompatible ccgxv2 or
|
|
# beaglebone-new MACHINE, since they are also accepted by the old ones.
|
|
SWU=$(ls -r $dev/${swu_base}-*.swu $dev/${swu_base}.swu 2>/dev/null | head -n1)
|
|
test -f "$SWU" && break
|
|
done
|
|
|
|
if [ -f "$SWU" ]; then
|
|
echo "Update found on $dev"
|
|
feed="$dev"
|
|
else
|
|
echo "Update not found. Exit."
|
|
swu_status -3
|
|
exit 1
|
|
fi
|
|
else
|
|
feed=$(get_setting ReleaseType)
|
|
|
|
case $feed in
|
|
0) feed=release ;;
|
|
1) feed=candidate ;;
|
|
2) feed=testing ;;
|
|
3) feed=develop ;;
|
|
*) echo "Invalid release type, exit."
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
if [ -z "$swubase" ]; then
|
|
swubase=https://static.innovenergy.ch/firmware/venus/${feed}/
|
|
fi
|
|
|
|
URL_BASE=${swubase}images/${machine}
|
|
SWU=${URL_BASE}/${swu_base}.swu
|
|
fi
|
|
|
|
if [[ -z $forceswu ]]; then
|
|
echo "Retrieving latest version... (from $SWU)"
|
|
swu_status 1
|
|
|
|
cur_version=$(get_version)
|
|
swu_version=$(get_swu_version "$SWU")
|
|
|
|
if [ -z "$swu_version" ]; then
|
|
echo "Unable to retrieve latest software version, exit."
|
|
swu_status -1
|
|
exit 1
|
|
fi
|
|
|
|
cur_build=${cur_version%% *}
|
|
swu_build=${swu_version%% *}
|
|
|
|
if [ "$offline" != y ]; then
|
|
# change SWU url into the full name
|
|
SWU=${URL_BASE}/${swu_base}-${swu_version// /-}.swu
|
|
fi
|
|
|
|
echo "installed: $cur_version"
|
|
echo "available: $swu_version"
|
|
|
|
if [ "$force" != y -a \( "${swu_build}" = "${cur_build}" -o "$auto" = "1" -a "${swu_build}" -le "${cur_build}" \) ]; then
|
|
echo "No newer version available, exit."
|
|
swu_status 0
|
|
exit
|
|
fi
|
|
|
|
if [ "$update" != 1 ]; then
|
|
swu_status 0 "$swu_version"
|
|
exit
|
|
fi
|
|
fi
|
|
|
|
altroot=$(get_altrootfs)
|
|
|
|
if [ -z "$altroot" ]; then
|
|
echo "Unable to determine rootfs. Exit."
|
|
swu_status -2 "$swu_version"
|
|
exit 1
|
|
fi
|
|
|
|
if ! lock; then
|
|
echo "Can't get lock, other process already running? Exit."
|
|
swu_status 0 "$swu_version"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Starting swupdate to install version $swu_version ..."
|
|
swu_status 2 "$swu_version"
|
|
|
|
# backup rootfs is about to be replaced, remove its version entry
|
|
get_version >/var/run/versions
|
|
|
|
if [ -f "$SWU" ]; then
|
|
swupdate_flags="-i"
|
|
else
|
|
swupdate_flags="-t 30 -r 3 -d"
|
|
fi
|
|
|
|
if do_swupdate -v $swupdate_flags "$SWU" -e "stable,copy$altroot"; then
|
|
echo "do_swupdate completed OK. Rebooting"
|
|
swu_status 3 "$swu_version"
|
|
reboot
|
|
else
|
|
echo "Error, do_swupdate stopped with exitcode $?, unlock and exit."
|
|
swu_status -2 "$swu_version"
|
|
fi
|
|
|
|
unlock
|