summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--[-rwxr-xr-x]rsyncshot35
-rw-r--r--rsyncshot.org196
2 files changed, 199 insertions, 32 deletions
diff --git a/rsyncshot b/rsyncshot
index 7a4d0b5..d12827e 100755..100644
--- a/rsyncshot
+++ b/rsyncshot
@@ -1,8 +1,4 @@
#!/bin/bash
-#
-# rsyncshot
-# Craig Jennings craigmartinjennings@gmail.com
-# Inspired by Mike Rubel: http://www.mikerubel.org/computers/rsync_snapshots/
# uncomment next 4 lines for debugging output
# exec 5> >(logger -t $0)
@@ -10,7 +6,6 @@
# PS4='$LINENO: '
# set -x
-# default locations for setup
SCRIPTLOC=/usr/local/bin/rsyncshot;
DESTINATION=/media/backup;
@@ -20,28 +15,24 @@ LOGHOME=/var/log/rsyncshot.log;
INCLUDES="$INSTALLHOME/include.txt";
EXCLUDES="$INSTALLHOME/exclude.txt";
-# default cron job entries
-# hourly -- hourly on minute 0 from 1am to 11pm
CRON_H="0 1-23 * * * $SCRIPTLOC hourly 22";
-# daily -- midnight, Monday - Saturday.
CRON_D="0 0 * * 1-6 $SCRIPTLOC daily 6";
-# weekly -- Sundays at midnight
CRON_W="0 0 * * 7 $SCRIPTLOC weekly 51";
-# print help
help()
{
echo ""
echo "rsyncshot - compact snapshots on Linux using rsync and hard links."
+ echo ""
+ echo "rsyncshot must be run as root"
+ echo ""
echo "Usage: "
echo "rsyncshot <name> <number of backups to retain>"
echo " setup (installs rsyncshot and cron jobs)"
echo " help (prints this info)"
echo "Notes:"
echo "- install and log locations defined in script."
-}
-# display error and exit
error()
{
echo "ERROR: $0: $@" 1>&2;
@@ -49,7 +40,6 @@ error()
exit 1;
}
-# copy files, create exclude, and setup cron job
setup()
{
# copy this file to directory on path
@@ -82,27 +72,19 @@ setup()
echo "hourly, daily, and weekly cron jobs installed.";
}
-# if user requested help, display and exit.
if [ "$TYPE" = "HELP" ]; then help; exit; fi
-# ensure running as root
if [ "$EUID" -ne 0 ]; then error "This script must be run as root."; fi
-# display how the script was started
echo "rsyncshot invoked on `date -u` with: $0 $1 $2";
-# validate first arg is alpha chars and make it case insensitive
if ! [[ $1 =~ [a-zA-Z] ]]; then error "snapshot type not recognized."; fi
TYPE=$(tr '[a-z]' '[A-Z]' <<< $1);
-
-# if user requested setup, and exit.
if [ "$TYPE" = "SETUP" ]; then setup; exit; fi
-# Validate second arg is numeric
if ! [[ $2 =~ [0-9] ]]; then error "max snapshots not a number."; fi
MAX=$(($2-1));
-# validate include file (source directories)
if [ ! -f "$INCLUDES" ]; then error "include file $INCLUDES not found."; fi
SOURCES=$(<$INCLUDES);
for SOURCE in $SOURCES
@@ -110,10 +92,8 @@ do
if [ ! -d "$SOURCE" ]; then error "source $SOURCE not found"; fi
done
-# validate exclude file (exclusion patters)
if [ ! -f "$EXCLUDES" ]; then error "Exclude file $EXCLUDES not found."; fi
-# sync each source directories in turn
for SOURCE in $SOURCES
do
rsync -avh -i --times \
@@ -122,15 +102,10 @@ do
--update $SOURCE $DESTINATION/latest ;
done
-# update the time of latest to reflect snapshot time
-# touch $DESTINATION/latest;
-
-# delete the last snapshot if it exists
if [ -d $DESTINATION/$TYPE.$MAX ]; then
rm -rf $DESTINATION/$TYPE.$MAX;
fi
-# rotate snapshots descending
for (( start=$(($MAX)); start>=0; start--)); do
end=$(($start+1));
if [ -d $DESTINATION/$TYPE.$start ]; then
@@ -138,15 +113,11 @@ for (( start=$(($MAX)); start>=0; start--)); do
fi
done
-# touch the directory for a timestamp
touch $DESTINATION/latest
-# make a hard-link-only copy into $TYPE.0
cp -al $DESTINATION/latest $DESTINATION/$TYPE.0;
-# make the directory $TYPE.0 read-only
chmod -w $DESTINATION/$TYPE.0
-# print end time and exit
echo "rsyncshot completed `date -u` ";
exit 0;
diff --git a/rsyncshot.org b/rsyncshot.org
new file mode 100644
index 0000000..77797a2
--- /dev/null
+++ b/rsyncshot.org
@@ -0,0 +1,196 @@
+* rsyncshot
+:PROPERTIES:
+:COMMENTS: org
+:TANGLE: rsyncshot
+:END:
+Craig Jennings craigmartinjennings@gmail.com
+Inspired by Mike Rubel: http://www.mikerubel.org/computers/rsync_snapshots/
+#+begin_SRC sh :tangle yes
+#!/bin/bash
+#+end_SRC
+** Debugging
+#+begin_SRC sh :tangle yes
+# uncomment next 4 lines for debugging output
+# exec 5> >(logger -t $0)
+# BASH_XTRACEFD="5"
+# PS4='$LINENO: '
+# set -x
+#+end_SRC
+** Config
+*** Default Locations
+Default locations for setup
+#+begin_SRC sh :tangle yes
+SCRIPTLOC=/usr/local/bin/rsyncshot;
+DESTINATION=/media/backup;
+
+INSTALLHOME=/etc/rsyncshot
+LOGHOME=/var/log/rsyncshot.log;
+
+INCLUDES="$INSTALLHOME/include.txt";
+EXCLUDES="$INSTALLHOME/exclude.txt";
+#+end_SRC
+*** Default Cron Job Entries
+Default cron job entries
+CRON_H = hourly on minute 0 from 1am to 11pm
+CRON_D = daily at midnight, Monday - Saturday
+CRON_W = weekly at midnight on Sundays
+#+begin_SRC sh :tangle yes
+CRON_H="0 1-23 * * * $SCRIPTLOC hourly 22";
+CRON_D="0 0 * * 1-6 $SCRIPTLOC daily 6";
+CRON_W="0 0 * * 7 $SCRIPTLOC weekly 51";
+#+end_SRC
+** Functions
+*** Help
+#+begin_SRC sh :tangle yes
+help()
+{
+ echo ""
+ echo "rsyncshot - compact snapshots on Linux using rsync and hard links."
+ echo ""
+ echo "rsyncshot must be run as root"
+ echo ""
+ echo "Usage: "
+ echo "rsyncshot <name> <number of backups to retain>"
+ echo " setup (installs rsyncshot and cron jobs)"
+ echo " help (prints this info)"
+ echo "Notes:"
+ echo "- install and log locations defined in script."
+
+#+end_SRC
+*** Error
+#+begin_SRC sh :tangle yes
+error()
+{
+ echo "ERROR: $0: $@" 1>&2;
+ echo "See \"rsyncshot help\" for usage."
+ exit 1;
+}
+#+end_SRC
+*** Setup
+#+begin_SRC sh :tangle yes
+setup()
+{
+ # copy this file to directory on path
+ cp -f $0 /usr/local/bin
+ echo "$0 copied to /usr/local/bin"
+
+ # make install home if it doesn't exist;
+ if [ ! -d $INSTALLHOME ]; then
+ mkdir -p $INSTALLHOME;
+ "Created install home at $INSTALLHOME.";
+ fi
+
+ # create includes file and add default entries
+ if [ -f $INCLUDES ]; then rm $INCLUDES; fi
+ printf "/home /etc /usr/local/bin" >> $INCLUDES;
+ echo "modify include file at $INCLUDES";
+
+ # create excludes file and add default entries
+ if [ -f $EXCLUDES ]; then rm $EXCLUDES; fi
+ printf "*.pyc\n*.pyo\n*.class\n*.elc\n*.o\n*.tmp\n.cache*" >> $EXCLUDES;
+ echo "modify exclude file at $EXCLUDES";
+
+ # write out current crontab, append default entries, and install
+ crontab -l > crontemp;
+ echo "$CRON_H >> $LOGHOME 2>&1" >> crontemp;
+ echo "$CRON_D >> $LOGHOME 2>&1" >> crontemp;
+ echo "$CRON_W >> $LOGHOME 2>&1">> crontemp;
+ crontab crontemp;
+ rm crontemp;
+ echo "hourly, daily, and weekly cron jobs installed.";
+}
+#+end_SRC
+** Script
+*** Check Help Option
+If user requested help, display and exit
+#+begin_SRC sh :tangle yes
+if [ "$TYPE" = "HELP" ]; then help; exit; fi
+#+end_SRC
+*** Ensure Root
+Ensure we're running as root
+#+begin_SRC sh :tangle yes
+if [ "$EUID" -ne 0 ]; then error "This script must be run as root."; fi
+#+end_SRC
+*** Display How Script Was Started
+Display how the script was started
+#+begin_SRC sh :tangle yes
+echo "rsyncshot invoked on `date -u` with: $0 $1 $2";
+#+end_SRC
+*** Parameter Validation
+Validate first arg is alpha chars and make it case insensitive. If user requested setup, call function and exit.
+#+begin_SRC sh :tangle yes
+if ! [[ $1 =~ [a-zA-Z] ]]; then error "snapshot type not recognized."; fi
+TYPE=$(tr '[a-z]' '[A-Z]' <<< $1);
+if [ "$TYPE" = "SETUP" ]; then setup; exit; fi
+#+end_SRC
+*** Validate Max Snapshots
+Validate second arg (max snapshots) is numeric.
+#+begin_SRC sh :tangle yes
+if ! [[ $2 =~ [0-9] ]]; then error "max snapshots not a number."; fi
+MAX=$(($2-1));
+#+end_SRC
+*** Validate Include File
+Validate include file (source directories)
+#+begin_SRC sh :tangle yes
+if [ ! -f "$INCLUDES" ]; then error "include file $INCLUDES not found."; fi
+SOURCES=$(<$INCLUDES);
+for SOURCE in $SOURCES
+do
+ if [ ! -d "$SOURCE" ]; then error "source $SOURCE not found"; fi
+done
+#+end_SRC
+*** Validate Exclude File
+Validate exclude file (exclusion patterns)
+#+begin_SRC sh :tangle yes
+if [ ! -f "$EXCLUDES" ]; then error "Exclude file $EXCLUDES not found."; fi
+#+end_SRC
+
+*** Sync
+Perform the sync, each directory in turn
+#+begin_SRC sh :tangle yes
+for SOURCE in $SOURCES
+do
+ rsync -avh -i --times \
+ --delete --delete-excluded \
+ --exclude-from=$EXCLUDES \
+ --update $SOURCE $DESTINATION/latest ;
+done
+#+end_SRC
+*** Delete Old Snapshot
+Delete the snapshot to go over max
+#+begin_SRC sh :tangle yes
+if [ -d $DESTINATION/$TYPE.$MAX ]; then
+ rm -rf $DESTINATION/$TYPE.$MAX;
+fi
+#+end_SRC
+*** Rotate Snapshots
+Rotate snapshots descending
+#+begin_SRC sh :tangle yes
+for (( start=$(($MAX)); start>=0; start--)); do
+ end=$(($start+1));
+ if [ -d $DESTINATION/$TYPE.$start ]; then
+ mv $DESTINATION/$TYPE.$start $DESTINATION/$TYPE.$end;
+ fi
+done
+#+end_SRC
+*** Set Directory Timestamp
+Touch the directory for a timestamp
+#+begin_SRC sh :tangle yes
+touch $DESTINATION/latest
+#+end_SRC
+*** Hard Link to Destination
+Make a hard-link-only copy into $TYPE.0
+#+begin_SRC sh :tangle yes
+cp -al $DESTINATION/latest $DESTINATION/$TYPE.0;
+#+end_SRC
+*** Make Directory Type Read-Only
+Make the directory $TYPE.0 read-only
+#+begin_SRC sh :tangle yes
+chmod -w $DESTINATION/$TYPE.0
+#+end_SRC
+*** Print Time and Exit
+Print end time and exit
+#+begin_SRC sh :tangle yes
+echo "rsyncshot completed `date -u` ";
+exit 0;
+#+end_SRC