fwupdate script is almost functional

This commit is contained in:
Calin Crisan 2017-02-11 13:19:14 +02:00
parent a9b69e0505
commit d79f4e0f00
3 changed files with 293 additions and 42 deletions

327
board/common/overlay/sbin/fwupdate Normal file → Executable file
View File

@ -1,16 +1,35 @@
#!/bin/bash
#### usage ####
function exit_usage() {
echo "Usage: $0 versions"
echo " $0 current"
echo " $0 download <version|url>"
echo " $0 extract"
echo " $0 flashboot"
echo " $0 flashreboot"
echo " $0 status"
exit -1
echo "Usage: fwupdate versions"
echo " - lists available versions"
echo " fwupdate current"
echo " - shows the current version"
echo " fwupdate download <version|url>"
echo " - downloads a firmware version"
echo " fwupdate extract"
echo " - extracts the downloaded firmware archive"
echo " fwupdate flashboot"
echo " - flashes the extracted boot partition"
echo " fwupdate flashreboot"
echo " - prepares for reboot + root partititon flash"
echo " fwupdate status"
echo " - shows the current firmware updating status (see below)"
echo ""
echo "Statuses:"
echo " idle"
echo " downloading <version>: <percent>%"
echo " downloaded <version>"
echo " extracting <version>"
echo " extracted <version>"
echo " flashing boot <version>"
echo " boot ready <version>"
echo ""
exit 1
}
if [ -z "$1" ]; then
@ -18,22 +37,48 @@ if [ -z "$1" ]; then
fi
#### configuration ####
SYS_VERSION_FILE=/etc/version
SYS_BOARD_FILE=/etc/board
OS_CONF=/data/etc/os.conf
BOOT_DEV=/dev/mmcblk0p1
MIN_FREE_DISK=$((500*1024)) # 500 MB
VER_FILE=version
ROOT_INFO_FILE=root_info
FW_DIR=/data/.fwupdate
FW_FILE=firmware.img.gz
FW_FILE_EXTR=firmware.img
WGET_LOG_FILE=wget.log
WGET_PID_FILE=wget.pid
GUNZIP_LOG_FILE=gunzip.log
GUNZIP_PID_FILE=gunzip.pid
DD_LOG_FILE=dd.log
DD_PID_FILE=dd.pid
#### versions ####
function show_versions() {
source $OS_CONF
board=$(cat $SYS_BOARD_FILE)
show_url=$1
# the /usr/libexec/list-versions-* helpers return a table with the following format:
# <version>|<prerelease>|<board>|<url>
versions=$(FW_USERNAME=$os_firmware_username FW_PASSWORD=$os_firmware_password \
/usr/libexec/list-versions-$os_firmware_method $os_firmware_repo)
for version in $versions:
$IFS="|" varr=($version)
for version in $versions; do
OIFS=$IFS
IFS="|"
varr=($version)
IFS=$OIFS
if [ "$os_prereleases" == "false" ] && [ "${varr[1]}" == "true" ]; then
continue # skip prereleases
fi
@ -41,52 +86,255 @@ function show_versions() {
continue # skip other boards
fi
echo "${varr[0]}"
if [ "$show_url" == "true" ]; then
echo ${varr[0]} ${varr[3]}
else
echo ${varr[0]}
fi
done
}
function show_current() {
source $SYS_VERSION_FILE
echo "Name: $os_name"
echo "Short Name: $os_short_name"
echo "Prefix: $os_prefix"
echo "Version: $os_version"
echo $os_version
}
#### download ####
function do_download() {
# TODO check space
# TODO cleanup download dir
# TODO prepare download dir
# TODO wget --no-check-certificate
echo "downloading..."
source $OS_CONF
board=$(cat $SYS_BOARD_FILE)
url=$1
version=$1
if ! [[ "$url" == http* ]]; then # a version was given
url=$(show_versions true | grep "^$1" | cut -d ' ' -f 2)
else
version="custom"
fi
if [ -z "$url" ]; then
echo "no such version" 1>&2
exit 1
fi
free_disk=$(df /data | tail -n 1 | tr -s ' ' | cut -d ' ' -f 4)
if [ "$free_disk" -lt $MIN_FREE_DISK ]; then
echo "not enough disk space" 1>&2
exit 1
fi
rm -rf $FW_DIR/*
mkdir -p $FW_DIR
echo $version > $FW_DIR/$VER_FILE
wget --no-check-certificate -O $FW_DIR/$FW_FILE --quiet --show-progress --progress=dot "$url" &> $FW_DIR/$WGET_LOG_FILE &
pid=$!
echo $pid > $FW_DIR/$WGET_PID_FILE
wait $pid
}
function download_status() {
if [ -f $FW_DIR/$WGET_PID_FILE ]; then
pid=$(cat $FW_DIR/$WGET_PID_FILE)
if kill -0 $pid &>/dev/null; then
progress=$(tail -n2 $FW_DIR/$WGET_LOG_FILE | grep -oe '[[:digit:]]*%')
if [ -z "$progress" ]; then
progress="0%"
fi
progress=($progress)
echo ${progress[0]}
return
fi
fi
if [ -f $FW_DIR/$FW_FILE ]; then
echo "done"
fi
}
#### extract ####
function do_extract() {
# TODO gunzip
echo "extracting..."
if ! [ -f $FW_DIR/$FW_FILE ]; then
echo "firmware file not downloaded" 1>&2
exit 1
fi
rm -f $FW_DIR/$FW_FILE_EXTR
gunzip -k -c $FW_DIR/$FW_FILE > $FW_DIR/$FW_FILE_EXTR 2>$FW_DIR/$GUNZIP_LOG_FILE &
pid=$!
echo $pid > $FW_DIR/$GUNZIP_PID_FILE
wait $pid
# TODO verify hash
}
function flash_boot() {
# TODO backup /boot/config.txt
# TODO umount /boot
# TODO set trap exit cleanup routine
# TODO disable rebooting (/sbin/reboot)
# TODO remount rw /
# TODO read partition table
# TODO dd boot.img
# TODO mount r/w /boot
# TODO restore /boot/config.txt
# TODO call cleanup routine
function extract_status() {
if [ -f $FW_DIR/$GUNZIP_PID_FILE ]; then
pid=$(cat $FW_DIR/$GUNZIP_PID_FILE)
if kill -0 $pid &>/dev/null; then
echo "running"
fi
fi
if [ -f $FW_DIR/$FW_FILE_EXTR ]; then
echo "done"
fi
}
#### flash boot ####
function flash_boot() {
echo "flashing boot..."
set +e
board=$(cat $SYS_BOARD_FILE)
cp -r /boot $FW_DIR/old_boot
umount /boot
trap flash_cleanup EXIT
mount -o remount,rw /
mv /sbin/reboot /sbin/reboot.bak
ln -s /bin/true /sbin/reboot
boot_info=$(fdisk --bytes -l -o device,start,end,size $FW_DIR/$FW_FILE_EXTR | grep "${FW_FILE_EXTR}1")
boot_info=($boot_info)
boot_start=$((${boot_info[1]} * 512)) # in bytes
boot_size=$((${boot_info[3]} / 1048576)) # in MB
root_info=$(fdisk --bytes -l -o device,start,end,size $FW_DIR/$FW_FILE_EXTR | grep "${FW_FILE_EXTR}2")
root_info=($root_info)
root_start=$((${root_info[1]} * 512)) # in bytes
root_size=$((${root_info[3]} / 1048576)) # in MB
echo $root_start $root_size > $FW_DIR/$ROOT_INFO
dd if=$FW_DIR/$FW_FILE_EXTR skip=$boot_start of=$BOOT_DEV bs=1048576 count=$boot_size &>$FW_DIR/$DD_LOG_FILE &
pid=$!
echo $pid > $FW_DIR/$DD_PID_FILE
wait $pid
mount -o rw /boot
restore_boot_$board $FW_DIR/old_boot 2>/dev/null || true
touch $FW_DIR/boot_flash_ready
}
function flash_boot_status() {
if [ -f $FW_DIR/$DD_PID_FILE ]; then
pid=$(cat $FW_DIR/$DD_PID_FILE)
if kill -0 $pid &>/dev/null; then
echo "running"
return
fi
fi
if [ -f $FW_DIR/boot_flash_ready ]; then
echo "done"
fi
}
function flash_cleanup() {
if [ -f /sbin/reboot.bak ]; then
rm -f /sbin/reboot
mv /sbin/reboot.bak /sbin/reboot
fi
mount /boot 2>/dev/null
}
function restore_boot_raspberrypi() {
old_boot=$1
cp $old_boot/config.txt /boot
}
function restore_boot_raspberrypi2() {
restore_boot_raspberrypi
}
function restore_boot_raspberrypi3() {
restore_boot_raspberrypi
}
#### flash reboot ####
function flash_reboot() {
# TODO sed /boot/config.txt initramfs
# TODO sync
# TODO umount
# TODO busybox reboot || b > sysrq
echo "preparing for reboot..."
board=$(cat $SYS_BOARD_FILE)
mount -o remount,rw /boot
prepare_boot_$board
sync
busybox reboot &
sleep 10
echo b > /proc/sysrq-trigger
exit 0
}
function prepare_boot_raspberrypi() {
echo "initramfs fwupdater.gz" >> /boot/config.txt
}
function prepare_boot_raspberrypi2() {
prepare_boot_raspberrypi
}
function prepare_boot_raspberrypi3() {
prepare_boot_raspberrypi
}
#### status ####
function show_status() {
status=$(flash_boot_status)
if [ "$status" == "running" ]; then
echo "flashing boot $(new_version)"
return
elif [ "$status" == "done" ]; then
echo "boot ready $(new_version)"
return
fi
status=$(extract_status)
if [ "$status" == "running" ]; then
echo "extracting $(new_version)"
return
elif [ "$status" == "done" ]; then
echo "extracted $(new_version)"
return
fi
status=$(download_status)
if [ "$status" == "done" ]; then
echo "downloaded $(new_version)"
return
elif [ -n "$status" ]; then
echo "downloading $(new_version): $status"
return
fi
echo "idle"
}
function new_version() {
cat $FW_DIR/$VER_FILE
}
@ -100,19 +348,22 @@ case "$1" in
;;
download)
if [ -z "$2" ];
if [ -z "$2" ]; then
exit_usage
fi
do_download $2
show_status
;;
extract)
do_extract
show_status
;;
flashboot)
flash_boot
show_status
;;
flashreboot)

View File

@ -6,9 +6,9 @@ if [ -z "$1" ]; then
fi
opts="-s -S -f"
test -n "$BITBUCKET_USERNAME" && opts+=" --user $BITBUCKET_USERNAME:$BITBUCKET_PASSWORD"
test -n "$FW_USERNAME" && opts+=" --user $FW_USERNAME:$FW_PASSWORD"
url=https://api.bitbucket.org/2.0/repositories/$1/downloads?pagelen=100
jq_expr='.values[] | [{a: .name | capture("[^-]+-(?<b>[^-]+)-(?<c>[^-]+)\\.img\\.?.*"), url: .links.self.href}] | map(.a.c, "false", .a.b, .url) | join("|")'
jq_expr='.values[] | [{a: .name | split("-"), url: .links.self.href}] | map((.a[2] | rtrimstr(".img.gz") | rtrimstr(".img")), "false", .a[1], .url) | join("|")'
curl $opts $url | jq --raw-output "$jq_expr"
exit ${PIPESTATUS[0]}

View File

@ -6,9 +6,9 @@ if [ -z "$1" ]; then
fi
opts="-s -S -f"
test -n "$GITHUB_USERNAME" && opts+=" --user $GITHUB_USERNAME:$GITHUB_PASSWORD"
test -n "$FW_USERNAME" && opts+=" --user $FW_USERNAME:$FW_PASSWORD"
url=https://api.github.com/repos/$1/releases
jq_expr='.[] | {version: .name, prerelease: .prerelease | tostring, name: .assets[].name | capture("[^-]+-(?<b>[^-]+)") | flatten, asset: .assets[].browser_download_url} | flatten | join("|")'
jq_expr='.[] | {version: .name, prerelease: .prerelease | tostring} + (.assets[] | {name: .name | split("-")[1], url: .browser_download_url}) | flatten | join("|")'
curl $opts $url | jq --raw-output "$jq_expr"
exit ${PIPESTATUS[0]}