#!/bin/sh set -eu root=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd) . "$root/scripts/secret-file-utils.sh" usage() { echo "usage: $0 --host HOST --database DB --user USER --password-file FILE --output FILE [--port PORT]" >&2 exit 2 } host= database= user= password_file= output= port=5432 while [ "$#" -gt 0 ]; do case "$1" in --host) host=${2-}; shift 2 ;; --port) port=${2-}; shift 2 ;; --database) database=${2-}; shift 2 ;; --user) user=${2-}; shift 2 ;; --password-file) password_file=${2-}; shift 2 ;; --output) output=${2-}; shift 2 ;; *) usage ;; esac done [ -n "$host" ] && [ -n "$database" ] && [ -n "$user" ] || usage [ -n "$password_file" ] && [ -n "$output" ] || usage validate_secret_file "$password_file" "backup password file" [ ! -e "$output" ] || { echo "refusing to overwrite existing backup: $output" >&2; exit 2; } output_dir=$(dirname "$output") output_name=$(basename "$output") [ -d "$output_dir" ] || { echo "backup destination directory does not exist" >&2; exit 2; } password=$(read_secret_file "$password_file" "backup password file") umask 077 passfile=$(mktemp "${TMPDIR:-/tmp}/thoth-vector-pgpass.XXXXXX") temporary_output=$(mktemp "$output_dir/.${output_name}.tmp.XXXXXX") cleanup() { rm -f "$passfile" "$temporary_output"; } trap cleanup EXIT HUP INT TERM escaped=$(printf '%s' "$password" | sed 's/\\/\\\\/g; s/:/\\:/g') printf '%s:%s:%s:%s:%s\n' "$host" "$port" "$database" "$user" "$escaped" >"$passfile" chmod 0600 "$passfile" PGPASSFILE=$passfile pg_dump \ --host="$host" --port="$port" --username="$user" --dbname="$database" \ --format=custom --compress=9 \ --table=vectors.schema_records --table=vectors.evidence --table=vectors.memory \ --table=public.tht_vector_migrations --file="$temporary_output" if ! ln "$temporary_output" "$output"; then echo "refusing to replace backup destination created concurrently: $output" >&2 exit 2 fi rm -f "$temporary_output" echo "Vector backup written: $output"