Commit a comprehensive file describing how to do incremental backups along
authorMatthew Dillon <dillon@dragonflybsd.org>
Sat, 16 Sep 2006 21:57:10 +0000 (21:57 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sat, 16 Sep 2006 21:57:10 +0000 (21:57 +0000)
with some example scripts.

bin/cpdup/BACKUPS [new file with mode: 0644]
bin/cpdup/PORTING [moved from bin/cpdup/README with 51% similarity]
bin/cpdup/scripts/crontab [new file with mode: 0644]
bin/cpdup/scripts/do_cleanup [new file with mode: 0755]
bin/cpdup/scripts/do_mirror [new file with mode: 0755]
bin/cpdup/scripts/do_mirror_host [new file with mode: 0755]
bin/cpdup/scripts/do_remote [new file with mode: 0755]
bin/cpdup/scripts/do_remote_host [new file with mode: 0755]
bin/cpdup/scripts/params [new file with mode: 0644]

diff --git a/bin/cpdup/BACKUPS b/bin/cpdup/BACKUPS
new file mode 100644 (file)
index 0000000..b893012
--- /dev/null
@@ -0,0 +1,258 @@
+$DragonFly: src/bin/cpdup/BACKUPS,v 1.1 2006/09/16 21:57:08 dillon Exp $
+
+                           INCREMENTAL BACKUP HOWTO
+
+    This document describes one of several ways to set up a LAN backup and
+    an off-site WAN backup system using cpdup's hardlinking capabilities.
+
+    The features described in this document are also encapsulated in scripts
+    which can be found in the scripts/ directory.  These scripts can be used
+    to automate all backup steps except for the initial preparation of the
+    backup and off-site machine's directory topology.  Operation of these
+    scripts is described in the last section of this document.
+
+
+                   PART 1 - PREPARE THE LAN BACKUP BOX
+
+    The easiest way to create a LAN backup box is to NFS mount all your
+    backup clients onto the backup box.  It is also possible to use cpdup's
+    remote host feature to access your client boxes but that requires root
+    access to the client boxes and is not described here.
+
+    Create a directory on the backup machine called /nfs, a subdirectory
+    foreach remote client, and subdirectories for each partition on each
+    client.  Remember that cpdup does not cross mount points so you will
+    need a mount for each partition you wish to backup.  For example:
+
+       [ ON LAN BACKUP BOX ]
+
+       mkdir /nfs
+       mkdir /nfs/box1
+       mkdir /nfs/box1/home
+       mkdir /nfs/box1/var
+
+    Before you actually do the NFS mount, create a dummy file for each
+    mount point that can be used by scripts to detect when an NFS mount
+    has not been done.  Scripts can thus avoid a common failure scenario
+    and not accidently cpdup an empty mount point to the backup partition
+    (destroying that day's backup in the process).
+
+       touch /nfs/box1/home/NOT_MOUNTED
+       touch /nfs/box1/var/NOT_MOUNTED
+
+    Once the directory structure has been set up, do your NFS mounts and
+    also add them to your fstab.  Since you will probably wind up with a
+    lot of mounts it is a good idea to use 'ro,bg' (readonly, background
+    mount) in the fstab entries.
+
+       mount box1:/home /nfs/box1/home
+       mount box1:/var /nfs/box1/var
+
+    You should create a huge /backup partition on your backup machine which
+    is capable of holding all your mirrors.  Create a subdirectory called
+    /backup/mirrors in your huge backup partition.
+
+       mount <huge_disk> /backup
+       mkdir /backup/mirrors
+
+
+                       PART 2 - DOING A LEVEL 0 BACKUP
+
+    (If you use the supplied scripts, a level 0 backup can be accomplished
+    simply by running the 'do_mirror' script with an argument of 0).
+
+    Create a level 0 backup using a standard cpdup with no special arguments
+    other then -i0 -s0 (tell it not to ask questions and turn off the
+    file-overwrite-with-directory safety feature).  Name the mirror with
+    the date in a string-sortable format.
+
+       set date = `date "+%Y%m%d"`
+       mkdir /backup/mirrors/box1.${date}
+       cpdup -i0 -s0 /nfs/box1/home /backup/mirrors/box1.${date}/home
+       cpdup -i0 -s0 /nfs/box1/var /backup/mirrors/box1.${date}/var
+
+    Create a softlink to the most recently completed backup, which is your
+    level 0 backup.
+
+       sync
+       ln -fs /backup/mirrors/box1.${date} /backup/mirrors/box1
+
+                       PART 3 - DO AN INCREMENTAL BACKUP
+
+    An incremental backup is exactly the same as a level 0 backup EXCEPT
+    you use the -H option to specify the location of the most recent 
+    completed backup.  We simply maintain the handy softlink pointing at
+    the most recent completed backup and the cpdup required to do this
+    becomes trivial.
+
+    Each day's incremental backup will reproduce the ENTIRE directory topology
+    for the client, but cpdup will hardlink files from the most recent backup
+    instead of copying them and this is what saves you all the disk space.
+
+       set date = `date "+%Y%m%d"`
+       mkdir /backup/mirrors/box1.${date}
+       if ( "`readlink /backup/mirrors/box1`" == "box1.${date}" ) then
+           echo "silly boy, an incremental already exists for today"
+           exit 1
+       endif
+       cpdup -H /backup/mirrors/box1 \
+             -i0 -s0 /nfs/box1/home /backup/mirrors/box1.${date}/home
+
+    Be sure to update your 'most recent backup' softlink, but only do it
+    if the cpdup's for all the partitions for that client have succeeded.
+    That way the next incremental backup will be based on the previous one.
+
+       ln -fs /backup/mirrors/box1.${date} /backup/mirrors/box1
+
+    Since these backups are mirrors, locating a backup is as simple
+    as CDing into the appropriate directory.  If your filesystem has a
+    hardlink limit and cpdup hits it, cpdup will 'break' the hardlink
+    and copy the file instead.  Generally speaking only a few special cases
+    will hit the hardlink limit for a filesystem.  For example, the
+    CVS/Root file in a checked out cvs repository is often hardlinked, and
+    the sheer number of hardlinked 'Root' files multiplied by the number 
+    of backups can often hit the filesystem hardlink limit.
+
+                   PART 4 - DO AN INCREMENTAL VERIFIED BACKUP
+
+    Since your incremental backups use hardlinks heavily the actual file
+    might exist on the physical /backup disk in only one place even though
+    it may be present in dozens of daily mirrors.  To ensure that the
+    file being hardlinked does not get corrupted cpdup's -f option can be
+    used in conjuction with -H to force cpdup to validate the contents 
+    of the file, even if all the stat info looks identical.
+
+       cpdup -f -H /backup/mirrors/box1 ...
+
+    You can create completely redundant (non-hardlinked-dependant) backups
+    by doing the equivalent of your level 0, i.e. not using -H.  However I
+    do NOT recommend that you do this, or that you do it very often (maybe
+    once every 6 months at the most), because each mirror created this way
+    will have a distinct copy of all the file data and you will quickly
+    run out of space in your /backup partition.
+
+                   MAINTAINANCE OF THE "/backup" DIRECTORY
+
+    Now, clearly you are going to run out of space in /backup if you keep
+    doing this, but you may be surprised at just how many daily incrementals
+    you can create before you fill up your /backup partition.
+
+    If /backup becomes full, simply start rm -rf'ing older mirror directories
+    until enough space is freed up.   You do not have to remove the oldest
+    directory first.  In fact, you might want to keep it around and remove
+    a day's backup here, a day's backup there, etc, until you free up enough
+    space.
+
+                               OFF-SITE BACKUPS
+
+    Making an off-site backup involves similar methodology, but you use
+    cpdup's remote host capability to generate the backup.  To avoid
+    complications it is usually best to take a mirror already generated on
+    your LAN backup box and copy that to the remote box. 
+
+    The remote backup box does not use NFS, so setup is trivial.  Just
+    create your super-large /backup partition and mkdir /backup/mirrors.
+    Your LAN backup box will need root access via ssh to your remote backup
+    box.
+
+    You can use the handy softlink to get the latest 'box1.date' mirror 
+    directory and since the mirror is all in one partition you can just
+    cpdup the entire machine in one command.  Use the same dated directory
+    name on the remote box, so:
+
+        # latest will wind up something like 'box1.20060915'
+       set latest = `readlink /backup/mirrors/box1`
+       cpdup -i0 -s0 /backup/mirrors/$latest remote.box:/backup/mirrors/$latest
+
+    As with your LAN backup, create a softlink on the backup box denoting the
+    latest mirror for any given site.
+
+       if ( $status == 0 ) then
+           ssh remote.box -n \
+               "ln -fs /backup/mirrors/$latest /backup/mirrors/box1"
+       endif
+
+    Incremental backups can be accomplished using the same cpdup command,
+    but adding the -H option to the latest backup on the remote box.  Note
+    that the -H path is relative to the remote box, not the LAN backup box
+    you are running the command from.
+
+       set latest = `readlink /backup/mirrors/box1`
+       set remotelatest = `ssh remote.box -n "readlink /backup/mirrors/box1"`
+       if ( "$latest" == "$remotelatest" ) then
+           echo "silly boy, you already made a remote incremental backup today"
+           exit 1
+       endif
+       cpdup -H /backup/mirrors/$remotelatest \
+             -i0 -s0 /backup/mirrors/$latest remote.box:/backup/mirrors/$latest
+       if ( $status == 0 ) then
+           ssh remote.box -n \
+               "ln -fs /backup/mirrors/$latest /backup/mirrors/box1"
+       endif
+
+    Cleaning out the remote directory works the same as cleaning out the LAN
+    backup directory.
+
+
+                           RESTORING FROM BACKUPS
+
+    Each backup is a full filesystem mirror, and depending on how much space
+    you have you should be able to restore it simply by cd'ing into the
+    appropriate backup directory and using 'cpdup blah box1:blah' (assuming
+    root access), or you can export the backup directory via NFS to your
+    client boxes and use cpdup locally on the client to extract the backup.
+    Using NFS is probably the most efficient solution.
+
+
+                       PUTTING IT ALL TOGETHER - SOME SCRIPTS
+
+    Please refer to the scripts in the script/ subdirectory.  These scripts
+    are EXAMPLES ONLY.  If you want to use them, put them in your ~root/adm
+    directory on your backup box and set up a root crontab.
+
+    First follow the preparation rules in PART 1 above.  The scripts do not
+    do this automatically.  Edit the 'params' file that the scripts use
+    to set default paths and such.
+
+       ** FOLLOW DIRECTIONS IN PART 1 ABOVE TO SET UP THE LAN BACKUP BOX **
+
+    Copy the scripts to ~/adm.  Do NOT install a crontab yet (but an example
+    can be found in scripts/crontab).
+
+    Do a manual lavel 0 LAN BACKUP using the do_mirror script.
+
+       cd ~/adm
+       ./do_mirror 0
+
+    Once done you can do incremental backups using './do_mirror 1' to do a
+    verified incremental, or './do_mirror 2' to do a stat-optimized
+    incremental.  You can enable the cron jobs that run do_mirror and 
+    do_cleanup now.
+
+    --
+
+    Setting up an off-site backup box is trivial.  The off-site backup box
+    needs to allow root ssh logins from the LAN backup box (at least for
+    now, sorry!).  Set up the off-site backup directory, typically
+    /backup/mirrors.  Then do a level 0 backup from your LAN backup box
+    to the off-site box using the do_remote script.
+
+       cd ~/adm
+       ./do_remote 0
+
+    Once done you can do incremental backups using './do_remote 1' to do a
+    verified incremental, or './do_mirror 2' to do a stat-optimized
+    incremental.  You can enable the cron jobs that run do_remote now.
+
+    NOTE!  It is NOT recommended that you use verified-incremental backups
+    over a WAN, as all related data must be copied over the wire every single
+    day.  Instead, I recommend sticking with stat-optimized backups
+    (./do_mirror 2).
+
+    You will also need to set up a daily cleaning script on the off-site
+    backup box.
+
+    SCRIPT TODOS - the ./do_cleanup script is not very smart.  We really
+    should do a tower-of-hanoi removal
+
+
similarity index 51%
rename from bin/cpdup/README
rename to bin/cpdup/PORTING
index 95d466a..4cc7812 100644 (file)
@@ -1,13 +1,17 @@
-$DragonFly: src/bin/cpdup/Attic/README,v 1.1 2006/09/16 18:24:37 dillon Exp $
+$DragonFly: src/bin/cpdup/PORTING,v 1.1 2006/09/16 21:57:08 dillon Exp $
 
-                           README FILE FOR CPDUP
+                               PORTING CPDUP
 
-    The manual page for cpdup is "cpdup.1".  This file describes various
-    porting issues.  
+    The manual page for cpdup is "cpdup.1".  This file describes how to
+    to port the program to other OS's.
 
-    Most BSDs should just be able to compile cpdup using the Makefile.
+                               PORTING TO BSD
+
+    cpdup was developed on BSD.  Most BSDs should just be able to compile
+    cpdup using the Makefile.
+
+                               PORTING TO LINUX
 
-Linux:
     This script should suffice when compiling under linux.  For some reason
     that I cannot fathom, linux defaults to using a 32 bit off_t.  It makes
     no sense at all to me why they would want to do this, BSDs went to
@@ -22,3 +26,8 @@ Linux:
     cc -c -D__unused= -D_GNU_SOURCE -D__USE_FILE_OFFSET64 -DNOMD5 *.c
     cc -D__unused= -D_GNU_SOURCE -D__USE_FILE_OFFSET64 -DNOMD5 *.o -o ~/bin/cpdup
 
+    BACKUP SCRIPT MODIFICATIONS - you will almost certainly have to adjust
+    the do_cleanup script to extract the proper field(s) from the df output.
+    You will probably have to use 'df' instead of 'df -i', and you may have
+    to adjust the script to not check the inode fields.
+
diff --git a/bin/cpdup/scripts/crontab b/bin/cpdup/scripts/crontab
new file mode 100644 (file)
index 0000000..4d85cba
--- /dev/null
@@ -0,0 +1,9 @@
+# Generally speaking a mirroring op runs much faster then an offsite
+# mirroring op, and a cleaning pass can seriously thrash the disk, so you
+# want to stagger operations
+#
+# $DragonFly: src/bin/cpdup/scripts/crontab,v 1.1 2006/09/16 21:57:10 dillon Exp $
+10 1 1 * *     (cd ~/adm; /usr/bin/lockf -k -t 0 .lockmirror ./do_mirror 1)
+15 1 2-31 * *  (cd ~/adm; /usr/bin/lockf -k -t 0 .lockmirror ./do_mirror 2)
+15 4 * * *     (cd ~/adm; /usr/bin/lockf -k -t 0 .lockremote ./do_remote 2)
+10 8 * * *     (cd ~/adm; /usr/bin/lockf -k -t 0 .lockclean ./do_cleanup 90)
diff --git a/bin/cpdup/scripts/do_cleanup b/bin/cpdup/scripts/do_cleanup
new file mode 100755 (executable)
index 0000000..d8cf4cc
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/csh
+#
+# $DragonFly: src/bin/cpdup/scripts/do_cleanup,v 1.1 2006/09/16 21:57:10 dillon Exp $
+
+source params
+
+if ( "$argv" == "" ) then
+       echo "./do_cleanup percentage"
+       exit 1
+endif
+
+set full = $argv[1]
+
+while (1)
+    set dcap = `df -i $cleaning_path | tail -1 | awk '{ print $5; }' | sed -e 's/%//'`
+    set icap = `df -i $cleaning_path | tail -1 | awk '{ print $8; }' | sed -e 's/%//'`
+    echo "space $dcap/$full inodes $icap/$full"
+
+    if ( $dcap < $full && $icap < $full ) then
+       break
+    endif
+
+    foreach i ( ${backup_nfs}/* )
+       set host = ${i:t}
+       if ( ! -d $backup_nfs/$host ) then
+           continue
+       endif
+       set curbackup = `readlink $cleaning_path/mirrors/$host`
+       foreach item ( `ls -1da $cleaning_path/mirrors/$host.*` )
+           if ( ! -d $item ) then
+               continue
+           endif
+           if ( "${item:t}" == "$curbackup" ) then
+               continue
+           endif
+           echo "Removing $item"
+           # for safety, use a full path and do not rely on item's path
+           #
+           rm -rf $cleaning_path/mirrors/${item:t}
+           break
+       end
+    end
+
+    # let the fs catch up and update the df info
+    #
+    sync
+    sync
+    foreach benice ( 1 2 3 4 5 )
+       sync
+       sleep 5
+    end
+    sync
+    sync
+end
diff --git a/bin/cpdup/scripts/do_mirror b/bin/cpdup/scripts/do_mirror
new file mode 100755 (executable)
index 0000000..daa7617
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/csh
+#
+# $DragonFly: src/bin/cpdup/scripts/do_mirror,v 1.1 2006/09/16 21:57:10 dillon Exp $
+
+source params
+
+if ( "$argv" == "" ) then
+    echo "do_mirror <level>"
+    exit 1
+endif
+
+echo "STARTING MIRRORS `date` level $argv"
+foreach i ( $backup_nfs/* )
+    set host = ${i:t}
+    if ( -d $i ) then
+       ./do_mirror_host $host $argv >& $backup_path/mirrors/${host}.log &
+    endif
+end
+echo "WAITING FOR MIRRORS TO COMPLETE `date`"
+wait
+foreach i ( ${backup_nfs}/* )
+    set host = ${i:t}
+    if ( -d $i ) then
+       echo -n "${host}: "
+       tail -1 $backup_path/mirrors/${host}.log
+    endif
+end
+echo "DONE MIRRORING `date`"
diff --git a/bin/cpdup/scripts/do_mirror_host b/bin/cpdup/scripts/do_mirror_host
new file mode 100755 (executable)
index 0000000..0d2e153
--- /dev/null
@@ -0,0 +1,107 @@
+#!/bin/csh
+#
+# $DragonFly: src/bin/cpdup/scripts/do_mirror_host,v 1.1 2006/09/16 21:57:10 dillon Exp $
+
+source params
+
+if ( "$argv" == "" ) then
+    echo "Specify host mounted in $backup_nfs (e.g. 'apollo'), and level."
+    echo "Level 0 - full backup, do not use hardlink trick"
+    echo "Level 1 - full backup, use hardlink trick but verify each file"
+    echo "Level 2 - full backup, use hardlink trick and stat shortcut"
+    echo "./do_mirror_host <host> <level> > $backup_path/mirrors/<host>.log"
+    exit 1
+endif
+
+set date = `date "+%Y%m%d"`
+set host = "$argv[1]"
+set level = "$argv[2]"
+
+if ( ! -d $backup_nfs/$host ) then
+    echo "Host not found in $backup_nfs"
+    exit 1
+endif
+if ( ! -d $backup_path/mirrors/$host ) then
+    mkdir $backup_path/mirrors/$host
+endif
+
+# Target directory for this backup
+#
+set target = $host.$date
+if ( ! -d $backup_path/mirrors/$target ) then
+    mkdir -p $backup_path/mirrors/$target
+endif
+
+set failed = 0
+
+# Record log
+#
+rm -f $backup_path/mirrors/$target/{INPROGRESS,FAILED,SUCCEEDED}
+if ( -f $backup_path/mirrors/$host.log ) then
+    ln $backup_path/mirrors/$host.log $backup_path/mirrors/$target/INPROGRESS
+else
+    echo "NO LOG RECORDED" > $backup_path/mirrors/$target/INPROGRESS
+endif
+
+# Iterate subdirectories.  Each subdirectory is considered to be a separate
+# filesystem.
+#
+foreach fs ( $backup_nfs/$host/* )
+    set dirname = $fs:t
+
+    echo "Backing up $fs"
+    if ( ! -d $backup_path/mirrors/$target/$dirname ) then
+       mkdir -p $backup_path/mirrors/$target/$dirname
+    endif
+    if ( -f $fs/NOT_MOUNTED ) then
+       echo "NOT MOUNTED"
+       set failed = 1
+       continue
+    endif
+    switch ( $level )
+    case 0:
+       echo "cpdup -i0 -s0 -I $fs $backup_path/mirrors/$target/$dirname"
+       cpdup -i0 -s0 -I $fs $backup_path/mirrors/$target/$dirname
+       if ( $status != 0 ) then
+           set failed = 1
+       endif
+       breaksw
+    case 1:
+       echo "cpdup -f -i0 -s0 -I -H $backup_path/mirrors/$host/$dirname $fs $backup_path/mirrors/$target/$dirname"
+       cpdup -f -i0 -s0 -I -H $backup_path/mirrors/$host/$dirname $fs $backup_path/mirrors/$target/$dirname
+       if ( $status != 0 ) then
+           set failed = 1
+       endif
+       breaksw
+    case 2:
+       echo "cpdup -i0 -s0 -I -H $backup_path/mirrors/$host/$dirname $fs $backup_path/mirrors/$target/$dirname"
+       cpdup -i0 -s0 -I -H $backup_path/mirrors/$host/$dirname $fs $backup_path/mirrors/$target/$dirname
+       if ( $status != 0 ) then
+           set failed = 1
+       endif
+       breaksw
+    default:
+       echo "UNKNOWN BACKUP LEVEL, USE ONLY 0-2"
+       set failed = 1
+       breaksw
+    endsw
+    sync
+    echo ""
+end
+
+# If we succeeded then set up a softlink so a higher level incremental
+# backup can locate the most recent version of the previous level,
+# another so we can locate the most recent backup period, and also
+# rename the log file.
+#
+if ( $failed == 0 ) then
+    ln -sf "$host.$date" $backup_path/mirrors/$host
+    mv $backup_path/mirrors/$target/{INPROGRESS,SUCCEEDED}
+    sync
+    echo "SUCCEEDED"
+else
+    mv $backup_path/mirrors/$target/{INPROGRESS,FAILED}
+    sync
+    echo "FAILED"
+endif
+
diff --git a/bin/cpdup/scripts/do_remote b/bin/cpdup/scripts/do_remote
new file mode 100755 (executable)
index 0000000..9cf5ccc
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/csh
+#
+# $DragonFly: src/bin/cpdup/scripts/do_remote,v 1.1 2006/09/16 21:57:10 dillon Exp $
+
+source params
+
+if ( "$argv" == "" ) then
+    echo "do_mirror <level>"
+    exit 1
+endif
+
+echo "STARTING OFFSITE MIRRORS `date`"
+foreach i ( ${backup_nfs}/* )
+    set host = ${i:t}
+    if ( -d $i ) then
+       ./do_remote_host $host $argv >& $backup_path/mirrors/remote.${host}.log &
+    endif
+end
+echo "WAITING FOR MIRRORS TO COMPLETE `date`"
+wait
+foreach i ( ${backup_nfs}/* )
+    set host = ${i:t}
+    if ( -d $i ) then
+       echo -n "${host}: "
+       tail -1 $backup_path/mirrors/remote.${host}.log
+    endif
+end
+echo "DONE WITH OFFSITE MIRRORS `date`"
diff --git a/bin/cpdup/scripts/do_remote_host b/bin/cpdup/scripts/do_remote_host
new file mode 100755 (executable)
index 0000000..a502787
--- /dev/null
@@ -0,0 +1,111 @@
+#!/bin/csh
+#
+# $DragonFly: src/bin/cpdup/scripts/do_remote_host,v 1.1 2006/09/16 21:57:10 dillon Exp $
+
+source params
+
+if ( "$argv" == "" ) then
+    echo "Specify host mounted in $backup_nfs (e.g. 'apollo'), and level."
+    echo "Level 0 - full backup, do not use hardlink trick"
+    echo "Level 1 - full backup, use hardlink trick but verify each file"
+    echo "Level 2 - full backup, use hardlink trick and stat shortcut"
+    echo "./do_remote_host <host> <level> > $remote_path/mirrors/<host>.log"
+    exit 1
+endif
+
+set host = "$argv[1]"
+set level = "$argv[2]"
+
+if ( ! -d $backup_nfs/$host ) then
+    echo "Host not found in $backup_nfs"
+    exit 1
+endif
+if ( ! -d $backup_path/mirrors/$host ) then
+    echo "No backup found for $host"
+    exit 1
+endif
+
+# Figure out the source directory
+#
+set source = `readlink $backup_path/mirrors/$host`
+if ( "$source" == "" ) then
+    echo "No backup found for $host at $backup_path/mirrors/$host"
+    echo "or it was not a softlink"
+    exit 1
+endif
+
+# Figure out the hardlink optimized side directory on
+# the target.
+#
+
+if ( $level != 0 ) then
+    set hlbase = `ssh $remote_host -n "readlink ${remote_path}/mirrors/$host"`
+    if ( "$hlbase" == "" ) then
+       echo "Missing softlink at ${remote_host}:${remote_path}/mirrors/${host}"
+       echo "cannot proceed.  Perhaps you did not run a level 0 with"
+       echo "the do_remote script to create the hardlink base and softlink?"
+       exit 1
+    endif
+
+    if ( "$hlbase" == "$source" ) then
+       echo "SUCCEEDED - NO NEW BACKUP SINCE LAST TIME"
+       exit 0
+    endif
+endif
+
+# Figure out the target path and add prefixes
+#
+set basename = $source
+set target = ${remote_host}:${remote_path}/mirrors/${source}
+set source = $backup_path/mirrors/${source}
+set hlbase = ${remote_path}/mirrors/${hlbase}
+
+echo "---------- OFFSITE BACKUP OF $source ---------"
+echo "SOURCE $source"
+echo "HLBASE $hlbase"
+echo "TARGET $target"
+
+# Do the actual backup
+#
+
+set failed = 0
+
+switch($level)
+case 0:
+    echo "cpdup -i0 -s0 -I $source $target"
+    cpdup -i0 -s0 -I $source $target
+    if ( $status != 0 ) then
+       set failed = 1
+    endif
+    breaksw
+case 1:
+    echo "cpdup -f -i0 -s0 -I -H $hlbase $source $target"
+    cpdup -f -i0 -s0 -I -H $hlbase $source $target
+    if ( $status != 0 ) then
+       set failed = 1
+    endif
+    breaksw
+case 2:
+    echo "cpdup -i0 -s0 -I -H $hlbase $source $target"
+    cpdup -i0 -s0 -I -H $hlbase $source $target
+    if ( $status != 0 ) then
+       set failed = 1
+    endif
+    breaksw
+default:
+    echo "UNKNOWN BACKUP LEVEL, USE ONLY 0-2"
+    set failed = 1
+    breaksw
+endsw
+
+if ( $failed == 0 ) then
+    ssh $remote_host -n "ln -sf $basename ${remote_path}/mirrors/$host"
+    sync
+    echo "SUCCEEDED"
+    exit 0
+else
+    sync
+    echo "FAILED"
+    exit 1
+endif
+
diff --git a/bin/cpdup/scripts/params b/bin/cpdup/scripts/params
new file mode 100644 (file)
index 0000000..0e392a7
--- /dev/null
@@ -0,0 +1,12 @@
+# sourced by do* scripts
+#
+# do not include the BLAH/mirrors subdirectory when specifying the backup 
+# path and the remote path.  The scripts will add it themselves, as a safety
+# feature.
+#
+# $DragonFly: src/bin/cpdup/scripts/params,v 1.1 2006/09/16 21:57:10 dillon Exp $
+set backup_nfs = "/nfs"
+set backup_path = "/backup"
+set remote_host = "OFF.SITE.HOST"
+set remote_path = "/backup"
+set cleaning_path = "$backup_path"