Skip to content

Instantly share code, notes, and snippets.

@cbruegg
Last active November 12, 2024 19:18
Show Gist options
  • Save cbruegg/70d8d9fcb7ebc7f53b7648084516b48c to your computer and use it in GitHub Desktop.
Save cbruegg/70d8d9fcb7ebc7f53b7648084516b48c to your computer and use it in GitHub Desktop.
Script to keep differential backups of your Dropbox with a maximum storage quota using rclone. Uses hardlinks to save space.
#!/bin/bash
# Configuration
RCLONE_REMOTE="dropbox:/" # Adjust this if you don't want the full Dropbox
BACKUP_DIR="/path/to/backups" # Adjust to your local backup directory
SNAPSHOT_LIMIT=500000 # Max usage in MB (500 GB)
# Create backup directory if it doesn't exist
mkdir -p "$BACKUP_DIR"
# Function to calculate disk usage (including 'backup-main')
calculate_usage() {
du -sm "$BACKUP_DIR" 2>/dev/null | awk '{print $1}'
}
# Step 1: Sync Dropbox to backup-main
echo "Starting rclone sync..."
if ! rclone sync "$RCLONE_REMOTE" "$BACKUP_DIR/backup-main"; then
echo "Error: rclone sync failed"
exit 1
fi
echo "rclone sync completed."
# Step 2: Create a snapshot with hardlinks
DATE=$(date -I) # ISO format (YYYY-MM-DD)
SNAPSHOT_DIR="$BACKUP_DIR/backup-$DATE"
echo "Creating snapshot for $DATE..."
if ! rsync -a --link-dest="$BACKUP_DIR/backup-main" "$BACKUP_DIR/backup-main/" "$SNAPSHOT_DIR"; then
echo "Error: rsync snapshot creation failed"
exit 1
fi
echo "Snapshot $SNAPSHOT_DIR created successfully."
# Step 3: Check disk usage and delete old snapshots if necessary
current_usage=$(calculate_usage)
echo "Current total backup usage: $current_usage MB"
if [ "$current_usage" -gt "$SNAPSHOT_LIMIT" ]; then
echo "Storage limit exceeded. Cleaning up old snapshots..."
while [ "$current_usage" -gt "$SNAPSHOT_LIMIT" ]; do
# Find the oldest snapshot (excluding 'backup-main')
oldest_snapshot=$(ls -1d "$BACKUP_DIR"/backup-* 2>/dev/null | grep -v "backup-main" | sort | head -n 1)
if [ -z "$oldest_snapshot" ]; then
echo "No snapshots found to delete. Exiting cleanup."
break
fi
# Failsafe: Ensure $oldest_snapshot is within $BACKUP_DIR
if [[ "$oldest_snapshot" != "$BACKUP_DIR/"* ]]; then
echo "Error: $oldest_snapshot is outside the backup directory. Aborting deletion."
exit 1
fi
echo "Deleting oldest snapshot: $oldest_snapshot"
if ! rm -rf "$oldest_snapshot"; then
echo "Error: Failed to delete $oldest_snapshot"
exit 1
fi
current_usage=$(calculate_usage)
echo "Updated total backup usage: $current_usage MB"
done
else
echo "Storage usage is within limit."
fi
echo "Backup process completed successfully."
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment