blob: 8c81b69ff794f768025402de592091de66126b10 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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.)"
|