#!/bin/sh
set -eu
trap update_failure 1 2 EXIT
# before we begin...
mb_path="$PATH"
mb_script="$0"
mb_success=no
mb_obtain=no
mb_state=true
mb_opt="${1:-}"
if [ "${mb_opt}" = '--mpackage' ]; then
mb_mpackage="${mb_opt}"
mb_dlopt="${2:-}"
else
mb_dlopt="${mb_opt}"
mb_mpackage="${2:-}"
fi
error_msg()
{
printf '%s\n' "$@" >&2
}
warning_msg()
{
printf '%s\n' "$@" >&2
}
update_failure()
{
if [ _$mb_success = _yes ]; then
return 0
fi
printf 'update info: exiting due to an error.\n' >&3
exit 2
}
update_needed()
{
trap '' EXIT
mb_success=yes
exit 1
}
update_success()
{
trap '' EXIT
mb_success=yes
exit 0
}
obtain_remote_file()
{
pathname="$1"
case "$mb_vendor" in
/ )
;;
/* )
cp -p "${mb_vendor}/${pathname}" \
"${pathname}"
;;
https://* )
wget "${mb_vendor}/${pathname}" \
--output-document="${pathname}" \
--no-check-certificate
;;
* )
error_msg "Invalid prefix in path argument ${pathname}"
update_failure
;;
esac
}
# logging
exec 3>> /updates/update.log
# previous state
if [ -f /updates/update.pending ]; then
rm /updates/update.pending
update_needed
fi
# vendor server location
mb_vendor=$(cat /etc/vendor.host)
# obtain list of advertised updates
obtain_remote_file /updates/updates.sha256
if [ "${mb_mpackage}" = '--mpackage' ]; then
mb_tarballs=$(cut -d' ' -f3 /updates/updates.sha256 | grep 'updater.tar.gz' || true)
else
mb_tarballs=$(cut -d' ' -f3 /updates/updates.sha256)
fi
# simple argument parsing
if [ "${mb_dlopt}" = '--obtain-tarballs' ]; then
mb_obtain=yes
fi
# compare against local state
for tarball in ${mb_tarballs:-}; do
printf 'checking local status of %s...\n' $tarball >&3
if ! [ -f /updates/$tarball ]; then
if [ -f /tarballs/$tarball ]; then
if ! [ -f /tarballs/$tarball.sha256 ]; then
sha256sum /tarballs/$tarball > /tarballs/$tarball.sha256
fi
mb_remotesig=$(grep $tarball /updates/updates.sha256 | cut -d' ' -f1)
mb_localsig=$(cat /tarballs/$tarball.sha256 | cut -d' ' -f1)
printf '\tremote signature: %s\n' $mb_remotesig >&3
printf '\tcached signature: %s\n' $mb_localsig >&3
if [ $mb_localsig != $mb_remotesig ]; then
mb_state=false
printf '\tsignatures do not match, download needed.\n' >&3
if [ $mb_obtain = no ]; then
update_needed
else
mb_needed=yes
fi
else
printf '\tsignatures match, installed tarball is already up-to-date.\n' >&3
mb_needed=no
fi
else
printf '\t/updates/%s does not exist, download needed.\n' $tarball >&3
if [ $mb_obtain = no ]; then
update_needed
else
mb_needed=yes
fi
fi
else
mb_state=false
printf '\t/updates/%s found, checking signatures...\n' $tarball >&3
if ! [ -f /updates/$tarball.sha256 ]; then
sha256sum /updates/$tarball > /updates/$tarball.sha256
fi
mb_remotesig=$(grep $tarball /updates/updates.sha256 | cut -d' ' -f1)
mb_localsig=$(cat /updates/$tarball.sha256 | cut -d' ' -f1)
printf '\tremote signature: %s\n' $mb_remotesig >&3
printf '\tlocal signature: %s\n' $mb_localsig >&3
if [ $mb_localsig != $mb_remotesig ]; then
printf '\tsignatures do not match, download needed.\n' >&3
if [ $mb_obtain = no ]; then
update_needed
else
mb_needed=yes
fi
else
printf '\tsignatures match, local tarball is already up-to-date.\n' >&3
mb_needed=no
fi
fi
if [ $mb_needed = yes ]; then
printf '\tattempting to download %s...\n' ${mb_vendor}/updates/$tarball >&3
obtain_remote_file /updates/$tarball
sha256sum /updates/$tarball > /updates/$tarball.sha256
mb_remotesig=$(grep $tarball /updates/updates.sha256 | cut -d' ' -f1)
mb_localsig=$(cat /updates/$tarball.sha256 | cut -d' ' -f1)
printf '\tremote signature: %s\n' $mb_remotesig >&3
printf '\tlocal signature: %s\n' $mb_localsig >&3
if [ $mb_localsig != $mb_remotesig ]; then
printf 'signatures do not match, aborting.\n' >&3
update_failure
else
printf '\t/local tarball is now up-to-date.\n' >&3
fi
fi
printf '\n' >&3
done
# already up-to-date?
if [ "${mb_dlopt}" = '--check-state' ]; then
if [ $mb_state = true ]; then
update_success
else
update_needed
fi
fi
# status
touch /updates/update.pending
# all done
update_success