Add Me!Close Menu Navigation

My technical corner about Linux, Perl, programming, computer networks and network security

Add Me!Open Categories Menu

Basics of writing bash scripts – advanced backup

More inteligent and advanced backup

Sometimes something may go wrong and then a simple script may not help us. There is nothing worse than an admin realising that his own script has crashed his professional career because it didn’t work correctly (corrupted spare files, low disc space, etc). Usually the disaster is hidden because when you know about the problem it’s too late usually (for example: Your script has been saving corrupted files for 3 months).

The script which I explained in the article was simple. Very simple. It’s enough for many people (admins) but sometimes we really need something more handy. For example, the last script doesn’t check disk usage for which disk it copies files and validate these files.

Now, we need a more advanced tool. Our new script should be able to “face” with common problems that it may encounter in the future. Hence the script must:

  • check free space on the destination backup place; if it’s too scarce free space, it must use an alternate location automatically.
  • check the integrity and to perform a simple validation of files which are being copied – corrupted files aren’t usable of course and should be trated as non saved.

Additionaly, if the script finds the such problems then it should send information by an e-mail to the admin. Many administrators who use scripts prefer their scripts to send an e-mail every time when a script is finished no matter if problems happen or not. In my opinion, this is a bad idea, because  in some moment you can get used to mails and ignore important one. I prefer to be informed by an e-mail only when it’s really necessary and this approach I will use in this tutorial.

Time to work. First, we check commands by hand. As you remember, the script will be doing the same as you, so you should know what do you do. :-)

We asumme that we have separate partition (/dev/sdb1 in this case) for backup. Now I use the df command to check free of space in the partition with the grep to clear the results:

$ df -h | grep /dev/sdb1
/dev/sdb1             184G   46G  129G  27% /backup

So as you can see, I have the separate partition /backup for backup. The df command lets me check the size and the usage of the partition. Usage its displayed as percentage, so I will try to use percents in my new script. To get the percent number from the df’s output I use the awk command:

$ df -h | grep /dev/sdb1 | awk {'print $5'}
27%

I won’t explain how the awk works – you shoud be able to use it because it’s very usefull tool in bash scripts. I use the awk with the „-F” switch – in the manual of awk you can find descriptions about not only this switch.

The command displays to me only percent number from the  entire data. It’s quite usefull now, but I need only a raw number, without the % char, for simple number comparison in bash. To remove this char I use the tr command:

$ df -h | grep /dev/sdb1 | awk {'print $5'} | tr -d %
27

Now, it’s ok! We can see that the /backup partition is used only in 27%. I decided to be informed by the script when the usage of the /backup partition exceeds 90%. This is a safe limit for me.

When the usage exceeds 90%, a few backups still can be done on the /backup partition even if I will ignore first warning.

However, If I ignore a few warnings and the /backup partition is full the script will use the second backup partition – /backup2.

$ df -h | grep backup2
/dev/sdb2              47G   33G   15G  70% /backup2

This partition is smaller than the primary /backup partition, but it will be only be used during a emergency scenario. Information about the usage this partition I get the same way as for /backup.

An e-mail will have been sent by the script only if a some problem will occur during the backup.

Advanced backup of a Firebird database

Ok, we have our basic guidelines. Now we can write the script. For example, I will write the advanced script which will perform backup of a small Firebird’s database (1 GB). Firebird databases is in common use in some companies so it will be a good example. The same priciples you can apply to another databases obviously.

Before the backup of any databases we have to check that databases files/dumps are valid. Why? Because the backup of a currupted database is completely useless. It’s the same situation as if backup never existed.

For checking of the validity of Firebird’s databases we use the gfix program which is the part of the Firebird package. The gfix syntax:

$ gfix -v -f database.fdb

The command is very simple to use in the script, because if the database is valid, the gfix returns nothing (0), otherwise it shows some information about possible error. This behaviour is enough to use the bash condition ‘-z’.

To save of disk space we will create an archive by the 7zip program, because the 7zip is one of the most effective at this area. And because of that, we must check that the created archive is valid as well. The reason is the same as the reason for checking if the backup is valid. To do this, we can use the command `7z t` which is simple mean as ‘only test archive’. If the command return the exit code of the last command ($?) different than 0 – something is wrong.

#!/bin/bash
TEST=`7z t somearchive.7z`
echo "Exit code: $?"

Time to some conclusions what our script should do:

  • It will check the free disk space on the backup partition
  • If the disk space is full then it will use an alternate location
  • It will check the validity of the backup database
  • It will check the validity of the created archives
  • If any problems occure it sends information by e-mail
  • It will complete a log about the backup process (some companies require this)

Here you are, the entire script (updated: 2018):

#!/bin/bash

### Path to database to backup dir
BACKUP_FROM="/database"

### Path to backup's dir/partition
BACKUP_PARTITION=/backup

### Path to emergency backup's dir/partition
BACKUP_PARTITION_SECONDARY=/backup2

### Percent of usage main partition backup when it exceeds then script
### will provide warning information
PERCENT=70

### Percent of usage main partition backup when it exceeds then script
### will backup on emergency partition
EMERGENCY_TRESHOLD=95

### Log dir about backup process
LOG_DIR=/var/log

### The CP command
CP=/bin/cp

### The RM command
RM=/bin/rm

### Path to the gfix to checking of validity
### Firebird database
GFIX=/usr/bin/gfix

### Path to the p7zip program to create archives
PACKER=/usr/bin/7z

### Path to the mail program
MAIL=/usr/bin/mail

### An e-mail address where the script will send information about
### detected problems during backup process
EMAIL="user@email.com"

#####################################################################
#####################################################################
#####################################################################

### Because it's more inteligent script, so it checks that some
### require to correctly working programs exists.

if [ ! -e "$GFIX" ]; then
echo "ERROR: $GFIX binary not found"
exit 1
fi

if [ ! -e "$PACKER" ]; then
echo "ERROR: $PACKER binary not found"
exit 1
fi

if [ ! -e "$MAIL" ]; then
echo "ERROR: $MAIL binary not found"
exit 1
fi

#####################################################################
#####################################################################
#####################################################################

### Date suffix
DATE=$(date +%Y-%m-%d)

### Creating the log filename
LOGFSTORAGE_USAGE="${LOG_DIR}/backup.${DATE}"
:>"${LOGFSTORAGE_USAGE}"
echo "${DATE}: Starting backup..." >> "${LOGFSTORAGE_USAGE}"

### 1. Check the free disk space on the main partition of backup
STORAGE_USAGE=$(df -h | grep ${BACKUP_PARTITION} | awk \{'print $5'\} | tr -d %)

###
### Sending the information when first limit was reached
###
if [ "$PERCENT" -ge "$STORAGE_USAGE" ]; then
### Warning
WARNING="$DATE: warning - small free disk space on $BACKUP_PARTITION "

### Writting the log
echo "$WARNING" >> "${LOGFSTORAGE_USAGE}"
fi

###
### Change the backup partition if the second limit was reached
###
if [ "$EMERGENCY_TRESHOLD" -ge "$STORAGE_USAGE" ]; then
### Writting the log
echo "${DATE}: !!! WARNING: There is no free space on the ${BACKUP_PARTITION}- emergency backup." >> "${LOGFSTORAGE_USAGE}"

### More danger warning
WARNING="${DATE}: !!! WARNING: There is no free space on the ${BACKUP_PARTITION}"

### Changing of the backup partition to an alternate location
### WARNING: be careful, this location is not being check to have free space!
BACKUP_PARTITION=$BACKUP_PARTITION_SECONDARY
fi

### Doing the backup

### Entering to the working directory
cd $BACKUP_FROM || echo "ERROR: cannot enter to place with files to backup" | ${MAIL} -s "$SUBJECT" $EMAIL

###
### Checking of all databases in a directory first
###
for db_files in *.fdb;
do
if [ ! "$("${GFIX} -v ${db_files}")" ]; then
### Corrupted database - write the log and go further
echo "${DATE}: *** ERROR: ${GFIX} claims the database $db_files is corrupted." >> "${LOGFSTORAGE_USAGE}"
WARNING="corrupted database ${db_files}"
else
### Valid database - write the log
echo "${DATE}: Copying ${db_files}.${DATE} to ${BACKUP_PARTITION}" >> "${LOGFSTORAGE_USAGE}"

### Copying the correctly database
$CP "${db_files} ${BACKUP_PARTITION}/${db_files}.${DATE}"
fi
done

###
### Creating archives now
###
cd "${BACKUP_PARTITION}" || echo "ERROR: cannot enter to backup partition and create archives" | ${MAIL} -s "$SUBJECT" $EMAIL

for file in *.$DATE;
do
### Packing
$PACKER a "${file}.7z ${file}"

### Report
echo "${DATE}: compression ${file} as ${file}.7z." > "${LOGFSTORAGE_USAGE}"

### Remove the original file
$RM -f "$file"
done

cd "${BACKUP_PARTITION}" || echo "ERROR: cannot enter to backup partition and VERIFY archives" | ${MAIL} -s "$SUBJECT" $EMAIL

###
### Time to tests
###
for archive in *.$DATE;
do
### Testing created archives
$PACKER t "${archive}"
if [ "$0" -gt "0" ]; then
echo "${DATE}: * ! * ERROR: the archive ${archive} is recognized as corrupted." >> "${LOGFSTORAGE_USAGE}"
WARNING="the archive ${archive} is corrupted"
fi
done

###
### Checking if any problems exist - if yes, we should
### send warning information to an administrator
###
if [ "$WARNING" ]; then
SUBJECT="$DATE: $WARNING"

### Sent and e-mail with backup's log
INFO=$(cat "${LOGFSTORAGE_USAGE}")
echo "${INFO}" | ${MAIL} -s "$SUBJECT" $EMAIL
fi

Leave a Reply

You must be logged in to post a comment.

Szukaj

Dziedziny

Miesiąc

Wpisy