aboutsummaryrefslogtreecommitdiff
path: root/shield-backup
blob: ccaff5bf35db2aed1ab488ee4307ac825596328c (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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/usr/bin/env bash
set -euo pipefail

export PATH="/usr/sbin:/sbin:/usr/bin:/bin:$PATH"
RCLONE_CONFIG="$HOME/.config/rclone/rclone.conf"
#################### CONFIG – EDIT THESE ####################

# LUKS2 block device
LUKS_DEVICE="/dev/disk/by-uuid/6659e638-d52a-4c32-9781-9dcedd44db35"

# Name for the mapper device (will appear as /dev/mapper/${LUKS_NAME})
LUKS_NAME="shield"

# Mount point for the decrypted filesystem
LUKS_MOUNTPOINT="/mnt/shield"

# Local folders to back up with rsync → LUKS volume
BACKUP_ITEMS=(
    "$HOME/"
    "/media/.secrets/"
)

# Machine identifier (destination subdir on the LUKS volume)
MACHINE_DIR="T480"

#################### INTERNALS – NO NEED TO EDIT ############

RSYNC_EXCLUDES_FILE="/tmp/rsync_excludes_$$.txt"

cat > "${RSYNC_EXCLUDES_FILE}" <<'EOF'
downloads/
# Caches & regenerable state
.cache/
.fasd
.viminfo
.zcompdump
.sqlite_history
.wget-hsts
.dbus/
.Xauthority
.pki/
tmp/

# Browser internals
.mozilla/firefox/*/cache2/
.mozilla/firefox/*/storage/
.mozilla/firefox/*/datareporting/
.mullvad-browser/*/cache2/
.mullvad-browser/*/storage/

# Crypto node data (re-syncs)
.bitmonero/
.shared-ringdb/

# Large reinstallable tooling
.cargo/registry
.cargo/git
.texlive2025/

# Java runtime junk
.java/
EOF

need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "ERROR: missing command: $1" >&2; exit 1; }; }

cleanup() {
    echo
    echo ">>> Cleaning up..."

    rm -f "${RSYNC_EXCLUDES_FILE}"

    # Try to unmount, if mounted
    if mountpoint -q "${LUKS_MOUNTPOINT}"; then
        echo ">>> Unmounting ${LUKS_MOUNTPOINT}..."
        sudo umount "${LUKS_MOUNTPOINT}" || true
    fi

    # Close LUKS mapping if it exists
    if [ -e "/dev/mapper/${LUKS_NAME}" ]; then
        echo ">>> Closing LUKS mapping ${LUKS_NAME}..."
        sudo cryptsetup close "${LUKS_NAME}" || true
    fi
}
trap cleanup EXIT

need_cmd cryptsetup
need_cmd rclone
need_cmd rsync
need_cmd mountpoint

# Cache sudo credentials early to avoid surprises mid-run
sudo -v

echo ">>> Ensuring mountpoint exists: ${LUKS_MOUNTPOINT}"
sudo mkdir -p "${LUKS_MOUNTPOINT}"

# Check if already open
if [ -e "/dev/mapper/${LUKS_NAME}" ]; then
    echo ">>> WARNING: /dev/mapper/${LUKS_NAME} already exists, assuming already open."
else
    echo ">>> Opening LUKS volume (interactive prompt)..."
    sudo cryptsetup open "${LUKS_DEVICE}" "${LUKS_NAME}"
fi

# At this point /dev/mapper/${LUKS_NAME} must exist
if [ ! -e "/dev/mapper/${LUKS_NAME}" ]; then
    echo "ERROR: /dev/mapper/${LUKS_NAME} not found after cryptsetup open." >&2
    exit 1
fi

# Mount if not already mounted
if mountpoint -q "${LUKS_MOUNTPOINT}"; then
    echo ">>> WARNING: ${LUKS_MOUNTPOINT} already mounted."
else
    echo ">>> Mounting /dev/mapper/${LUKS_NAME} on ${LUKS_MOUNTPOINT}..."
    sudo mount "/dev/mapper/${LUKS_NAME}" "${LUKS_MOUNTPOINT}"
fi

echo ">>> LUKS volume mounted at ${LUKS_MOUNTPOINT}"

# Ensure SharePoint destinations exist in root of shield
sudo mkdir -p \
  "${LUKS_MOUNTPOINT}/SP_Administration" \
  "${LUKS_MOUNTPOINT}/SP_Operations" \
  "${LUKS_MOUNTPOINT}/SP_Skyscale"

echo ">>> Starting rclone syncs (SharePoint -> ${LUKS_MOUNTPOINT}/SP_*)..."
rclone --config "$RCLONE_CONFIG" sync 'SP_Administration:'    "${LUKS_MOUNTPOINT}/SP_Administration" --create-empty-src-dirs --fast-list --progress
rclone --config "$RCLONE_CONFIG" sync 'SP_Operations:'        "${LUKS_MOUNTPOINT}/SP_Operations"     --create-empty-src-dirs --fast-list --progress
rclone --config "$RCLONE_CONFIG" sync 'SP_SkyscaleCommerce:'  "${LUKS_MOUNTPOINT}/SP_Skyscale"       --create-empty-src-dirs --fast-list --progress
echo ">>> All rclone syncs finished."

echo ">>> Starting rsync backups of local folders -> ${LUKS_MOUNTPOINT}/${MACHINE_DIR}/..."

# Ensure machine root exists
sudo mkdir -p "${LUKS_MOUNTPOINT}/${MACHINE_DIR}"

for SRC in "${BACKUP_ITEMS[@]}"; do
    if [ ! -d "$SRC" ]; then
        echo ">>> WARNING: source folder does not exist, skipping: $SRC"
        continue
    fi

    case "$SRC" in
        "$HOME/"|"$HOME")
            RELDEST="${MACHINE_DIR}/HOME"
            ;;
        "/media/.secrets/"|"/media/.secrets")
            RELDEST="${MACHINE_DIR}/secrets"
            ;;
        *)
            NAME="$(basename "${SRC%/}")"
            RELDEST="${MACHINE_DIR}/${NAME}"
            ;;
    esac

    DEST="${LUKS_MOUNTPOINT}/${RELDEST}"
    sudo mkdir -p "${DEST}"

    echo ">>> rsync: ${SRC} -> ${DEST}"
    rsync -a --delete --progress \
        --exclude-from="${RSYNC_EXCLUDES_FILE}" \
        "${SRC%/}/" \
        "${DEST}/"
done

echo ">>> All rsync backups finished."
echo ">>> Unmounting and closing LUKS (via trap)..."
# cleanup() will run automatically on script exit