#!/bin/bash
# *************************************************************************
#  EasyWPUpdate ver 2.0 RC 2                                   01/Aug/2006
#  Written by Brian Layman                            Copyright 2006, 2007
#
#  A UNIX shell script to update multiple WordPress blogs to the current
#  stable release.  See TheCodeCave.com for current version and to submit
#  your Shell version to the compatibility list.
#
#  A BBPress auto update script is also available.
#
#  Usage: (A full instruction set is at http://thecodecave.com/EastWPUpdate)
#    Browse out to www.TheCodeCave.com and get the latest
#    Customize the "Configuration variables" found below
#    Use chmod to grant yourself execute status on the script
#    Run the program
#
#  You can use this program in several ways:  
#    * In the default mode to download the latest and greatest update,
#      make an uncompressed copy of your files, makes a compressed backup
#      of your database(s), distributes the file to any number of 
#      directories, and performs the web steps
#    * Configure it to make a online copy of your files you use for easy 
#      recovery AND a compressed copy that you can download.
#    * Add custom directories and backup MORE than just WP. 
#    * Configure it update from a local file each night and start with
#      a clean blog every morning.  
#    * Use it as a nightly backup script by disabling all other steps
#
# Original Author - Brian Layman
#
# Created       - 01/AUG/2006
# Last Modified - 15/MAY/2007
# Contributors: (Put your name & Initials at the top)
#   Brian Layman - BL - http://www.TheCodeCave.com
#
#
# History:
#    01/AUG/2006 - BL - Created
#    21/DEC/2006 - BL - Added multiple blog arrays
#                       Added options at the top of the script
#    04/JAN/2007 - BL - Added File Backup routines
#                       Added web update
#                       Added tmp directory usage
#                       Added local source "freshen" option
#    11/JAN/2007 - BL - Added "steps" and further comments
#                       Added quotes around many vars to protect against spaces
#                       Changed TMPDIR-/tmp to TMPDIR:-/tmp
#                       Changed `pwd` != "$tmp" to `$pwd` != "$tmp"
#                       Added further error trapping around cd and cp routines
#                       Fixed file backup procedure, was adding extra layers
#                       Added ability to backup to tarball
#                       Added SQL backup procedure
#                       Fixed local file backup procedure
#                       Removed “Verbose” from cp to make messages clearer
#                       Added log to webpage for Joe.
#                       Fixed inconsistent use of trailing / in path variables
#                       Added status messages throughout
#                       Added recovery instructions in case of failure mid backup
#                       Added a list of directories to backup
#                       Added Credits section
#    11/JAN/2007 - BL - Added "steps" and further comments
#    15/MAY/2007 - BL - Eliminated the temp files that dirtied the install.
#                       Added samples of 2.0 and 2.1 latest release names
#
# Credits - I want to thank all of the readers of TheCodeCave.com, for
#   their testing of this script. I especially appreciated Michael, Maciek,
#   Aaron and Joe for all of the helpful suggestions.
#   A very special thanks goes out to goldfish on the FreeNode #sed channel
#   who will be PayPaled a Cafe Voltaire tomorrow.  I would have spent days
#   figuring out the RegEx for the SED commands.  Prec, also from #sed gave
#   provided me with a working cr/lf stripper.  For bash, lhunath, jp-_ and the
#   whole crew at #bash on FreeNode gave great line by line suggestions.
#   They basically gave it a full code review!  None of this would have been
#   possible without Advanced Bash-Scripting Guide. 20 days ago I didn't know
#   what bash was.  Now I've written a powerful script with features I've not
#   seen anywhere else.  If you have any questions about the code in this
#   script, you'll find the answers here: http://www.tldp.org/LDP/abs/html/
#
# License - If this helps you - Great! Use it, modify it share it. I would
#   appreciate credit and a link to my site be mentioned somewhere, but it's
#   not a requirement.
#
# Indemnity -
#   Use this file at your own risk. I'm not going to deliberately hack
#   your server, but others might. This is a shell script. Very bad 
#   things can happen.  I am relatively new to *nix scripts.  So,
#   I've had others review this script. But NONE of this guarantees
#   things won't go wrong or that this script is unchanged.  Only
#   use this script IF you've gotten it from TheCodeCave.com or another
#   site you trust.
#
#   THIS SCRIPT SHOULD BE USED AT YOUR OWN RISK. It can erase hours of
#   hard work put into your site.  Before using this script it is
#   required that you review and understand every line and vouch for its
#   safety.  If you are not comfortable with this, you might want to stop
#   now.  I have one host that I can test this on.  Dozens of other people
#   have tested it, but still some things were only found by me.  So, only 
#   you can say that this script will not do irreparable harm to your host 
#   if you use it.
#
#   YOU are responsible for YOUR site.  Learn how to protected it and
#   understand what every line of code does before you call it.
#
# Donations - If this batch file really helps you out, feel free to
#   make a donation of the cost of a cup of espresso via Paypal to
#   Brian@TheCodeCave.com, visit my Amazon Wish List or leave a comment at
#   http://www.thecodecave.com/thanks
#
# *************************************************************************


# ##################################################################
#  Configuration and Instructions
# ##################################################################
# ##################################################################
#  Step 1. Tell the script where to find the blogs
# ##################################################################
# List all of your WordPress directories and urls here.
# 
# Each Blog should have a BlogDir and a BlugURL.
# Each Blog should have its own number [1],[2],[3] etc
# Delete the ones you don't need.
# 
BlogDir[1]='site1dir'
BlogURL[1]='www.example.com'

BlogDir[2]='site2/news'
BlogURL[2]='www.site2.com/news'

BlogDir[3]='wordpress'
BlogURL[3]='blog.site3.com'


# ##################################################################
#  Step 2. Tell the script where to find all of the files
# ##################################################################
#
# MOST USERS CAN IGNORE THIS SECTION if they run the batch file 
# from their telnet login directory.  BUT, you might want to change 
# where the backups are stored for security reasons.
#
# These variables are paths to your local directories.  They 
# control which blogs are updated and which are not.
#
# IMPORTANT: Always think about security.  You really don't
# want to have backup or log files where just anyone can get at   
# them. One solution is to always remember to download these files
# when you are done and then delete them from the server.
# Another way to secure your backups is to use a "protected"
# directory.  An easy way to do this would be to use your logs
# directory.  Another way would be to create a directory and 
# then copy the .htaccess file from your logs directory into
# your new directory.  This won't work on all servers, but should
# on most.  Google "htaccess protect directory" for more info.
#
# Descriptions:
# CommonRootPrefix - The part of your path that is shared by all of 
# your blogs.  It is probably your htdocs directory.  If your blogs
# don't share a common root directory, leave this blank.
#
# CommonRootPrefix - The part of your path that is shared by all of 
# your blogs.  It is probably your htdocs directory.  If your blogs
# don't share a common root directory, leave this blank.
#
# CommonBackupPrefix - The first part of the file backup directory's
# name. the whole name will look something like WPBackups-YYYY-MM-DD
#
# CommonSQLBackupPrefix - Same as above but for the compressed SQL.
#
# LogFile - The full path and filename to the HTML file.
#
# You can probably just leave these alone:
# DO *NOT* PUT A SLASH AFTER ANY OF THESE VARIABLES
#
CommonRootPrefix=$(pwd)

# If your commonroot prefix is accessible from the web, add a unique
# number to the backup prefixes and logfile name  You don't want people
# to guess at the names of these files and download them.
CommonBackupPrefix="$CommonRootPrefix/WPBackUps" # Each backup dir starts like this
CommonSQLBackupPrefix="$CommonRootPrefix/WPSQLBackUps" # SQLDumps will be in here
LogFile="$CommonRootPrefix/EasyWPUpdateLog.html"


# ##################################################################
#  Step 3. Decide what you want this script to do
# ##################################################################
#
# MOST USERS CAN IGNORE THIS SECTION.
#
# Descriptions: (*=Enabled by Default)
# PerformWebSteps* - Use the wget function to perform the online .
# updates You might want to perform this manually.   Comment out 
# this next line if you want to do this step yourself
#
# BackupFilesToTarball - Compresses your WordPress files to a
# tarball.  This option requires TAR and GZip.  All the files in
# the root directory are  backed up and all of the files in the
# default WP directories.  Other  directories are ignored.
# This can take much longer and requires Tar. 
#
# BackupFilesToDir* - Copy all of the WP files to the backup
# directory. All the files in the root directory are backed up and
# all of the files in the default  WP directories.  Other
# directories are ignored.
#
# MakeSQLBackups - Enables Database backups to be made of the WP
# specific tables for each blog.  You do not need to supply
# database, username and password info. That is retrieved
# automatically for each blog.  This option requires both  MySQL
# and MySQLDump to function.
#
# LogToFile* - Creates a HTML file record of what was done
#
# Verbose* - Shows the process in greater detail on the screen
# and in the log file.
#
# Add or Remove a leading # to Disable or enable these features:
#
PerformWebSteps=1  # Uncomment this if you want call the web update
#BackupFilesToTarball=1 # Uncomment to backup to a compressed file
BackupFilesToDir=1 # Uncomment to backup to uncompressed files
MakeSQLBackups=1  # Uncomment to backup the database tables
LogToFile=1 # Route a copy of each message to a log file
Verbose=1 # Explain in detail what is happening.


# ##################################################################
#  Step 4. Tell the script which directories to include
# ##################################################################
#
# MOST USERS CAN IGNORE THIS SECTION.
#
# Most users will only want to backup the default WP directories.
# This is desired because other directories may contain gigabytes 
# of information that is handled by other backup procedures.
# The (currently) standard WP directories are listed below.
# Advanced users may want to backup other common directories too.
# That can be achieved by adding more entries to this list. The
# script will attempt to backup that directory for each of your 
# blogs.  If a directory doesn't exist for a particular blog, a 
# warning will be displayed and that directory will be ignored for
# that particular blog.  
#
# To my own list I've add WPDirs[4]='images' but not all of my 
# blogs have that subdirectory. Those that do, will have that 
# directory included in the compressed and/or uncompressed backups.
WPDirs[1]='wp-admin'
WPDirs[2]='wp-content'
WPDirs[3]='wp-includes'


# ##################################################################
#  Step 5. Tell the script where to find the update file it'll use
# ##################################################################
#
# MOST USERS CAN IGNORE THIS SECTION.
#
# These variable can be used to change where you get the clean copy
# of WordPress Override this variable if you wish to use this script
# to restore your files to a known version of WordPress.  As part of
# a nightly routine, this can keep all of your sites running
# un-hacked code.
# 
# Choose a different ArchiveName if you wish to use another release.
# For more releases: http://wordpress.org/download/release-archive/
#
# SourceURL and SourcePath are mutually exclusive. Uncomment only
# one.  Otherwise SourcePath wins.
#
# Comment out both SourceURL and SourcePath  if you do not wish to
# perform an update and only want the script only to do backups.
#
ArchiveName='latest.tar.gz'
#ArchiveName='wordpress-2.1.3.tar.gz'
#ArchiveName='wordpress-2.0.9.tar.gz'
SourceURL='http://wordpress.org/'
#SourcePath='/this/needs/a/full/path' # NEVER USE A TRAILING SLASH


# ##################################################################
#  Step 6. That's It!  You're done. Run the thing.
# ##################################################################
#
# All you need to do run this script.  At your prompt just type in
# the name.  If you get a permissions error, you need to give
# yourself permission to run the script.  Like this: 
# chmod +x filename
#
# If you get a bunch of errors about /n this or /n that then your 
# file is formatted for windows.  Fix that by running this a command
# that looks like this: tr -d '\r' filename > xx && mv -f xx filename
#
# Of course replace "filename" in those examples with whatever you
# named this script EasyWPUpdate for example.
# ##################################################################




# ##################################################################
#  Constants - Do not change these
# ##################################################################
# Error Codes
E_SUCCESS=0 # No Error Code. It worked.
E_XCD=66 # Can't change directory?
E_XMD=67 # Can't make directory?
E_XNOFILE=68 # No archive file was found.
E_XBACKUP=69 # Backup started but failed to complete
E_XPARTIALUpdate=70 # Update started but failed to complete

# What is the prefix the your tmp directory? A random number is added
# to this directory
TMPPrefix="EasyWPUpdate-"

# If a tarball backup is to be made, what should it be called?
BackupTarballName="BlogBackup.tar.gz"

# The name of the file if a database backup was made
MySQLDumpFileName="WordpressTables.gz"

# The table listing filename.  This will be dynamicaly created in the tmp directory and then deleted.
TablesToBackup="TablesToBackup.txt"

# Updates may require a step or two to complete the process.
# This ensures we have call enough steps even if some aren't needed.
UpgradeURL[1]='/wp-admin/upgrade.php'
UpgradeURL[2]='/wp-admin/upgrade.php?step=1&backto='
UpgradeURL[3]='/wp-admin/upgrade.php?step=2&backto='
UpgradeURL[4]='/wp-admin/upgrade.php?step=3&backto='

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



# ##################################################################
#  Functions 
# ##################################################################

# ###################################################
#  ShowMessage 
#  Displays a message on the screen AND logs it.
# ###################################################
function ShowMessage {
  echo $1
  if [ $LogToFile ]
  then    
    echo "$1<br/>"|sed 's/ /\&nbsp;/g'>>$LogFile
  fi
}

# ###################################################
#  LogMessage
#  Records the message only in the log. Not visible.
# ###################################################
function LogMessage {
  if [ $LogToFile ]
  then
    echo "$1<br/>"|sed 's/ /\&nbsp;/g'>>$LogFile
  fi
}

# ###################################################
#  OpenLogFile 
#  Creates a web log. (A blog if you will ;) )
# ###################################################
function OpenLogFile {
  echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'>$LogFile
  echo '<html>'>>$LogFile
  echo '<head>'>>$LogFile
  echo '<title>The Easy WordPress Update Script from TheCodeCave.com</title>'>>$LogFile
  if [ $Verbose ]
  then
    echo '<style>'>>$LogFile
    echo 'body {font: 15px Georgia, "Times New Roman" Georgia Times serif; margin: 0; padding: 0; text-align: center; color: #2d2d2d; }'>>$LogFile
    echo 'A:link {COLOR: #726474;      font-size: 15px; TEXT-DECORATION: none;}'>>$LogFile
    echo 'A:visited {COLOR: #726474;font-size: 15px;TEXT-DECORATION: none}'>>$LogFile
    echo 'a:hover { color: #345bfe; }'>>$LogFile
    echo 'h1, h2, h3 { margin: 0; padding: 0; }'>>$LogFile
    echo 'p { line-height: 22px; }'>>$LogFile
    echo '.extended a:link {font-size:11px; }'>>$LogFile
    echo '.extended A:visited {COLOR: #726474;font-size: 11px;TEXT-DECORATION: none}'>>$LogFile
    echo '.extended a:hover { color: #345bfe;font-size: 11px }'>>$LogFile
    echo '.extended {font-size: 11px; }'>>$LogFile
    echo '</style>'>>$LogFile
  fi
  echo '</head>'>>$LogFile
  echo '<body>'>>$LogFile
  echo '<h1><font color="#003399">Word</font>Press <font color="#003399">Update Script</font></h1>'>>$LogFile
  echo '<br/>'>>$LogFile
  echo "<center>$(date)</center><br/>">>$LogFile
  echo '<br/>'>>$LogFile
  if [ $Verbose ]
  then
    echo '<TABLE WIDTH=700 BORDER=0 CELLPADDING=20 CELLSPACING=0 align="center"  style="BORDER: #000000 1px solid;" bgcolor="#FFFFFF">'>>$LogFile
    echo '<TR><TD>'>>$LogFile
    echo '<div align=left>'>>$LogFile
  fi
}

# ###################################################
#  CloseLogFile
#  Closes off the web log
# ###################################################
function CloseLogFile {
  if [ $Verbose ]
  then
    echo '<br/>'>>$LogFile
    echo '<br/>'>>$LogFile
    echo '<br/>'>>$LogFile
    echo '<center><hr width=40%></center>'>>$LogFile
    echo '<div class="extended">'>>$LogFile
    echo '<br/>'>>$LogFile
    echo '<center><a href="http://www.TheCodeCave.com">The Code Cave</a> - <a href="http://www.TheCodeCave.com/EasyWPUpdate">The latest EasyWPUpdate Script</a> - <a href="http://www.wordpress.org/support">WordPress Support</a> - <a href="http://www.BloggersBuildAHouse.org">Bloggers Build a House</a> - <a href="http://www.wordpress.org/development">Latest WP News</a></center>'>>$LogFile
    echo '</div>'>>$LogFile
    echo '</TD>'>>$LogFile
    echo '</TR></TABLE>'>>$LogFile
  fi
  echo '</body>'>>$LogFile
  echo '</html>'>>$LogFile
}

# ###################################################
#  CleanUp 
#  Performs the tasks that MUST happen when the 
#  script exits cleanly or abrupty due to an error.
# ###################################################
function CleanUp {
  # Each new section gets a blank line for readablity
  ShowMessage 

  # Always remove the temp directory we created
  rm -R "$tmp" 
  LogMessage "Temp directory removed."
  
  # Close the log file if it is used.
  if [ $LogToFile ]
  then
    ShowMessage 
    ShowMessage
    ShowMessage
    ShowMessage "Process Ended at $(date)"
    ShowMessage "Log file written to: $LogFile"
    CloseLogFile
  fi
}

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



# ##################################################################
#  The Works
# ##################################################################

# ##################################################################
#  Create a log file if one is needed.
# ##################################################################
if [ $LogToFile ]
then
  OpenLogFile
fi

# ##################################################################
#  Provide a summary of what will be done.
# ##################################################################
ShowMessage "This update session was begun at $(date)"
ShowMessage 
if [ $Verbose ]
then
  BlogCount=${#BlogDir[@]}
  ShowMessage "This session will update $BlogCount WordPress installs:"
  # Show them
  let "index=1"
  for CurDir in "${BlogDir[@]}"
  do
    CurBlogURL=${BlogURL[$index]}
    ShowMessage "    $CurBlogURL in the directory: $CommonBackupPrefix$BackupSuffix/$CurDir"
    let "index=$index+1"
  done
  ShowMessage
  ShowMessage "With the following options:"
  if [ $BackupFilesToTarball ]||[ $BackupFilesToDir ]
  then 
    if [ $BackupFilesToTarball ]; then ShowMessage "    Files will be backed up to a compressed achive"; fi
    if [ $BackupFilesToDir ]; then ShowMessage "    Files will be backed up to an uncompressed directory"; fi
  else
    ShowMessage "    Files will be **NOT** be backed up"
  fi
  if [ $MakeSQLBackups ] 
  then 
    ShowMessage "    The data tables for each blog will be exported to a compressed backupfile"
  else 
    ShowMessage "    The database will **NOT** be backed up"
  fi
  if [ $PerformWebSteps ]
  then 
    ShowMessage "    Each blog will be updated via the web after the file update is complete."
  else 
    ShowMessage "   Each blog must be updated manually on its website."
  fi
  if [ $LogToFile ]; then ShowMessage "    Logging to file: $CommonBackupPrefix$LogFile"; fi
  if [ $Verbose ]; then ShowMessage "    Maximum Verbosity"; fi
  ShowMessage 
  ShowMessage "The following directories will be used:"
  ShowMessage "    The blogs are all in the common folder: $CommonRootPrefix"
  ShowMessage "    The backups will be placed in: $CommonBackupPrefix"
  ShowMessage "    The SQL backups will be in: $CommonSQLBackupPrefix"
  ShowMessage "    The log file will be: $LogFile"

  ShowMessage
  if [ $SourcePath ]
  then
    ShowMessage "The update is coming from a file: $SourcePath/$ArchiveName"
  else
    if [ $SourceURL ]
    then
      ShowMessage "The update is coming from a website: $SourceURL$ArchiveName"
	else
	  ShowMessage "No update will be performed as no source was specified."
	fi
  fi
  ShowMessage
  ShowMessage
  ShowMessage "Starting Update..."
  ShowMessage
fi

# ##################################################################
#  Make a temp directory
#  Why do I do it this way? Compatiblity.
#  Tempfile -d has different implementations
#  mktemp -d isn't on all systems
#  $RANDOM doesn't HAVE need to be seeded on Bash but seeding it
#  also means that $RANDOM doesn't make this script bash specific.
# ##################################################################

#  Seed or create $RANDOM
RANDOM=$$$(date +%N)  # %N is nano seconds

# Make Temporary directory for downloading the WordPress file
tmp=${TMPDIR:-/tmp}
tmp="$tmp/$TMPPrefix$RANDOM$RANDOM$RANDOM.$$"
(umask 077 && mkdir "$tmp") || {
  ShowMessage "Could not create temporary directory! Exiting." 1>&2
  exit $E_XMD
}

# Show this to allow potential manual cleanup...
ShowMessage "A temp dir was created at: $tmp"

# ##################################################################
#  Set the global traps
# ##################################################################

# Trap 0 always runs on success or fail - or so I'm told
# Now that the $temp dir exists, trap for it's deletion.
trap "CleanUp" 0


# ##################################################################
#  Retrieve the archive and extract it
# ##################################################################

# For debuging purposes you can disable the update part of this script
# by not specifying a source.
if [ $SourcePath ]||[ $SourceURL ]
then
  # Each new section gets a blank line for readablity
  ShowMessage

  #Change to the temporary directory
  cd $tmp

  # Doublecheck if in right directory, before messing with downloading files.
  if [ `pwd` != "$tmp" ]
  then
    ShowMessage "Can't change to new temp dir: $tmp.  Aborting."
    exit $E_XCD
  fi

  # Download/Copy the Archive into the temp directory, extract it and deleted it.
  if [ $SourcePath ]
  then
    LogMessage "Copying File: $SourcePath/$ArchiveName"
    (cp "$SourcePath/$ArchiveName" "$tmp") || {
      ShowMessage "Archive file ($SourcePath/$ArchiveName) could not be copied.  Aborting."
      exit $E_XNOFILE
    }

    LogMessage "Archive file ($SourcePath/$ArchiveName) copied."
  else
    ShowMessage "GETTING URL: $SourceURL$ArchiveName"
    (wget "$SourceURL$ArchiveName")|| {
      ShowMessage "Archive file ($SourceURL$ArchiveName) could not be retrieved.  Aborting."
      exit $E_XNOFILE
    }
    ShowMessage "Archive file ($SourceURL$ArchiveName) retrieved."
  fi

  # If we are here, we have an archive.  Untar it.
  (tar -zxf "$ArchiveName")|| {
      ShowMessage "Tarball $tmp/$ArchiveName could not be decompressed.  Aborting.  Is GNU Tar installed?"
      exit $E_XNOFILE
  }

  # Delete it if uncompression was successful
  rm "$ArchiveName"

  ShowMessage "Uncompression was successful and the copy of the archive has been removed."
fi


# ##################################################################
#  Create backups of the files.
# ##################################################################

# Only enter this section if some kind of backup will be made.
if [ $BackupFilesToDir ]||[  $BackupFilesToTarball ]
then
  # Each new section gets a blank line for readablity
  ShowMessage

  BackupSuffix=-$(date +%F)
  if [ ! -d "$CommonBackupPrefix$BackupSuffix" ]; then
    (umask 077 && mkdir -p "$CommonBackupPrefix$BackupSuffix") || {
      ShowMessage "Could not create common backup directory ($CommonBackupPrefix$BackupSuffix). Exiting." 1>&2
      exit $E_XMD
    }
  fi

  for CurDir in "${BlogDir[@]}"
  do
    if [ $Verbose ]
	then
	  ShowMessage "Back up started for: $CurDir"
	  ShowMessage "Please be patient. This may take a while."
	fi

    #Make the backup dir
    BackupDir="$CommonBackupPrefix$BackupSuffix/$CurDir"

    if [ ! -d "$BackupDir" ]
    then
      (umask 077 && mkdir -p "$BackupDir") || {
        ShowMessage "Could not create common backup directory ($BackupDir). Exiting." 1>&2
        exit $E_XMD
      }
    fi 

    # Backup the files in the root, with no recursion
    if [ $BackupFilesToTarball ]
    then
      # Work out of the blog dir to create relative path in tarball
      cd "$CommonRootPrefix/$CurDir"

      # Convert the WPDirs array into a the format we need for tar
      for CurSubDir in "${WPDirs[@]}"
      do
        if [ -d "$CommonRootPrefix/$CurDir/$CurSubDir" ]
        then
          SubDirs="$SubDirs ./$CurSubDir"
        else 
          ShowMessage "  WARNING: $CommonRootPrefix/$CurDir/$CurSubDir not found. This is not an error.  Continuing."
        fi
      done

      # Backup the blog dir and only the requested sub dirs, replacing the tarball
      # if it already exists.
      (tar --no-recursion -zcf "$BackupDir/$BackupTarballName" . --recursion $SubDirs) || {
        ShowMessage "Tar Backups failed.  Permissions issue?  Aborting." 1>&2
        rm -R "$BackupDir"
        exit $E_XBACKUP
      }
      if [ $Verbose ] 
	  then 
	    ShowMessage "  Backup of files to $BackupDir/$BackupTarballName complete." 1>&2
	  fi
    fi

    if [ $BackupFilesToDir ]
    then
      # Work out of the Backup dir to create relative paths in directory
      cd "$BackupDir"

      LogMessage "  Making $CurDir backup to $BackupDir"

      # Copy all of the files in the root of the blog directory
      # --remove-destination erases a file if it exists in the backup directory
      # That would only happen if you update twice in the same day.
	  LogMessage "Calling 'cp --remove-destination \"$CommonRootPrefix/$CurDir/\"* .'"
      cp --remove-destination "$CommonRootPrefix/$CurDir/"* .

      # Loop through all of the sub directories we want to backup. 
      for CurSubDir in "${WPDirs[@]}"
      do
        if [ -d "$CommonRootPrefix/$CurDir/$CurSubDir" ]
        then
          ShowMessage "  Making $CurDir/$CurSubDir backup to $BackupDir/$CurSubDir"
          if [ ! -d "$BackupDir/$CurSubDir" ]
          then
            (umask 077 && mkdir -p "$BackupDir/$CurSubDir") || {
              ShowMessage "Could not create backup sub directory ($BackupDir/$CurSubDir).  Aborting." 1>&2
              rm -R "$BackupDir"
              exit $E_XBACKUP
            }
          fi
          cd "$BackupDir/$CurSubDir"
          LogMessage "Calling 'cp -R --remove-destination \"$CommonRootPrefix/$CurDir/\"* .'"
          (cp -R --remove-destination "$CommonRootPrefix/$CurDir/$CurSubDir/"* .) || {
            ShowMessage "Backup Process not complete ($BackupDir/$CurSubDir).  Aborting." 1>&2
            rm -R "$BackupDir"
            exit $E_XBACKUP
          }
        fi
      done
    fi
  done
  ShowMessage "All file backups have been completed successfully."
else
  ShowMessage "File backups skipped.  Neither file backup option was enabled."
fi 



# ##################################################################
#  Perform the full table backups before touching any files.
# ##################################################################

# Only do this if needed.
if [ $MakeSQLBackups ]
then
  # Each new section gets a blank line for readablity
  ShowMessage 

  ShowMessage "Making Targeted Database Backups..."
  BackupSuffix=-$(date +%F)
  if [ ! -d $CommonSQLBackupPrefix$BackupSuffix ]; then
    (umask 077 && mkdir -p $CommonSQLBackupPrefix$BackupSuffix) || {
      ShowMessage "Could not create common SQL backup directory ($CommonBackupPrefix$BackupSuffix). Exiting." 1>&2
      exit $E_XMD
    }
  fi
  for CurDir in "${BlogDir[@]}"
  do
    if [ $Verbose ]
    then
      ShowMessage "Processing SQL Backup for: $CurDir"
    fi
    BackupDir="$CommonSQLBackupPrefix$BackupSuffix/$CurDir"
    if [ ! -d "$BackupDir" ]; then
      (umask 077 && mkdir -p "$BackupDir") || {
        ShowMessage "Could not create SQL backup directory ($BackupDir). Exiting." 1>&2
        exit $E_XMD
      }
    fi
    cd "$CommonRootPrefix/$CurDir/"
    DB_NAME=$(sed -n "/define('DB_NAME', '/s/.*, '\([^']*\).*/\1/p" wp-config.php)
    DB_USER=$(sed -n "/define('DB_USER', '/s/.*, '\([^']*\).*/\1/p" wp-config.php)
    DB_PASSWORD=$(sed -n "/define('DB_PASSWORD', '/s/.*, '\([^']*\).*/\1/p" wp-config.php)
    DB_HOST=$(sed -n "/define('DB_HOST', '/s/.*, '\([^']*\).*/\1/p" wp-config.php)
    TABLE_PREFIX=$(sed -n "/\$table_prefix  = '/s/.*= '\([^']*\).*/\1/p" wp-config.php)
    (mysql $DB_NAME --port=3306 --protocol=TCP --host=$DB_HOST  --user=$DB_USER --password=$DB_PASSWORD -e"show tables like '$TABLE_PREFIX%'">$tmp/$TablesToBackup)||{
      ShowMessage "Could not retrieve table names. SQLBackup failed."
      exit $E_XSQLBackupFailed
    }

    WPTables=$(sed -e "/^\($TABLE_PREFIX[^ ]*\).*/!d;s//\1/" -e :b -e "N;s/\n/ /;bb" $tmp/$TablesToBackup)
   (mysqldump --opt --port=3306 --protocol=TCP --host=$DB_HOST  --user=$DB_USER --password=$DB_PASSWORD $DB_NAME $WPTables | gzip > $BackupDir/$MySQLDumpFileName)||{
     ShowMessage "SQL Dump Failed"
    exit $E_XSQLBackupFailed
   }
  done
else
  ShowMessage "Database backups skipped.  The were not enabled."
fi 


# ##################################################################
#  Perform the update of the files
# ##################################################################

# For debuging purposes you can disable the update part of this script 
# by not specifying a source.
if [ $SourcePath ]||[ $SourceURL ]
then
  # Each new section gets a blank line for readablity
  ShowMessage 

  # In order to access two arrays from the same loop, I am putting in a simple counter
  # This counter starts at 1. So DO NOT change the starting index of the arrays to 0
  # without also changing this next line.
  let "index=1"
  # Iterate all of the directories and overwrite their contents.
  for CurDir in "${BlogDir[@]}"
  do
    ShowMessage "Now Updating: $CurDir"

    # Go to each directory
    cd $CommonRootPrefix/$CurDir

    # Doublecheck if in right directory, before messing with files.
    if [ `pwd` != "$CommonRootPrefix/$CurDir" ]
    then
      ShowMessage "Can't reach one of the blog directories: $CommonRootPrefix/$CurDir. Aborting."
      rm $CommonBackupPrefix$BackupSuffix -R # Don't leave the backup dirs out there if they are not complete
      exit $E_XCD
    fi      

    # Copy all of of the files from the temp dir
    (cp -R --remove-destination $tmp/wordpress/* . ) || {
      ShowMessage "CATASTRAUPHIC FAILURE: The update of $CommonRootPrefix/$CurDir started but failed."
      ShowMessage "The site ${BlogURL[$index]} is probably down.  Restore the files from the backup."
      if [ $BackupFilesToDir ]||[  $BackupFilesToTarball ]
      then
        ShowMessage "You may wish to attempt a recovery using the following steps:"    
        ShowMessage "   cd ""$CommonRootPrefix/$CurDir"""
        if [ $BackupFilesToDir ]
        then
          ShowMessage "   tar -zxf ""$CommonBackupPrefix$BackupSuffix/$CurDir/$BackupTarballName"""
        else
          ShowMessage "   cp ""$CommonBackupPrefix$BackupSuffix/$CurDir/""* ."
        fi
      ShowMessage "Your database was not touched."
    else
        ShowMessage "You did not have the script create a backup."
        ShowMessage "Restore from your own backup files."
      fi
      exit $E_XPARTIALUpdate
    }

    # If enabled, update this blog NOW rather than waiting. Besides,
    # an error might occur later that prevents us reaching a common
    # websteps section at the end of the script.
    if [ $PerformWebSteps ]
    then
      # Call wget for each blog
      CurBlogURL=${BlogURL[$index]}
      ShowMessage "  Perfoming Online Steps for: $CurBlogURL"
      for CurUpgradeURL in "${UpgradeURL[@]}"
      do
        LogMessage "  Calling wget -O /dev/null -q $CurBlogURL$CurUpgradeURL"
        wget -O /dev/null -q $CurBlogURL$CurUpgradeURL
      done
    fi

    # Get the loop ready for the next url
    let "index=$index+1"
    ShowMessage "$CurDir Update complete"
    ShowMessage
  done
else
  ShowMessage "No source was specified for the update.  Update skipped for all blogs."
fi

# ##################################################################
#  Close
# ##################################################################

# Each new section gets a blank line for readablity
ShowMessage
ShowMessage
ShowMessage "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
ShowMessage "Update Complete."
ShowMessage "$BlogCount Blogs updated."
ShowMessage "There... wasn't that fun?"
ShowMessage "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"

exit $E_SUCCESS