aboutsummaryrefslogtreecommitdiff
path: root/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'handlers')
-rw-r--r--handlers/ldap69
-rw-r--r--handlers/mysql133
-rw-r--r--handlers/parseini130
-rw-r--r--handlers/rdiff116
-rw-r--r--handlers/sh6
5 files changed, 454 insertions, 0 deletions
diff --git a/handlers/ldap b/handlers/ldap
new file mode 100644
index 0000000..06e4e28
--- /dev/null
+++ b/handlers/ldap
@@ -0,0 +1,69 @@
+#
+# openldap backup handler script for backupninja
+#
+
+getconf backupdir /var/backups/ldap
+getconf conf /etc/ldap/slapd.conf
+getconf databases all
+getconf compress yes
+getconf ldif yes
+getconf hotcopy no
+
+# hot copy is not yet supported
+
+status="ok"
+
+[ -f $conf ] || fatal "slapd config file ($conf) not found"
+[ -d $backupdir ] || mkdir -p $backupdir
+[ -d $backupdir ] || fatal "Backup directory '$backupdir'"
+
+dbsuffixes=(`awk 'BEGIN {OFS=":"} /[:space:]*^database[:space:]*\w*/ {db=$2}; /^[:space:]*suffix[:space:]*\w*/ {if (db=="bdb"||db=="ldbm") print db,$2}' $conf|sed -e 's/[" ]//g'`)
+
+## LDIF DUMP
+
+if [ "$ldif" == "yes" ]; then
+ dumpdir="$backupdir"
+ [ -d $dumpdir ] || mkdir -p $dumpdir
+
+ if [ "$databases" == 'all' ]; then
+ dbcount=`grep '^database' $conf | wc -l`
+ let "dbcount = dbcount - 1"
+ databases=`seq 0 $dbcount`;
+ fi
+
+ for db in $databases; do
+ if [ `expr index "$dbnum" "="` == "0" ]; then
+ # db is a number, get the suffix.
+ dbsuffix=${dbsuffixes[$db]/*:/}
+ else
+ dbsuffix=$db
+ fi
+ # some databases don't have suffix (like monitor), skip these
+ if [ "$dbsuffix" == "" ]; then
+ continue;
+ fi
+ touch $dumpdir/$dbsuffix.ldif
+ if [ ! -f $dumpdir/$dbsuffix.ldif ]; then
+ fatal "Couldn't create ldif dump file: $dumpdir/$dbsuffix.ldif"
+ fi
+ execstr="$SLAPCAT -f $conf -b $dbsuffix -l $dumpdir/$dbsuffix.ldif"
+ debug 0 "$execstr"
+ if [ ! $test ]; then
+ output=`$execstr`
+ code=$?
+ if [ "$code" == "0" ]; then
+ debug 0 $output
+ debug 1 "Successfully finished ldif export of $dbsuffix"
+ else
+ debug 2 $output
+ debug 2 "Failed ldif export of $dbsuffix"
+ fi
+ if [ "$compress" == "yes" ]; then
+ output=`$GZIP -f "$dumpdir/$dbsuffix.ldif" 2>&1`
+ debug 0 $output
+ fi
+ fi
+ done
+fi
+
+return 0
diff --git a/handlers/mysql b/handlers/mysql
new file mode 100644
index 0000000..4439bcc
--- /dev/null
+++ b/handlers/mysql
@@ -0,0 +1,133 @@
+#
+# mysql handler script for backupninja
+#
+
+getconf backupdir /var/backups/mysql
+getconf databases all
+getconf compress yes
+getconf dbusername
+getconf dbpassword
+getconf dbhost localhost
+getconf hotcopy no
+getconf sqldump no
+getconf user root
+
+# create backup dirs
+
+[ -d $backupdir ] || mkdir -p $backupdir
+[ -d $backupdir ] || fatal "Backup directory '$backupdir'"
+hotdir="$backupdir/hotcopy"
+dumpdir="$backupdir/sqldump"
+[ "$sqldump" == "no" -o -d $dumpdir ] || mkdir -p $dumpdir
+[ "$hotcopy" == "no" -o -d $hotdir ] || mkdir -p $hotdir
+
+# create .my.cnf
+ # (we do this because we don't want to have to specify the password on the command line
+ # because then anyone would be able to see it with a 'ps aux'. instead, we create a
+ # temporary ~/.my.cnf in root's home directory).
+
+if [ "$dbusername" != "" ]; then
+ home=`grep '^root' /etc/passwd | awk -F: '{print $6}'`
+ [ -d $home ] || fatal "Can't find root's home directory ($home)."
+ mycnf="$home/.my.cnf"
+ if [ -f $mycnf ]; then
+ # rename temporarily
+ tmpcnf="$home/my.cnf.disable"
+ debug 0 "mv $mycnf $tmpcnf"
+ mv $mycnf $tmpcnf
+ fi
+ oldmask=`umask`
+ umask 077
+ cat > $mycnf <<EOF
+# auto generated backupninja mysql conf
+[mysql]
+user=$dbusername
+password=$dbpassword
+
+[mysqldump]
+user=$dbusername
+password=$dbpassword
+
+[mysqlhotcopy]
+user=$dbusername
+password=$dbpassword
+EOF
+ umask $oldmask
+fi
+
+## HOT COPY
+
+if [ "$hotcopy" == "yes" ]; then
+ if [ "$databases" == "all" ]; then
+ execstr="$MYSQLHOTCOPY --quiet --allowold --regexp /.\*/./.\*/ $hotdir"
+ debug 0 "su $user -c '$execstr'"
+ if [ ! $test ]; then
+ output=`su $user -c "$execstr" 2>&1`
+ code=$?
+ if [ "$code" == "0" ]; then
+ debug 0 $output
+ debug 1 "Successfully finished hotcopy of all mysql databases"
+ else
+ debug 2 $output
+ debug 2 "Failed to hotcopy all mysql databases"
+ fi
+ fi
+ else
+ for db in $databases; do
+ execstr="$MYSQLHOTCOPY --allowold $db $hotdir"
+ debug 0 "su $user -c '$execstr'"
+ if [ ! $test ]; then
+ output=`su $user -c "$execstr" 2>&1`
+ code=$?
+ if [ "$code" == "0" ]; then
+ debug 0 $output
+ debug 1 "Successfully finished hotcopy of mysql database $db"
+ else
+ debug 2 $output
+ debug 2 "Failed to hotcopy mysql database $db"
+ fi
+ fi
+ done
+ fi
+fi
+
+## SQL DUMP
+
+if [ "$sqldump" == "yes" ]; then
+ if [ "$databases" == "all" ]; then
+ databases=`echo 'show databases' | su $user -c "$MYSQL" | grep -v Database`
+ fi
+
+ for db in $databases; do
+ execstr="$MYSQLDUMP --lock-tables --complete-insert --add-drop-table --quick --quote-names $db > $dumpdir/${db}.sql"
+ debug 0 "su $user -c '$execstr'"
+ if [ ! $test ]; then
+ output=`su $user -c "$execstr" 2>&1`
+ code=$?
+ if [ "$code" == "0" ]; then
+ debug 0 $output
+ debug 1 "Successfully finished dump of mysql database $db"
+ else
+ debug 2 $output
+ debug 2 "Failed to dump mysql databases $db"
+ fi
+ fi
+ done
+
+ if [ "$compress" == "yes" ]; then
+ output=`$GZIP -f $dumpdir/*.sql 2>&1`
+ debug 0 $output
+ fi
+fi
+
+if [ "$dbusername" != "" ]; then
+ ## clean up tmp config file
+ debug 0 "rm $mycnf"
+ rm $mycnf
+ if [ -f "$tmpcnf" ]; then
+ debug 0 "mv $tmpcnf $mycnf"
+ mv $tmpcnf $mycnf
+ fi
+fi
+
+return 0
diff --git a/handlers/parseini b/handlers/parseini
new file mode 100644
index 0000000..6f56d42
--- /dev/null
+++ b/handlers/parseini
@@ -0,0 +1,130 @@
+#
+# parseini --- parses 'ini' style configuration files.
+#
+# Usage:
+# awk -f parseini S=<section> P=<param> <ini file>
+#
+# if section is an empty string, then we use the default section
+#
+# example ini file:
+#
+# fruit = apple
+# fruit = pear
+# multiline = this is a multiline \
+# parameter
+#
+# # this is a comment
+#
+# [colors]
+# red = yes
+# green = no
+# blue = maybe
+#
+# [ocean]
+# fish = red
+# fish = blue
+#
+# example usage:
+# > awk -f parseini S=ocean P=fish testfile.ini
+# would return:
+# red
+# blue
+#
+
+BEGIN {
+ readlines = 1
+ implied = 1
+}
+
+# remove lines starting with #, but not #!
+/^#[^!]/ {next}
+
+# skip blank
+/^[ \r\t]*$/ {next}
+
+# we want to read the lines of the matched section
+# and disable for other sections
+/^\[.+\][ \r\t]*$/ {
+ continueline = 0
+ if (S && implied) {
+ nline = 0
+ implied = 0
+ }
+ if (S && match($0, "^\\[" S "\\][ \n]*")) {
+ # we found the section, so start reading.
+ readlines = 1
+ }
+ else {
+ # no section, so stop reading lines
+ if (readlines) readlines = 0
+ }
+ next
+}
+
+# when reading, store lines.
+
+{
+ if (!readlines) next
+ line[nline++] = $0
+ if ($0 ~ /\\[ \r\t]*$/)
+ continueline = 1
+ else
+ continueline = 0
+}
+
+# process the read lines lines, matching parameters
+
+END {
+ # if section is set but implied is still true
+ # then we never found the section, so use everything
+ if (S && implied) {
+ nline = 0
+ }
+
+ # if have P then find P in read lines and get values
+ if (P) {
+ MATCH = "^[ \r\t]*" P "[ \r\t]*="
+ continueline = 0
+ for (x = 0; x < nline; ++x) {
+ v = line[x]
+ if (continueline) {
+ sub(/[ \r\t]+$/, "", v)
+ if (v ~ /\\$/) {
+ v = substr(v, 1, length(v)-1)
+ sub(/[ \r\t]+$/, "", v)
+ }
+ if (v) value[nvalue++] = v
+ }
+ else if (v ~ MATCH) {
+ sub(MATCH, "", v)
+ sub(/^[ \r\t]+/, "", v)
+ sub(/[ \r\t]+$/, "", v)
+ if (v ~ /\\$/) {
+ continueline = 1
+ v = substr(v, 1, length(v)-1)
+ sub(/[ \r\t]+$/, "", v)
+ }
+ if (v) value[nvalue++] = v
+ }
+ }
+ # copy parameter definition to output array
+ nline = nvalue
+ for (x = 0; x < nvalue; ++x)
+ line[x] = value[x]
+ }
+
+ # trim all leading & trailing whitespace;
+ # except for leading whitespace in continuation lines,
+
+ for (x = 0; x < nline; ++x) {
+ sub(/^[ \r\t]+/, "", line[x])
+ sub(/[ \r\t]+$/, "", line[x])
+ }
+
+ # output the final result
+ for (x = 0; x < nline; ++x)
+ print line[x]
+
+ if (nline) exit 0
+ else exit 1
+}
diff --git a/handlers/rdiff b/handlers/rdiff
new file mode 100644
index 0000000..1f2058f
--- /dev/null
+++ b/handlers/rdiff
@@ -0,0 +1,116 @@
+#
+# rdiff-backup handler script for backupninja
+# requires rdiff-backup
+#
+
+setsection source
+getconf type; sourcetype=$type
+getconf label
+getconf user; sourceuser=$user
+getconf keep
+getconf include
+getconf exclude
+
+### DESTINATION ###
+
+setsection dest
+getconf directory; destdir=$directory
+# strip trailing /
+destdir=${destdir%/}
+getconf type; desttype=$type
+getconf user; destuser=$user
+getconf host; desthost=$host
+
+[ "$destdir" != "" ] || fatal "Destination directory not set"
+[ "$desttype" == "remote" ] || fatal "Only remote destinations are supported"
+
+# see if we can login
+debug 0 "su $sourceuser -c \"ssh -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'\""
+if [ ! $test ]; then
+ result=`su $sourceuser -c "ssh -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'" 2>&1`
+ if [ "$result" != "1" ]; then
+ fatal "Can't connect to $desthost as $destuser."
+ fi
+fi
+
+# see that rdiff-backup has the same version as here
+debug 0 "su $sourceuser -c \"ssh $desthost -l $destuser '$RDIFFBACKUP -V'\""
+if [ ! $test ]; then
+ remoteversion=`su $sourceuser -c "ssh $desthost -l $destuser '$RDIFFBACKUP -V'" 2>&1`
+ localversion=`$RDIFFBACKUP -V`
+ if [ "$remoteversion" != "$localversion" ]; then
+ fatal "rdiff-backup does not have the same version on this computer and the backup server."
+ fi
+fi
+
+execstr_serverpart="$destuser@$desthost::$destdir/$label"
+
+### SOURCE ###
+
+[ "$label" != "" ] || fatal "Source missing label"
+[ "$sourcetype" == "local" ] || fatal "Only local source type supported"
+[ "$include" != "" ] || fatal "No source includes specified"
+
+execstr_clientpart="/"
+
+## REMOVE OLD BACKUPS
+
+if [ "$keep" -gt "0" ]; then
+ removestr="rdiff-backup --force --remove-older-than ${keep}D "
+ if [ "$desttype" == "remote" ]; then
+ removestr="${removestr}${destuser}@${desthost}::"
+ fi
+ removestr="${removestr}${destdir}/${label}";
+
+ debug 0 "su $sourceuser -c '$removestr'"
+ if [ ! $test ]; then
+ output=`su $sourceuser -c "$removestr" 2>&1`
+ code=$?
+ if [ "$code" == "0" ]; then
+ debug 0 $output
+ debug 1 "Removing backups older than $keep days succeeded."
+ else
+ debug 2 $output
+ debug 2 "Failed removing backups older than $keep."
+ fi
+ fi
+fi
+
+## EXECUTE ##
+
+execstr="$RDIFFBACKUP --print-statistics "
+
+# TODO: order the includes and excludes
+
+# excludes
+for i in $exclude; do
+ str="${i//__star__/*}"
+ execstr="${execstr}--exclude '$str' "
+done
+
+# includes
+for i in $include; do
+ str="${i//__star__/*}"
+ execstr="${execstr}--include '$str' "
+done
+
+# exclude everything else
+execstr="${execstr}--exclude '/*' "
+
+# include client-part and server-part
+execstr="${execstr}$execstr_clientpart $execstr_serverpart"
+
+debug 0 "su $sourceuser -c '$execstr'"
+if [ ! $test ]; then
+ output=`su $sourceuser -c "$execstr" 2>&1`
+ code=$?
+ if [ "$code" == "0" ]; then
+ debug 0 $output
+ debug 1 "Successfully finished backing up source '$label'"
+ else
+ debug 2 $output
+ debug 2 "Failed backup up source '$label'"
+ fi
+fi
+
+return 0
diff --git a/handlers/sh b/handlers/sh
new file mode 100644
index 0000000..6b1644d
--- /dev/null
+++ b/handlers/sh
@@ -0,0 +1,6 @@
+#
+# shell script handler for backupninja
+# runs the file /etc/backup.d/scriptname.sh
+#
+
+[ $test ] || ( . $1 )