Initial Commit
This commit is contained in:
Executable
+82
@@ -0,0 +1,82 @@
|
||||
#!/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")"
|
||||
Reference in New Issue
Block a user