#!/bin/bash # ===================================================================== # Take an installation disc the operator staged, and put it in the # library where the launcher will find it. # # owuivm-insert-media # # 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")"