#!/bin/bash
#
# The core of the updater mechanism. This script is launched by systemd when
# activity under $UPL is detected.
#
# There are two ways to format the incoming materials: as individual package
# files, or as a single ISO image containing an APT repository.
#
# There are two ways to deliver the incoming materials to the system: by
# uploading them, i.e. over HTTPS; or, by inserting an auto-mountable storage
# device, i.e. a USB stick. We treat both mechanisms the same, but support only
# one mechanism at a time during an update session.
#
# When users provide individual package files, we make no attempt here to
# resolve inter-package installation dependencies. If there are any, it's up to
# the user to either send us the files one at a time in the correct order, or
# lexically name them so that a wildcard regex will accomplish the same thing.
#
# Inter-package dependencies are handled correctly when the incoming materials
# are an APT repository.

UPL=${1:=/var/www/akna/update}
DEBHELPER=akna-updater-helper
ISOHELPER=akna-updater-apthelper

# The user provided a package file. Install it using systemd-run, so that we
# don't nuke ourselves if the package being updated is ourselves.
do_deb() {
    systemd-run --wait --collect --unit="$DEBHELPER" /usr/bin/$DEBHELPER $1
}

# The user provided an APT repository. Feed it to ISOHELPER.
do_iso() {
    TMP=$(mktemp -d)
    mount $1 $TMP
    systemd-run --wait --collect --unit="$ISOHELPER" /usr/bin/$ISOHELPER $TMP
    umount $TMP
    rm -rf $TMP
}

# Redirect the incoming materials based on the file type. We use --mime-type
# here so that users can name the incoming file whatever they like without
# confusing us.
#
# We intentionally disallow gzip'ed types here, so that we don't preclude a
# highly-constrained file/memory situations. In particular, we don't want to
# have to require intermediate storage for a large repository.
#
# Not that ISO is both read-only and mountable, so (a) we don't have to worry
# about accidentally modifying the incoming media, because that isn't possible;
# and (b) we don't have to reserve room to "extract" anything from it.
#
for file in ${UPL}/*; do
    if [[ ! -f "$file" ]]; then
        break
    fi

    type=$(file --mime-type -b "$file")
    case $type in

        application/vnd.debian.binary-package)
            do_deb "$file"
            ;;

        application/x-iso9660-image)
            do_iso "$file"
            ;;

        *)
            echo "${file##*/}($type) discarded."
            ;;
    esac

    # Discard the file, if we haven't already. This will nuke the
    # aforementioned ISO file, rendering the USB stick non-reusable. Future
    # revisions may want to reconsider this.
    rm -f "$file"
done
