#!/bin/sh # Dump directories in cool dry place :-) # # To allow to run, you must include # weekly_backup_enable=YES # in your /etc/periodic.conf. Also you can specify next settings: # # There are common settings # weekly_backup_fileplace="/path/to/backup" # weekly_backup_dirs_cfg="/path/to/backup/dirs/config" # weekly_backup_owner="owner" # weekly_backup_group="group" # weekly_backup_mode="octal_mode_like_0644" # weekly_backup_dirmode="octal_mode_like_0755" # weekly_backup_startup="/path/to/startup/scripts" # # These settings used for SMBFS # weekly_backup_connect="username" # # These settings used for databases at all # weekly_backup_dbconnect_conf="/path/to/dbconnect.conf" # # Backup dirs config is a simply text file with ordinary comment char (#) and # three sections - [daily], [weekly] and [monthly]. At each sections you should # specify one-by-line path to directory, which should be backup. # # '|' char in directory path specifies "separable part" which will be separated # before checking mount point and doing mounting. This will intended mostly for # SMB backup to allow backup some underlying part of mounted directory # # BEWARE! You can backup only whole MSDOS/SMBFS filesystems or shares! # Filesystems are: UFS (any Unix FS), MSDOS, SMBFS # In order to mount MSDOS FS you should describe it in /etc/fstab, as usual # In order to mount SMBFS filesystems you should have necessary kernel config # lines (man smbfs) and preliminary setuped nsmbrc.conf (.nsmbrc in root home also) # Also you should have filled in .mssmbrc file in root homedir, described ALL # backed up SMB shares. Also you must describe server in /etc/nsmb.conf # # BEWARE! All mount points MUST be created before starting script! # # When you specify SMBFS filesystem, connect will doing with $weekly_backup_connect # credenitals, not $weekly_backup_owner! # # BSD License. Copyright (C) by Rashid N. "CityCat" Achilov # $Id: 150.backup-dirs,v 1.1.1.1 2008/02/06 18:19:11 shelton Exp $ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/local/mysql/bin # Parse sectioned configuration file. # Read and parse sectioned configuration file (Windows standart, [section] # as separator, and massive "name=value" pairs with related info # # Input: section (string) - section name to search # filename (string) - filename to read # Output: line (string) - line, which contains "name=value" pairs # parse_sectioned_config() { # Throw out comments from file bla=`awk '{if ($1 == "#") next; else print $0}' < $filename` # Spilt by first [ bracket, so chunks will be: # "section] /path/to /path/to" "section] /path/another /path/more" saveifs=$IFS IFS=[ set $bla # Take one chunk as "section] /path/to /path/more" for blabla in $bla do IFS=] set $blabla # Split by second bracket, so chunks will be: "section" "/path/to /path/more" # This need for checking section name if [ $1 = $section ]; then line=$2 IFS=$saveifs return fi done } # Create storage directory # # Input: none # Output: none # create_storage_directory() { if [ ! -e $weekly_backup_fileplace ]; then echo "Root fileplace missing, will be created now" mkdir $weekly_backup_fileplace chown $weekly_backup_owner:$weekly_backup_group $weekly_backup_fileplace chmod $weekly_backup_dirmode $weekly_backup_fileplace fi # Create underlying directoris, when missed if [ ! -e $weekly_backup_fileplace/$fileyear ]; then mkdir $weekly_backup_fileplace/$fileyear chown $weekly_backup_owner:$weekly_backup_group $weekly_backup_fileplace/$fileyear chmod $weekly_backup_dirmode $weekly_backup_fileplace/$fileyear fi if [ ! -e $weekly_backup_fileplace/$fileyear/$filemon-$fileyear ]; then mkdir $weekly_backup_fileplace/$fileyear/$filemon-$fileyear chown $weekly_backup_owner:$weekly_backup_group $weekly_backup_fileplace/$fileyear/$filemon-$fileyear chmod $weekly_backup_dirmode $weekly_backup_fileplace/$fileyear/$filemon-$fileyear fi if [ ! -e $weekly_backup_fileplace/$fileyear/$filemon-$fileyear/$fileday-$filemon-$fileyear ]; then mkdir $weekly_backup_fileplace/$fileyear/$filemon-$fileyear/$fileday-$filemon-$fileyear chown $weekly_backup_owner:$weekly_backup_group $weekly_backup_fileplace/$fileyear/$filemon-$fileyear/$fileday-$filemon-$fileyear chmod $weekly_backup_dirmode $weekly_backup_fileplace/$fileyear/$filemon-$fileyear/$fileday-$filemon-$fileyear fi } # If there is a global system configuration file, suck it in. # if [ -r /etc/defaults/periodic.conf ] then . /etc/defaults/periodic.conf source_periodic_confs fi # Set directory lists fileyear=`date "+%Y"` filemon=`date "+%m"` fileday=`date "+%d"` # Set various flags domount="no" doclean="no" dostop="no" # Newline separator nlsep=" " case "$weekly_backup_enable" in [Yy][Ee][Ss]) echo "" echo "Weekly portion backup:" # Simply parameters check. Backup list missing issued abort, other issued # change it to default mode if [ -z "$weekly_backup_dirs_cfg" ]; then echo 'weekly_backup_enable is set but' \ 'weekly_backup_dirs is not' rc=2 fi if [ ! -e "$weekly_backup_dirs_cfg" ]; then echo '$weekly_backup_dirs_cfg file does not exist' \ rc=2 fi if [ -z "$weekly_backup_fileplace" ]; then echo 'weekly_backup_enable is set but' \ 'weekly_backup_fileplace is not' rc=2 fi # On place cd / filepath="$weekly_backup_fileplace/$fileyear/$filemon-$fileyear/$fileday-$filemon-$fileyear" # Separate weekly backup section from backup list file section="weekly" filename=$weekly_backup_dirs_cfg parse_sectioned_config backdirs=$line # When backup list contains at least one entry, do backup, else go home if [ ${#backdirs} -eq 0 ]; then echo "Nothing to $section backup" else create_storage_directory fi IFS=$nlsep # Process one backup entry point specification for onedir in $backdirs do # Parse record about one backup entry point saveifs=$IFS IFS=: set $onedir bpath=$1 bfsys=$2 bstopper=$3 # Check on presence filesystem type if [ ${#bfsys} -eq 0 ]; then echo "Filesystem type omitted, entry point $onedir ignored" continue fi # Display appropriate message if [ $bfsys = "mysql" ] || [ $bfsys = "pgsql" ]; then echo "Backup $bpath database (database type $bfsys)" else echo "Backup $bpath directory (filesystem $bfsys)" fi # Check on presence separable part IFS="|" set $bpath bmount=$1 bsepart=$2 IFS=$saveifs # Issue stop processes, which can modify data at target directory if [ ! ${#bstopper} -eq 0 ]; then dostop="yes" $weekly_backup_startup/$bstopper stop fi # Check about mounted filesystems. UFS don't check, MSDOS and SMBFS will check case "$bfsys" in # UFS (mean any Unix filesystem, not real UFS1 FS!) doesn't check at all ufs) ;; # MSDOS filesystem will check and auto-mount, when necessary msdos) dosmp=`grep $bpath /etc/fstab` if [ -z $dosmp ]; then echo "$bpath missed in /etc/fstab, mount aborted" rc=3 else # Checking, if this share was already mounted mounts=`mount | grep $bpath` if [ -z $mounts ]; then mount $bpath if [ $? -ne 0 ]; then status=$? echo "$bpath cannot be mounted, error code is $status" rc=3 else domount="yes" fi fi fi ;; # SMBFS filesystem will check and auto-mount, when necessary smbfs) # Check on presence HOME environment variable homedir=`grep $weekly_backup_owner /etc/passwd | \ awk 'BEGIN {FS=":"} {print $6}'` # Check on existance backup owner home directory if [ ! -e $homedir ]; then echo "Backup user has not home directory" rc=3 continue fi # Checking on presence description in .mssmbrc in home dir smbmp=`grep $bmount $homedir/.mssmbrc` if [ -z "$smbmp" ]; then echo "$bmount missed in $homedir/.mssmbrc, mount aborted" rc=3 else set $smbmp userver=`echo $1 | tr "[:lower:]" "[:upper:]"` # Checking on presence server description in /etc/nsmb.conf gserver=`grep $userver /etc/nsmb.conf` if [ -z $gserver ]; then echo "$1 did not described in /etc/nsmb.conf, mount aborted" rc=3 fi # Checking, if this share was already mounted mounts=`mount | grep $bmount` if [ -z "$mounts" ]; then mount_smbfs -f $5 -d $4 \ //$weekly_backup_connect@$1/$2 $bmount if [ $? -ne 0 ]; then status=$? echo "$bmount cannot be mounted, error code is $status" rc=3 else domount="yes" fi fi fi ;; # Mysql is pseudo-filesystem, real is it a database mysql) # First, we should check some needful parameters if [ -z "$weekly_backup_dbconnect_conf" ]; then echo 'backup list includes mysql fs, but ' \ 'weekly_backup_dbconnect_conf is not set' rc=3 continue fi # Also we should check "mysql" presence wmysql=`which mysql` if [ -z $wmysql ]; then echo 'backup list includes mysql fs, but ' \ 'cannot find mysql binary' rc=3 continue fi # Set default token values port="3306" location="/var/db/mysql" hostname="localhost" # Connection tickets file found, we should read and parse it section=$bpath filename=$weekly_backup_dbconnect_conf parse_sectioned_config tokens=$line # Issue tokens recognizion for onetoken in $tokens do eval $onetoken done # We try to read tables list from database tables=`$wmysql -B -u $user -h $hostname -P $port -p$password \ -e "use $bpath; show tables;" | tail -n +2` # When attempt was unsuccesful, it means credenitals were invalid status=$? if [ $status -ne 0 ]; then echo "Cannot read tables list from database $bpath, " \ "probably invalid authentication credenitals" rc=3 continue fi # Else we lock database from changes and copy it. # BEWARE! We MUST copy in current MySQL connection context, elsewhere MySQL # drops any our locks. # Before lock, we should prepare list of tables, included in database comma=0 locks="" for onetable in $tables do if [ ! $comma -eq 0 ]; then locks="$locks, " fi locks="$locks $onetable read" comma=1 done # Next we issuing lock and copy at ONE process! printf "use $bpath;\nlock tables $locks;\n \ \\\! cp -Rp $location/$bpath $filepath;\nunlock tables;" | \ mysql -B -n -u $user -P $port -h $hostname -p$password status=$? if [ $status -ne 0 ]; then echo "Cannot copy tables for base $bpath, " \ "copying routine returned $status" rc=3 continue fi # Here we substitute copied database as backup object cd $filepath bmount=$bpath # And here we set clean flag doclean="yes" ;; *) echo "Unsupported filesystem type: $bfsys" rc=3 ;; esac # Doing backup and reset rights tradir=`echo $bmount$bsepart | sed 's@/@_@g'` tar -cyf "$filepath/$tradir.tar.bz2" $bmount$bsepart > /dev/null 2> /dev/null \ && chown $weekly_backup_owner:$weekly_backup_group $filepath/$tradir.tar.bz2 \ && chmod $weekly_backup_mode $filepath/$tradir.tar.bz2 \ && rc=0 || rc=3 # Doing umount share, when it was mounted by script itself if [ $domount = "yes" ]; then umount $bmount if [ $? -ne 0 ]; then status=$? echo "Umount $bmount failed, error code is $status" rc=3 fi fi # Doing clean action, when need if [ $doclean = "yes" ]; then rm -rf $bmount$bsepart fi # Doing start server action, when need if [ $dostop = "yes" ]; then $weekly_backup_startup/$bstopper start fi done ;; *) rc=0;; esac exit $rc