Skip to content

Commit 5ac4139

Browse files
authored
Merge pull request #3 from buildplan/resilient-curl
Implemented curl retry
2 parents 49e78de + bb0bbac commit 5ac4139

File tree

2 files changed

+27
-48
lines changed

2 files changed

+27
-48
lines changed

restic-backup.sh

Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#!/bin/bash
22

33
# =================================================================
4-
# Restic Backup Script v0.19 - 2025.09.09
4+
# Restic Backup Script v0.20 - 2025.09.09
55
# =================================================================
66

77
set -euo pipefail
88
umask 077
99

1010
# --- Script Constants ---
11-
SCRIPT_VERSION="0.19"
11+
SCRIPT_VERSION="0.20"
1212
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
1313
CONFIG_FILE="${SCRIPT_DIR}/restic-backup.conf"
1414
LOCK_FILE="/tmp/restic-backup.lock"
@@ -66,30 +66,25 @@ import_restic_key() {
6666
check_and_install_restic() {
6767
echo -e "${C_BOLD}--- Checking Restic Version ---${C_RESET}"
6868

69-
# Check for dependencies
7069
if ! command -v bzip2 &>/dev/null || ! command -v curl &>/dev/null || ! command -v gpg &>/dev/null; then
7170
echo -e "${C_RED}ERROR: 'bzip2', 'curl', and 'gpg' are required for secure auto-installation.${C_RESET}" >&2
72-
echo -e "${C_YELLOW}Please install them with: sudo apt-get install bzip2 curl gnupg${C_RESET}" >&2
71+
echo -e "${C_YELLOW}On Debian based systems install with: sudo apt-get install bzip2 curl gnupg${C_RESET}" >&2
7372
exit 1
7473
fi
75-
7674
local latest_version
7775
latest_version=$(curl -s "https://api.github.com/repos/restic/restic/releases/latest" | grep -o '"tag_name": "[^"]*"' | sed -E 's/.*"v?([^"]+)".*/\1/')
7876
if [ -z "$latest_version" ]; then
7977
echo -e "${C_YELLOW}Could not fetch latest restic version from GitHub. Skipping check.${C_RESET}"
8078
return 0
8179
fi
82-
8380
local local_version=""
8481
if command -v restic &>/dev/null; then
8582
local_version=$(restic version | head -n1 | awk '{print $2}')
8683
fi
87-
8884
if [[ "$local_version" == "$latest_version" ]]; then
8985
echo -e "${C_GREEN}✅ Restic is up to date (version $local_version).${C_RESET}"
9086
return 0
9187
fi
92-
9388
echo -e "${C_YELLOW}A new version of Restic is available ($latest_version). Current version is ${local_version:-not installed}.${C_RESET}"
9489
if [ -t 1 ]; then
9590
read -p "Would you like to download and install it? (y/n): " confirm
@@ -102,12 +97,12 @@ check_and_install_restic() {
10297
echo "Skipping interactive installation in non-interactive mode (cron)."
10398
return 0
10499
fi
105-
106100
if ! import_restic_key; then
107101
return 1
108102
fi
109-
110-
# Determine architecture and URLs
103+
local temp_binary temp_checksums temp_signature
104+
temp_binary=$(mktemp) && temp_checksums=$(mktemp) && temp_signature=$(mktemp)
105+
trap 'rm -f "$temp_binary" "$temp_checksums" "$temp_signature"' RETURN
111106
local arch=$(uname -m)
112107
local arch_suffix=""
113108
case "$arch" in
@@ -118,40 +113,27 @@ check_and_install_restic() {
118113
local latest_version_tag="v${latest_version}"
119114
local filename="restic_${latest_version}_linux_${arch_suffix}.bz2"
120115
local base_url="https://github.com/restic/restic/releases/download/${latest_version_tag}"
121-
122-
# Download artifacts
116+
local curl_opts=(-sL --fail --retry 3 --retry-delay 2)
123117
echo "Downloading Restic binary, checksums, and signature..."
124-
local temp_binary temp_checksums temp_signature
125-
temp_binary=$(mktemp) && temp_checksums=$(mktemp) && temp_signature=$(mktemp)
126-
curl -sL -o "$temp_binary" "${base_url}/${filename}" || { echo "Download failed"; rm -f "$temp_binary" "$temp_checksums" "$temp_signature"; return 1; }
127-
curl -sL -o "$temp_checksums" "${base_url}/SHA256SUMS" || { echo "Download failed"; rm -f "$temp_binary" "$temp_checksums" "$temp_signature"; return 1; }
128-
curl -sL -o "$temp_signature" "${base_url}/SHA256SUMS.asc" || { echo "Download failed"; rm -f "$temp_binary" "$temp_checksums" "$temp_signature"; return 1; }
129-
130-
# Verify signature of checksums
118+
if ! curl "${curl_opts[@]}" -o "$temp_binary" "${base_url}/${filename}"; then echo "Download failed"; return 1; fi
119+
if ! curl "${curl_opts[@]}" -o "$temp_checksums" "${base_url}/SHA256SUMS"; then echo "Download failed"; return 1; fi
120+
if ! curl "${curl_opts[@]}" -o "$temp_signature" "${base_url}/SHA256SUMS.asc"; then echo "Download failed"; return 1; fi
131121
echo "Verifying checksum signature..."
132122
if ! gpg --verify "$temp_signature" "$temp_checksums" >/dev/null 2>&1; then
133123
echo -e "${C_RED}FATAL: Invalid signature on SHA256SUMS. Aborting.${C_RESET}" >&2
134-
rm -f "$temp_binary" "$temp_checksums" "$temp_signature"
135124
return 1
136125
fi
137126
echo -e "${C_GREEN}✅ Checksum file signature is valid.${C_RESET}"
138-
139-
# Verify the binary checksum (exact match by filename)
140127
echo "Verifying restic binary checksum..."
141128
local expected_hash
142129
expected_hash=$(awk -v f="$filename" '$2==f {print $1}' "$temp_checksums")
143130
local actual_hash
144-
# --- THIS LINE IS THE FIX ---
145131
actual_hash=$(sha256sum "$temp_binary" | awk '{print $1}')
146132
if [[ -z "$expected_hash" || "$expected_hash" != "$actual_hash" ]]; then
147133
echo -e "${C_RED}FATAL: Binary checksum mismatch. Aborting.${C_RESET}" >&2
148-
rm -f "$temp_binary" "$temp_checksums" "$temp_signature"
149134
return 1
150135
fi
151136
echo -e "${C_GREEN}✅ Restic binary checksum is valid.${C_RESET}"
152-
rm -f "$temp_checksums" "$temp_signature"
153-
154-
# Decompress and install
155137
echo "Decompressing and installing to /usr/local/bin/restic..."
156138
if bunzip2 -c "$temp_binary" > /usr/local/bin/restic.tmp; then
157139
chmod +x /usr/local/bin/restic.tmp
@@ -160,15 +142,14 @@ check_and_install_restic() {
160142
else
161143
echo -e "${C_RED}Installation failed.${C_RESET}" >&2
162144
fi
163-
rm -f "$temp_binary"
164145
}
165146

166147
check_for_script_update() {
167148
if ! [ -t 0 ]; then
168149
return 0
169150
fi
170-
local SCRIPT_URL="https://raw.githubusercontent.com/buildplan/restic-backup-script/main/restic-backup.sh"
171151
echo -e "${C_BOLD}--- Checking for script updates ---${C_RESET}"
152+
local SCRIPT_URL="https://raw.githubusercontent.com/buildplan/restic-backup-script/main/restic-backup.sh"
172153
local remote_version
173154
remote_version=$(curl -sL "$SCRIPT_URL" | grep 'SCRIPT_VERSION=' | head -n1 | sed -E 's/.*"([^"]+)".*/\1/')
174155
if [ -z "$remote_version" ] || [[ "$remote_version" == "$SCRIPT_VERSION" ]]; then
@@ -181,38 +162,36 @@ check_for_script_update() {
181162
echo "Skipping update."
182163
return 0
183164
fi
184-
local temp_file
185-
temp_file=$(mktemp)
186-
if ! curl -sL -o "$temp_file" "$SCRIPT_URL"; then
187-
echo -e "${C_RED}Download failed. Please try updating manually.${C_RESET}" >&2
188-
rm -f "$temp_file"
189-
return 1
190-
fi
191-
echo "Verifying downloaded file integrity..."
165+
local temp_script temp_checksum
166+
temp_script=$(mktemp)
167+
temp_checksum=$(mktemp)
168+
trap 'rm -f "$temp_script" "$temp_checksum"' RETURN
192169
local CHECKSUM_URL="${SCRIPT_URL}.sha256"
170+
local curl_opts=(-sL --fail --retry 3 --retry-delay 2)
171+
echo "Downloading script update..."
172+
if ! curl "${curl_opts[@]}" -o "$temp_script" "$SCRIPT_URL"; then echo "Download failed"; return 1; fi
173+
if ! curl "${curl_opts[@]}" -o "$temp_checksum" "$CHECKSUM_URL"; then echo "Download failed"; return 1; fi
174+
echo "Verifying downloaded file integrity..."
193175
local remote_hash
194-
remote_hash=$(curl -sL "$CHECKSUM_URL" | awk '{print $1}')
176+
remote_hash=$(awk '{print $1}' "$temp_checksum")
195177
if [ -z "$remote_hash" ]; then
196-
echo -e "${C_RED}Could not download checksum file. Aborting update.${C_RESET}" >&2
197-
rm -f "$temp_file"
178+
echo -e "${C_RED}Could not read remote checksum. Aborting update.${C_RESET}" >&2
198179
return 1
199180
fi
200181
local local_hash
201-
local_hash=$(sha256sum "$temp_file" | awk '{print $1}')
182+
local_hash=$(sha256sum "$temp_script" | awk '{print $1}')
202183
if [[ "$local_hash" != "$remote_hash" ]]; then
203184
echo -e "${C_RED}FATAL: Checksum mismatch! File may be corrupt or tampered with.${C_RESET}" >&2
204185
echo -e "${C_RED}Aborting update for security reasons.${C_RESET}" >&2
205-
rm -f "$temp_file"
206186
return 1
207187
fi
208188
echo -e "${C_GREEN}✅ Checksum verified successfully.${C_RESET}"
209-
if ! grep -q "#!/bin/bash" "$temp_file"; then
189+
if ! grep -q "#!/bin/bash" "$temp_script"; then
210190
echo -e "${C_RED}Downloaded file does not appear to be a valid script. Aborting update.${C_RESET}" >&2
211-
rm -f "$temp_file"
212191
return 1
213192
fi
214-
chmod +x "$temp_file"
215-
mv "$temp_file" "$0"
193+
chmod +x "$temp_script"
194+
mv "$temp_script" "$0"
216195
if [ -n "${SUDO_USER:-}" ] && [[ "$SCRIPT_DIR" != /root* ]]; then
217196
chown "${SUDO_USER}:${SUDO_GID:-$SUDO_USER}" "$0"
218197
fi

restic-backup.sh.sha256

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
acda79afb0d51a66a4141c3a9e790caab14ae949e6efe5acb49106338b0512b8 restic-backup.sh
1+
c0a7ffdc8f433e992040947a9cb22285d7ee94be4f210ac5a54b1ee6751d89b1 restic-backup.sh

0 commit comments

Comments
 (0)