FS-independent bash backup

Dirty and quick, a little script to backup an entire hard drive from bash:

#!/bin/bash
# License: do what you want but cite my blog ;)
# http://binaryunit.blogspot.com
#
# *** superSalva 1.0 by Eugenio Rustico ***
# Backup utility for ALL types of partitions
#
# FEATURES
# - Easy disk/partition image *even of unknown filesystems*
# - On the fly compression: no need for temporary files
# - Customizeable process
#
# LIMITS
# - May be more speedy
# - No fs-specific support
# - Reads and compress even zero-zones
#
# TODO:
# - Support for decompressor without zcat equivalent
# - Support for creating (better if bootable) iso images
# - Support for md5sum integrity verification (!)
# - Free space checking
# - Wizard
# - Final statistics and estimated time
# - Trap for CTRL+C

# Device to be backupped, even if NTFS or unknown. May be a partition or a whole disk
export DEVICE=/dev/hda6

# AUTOMATIC: device capability, in kb
export DEVICE_DIM=`df -k | grep $DEVICE | awk {'print $2'}`

# Actually unused
export DEVICE_FREE=`df -k | grep $DEVICE | awk {'print $4'}`

# Destination/source directory. If destination, should have $(dim of $DEVICE) space free
# Do NOT locate destination on the same drive you're backupping!
# export DIR=/d/ripristino/e
export DIR=/pozzo

# Destination/source base filename. During backup files are overwritten.
export FILENAME=Immagine_E_20_6_2006

# On the fly compression commands. Shoud support reading from stdin and writing on stdout
# DEFAULT: gzip, well-known
# EXPERIMENTAL: 7zip, slower but better compression. YOU MUST HAVE 7zip ALREADY INSTALLED. But does "7cat" exist?
export COMPRESSOR=gzip
export DECOMPRESSOR=zcat

# Compression parameters
# Actually, only a compression level sent to gzip
export COMPRESSOR_PARAMS=-9

# Compressed file extension. Optional but useful
export EXTENSION=gz

# Number of piecese to skip while backuppin/restoring
# Useful for testing and for resuming interrupted backups
# CHANGE THIS ONLY IF YOU KNOW WHAT YOU ARE DOING
# Default: 0
export SKIP=0

# Block size. NOTE: from it depend default piece dimensions!
# CHANGE THIS ONLY IF YOU KNOW WHAT YOU ARE DOING
export BLOCK_SIZE=1024

# Dimension of pieces to compress and backup, in kb.
# Too small = too many pieces, not useful
# Too large = unefficient compression
# MAX = 4194303 (if dest fs is not FAT, may be higher), few pieces
# MEDIUM VALUES:
# 524288 (512 Mb)
# 262144 (256Mb)
# 131072 (128 Mb), many pieces
# 65536 (64 Mb)
# 32768 (32 Mb), definitely too much pieces!
# MIN = 1 (nonsense)
# DEFAULT = 1048576 (1 Gb, RECOMMENDED)
# NOTE: this values are block-size dependent (in this case, we use 1024 bytes blocks)
export PIECE_DIM=32768

# AUTOMATIC: number of pieces
# Should be plus one, but it's zero based so no matter
export NUM=$(($DEVICE_DIM/$PIECE_DIM))

# Action: BACKUP or RESTORE
export ACTION=BACKUP

# Want to see what I'm doing?
export VERBOSE=1

echo
echo
echo " *** superSalva 1.0 *** "
echo
echo
echo "Device: $DEVICE ($DEVICE_DIM kb)"
echo Compressor: $COMPRESSOR
echo Decompressor: $DECOMPRESSOR
echo Parameters: $COMPRESSOR_PARAMS
echo Destination: $DIR/$FILENAME.NUM.TOT.$EXTENSION
echo Device: $DEVICE
echo Pieces: $(($NUM+1)) pieces, $PIECE_DIM kb each
echo Action: $ACTION
echo
echo Ready? CTRL+C to abort, ENTER to start. May take LONG time.
read
echo
echo

export SUM=0
for i in `seq $SKIP $NUM`
do
export FILEN="$DIR/$FILENAME.$(($i+1)).$(($NUM+1)).$EXTENSION"
export SK=$(($i*$PIECE_DIM))
#export
#if [ ]
#then
#fi
if [ "$ACTION" == "RESTORE" ]
then
echo "* Decompressing and writing piece $(($i+1)) of $(($NUM+1)) (kb $(($SK+1)) to $((($i+1)*$PIECE_DIM)))..."
export COMMAND="$DECOMPRESSOR $FILEN | dd of=$DEVICE seek=$SK count=$PIECE_DIM bs=$BLOCK_SIZE"
if [ $VERBOSE == 1 ]; then echo $COMMAND; fi
$COMMAND
echo "* Successfully restored $FILEN"
echo
else
echo "* Reading and compressing piece $(($i+1)) of $(($NUM+1)) (kb $(($SK+1)) to $((($i+1)*$PIECE_DIM)))..."
export COMMAND="dd if=$DEVICE skip=$SK count=$PIECE_DIM bs=$BLOCK_SIZE | $COMPRESSOR $COMPRESSOR_PARAMS > $FILEN"
if [ $VERBOSE == 1 ]; then echo $COMMAND; fi
$COMMAND
export LAST_DIM=$((`ls -l $FILEN | awk {'print $5'}`/1000))
echo "* Saved $FILEN ($LAST_DIM kb, ratio $(((100*$LAST_DIM)/$PIECE_DIM))%)"
export SUM=$(($SUM+$LAST_DIM))
echo
fi
done

echo
if [ $ACTION == "RESTORE" ]
then
echo "Finished. $DEVICE seems to be restored."
else
echo "Finished. $(($NUM+1)) files, tot $SUM kb ($((100*$SUM/$DEVICE_DIM))% of original $DEVICE size)"
fi
echo Bye!
echo

Thanks to dd. Features:
  • On the fly compression
  • Non need for temporary files
  • File-system independent
  • Backup and restore facilities
  • Keeps master boot records
  • ...
TODO: lots of things (checksumming facilities, configuring wizard, free space checking, command tests...); the complete TODO list is inside the script.

No comments:

Post a Comment