-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbackup-home.sh
executable file
·162 lines (139 loc) · 4.84 KB
/
backup-home.sh
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
#!/bin/bash
# ==============================================================#
# Script: backup-home.sh
# Purpose:
# This script securely backs up the user's home directory with
# incremental updates powered by `rsync`. All backups are encrypted
# using `gpg` for data security, with an option to enable or skip
# compression. The script is designed for portability across
# Unix-like systems, including Linux and macOS.
#
# Usage:
# ./backup-home.sh [-d] [-n]
#
# Options:
# -d Dry run: Preview the backup without making changes.
# -n No compression: Skip tarball compression.
# ==============================================================#
set -e # Exit on errors
# Constants
SCRIPT_DIR=$(dirname "$(realpath "$0")")
CONFIG_DIR="${SCRIPT_DIR}/config"
BACKUP_ROOT=$(<"${CONFIG_DIR}/backup-location.txt") # Root backup directory
BACKUP_DIR="${BACKUP_ROOT}/home-$(whoami)-$(date +%Y%m%d)"
TARBALL="${BACKUP_ROOT}/home-$(whoami)-$(date +%Y%m%d).tar.gz"
ENCRYPTED_TARBALL="${TARBALL}.gpg"
LAST_BACKUP="${BACKUP_ROOT}/latest"
EXCLUDE_LIST="${CONFIG_DIR}/exclude-list.txt"
RSYNC_OPTIONS="${CONFIG_DIR}/rsync-options.txt"
LOG_FILE="${BACKUP_ROOT}/backup-home.log"
# Flags
DRY_RUN=false
COMPRESS_BACKUP=true
# Parse options
while getopts "dn" opt; do
case $opt in
d) DRY_RUN=true ;;
n) COMPRESS_BACKUP=false ;;
*)
echo "Invalid option: -$OPTARG"
exit 1
;;
esac
done
# Ensure backup root directory exists
mkdir -p "${BACKUP_ROOT}"
# Display script settings
echo "========================="
echo " Home Directory Backup"
echo "========================="
echo "Backup Location: ${BACKUP_ROOT}"
echo "Exclude List: ${EXCLUDE_LIST}"
echo "Latest Backup (for incremental): ${LAST_BACKUP}"
[ "$DRY_RUN" == true ] && echo "Dry Run: Enabled"
[ "$COMPRESS_BACKUP" == false ] && echo "Compression: Skipped"
echo
read -rp "Do you want to proceed? (y/n): " CONFIRM
if [[ "$CONFIRM" != "y" ]]; then
echo "Backup canceled."
exit 0
fi
# Check for required tools
REQUIRED_TOOLS=("rsync" "tar" "gpg")
for tool in "${REQUIRED_TOOLS[@]}"; do
if ! command -v "$tool" &>/dev/null; then
echo "Error: Required tool '$tool' is not installed."
exit 1
fi
done
# Rsync options
RSYNC_CMD=(
rsync -avhPAX --delete --delete-excluded --backup --suffix="$(date +%Y%m%d)"
--log-file="${BACKUP_ROOT}/rsync.log" --verbose
)
# Include incremental backup with --link-dest
if [[ -d "${LAST_BACKUP}" ]]; then
RSYNC_CMD+=(--link-dest="${LAST_BACKUP}")
echo "Using incremental backup with previous snapshot: ${LAST_BACKUP}"
fi
# Add custom rsync options
if [[ -f "${RSYNC_OPTIONS}" ]]; then
while IFS= read -r option; do
RSYNC_CMD+=("$option")
done <"${RSYNC_OPTIONS}"
fi
# Exclude list
if [[ -f "${EXCLUDE_LIST}" ]]; then
RSYNC_CMD+=(--exclude-from="${EXCLUDE_LIST}")
echo "Using exclude list: ${EXCLUDE_LIST}"
fi
# Add dry-run mode if enabled
[ "$DRY_RUN" == true ] && RSYNC_CMD+=(--dry-run)
# Final confirmation before starting backup
echo
echo "Ready to start backup to: ${BACKUP_DIR}"
read -rp "Proceed with backup? (y/n): " FINAL_CONFIRM
if [[ "$FINAL_CONFIRM" != "y" ]]; then
echo "Backup canceled."
exit 0
fi
# Perform the backup
echo "Starting backup..."
"${RSYNC_CMD[@]}" "${HOME}/" "${BACKUP_DIR}/" || {
echo "Error: Rsync backup failed."
exit 1
}
# Update latest symlink
ln -sfn "${BACKUP_DIR}" "${BACKUP_ROOT}/latest"
# Compress and encrypt the backup directory
if $COMPRESS_BACKUP; then
echo "Compressing backup files..."
tar -cvzf "${TARBALL}" -C "${BACKUP_ROOT}" "$(basename "${BACKUP_DIR}")"
echo "Encrypting the backup tarball..."
gpg --symmetric --cipher-algo AES256 --output "${ENCRYPTED_TARBALL}" "${TARBALL}"
# Remove the uncompressed tarball
rm -f "${TARBALL}"
echo "Backup encrypted and saved at: ${ENCRYPTED_TARBALL}"
fi
# Log backup details
echo "Logging backup details..."
{
echo "Backup Date: $(date)"
echo "Backup Directory: ${BACKUP_DIR}"
[ "$COMPRESS_BACKUP" == true ] && echo "Encrypted Archive: ${ENCRYPTED_TARBALL}"
du -sh "${BACKUP_DIR}" "${ENCRYPTED_TARBALL}" 2>/dev/null | awk '{print $2 ": " $1}'
echo "--------------------------------------------"
} >>"${LOG_FILE}"
# Retention policy: Clean up backups older than six months
# This unified `find` command:
# - Searches for both directories (incremental backups) and files (compressed tarballs)
# - Uses `-mtime +180` to target items last modified more than 180 days ago
# - Ensures compatibility with Linux and macOS by avoiding GNU-specific options
# - Executes `rm -rf` on matching items to clean them up
echo "Cleaning up old backups..."
find "${BACKUP_ROOT}" \( -type d -o -type f -name "*.tar.gz.gpg" \) -mtime +180 -exec rm -rf {} +
echo
echo "Backup completed successfully!"
echo "Backup location: ${BACKUP_DIR}"
[ "$COMPRESS_BACKUP" == true ] && echo "Encrypted archive: ${ENCRYPTED_TARBALL}"
du -sh "${BACKUP_DIR}" "${ENCRYPTED_TARBALL}" 2>/dev/null | awk '{print $2 ": " $1}'