#!/bin/bash # # mybackup.sh # # Copyright (C) 2010, Branko Majic # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # program="mybackup.sh" version="0.1" function usage() { cat <. EOF } function version() { cat < | | | | This program is free software: you can redistribute it and/or modify | | it under the terms of the GNU General Public License as published by | | the Free Software Foundation, either version 3 of the License, or | | (at your option) any later version. | | | | This program is distributed in the hope that it will be useful, | | but WITHOUT ANY WARRANTY; without even the implied warranty of | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | GNU General Public License for more details. | | | | You should have received a copy of the GNU General Public License | | along with this program. If not, see . | +-----------------------------------------------------------------------+ EOF } # # Helper function that generates a timestamp for the log. Current date is used # for the timestmap. # # Outputs: # Current date in format 'YYYY-MM-DD HH:mm:SS'. # function timestamp() { date '+%Y-%m-%d %H:%M:%S' } # # Helper function for logging the events. The events are logged into a file and # into a variable "logCache". This variable can be used later on for sending # mail notifications etc. Entries in logCache are generated taking the threshold # into account. # # Arguments: # $1 - Event level, INFO, WARN, or ERROR. # $2 - Message which should be written to log. # function logMessage() { local level="$1" local message="$2" local logEntry if [[ $level == "INFO" || $level == "WARN" || $level == "ERROR" ]]; then logEntry="$(timestamp) $level $message" echo "$logEntry" >> "$logFile" if [[ $level == INFO && $mailThreshold == INFO ]]; then logCache[${#logCache[@]}]="$logEntry" elif [[ $level == WARN && ($mailThreshold == WARN || $mailThreshold == INFO) ]]; then logCache[${#logCache[@]}]="$logEntry" elif [[ $level == ERROR ]]; then logCache[${#logCache[@]}]="$logEntry" fi fi } # If no arguments were given, just show usage help. if [[ -z $1 ]]; then usage exit 0 fi # Setup static variables dateFormat="+%Y%m%d_%H%M%S" # Setup default argument values mailThreshold="WARN" logFile="/var/log/mybackup/mybackup.log" # Parse the arguments while getopts "d:c:m:t:l:vh" opt; do case "$opt" in d) backupDirectory="$OPTARG";; c) compression="$OPTARG";; m) mail="$OPTARG";; t) mailThreshold="$OPTARG";; l) logFile="$OPTARG";; v) version exit 0;; h) usage exit 0;; *) usage exit 1;; esac done i=$OPTIND shift $(($i-1)) # Verify parameters if [[ -z $backupDirectory ]]; then echo "No backup directory was supplied." >&2 exit 2 fi if [[ ($compression != "bz2" && $compression != "gz") && -n $compression ]]; then echo "Compression type '$compression' is not supported." >&2 exit 3 fi if [[ $mailThreshold != "INFO" && $mailThreshold != "WARN" && $mailThreshold != "ERROR" ]]; then echo "Unrecognised threshold '$mailThreshold'" >&2 exit 3 fi # Setup the compression command if [[ $compression == "bz2" ]]; then compressionCommand="bzip2" elif [[ $compression == "gz" ]]; then compressionCommand="gzip" else compressionCommand="cat" fi # Retrieve a list of all the databases provided at the command line databases=() while [[ -n $1 ]]; do databases=(${databases[@]} $1) shift done # If no databases were specified, back-up all the MySQL databases if [[ ${#databases[@]} == 0 ]]; then if ! databases=($(mysql --batch --skip-column-names -e 'SHOW DATABASES')); then logMessage ERROR "Could not retrieve the list of databases. Aborting backup." exit 4 fi fi # Add a dot to the compression so it's easier to build-up extensions if [[ -n $compression ]]; then compression=".$compression" fi # Create the backup directory if it doesn't exist mkdir -p "$backupDirectory" logMessage INFO "Starting the back-up of databases to $backupDirectory" for db in ${databases[@]}; do outputFile="$db.$(date $dateFormat)${compression:-}" if [[ -e $outputFile ]]; then logMessage WARN "File already exists ($outputFile), skipping" else logMessage INFO "Starting the back-up of database $db" mysqldump --single-transaction "$db" | "$compressionCommand" > "$backupDirectory/$outputFile" exitCodes=(${PIPESTATUS[@]}) if [[ ${exitCodes[0]} != 0 ]]; then logMessage ERROR "Failed to back-up $db. Command 'mysqldump' exited with error code ${exitCodes[0]}" fi if [[ ${exitCodes[1]} != 0 ]]; then logMessage ERROR "Failed to back-up $db. Compression command '$compressionCommand' exited with error code ${exitCodes[1]}" fi if [[ ${exitCodes[0]} == 0 && ${exitCodes[1]} == 0 ]]; then logMessage INFO "Finished the back-up of database $db" fi fi done logMessage INFO "Finished the back-up of databases to $backupDirectory" if [[ -n $mail && ${logCache[@]} != 0 ]]; then { cat <