83 lines
3.4 KiB
Bash
Executable File
83 lines
3.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# =====================================================================
|
|
# Take an installation disc the operator staged, and put it in the
|
|
# library where the launcher will find it.
|
|
#
|
|
# owuivm-insert-media <machine-id>
|
|
#
|
|
# WHY THE OPERATOR STAGES IT AND THIS ONLY MOVES IT
|
|
#
|
|
# The obvious design is "pass the chosen path to a privileged unit and
|
|
# let it copy". It does not work and should not:
|
|
#
|
|
# * the maintenance units run with ProtectHome=yes, so the unit cannot
|
|
# see ~/Downloads at all; and
|
|
# * owuivmadm is not in the operator's group, so even without that it
|
|
# could not read a file under a 0750 home; and
|
|
# * fixing either by running the copy as root would hand the operator a
|
|
# "copy any file root can read into a world-readable directory"
|
|
# primitive, in exchange for saving one move.
|
|
#
|
|
# So the desktop tool copies the disc - as the operator, out of their own
|
|
# home, needing no privilege at all - into /var/lib/owuivm/incoming,
|
|
# which they own. This runs afterwards and does the part that does need
|
|
# privilege: check it, and move it into /var/lib/owuivm/iso.
|
|
#
|
|
# The move is a rename within one filesystem, so it is instant and
|
|
# atomic. The copy, which is the slow part, already happened.
|
|
# =====================================================================
|
|
set -euo pipefail
|
|
|
|
ISOS=${OWUIVM_ISO_DIR:-/var/lib/owuivm/iso}
|
|
INCOMING=${OWUIVM_INCOMING_DIR:-/var/lib/owuivm/incoming}
|
|
REGISTRY=${OWUIVM_REGISTRY:-/var/lib/owuivm/registry/vms.toml}
|
|
|
|
name="${1:-}"
|
|
[[ "$name" =~ ^[a-z0-9][a-z0-9-]{0,30}$ ]] || { echo "bad machine id '$name'" >&2; exit 64; }
|
|
|
|
# The machine has to be one the registry knows. Reading it with grep
|
|
# rather than a TOML parser keeps this script dependency-free; the id is
|
|
# already pattern-checked above, so it cannot be a regex of its own.
|
|
if [ -r "$REGISTRY" ]; then
|
|
grep -qE "^[[:space:]]*id[[:space:]]*=[[:space:]]*\"$name\"" "$REGISTRY" \
|
|
|| { echo "no machine '$name' in $REGISTRY" >&2; exit 64; }
|
|
fi
|
|
|
|
shopt -s nullglob
|
|
staged=("$INCOMING/$name".*.iso)
|
|
if [ ${#staged[@]} -eq 0 ]; then
|
|
echo "nothing staged for $name in $INCOMING" >&2
|
|
exit 65
|
|
fi
|
|
# Newest wins, and everything else for this machine is discarded below:
|
|
# a half-copied disc from an earlier attempt must not be installable.
|
|
disc=""
|
|
for f in "${staged[@]}"; do
|
|
[ -z "$disc" ] || [ "$f" -nt "$disc" ] && disc="$f"
|
|
done
|
|
|
|
# A regular file, not a symlink into somewhere this account should not be
|
|
# reading, and not a device. -h before -f because -f follows links.
|
|
[ ! -h "$disc" ] || { echo "$disc is a symlink; refusing" >&2; exit 65; }
|
|
[ -f "$disc" ] || { echo "$disc is not a regular file" >&2; exit 65; }
|
|
|
|
# An ISO 9660 image carries the string CD001 at offset 0x8001. Costs one
|
|
# read and catches the case this is most likely to hit in practice: a
|
|
# download that was actually an HTML error page, or a .zip renamed by
|
|
# hand, which would otherwise fail much later as a machine that will not
|
|
# boot for no visible reason.
|
|
magic=$(dd if="$disc" bs=1 skip=32769 count=5 2>/dev/null || true)
|
|
[ "$magic" = "CD001" ] || {
|
|
echo "$(basename "$disc") is not an ISO 9660 image (no CD001 signature)" >&2
|
|
rm -f -- "$disc"
|
|
exit 65
|
|
}
|
|
|
|
install -d -m 0755 "$ISOS"
|
|
target="$ISOS/$(basename "$disc")"
|
|
mv -f -- "$disc" "$target"
|
|
chmod 0644 "$target"
|
|
# Whatever else was staged for this machine is stale by definition.
|
|
rm -f -- "$INCOMING/$name".*.iso
|
|
echo "inserted $(basename "$target")"
|