diff --git a/AUTHORS b/AUTHORS
index 03a9de4f0a73e082924c00324906ae0ecd83f1e0..fad2bbb7f9e20b33958e401eef03e69c18e0b987 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -20,4 +20,5 @@ Brad Fritz <brad@fritzfam.com> -- trac patch
 garcondumonde@riseup.net
 Martin Krafft madduck@debian.org -- admingroup patch
 Anarcat -- lotsa patches
-Jamie McClelland - cstream patches
+Jamie McClelland -- cstream patches
+ale -- ldap cleanup
\ No newline at end of file
diff --git a/ChangeLog b/ChangeLog
index 98482ac154e6a93e8c04664960a7edebe72316b4..0bae02e63f85aeb201225b20f17c3a8265e928d1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,32 +1,44 @@
 version 0.9.5 -- unreleased
+    ninjareport
+	 . Added first draft of method to aggregate reports from many servers into
+	   one email. Requires logtail, rsync, configuration of reporthost, 
+	   reportdirectory and reportuser in backupninja.conf. Configure cron to
+	   run once a day, and individual backupninjas not to report by email their
+	   status, then enjoy one email report from all hosts, rather than multiple
     backupninja changes
 	 . Fixed checks on configuration files permissions, since the patch
 	   applied to fix #370396 broke this, especially for configuration files
 	   created with permissions 000 by an older ninjahelper version.
 	 . Enhanced portability for other platforms 
     handler changes
-	sys:
-	 . Fixed typo breaking things for VServers.
-	 . Fix bug when vrootdir is on its own partition (Closes: #395928)
-	 . Better sfdisk error and output handling: should now properly warn
-	   when it does not manage to backup a partition table, and shut up when
-	   it succeeds (Closes: #396632)
-	rub
-	 . Fixed typo in rub handler that caused it to not work
-	 . Changed to use lib/vserver code
-	 . Fixed fsck error
+        ldap:
+	 . Fixed shell command quoting issues, missing 'then' clauses, cleaned up
+	   compress=yes to be less redundant and not create empty uncompressed file
+        mysql:
+	 . Fixed case where odd combination of configuration options caused sqldump
+	   backups to get overwritten with an empty file (Closes: #402679)
 	pgsql:
 	 . Support configuring PGSQLUSER for real, and document it a bit; this
 	   broken support actually prevented pgsql handler to work for VServers
 	   (Closes: #396578)
-	mysql:
-	 . Fixed case where odd combination of configuration options caused sqldump
-	   backups to get overwritten with an empty file (Closes: #402679)
 	rdiff:
 	 . Added cstream support to allow for bandwidth limiting
+	rub
+	 . Fixed typo in rub handler that caused it to not work
+	 . Changed to use lib/vserver code
+	 . Fixed fsck error
+	sys:
+	 . Fixed typo breaking things for VServers.
+	 . Fix bug when vrootdir is on its own partition (Closes: #395928)
+	 . Better sfdisk error and output handling: should now properly warn
+	   when it does not manage to backup a partition table, and shut up when
+	   it succeeds (Closes: #396632)
+	 . Added option to not use sfdisk at all, useful for vserver/xen instances
+	   that produce warnings about no harddisks found (Closes: #404071)
     fixed 'make install' bug that failed if /etc/backup.d already existed
     changed spaces to tabs in Makefile.am
     updated examples/Makefile.am and handlers/Makefile.am to include rsnap/rub files
+    
 
 version 0.9.4 -- October 6th, 2006
     backupninja changes
diff --git a/etc/backupninja.conf.in b/etc/backupninja.conf.in
index 090561f594916a8acdc1891c78e2400ad0b3b242..f7668a5c769412e61ce896f126ab45e48de0a3a0 100644
--- a/etc/backupninja.conf.in
+++ b/etc/backupninja.conf.in
@@ -29,6 +29,19 @@ reportwarning = yes
 # the backup email report
 reportspace = no
 
+# where to rsync the backupninja.log to be aggregated in
+# a ninjareport
+reporthost = 
+
+# what user to connect to reporthost to sync the
+# backupninja.log
+reportuser = ninja
+
+# where on the reporthost should the report go
+# NOTE: the name of the log will be used in the report, 
+# use a globally unique name, preferably the hostname
+reportdirectory = /var/lib/backupninja/reports
+
 # set to the administration group that is allowed to 
 # read/write configuration files in /etc/backup.d
 admingroup = root
diff --git a/examples/example.sys b/examples/example.sys
index a05726b0482905da0aa35bbc17c9ec3fe2d880c8..a5b349b396a390611113969f2b8376fd194c0b51 100644
--- a/examples/example.sys
+++ b/examples/example.sys
@@ -26,7 +26,9 @@
 
 # partitions = yes
 # partitionsfile = /var/backups/partitions.*.txt
+# dosfdisk = yes
 
 # hardware = yes
 # hardwarefile = /var/backups/hardware.txt
+# dohwinfo = yes
 
diff --git a/handlers/sys b/handlers/sys
index ce9c5b03e2d523f267d950dc2186078c9e60aacf..3e7f03e2e74f1472e799b93ce301e90aa02bbb63 100755
--- a/handlers/sys
+++ b/handlers/sys
@@ -33,6 +33,8 @@ else
 fi
 
 getconf packages yes
+getconf dosfdisk yes
+getconf dohwinfo yes
 if [ $os = "debian" ]
 then
    getconf packagesfile /var/backups/dpkg-selections.txt
@@ -419,14 +421,18 @@ if [ $usevserver = yes ]; then
 fi
 
 if [ "$partitions" == "yes" ]; then
+   if [ "$dosfdisk" == "yes" ]; then
 	if [ ! -x "$SFDISK" ]; then
 		warning "can't find sfdisk, skipping sfdisk report."
 		partitions="no"
 	fi
+   fi
+   if [ "$dohwinfo" == "yes" ]; then
 	if [ ! -x "$HWINFO" ]; then
 		warning "can't find hwinfo, skipping partition report."
 		partitions="no"
 	fi
+   fi
 fi
 
 if [ "$hardware" == "yes" ]; then
@@ -436,6 +442,29 @@ if [ "$hardware" == "yes" ]; then
 	fi
 fi
 
+## HARDWARE #############################
+
+#
+# here we use hwinfo to dump a table listing all the
+# information we can find on the hardware of this machine
+# 
+
+if [ "$hardware" == "yes" ]; then
+   if [ "dohwinfo" == "yes" ]; then
+      if [ -f $hardwarefile ]; then
+	 rm $hardwarefile
+      fi
+      touch $hardwarefile
+      echo -e "\n\n====================== summary ======================\n" >>  $hardwarefile
+      debug "$HWINFO --short --cpu --network --disk --pci  >> $hardwarefile"
+      $HWINFO --short --cpu --network --disk --pci  >> $hardwarefile
+      for flag in cpu network bios pci; do
+	 echo -e "\n\n====================== $flag ======================\n" >>  $hardwarefile
+	 $HWINFO --$flag >> $hardwarefile
+      done
+   fi
+fi
+
 
 ## PARTITIONS #############################
 
@@ -443,7 +472,8 @@ fi
 # these files can be used to directly partition a disk of the same size.
 
 if [ "$partitions" == "yes" ]; then
-	devices=`$SFDISK -l 2>/dev/null | grep "^Disk /dev" | @AWK@ '{print $2}' | cut -d: -f1`
+   if [ "$dosfdisk" == "yes" ]; then
+      devices=`$SFDISK -l 2>/dev/null | grep "^Disk /dev" | @AWK@ '{print $2}' | cut -d: -f1`
 	if [ "$devices" == "" ]; then 
 	   warning "No harddisks found" 
 	fi
@@ -459,25 +489,10 @@ if [ "$partitions" == "yes" ]; then
                    warning "The partition table for $dev could not be saved."
                 fi
 	done
-fi
-
-## HARDWARE #############################
-
-#
-# here we use hwinfo to dump a table listing all the
-# information we can find on the hardware of this machine
-# 
-
-if [ "$hardware" == "yes" ]; then
-	if [ -f $hardwarefile ]; then
-		rm $hardwarefile
-	fi
-	touch $hardwarefile
-	echo -e "\n\n====================== summary ======================\n" >>  $hardwarefile
-	debug "$HWINFO --short --cpu --network --disk --pci  >> $hardwarefile"
-	$HWINFO --short --cpu --network --disk --pci  >> $hardwarefile
-	for flag in cpu network disk bios pci; do
-		echo -e "\n\n====================== $flag ======================\n" >>  $hardwarefile
-		$HWINFO --$flag >> $hardwarefile
-	done
+   fi
+   if [ "$dohwinfo" == "yes" ]; then
+      debug "Using $HWINFO to get all available disk information"
+      echo -e "\n\n====================== $disk ======================\n" >>  $hardwarefile
+      $HWINFO --disk >> $hardwarefile
+   fi
 fi
diff --git a/handlers/sys.helper b/handlers/sys.helper
index b6e3b8c745796492dc4eae4cd8b273a3ee3ecfdd..6451ae299669233c42e85c4d180e3f643d0f2c49 100644
--- a/handlers/sys.helper
+++ b/handlers/sys.helper
@@ -7,16 +7,19 @@ sys_wizard() {
    checkBox "new sys action" "check options" \
        "packages" "list of all installed packages." on \
        "partitions" "the partition table of all disks." on  \
+       "sfdisk" "use sfdisk to get partition information." on \
        "hardware" "detailed hardware information" on
    [ $? = 1 ] && return;    
    result="$REPLY"
    packages="packages = no"
    partitions="partitions = no"
+   sfdisk="dosfdisk = no"
    hardware="hardware = no"
    for opt in $result; do
       case $opt in
         '"packages"') packages="packages = yes";;
         '"partitions"') partitions="partitions = yes";;
+        '"sfdisk"') sfdisk="dosfdisk = yes";;
         '"hardware"') hardware="hardware = yes";;
       esac
    done
@@ -24,6 +27,7 @@ sys_wizard() {
    cat > $next_filename <<EOF
 $packages
 $partitions
+$sfdisk
 $hardware
 # packagesfile = /var/backups/dpkg-selections.txt
 # partitionsfile = /var/backups/partitions.__star__.txt
diff --git a/src/Makefile.am b/src/Makefile.am
index f0cb69c12ff15061c3a78b8d7c426fbaf46827ab..3d5bdb8d630e443cd99b7d23cd80939a6f3951b3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,7 +4,7 @@ sbin_SCRIPTS  = backupninja ninjahelper
 # a proto je taky musíme smazat ...
 CLEANFILES = $(sbin_SCRIPTS)
 
-EXTRA_DIST = backupninja.in ninjahelper.in
+EXTRA_DIST = backupninja.in ninjahelper.in ninjareport.in
 
 edit = sed \
     -e "s,@CFGDIR\@,$(CFGDIR),g" \
@@ -28,3 +28,7 @@ ninjahelper: $(srcdir)/ninjahelper.in
 	$(edit) $(srcdir)/ninjahelper.in > ninjahelper
 	chmod ugo+x ninjahelper
 
+ninjareport: $(srcdir)/ninjareport.in
+	rm -f ninjareport
+	$(edit) $(srcdir)/ninjareport.in > ninjareport
+	chmod ugo+x ninjareport
diff --git a/src/backupninja.in b/src/backupninja.in
index 02ffa25b519fc5cd7f860cd580b3c5ca8918169e..ef959f2c6c7dc2eede15c5a27584aa2fd4add1ad 100755
--- a/src/backupninja.in
+++ b/src/backupninja.in
@@ -433,9 +433,12 @@ setfile $conffile
 # get global config options (second param is the default)
 getconf configdirectory @CFGDIR@/backup.d
 getconf scriptdirectory @datadir@
+getconf reportdirectory
 getconf reportemail
+getconf reporthost
 getconf reportspace
 getconf reportsuccess yes
+getconf reportuser
 getconf reportwarning yes
 getconf loglevel 3
 getconf when "Everyday at 01:00"
@@ -555,3 +558,8 @@ fi
 if [ $actions_run != 0 ]; then
 	info "FINISHED: $actions_run actions run. $fatals fatal. $errors error. $warnings warning."
 fi
+
+if [ -n "$reporthost" ]; then
+	debug "send $logfile to $reportuser@$reporthost:$reportdirectory"
+	rsync -qt $logfile $reportuser@$reporthost:$reportdirectory
+fi
diff --git a/src/ninjareport.in b/src/ninjareport.in
new file mode 100755
index 0000000000000000000000000000000000000000..b68efb87919ccc131ee019b1de0b40b04a6f2698
--- /dev/null
+++ b/src/ninjareport.in
@@ -0,0 +1,205 @@
+#!@BASH@
+# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
+#
+#
+# Ninjareport - generate a single simple report for a lot of hosts
+#
+# requires logtail
+#
+# Copyright (C) 2007 - riseup.net -- property is theft.
+
+# TODO:
+#
+#  . check for logs that are never updating and warn
+#  . change constantly updating logs (maildir) to be more friendly
+#  . documentation
+#  . maybe make config option that lists all hosts that should report-in, and if 
+#    one doesn't then warn
+#  . restrict rsync somehow?
+#  . abstract path for logtail
+#  . on the report master, the reportdirectory should be set where the reports will be going, note this
+
+mail=1
+display=0
+
+process() {
+
+# look in the logfile for any lines like the following:
+# Jan 20 01:02:46 Info: FINISHED: 2 actions run. 0 fatal. 0 error. 0 warning.
+#
+# note: some backups never finish, such as the maildir one, need to handle these
+# perhaps by looking for FAILED messages?
+# note2: what about logs that aren't being updated? this is a failure case and 
+# should be looked for
+# note3: there are also these entries:
+# Jan 20 14:00:01 Fatal: No backup actions configured in '/etc/backup.d', run ninjahelper!
+
+# The following has to be done without invoking a subshell (see BashFAQ #24)
+logupdates=`maketemp ninjadata`
+
+/usr/sbin/logtail -f $host > $logupdates
+grep FINISHED $logupdates | 
+(
+	fatal=0
+	warning=0
+	error=0
+
+	while read line
+	do
+		line_array=($line)
+		fatal=$(($fatal + ${line_array[8]}))
+		error=$(($error + ${line_array[10]}))
+		warning=$(($warning + ${line_array[12]}))
+	done
+	if (( $fatal || $warning || $error )); then
+		echo "`basename $host .log`: $fatal fatals found, $error errors found, $warning warnings found" >> $statusfile
+		echo "" >> $reportappend
+		echo "`basename $host .log` log entries since last ninjareport" >> $reportappend
+		echo "---------" >> $reportappend
+		cat $logupdates >> $reportappend
+		rm $logupdates
+	fi
+)
+
+}
+
+generatereport() {
+
+reportfile=`maketemp ninjareport`
+
+# Generate a report, only if there are failures
+if [ -s $statusfile ]; then
+	echo "         backupninja mission failures - `date`" >> $reportfile
+	echo "       --------------------------------------------------------------" >> $reportfile
+	echo "" >> $reportfile
+	cat $statusfile | column -t >> $reportfile
+	echo "" >> $reportfile
+	echo "         log entries from failed reports" >> $reportfile
+	echo "       -----------------------------------" >> $reportfile
+	cat $reportappend >> $reportfile
+fi
+
+}
+
+usage() {
+	cat << EOF
+This script generates a backupninja status report for all configured
+systems. It requires that each status report is placed in a spot where
+ninjareport can read it, reports are mailed to the reportemail
+configured in @CFGDIR@/backupninja.conf.
+
+The following options are available:
+-h, --help		This usage message
+-f, --conffile FILE	Use FILE for the configuration instead
+			of @CFGDIR@/backupninja.conf
+-m, --mail <email>	Mail the report to this address
+-o, --out 		Don't mail the report, just display it
+
+EOF
+}
+
+#####################################################
+## MAIN
+
+conffile="@CFGDIR@/backupninja.conf"
+
+## process command line options
+
+while [ $# -ge 1 ]; do
+	case $1 in
+		-h|--help) 
+                        usage
+			exit 0
+			;;
+		-f|--conffile)
+			if [ -f $2 ]; then
+				conffile=$2
+			else
+				echo "-f|--conffile option must be followed by an existing filename"
+				fatal "-f|--conffile option must be followed by an existing filename"
+				usage
+			fi
+			# we shift here to avoid processing the file path 
+			shift
+			;;
+		-m|--mail)
+			reportemail=$2
+			shift
+			;;
+		-o|--out)
+			mail=0
+			display=1
+			;;
+		*)
+			echo "Unknown option $1"
+			usage
+			exit
+			;;
+	esac
+	shift
+done																										
+
+## Load and confirm basic configuration values
+
+# bootstrap
+if [ ! -r "$conffile" ]; then
+	echo "Configuration file $conffile not found." 
+	fatal "Configuration file $conffile not found."
+fi
+
+# find $libdirectory
+libdirectory=`grep '^libdirectory' $conffile | awk '{print $3}'`
+if [ -z "$libdirectory" ]; then
+   if [ -d "@libdir@" ]; then
+      libdirectory="@libdir@"
+   else
+      echo "Could not find entry 'libdirectory' in $conffile." 
+      exit 1
+   fi
+else
+   if [ ! -d "$libdirectory" ]; then
+      echo "Lib directory $libdirectory not found." 
+      exit 1
+   fi
+fi
+
+# include shared functions
+. $libdirectory/tools
+
+setfile $conffile
+
+getconf reportdirectory
+getconf reportemail
+
+## Process each configuration file
+
+hosts=`find $reportdirectory -follow -mindepth 1 -maxdepth 1 -type f ! -name '*.offset' | sort -n`
+
+if [ -z "$hosts" ]; then
+	echo "Fatal: No backupninja reports found in '$reportdirectory'!"
+	mail=0
+fi
+
+statusfile=`maketemp ninjastatus`
+reportappend=`maketemp ninjaappend`
+
+for host in $hosts; do
+	[ -f "$host" ] || continue
+	# Check somehow that the file is a valid report file
+	process $host
+done
+
+generatereport
+
+## mail the report to the report address or display it
+
+if [ -s $reportfile ]; then
+    if [ $mail == 1 ]; then
+	mail -s "backupninja mission failure report" $reportemail < $reportfile
+    fi
+fi
+
+if [ $display == 1 ]; then
+	cat $reportfile
+fi
+