Blob Blame History Raw
#!/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