commit 65e21e5b307ed9b36c02a2671d6e69631b2168dd Author: root Date: Fri May 23 10:16:57 2025 +0200 first commit diff --git a/backups2smb.sh b/backups2smb.sh new file mode 100755 index 0000000..66c3a32 --- /dev/null +++ b/backups2smb.sh @@ -0,0 +1,242 @@ +#!/bin/bash + +# === Config === +SERVER_IP="192.168.2.194" +SHARE_NAME="PBS-back" +MOUNT_POINT="/mnt/smb-backup" +CREDENTIALS_FILE="/root/.smb-pbs-cred" +DATE=$(date +%F-%H%M) +BACKUP_NAME="pbs-config-$DATE" +TMP_BACKUP="/tmp/$BACKUP_NAME" +CHUNK_SIZE="10G" +MIN_SPACE_REQUIRED="5G" # Minimum space required in /tmp +LOG="/var/log/pbs-smb-backup.log" +SRC="/etc /root /mypool" +MAX_BACKUPS=3 # Keep exactly 3 backups + +# === Cleanup function === +cleanup_old_backups() { + echo "[$(date)] ๐Ÿงน Starting cleanup of old backups..." | tee -a "$LOG" + + # Cleanup old backups on SMB share + if mountpoint -q "$MOUNT_POINT"; then + echo "[$(date)] Keeping only the $MAX_BACKUPS most recent backups..." | tee -a "$LOG" + # List all backup directories, sort by date (newest first), and remove older ones + cd "$MOUNT_POINT" || exit 1 + ls -td pbs-config-* 2>/dev/null | tail -n +$((MAX_BACKUPS + 1)) | xargs -r rm -rf + echo "[$(date)] Current backups:" | tee -a "$LOG" + ls -lhd pbs-config-* 2>/dev/null | tee -a "$LOG" + fi + + # Cleanup old logs + echo "[$(date)] Cleaning up old log files..." | tee -a "$LOG" + find /var/log -name "pbs-smb-backup.*.log" -mtime +7 -delete + + # Cleanup /tmp + echo "[$(date)] Cleaning up old temporary files..." | tee -a "$LOG" + rm -rf /tmp/pbs-config-* + rm -rf /tmp/restore-* +} + +# === Create mount point if needed === +mkdir -p "$MOUNT_POINT" + +# === Ensure credentials file exists === +if [ ! -f "$CREDENTIALS_FILE" ]; then + echo "username=pbs" > "$CREDENTIALS_FILE" + echo "password=2104" >> "$CREDENTIALS_FILE" + chmod 600 "$CREDENTIALS_FILE" +fi + +# === Helper functions === +get_available_space() { + df -B1 /tmp | awk 'NR==2 {print $4}' +} + +check_space() { + local required_space=$(numfmt --from=iec $MIN_SPACE_REQUIRED) + local available_space=$(get_available_space) + + if [ "$available_space" -lt "$required_space" ]; then + echo "[$(date)] โš ๏ธ Warning: Only $(numfmt --to=iec $available_space) available in /tmp" | tee -a "$LOG" + return 1 + fi + return 0 +} + +wait_for_space() { + local required_space=$(numfmt --from=iec $MIN_SPACE_REQUIRED) + local available_space + + while true; do + available_space=$(get_available_space) + if [ "$available_space" -ge "$required_space" ]; then + return 0 + fi + echo "[$(date)] โš ๏ธ Waiting for more space in /tmp (need $MIN_SPACE_REQUIRED, have $(numfmt --to=iec $available_space))..." | tee -a "$LOG" + sleep 10 + done +} + +mount_share() { + echo "[$(date)] Mounting SMB share..." | tee -a "$LOG" + + # Check if already mounted + if mountpoint -q "$MOUNT_POINT"; then + echo "[$(date)] Share already mounted, unmounting first..." | tee -a "$LOG" + umount "$MOUNT_POINT" + fi + + # Try mounting with different SMB versions if needed + for smb_ver in "3.0" "2.1" "2.0" "1.0"; do + echo "[$(date)] Attempting mount with SMB version $smb_ver..." | tee -a "$LOG" + mount -t cifs "//$SERVER_IP/$SHARE_NAME" "$MOUNT_POINT" -o "credentials=$CREDENTIALS_FILE,iocharset=utf8,vers=$smb_ver,sec=ntlmssp,uid=0,gid=0,file_mode=0644,dir_mode=0755" + if [ $? -eq 0 ]; then + echo "[$(date)] Successfully mounted with SMB version $smb_ver" | tee -a "$LOG" + return 0 + fi + # Show dmesg output for debugging + echo "[$(date)] Mount failed, checking dmesg for details..." | tee -a "$LOG" + dmesg | tail -n 20 | tee -a "$LOG" + done + + echo "[$(date)] โŒ Failed to mount SMB share. Please check:" | tee -a "$LOG" + echo "1. SMB server is running and accessible" | tee -a "$LOG" + echo "2. Credentials are correct" | tee -a "$LOG" + echo "3. Network connectivity to $SERVER_IP" | tee -a "$LOG" + echo "4. SMB share '$SHARE_NAME' exists and is accessible" | tee -a "$LOG" + exit 1 +} + +unmount_share() { + echo "[$(date)] Unmounting SMB share..." | tee -a "$LOG" + if mountpoint -q "$MOUNT_POINT"; then + umount "$MOUNT_POINT" + fi +} + +# === Handle -u option for restore === +if [ "$1" == "-u" ]; then + echo "[$(date)] ๐Ÿ” Restore mode selected. Starting cleanup..." | tee -a "$LOG" + cleanup_old_backups + mount_share + + # Get latest backup directory + LATEST_BACKUP_DIR=$(ls -td "$MOUNT_POINT"/pbs-config-* 2>/dev/null | head -n1) + + if [ -z "$LATEST_BACKUP_DIR" ]; then + echo "[$(date)] โŒ No backup found on SMB share." | tee -a "$LOG" + unmount_share + exit 1 + fi + + echo "[$(date)] โฌ‡๏ธ Starting streaming restore process from $LATEST_BACKUP_DIR..." | tee -a "$LOG" + + # Create a temporary directory for processing + TMP_RESTORE_DIR="/tmp/restore-$(basename "$LATEST_BACKUP_DIR")" + mkdir -p "$TMP_RESTORE_DIR" + + # Process chunks one by one + for chunk in "$LATEST_BACKUP_DIR"/chunk_*; do + if [ ! -f "$chunk" ]; then + continue + fi + + echo "[$(date)] Processing chunk: $(basename "$chunk")" | tee -a "$LOG" + + # Copy chunk to temp + rsync -ah --progress "$chunk" "$TMP_RESTORE_DIR/" + + # If this is the first chunk, start extraction + if [ "$(basename "$chunk")" = "chunk_aa" ]; then + 7z x -y "$TMP_RESTORE_DIR/$(basename "$chunk")" -o/ & + extract_pid=$! + else + # For subsequent chunks, append to the extraction + cat "$TMP_RESTORE_DIR/$(basename "$chunk")" >> "$TMP_RESTORE_DIR/combined.7z" + fi + + # Clean up the processed chunk + rm -f "$TMP_RESTORE_DIR/$(basename "$chunk")" + done + + # Wait for extraction to complete + wait $extract_pid + + # Cleanup + rm -rf "$TMP_RESTORE_DIR" + unmount_share + echo "[$(date)] โœ… Restore completed." | tee -a "$LOG" + exit 0 +fi + +# === Regular backup mode === + +# Step 1: Start cleanup +echo "[$(date)] ๐Ÿงน Starting initial cleanup..." | tee -a "$LOG" +cleanup_old_backups + +if ! check_space; then + echo "[$(date)] โš ๏ธ Proceeding with caution due to limited space" | tee -a "$LOG" +fi + +# Step 2: Create temporary directory for chunks +mkdir -p "$TMP_BACKUP" + +# Step 3: Mount share +mount_share + +# Step 4: Create backup directory on SMB +BACKUP_DIR="$MOUNT_POINT/$BACKUP_NAME" +mkdir -p "$BACKUP_DIR" + +# Step 5: Create backup in chunks with space management +echo "[$(date)] ๐Ÿ—œ๏ธ Starting backup with space management..." | tee -a "$LOG" + +# Create a temporary file list +echo "[$(date)] ๐Ÿ“‹ Creating file list..." | tee -a "$LOG" +find $SRC -type f > "$TMP_BACKUP/filelist.txt" + +# Process files in chunks +while IFS= read -r file; do + # Check space before processing each file + if ! check_space; then + echo "[$(date)] โณ Waiting for more space..." | tee -a "$LOG" + wait_for_space + fi + + # Get the relative path for the file + rel_path="${file#/}" + chunk_dir="$TMP_BACKUP/$(dirname "$rel_path")" + mkdir -p "$chunk_dir" + + # Compress the file + echo "[$(date)] ๐Ÿ“ฆ Compressing: $file" | tee -a "$LOG" + 7z a -t7z -m0=lzma2 -mx=5 "$TMP_BACKUP/$(echo "$rel_path" | tr / _).7z" "$file" + + # If we have enough chunks or space is low, transfer them + if [ $(ls "$TMP_BACKUP"/*.7z 2>/dev/null | wc -l) -ge 5 ] || ! check_space; then + echo "[$(date)] โฌ†๏ธ Transferring chunks to SMB..." | tee -a "$LOG" + for chunk in "$TMP_BACKUP"/*.7z; do + if [ -f "$chunk" ]; then + rsync -ah --progress "$chunk" "$BACKUP_DIR/" + rm -f "$chunk" + fi + done + fi +done < "$TMP_BACKUP/filelist.txt" + +# Transfer any remaining chunks +echo "[$(date)] โฌ†๏ธ Transferring remaining chunks..." | tee -a "$LOG" +for chunk in "$TMP_BACKUP"/*.7z; do + if [ -f "$chunk" ]; then + rsync -ah --progress "$chunk" "$BACKUP_DIR/" + rm -f "$chunk" + fi +done + +# Step 6: Final cleanup and finish +rm -rf "$TMP_BACKUP" +unmount_share +echo "[$(date)] โœ… Backup completed successfully: $BACKUP_NAME" | tee -a "$LOG" +