aboutsummaryrefslogtreecommitdiff
path: root/usb-backup
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukasz.kasprzak@pm.me>2026-02-17 16:20:40 +0100
committerLukasz Kasprzak <lukasz.kasprzak@pm.me>2026-02-17 16:20:40 +0100
commitc74163f1ecbd809c83bb465ee89fa04369a89972 (patch)
treec1a52692a47566652d7f2a9a8eceb9f1839991b7 /usb-backup
parent70e6d80c2d367480478eacf46363ee88a0e994ff (diff)
downloadbin-c74163f1ecbd809c83bb465ee89fa04369a89972.tar.gz
bin-c74163f1ecbd809c83bb465ee89fa04369a89972.zip
cleaned up names and dir
Diffstat (limited to 'usb-backup')
-rwxr-xr-xusb-backup155
1 files changed, 155 insertions, 0 deletions
diff --git a/usb-backup b/usb-backup
new file mode 100755
index 0000000..8c81b69
--- /dev/null
+++ b/usb-backup
@@ -0,0 +1,155 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+#################### CONFIG ####################
+
+# LUKS2 container UUID (LUKS header UUID)
+LUKS_SOURCE="/dev/disk/by-uuid/bdd2a016-b6db-493d-ad0a-e8dd8a93dfbd"
+
+# Name for /dev/mapper/<name>
+MAPPER_NAME="usb_safe"
+
+# Mountpoint for decrypted filesystem
+MOUNTPOINT="/mnt/usb_safe"
+
+# Optional underlying block device for power-off (set "" to disable)
+RAW_DEVICE=""
+
+# Items to mirror from $HOME to the encrypted drive (files and directories)
+BACKUP_ITEMS=(
+ "$HOME/.abook"
+ "$HOME/.config"
+ "$HOME/Documents"
+ "$HOME/dotfiles"
+ "$HOME/.password-store"
+ "$HOME/secure"
+ "$HOME/vimwiki"
+ "$HOME/.password.tomb"
+ "$HOME/.secrets.tomb"
+)
+
+RSYNC_OPTS=(
+ -a
+ --delete
+ --no-perms
+ --no-owner
+ --no-group
+ --no-xattrs
+ --omit-dir-times
+ --progress
+)
+
+LOGFILE="$HOME/backup_flash_rsync.log"
+
+#################### HELPERS ####################
+
+die() { echo "ERROR: $*" >&2; exit 1; }
+
+is_mapper_open() { [[ -e "/dev/mapper/${MAPPER_NAME}" ]]; }
+is_mounted() { mountpoint -q "${MOUNTPOINT}"; }
+
+busy_report() {
+ echo ">>> Busy report for ${MOUNTPOINT}:"
+ echo ">>> lsof:"
+ sudo lsof +f -- "${MOUNTPOINT}" || true
+ echo ">>> fuser:"
+ sudo fuser -vm "${MOUNTPOINT}" || true
+}
+
+cleanup() {
+ set +e
+
+ if is_mounted; then
+ echo ">>> Unmounting ${MOUNTPOINT}..."
+ sudo umount "${MOUNTPOINT}" || {
+ echo ">>> Unmount failed (device busy)."
+ busy_report
+ echo ">>> Last resort: sudo umount -l '${MOUNTPOINT}'"
+ }
+ fi
+
+ if is_mapper_open; then
+ echo ">>> Closing LUKS mapper ${MAPPER_NAME}..."
+ sudo cryptsetup close "${MAPPER_NAME}" || true
+ fi
+
+ if [[ -n "${RAW_DEVICE}" ]]; then
+ echo ">>> Powering off ${RAW_DEVICE}..."
+ udisksctl power-off -b "${RAW_DEVICE}" >/dev/null 2>&1 || true
+ fi
+}
+
+trap cleanup EXIT
+
+#################### OPEN + MOUNT ####################
+
+echo ">>> Checking LUKS source exists: ${LUKS_SOURCE}"
+[[ -e "${LUKS_SOURCE}" ]] || die "LUKS source not found: ${LUKS_SOURCE}"
+
+echo ">>> Ensuring mountpoint exists: ${MOUNTPOINT}"
+sudo mkdir -p "${MOUNTPOINT}"
+
+is_mounted && die "Mountpoint already in use: ${MOUNTPOINT}"
+is_mapper_open && die "Mapper already open: /dev/mapper/${MAPPER_NAME}"
+
+echo ">>> Opening LUKS2 container (prompt for passphrase)..."
+sudo cryptsetup open --type luks2 "${LUKS_SOURCE}" "${MAPPER_NAME}"
+
+echo ">>> Mounting decrypted filesystem..."
+sudo mount "/dev/mapper/${MAPPER_NAME}" "${MOUNTPOINT}"
+
+echo ">>> Mounted at ${MOUNTPOINT}"
+echo ">>> Logging rsync output to: ${LOGFILE}"
+echo "[$(date)] Backup run started" >> "${LOGFILE}"
+
+#################### RSYNC LOOP ####################
+
+ANY_WARNING=0
+
+for SRC in "${BACKUP_ITEMS[@]}"; do
+ [[ -e "${SRC}" ]] || die "Missing source item: ${SRC}"
+
+ NAME="$(basename "${SRC}")"
+ DEST="${MOUNTPOINT}/${NAME}"
+
+ echo ">>> rsync: ${SRC} -> ${DEST}"
+ echo "[$(date)] rsync: ${SRC} -> ${DEST}" >> "${LOGFILE}"
+
+ set +e
+ if [[ -d "${SRC}" ]]; then
+ rsync "${RSYNC_OPTS[@]}" "${SRC}/" "${DEST}/" 2>> "${LOGFILE}"
+ else
+ # file
+ rsync "${RSYNC_OPTS[@]}" "${SRC}" "${DEST}" 2>> "${LOGFILE}"
+ fi
+ RS=$?
+ set -e
+
+ if [[ "${RS}" -eq 0 ]]; then
+ echo ">>> rsync OK: ${SRC}"
+ echo "[$(date)] rsync OK: ${SRC}" >> "${LOGFILE}"
+ elif [[ "${RS}" -eq 23 || "${RS}" -eq 24 ]]; then
+ echo ">>> WARNING: rsync non-critical issues (code ${RS}) for: ${SRC}"
+ echo ">>> See ${LOGFILE}."
+ echo "[$(date)] WARNING: rsync code ${RS} for: ${SRC}" >> "${LOGFILE}"
+ ANY_WARNING=1
+ else
+ echo "[$(date)] ERROR: rsync failed code ${RS} for: ${SRC}" >> "${LOGFILE}"
+ exit "${RS}"
+ fi
+done
+
+echo ">>> Backup loop finished."
+if [[ "${ANY_WARNING}" -eq 1 ]]; then
+ echo ">>> Backup completed WITH WARNINGS. See ${LOGFILE}."
+ echo "[$(date)] Backup completed WITH WARNINGS" >> "${LOGFILE}"
+else
+ echo ">>> Backup completed OK."
+ echo "[$(date)] Backup completed OK" >> "${LOGFILE}"
+fi
+
+echo ">>> Syncing..."
+sync
+
+echo ">>> Done. (Auto-cleanup will unmount + close mapper.)"
+