Add a vim modeline with indentation settings.
[matthijs/upstream/backupninja.git] / handlers / sys.in
index cc8ed095931fcaa6de46113ccd6ccd7caf1e0a1b..69751ed125978d7c2df25ea4ee0e14634252a301 100755 (executable)
@@ -1,7 +1,8 @@
 # -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
+# vim: set filetype=sh sw=3 sts=3 expandtab autoindent:
 #
 # this handler will save various reports of vital system information.
-# by default, all the reports are enabled and are saved in /var/backups.
+# by default, all the reports are saved in /var/backups.
 #
 # (1) a capture of the debconf package selection states. This file
 #     can be used to restore the answers to debconf questions for
 # (2) a list of all the packages installed and removed.
 #     this file can be used to restore the state of installed packages
 #     by running "dpkg --set-selections < dpkg-selections.txt and
-#     then run "apt-get -u dselect-upgrade". If you have the 
+#     then run "apt-get -u dselect-upgrade". If you have the
 #     debconf-set-selections file from (1), you should restore those first.
-# 
-# (3) the partition table of all disks. 
+#
+# (3) the partition table of all disks.
 #     this partition table can be used to format another disk of
-#     the same size. this can be handy if using software raid and 
+#     the same size. this can be handy if using software raid and
 #     you have a disk go bad. just replace the disk and partition it
 #     by running "sfdisk /dev/sdb < partitions.sdb.txt"
 #     (MAKE SURE YOU PARTITION THE CORRECT DISK!!!)
 #
-# (4) hardware information. 
+# (4) hardware information.
 #     write to a text file the important things which hwinfo can gleen.
 #
+# (5) the Luks header of every Luks block device, if option luksheaders
+#     is enabled.
+#     in case you (have to) scramble such a Luks header (for some time),
+#     and restore it later by running "dd if=luksheader.sda2.bin of=/dev/sda2"
+#     (MAKE SURE YOU PASS THE CORRECT DEVICE AS of= !!!)
+#
+# (6) LVM metadata for every detected volume group, if "lvm = yes"
+#
 
 if [ -f /etc/debian_version ]
 then
@@ -47,7 +56,7 @@ getconf dohwinfo yes
 if [ ! -d $parentdir ]; then
    mkdir -p $parentdir
 fi
-   
+
 if [ $os = "debian" ]
 then
    getconf packagesfile $parentdir/dpkg-selections.txt
@@ -57,9 +66,9 @@ then
    getconf debconfgetselections `which debconf-get-selections`
 elif [ $os = "redhat" ]
 then
-   getconf packagesfile  $parentdir/rpmpackages.txt 
-   getconf packagemgr  `which rpm`
-   getconf packagemgroptions   ' -qa '
+   getconf packagesfile  $parentdir/rpmpackages.txt
+   getconf packagemgr   `which rpm`
+   getconf packagemgroptions   ' -qa '
 
    getconf SYSREPORT `which sysreport`
    getconf sysreport_options ' -norpm '
@@ -82,6 +91,15 @@ getconf HWINFO `which hwinfo`
 getconf sfdisk_options ""
 getconf hwinfo_options ""
 
+getconf CRYPTSETUP `which cryptsetup`
+getconf DD `which dd`
+getconf luksheaders no
+getconf luksheadersfile $parentdir/luksheader.__star__.bin
+
+getconf VGS `which vgs`
+getconf VGCFGBACKUP `which vgcfgbackup`
+getconf lvm no
+
 getconf vsnames all
 
 # If vservers are configured, check that the ones listed in $vsnames are running.
@@ -97,6 +115,30 @@ if [ $vservers_are_available = yes ]; then
    usevserver=yes
 fi
 
+## SANITY CHECKS #########################
+
+if [ "$luksheaders" == "yes" ]; then
+   if [ ! -x "$DD" ]; then
+      warning "can't find dd, skipping backup of Luks headers."
+      luksheaders="no"
+   fi
+   if [ ! -x "$CRYPTSETUP" ]; then
+      warning "can't find cryptsetup, skipping backup of Luks headers."
+      luksheaders="no"
+   fi
+fi
+
+if [ "$lvm" == "yes" ]; then
+   if [ ! -x "$VGS" ]; then
+      warning "can't find vgs, skipping backup of LVM metadata"
+      lvm="no"
+   fi
+   if [ ! -x "$VGCFGBACKUP" ]; then
+      warning "can't find vgcfgbackup, skipping backup of LVM metadata"
+      lvm="no"
+   fi
+fi
+
 ## PACKAGES ##############################
 
 #
@@ -116,27 +158,36 @@ if [ "$packages" == "yes" ]; then
             continue
          fi
          # is $packagemgr available inside $vserver ?
-         if [ ! -x "$VROOTDIR/$vserver`$VSERVER $vserver exec which $packagemgr`" ]; then
+         if [ ! -x "${VROOTDIR}/${vserver}${packagemgr}" ]; then
             warning "can't find $packagemgr in vserver $vserver, skipping installed packages report."
          else
             # don't expand * since it can be used in $packagemgroptions
             set -o noglob
             debug "$VSERVER $vserver exec $packagemgr $packagemgroptions > $VROOTDIR/$vserver$packagesfile"
-           $VSERVER $vserver exec $packagemgr $packagemgroptions > $VROOTDIR/$vserver$packagesfile || fatal "can not save $packagemgr info to $packagesfile"
+       $VSERVER $vserver exec $packagemgr $packagemgroptions > $VROOTDIR/$vserver$packagesfile || fatal "can not save $packagemgr info to $packagesfile"
             set +o noglob
          fi
          # is $debconfgetselections available inside $vserver ?
-         if [ -z "`$VSERVER $vserver exec which debconf-get-selections`" ]; then
-            warning "can't find debconf-get-selections in vserver $vserver, skipping package selection states."
+         found=no
+         # case #1: it is available on the host, is it available inside $vserver ?
+         if [ -n "$debconfgetselections" ]; then
+            [ -x "${VROOTDIR}/${vserver}${debconfgetselections}" ] && found=yes
+         # case #2: it is not available on the host, is it available inside $vserver ?
+         else
+            [ -n "`$VSERVER $vserver exec which debconf-get-selections`" ] && found=yes
+         fi
+         if [ "$found" != yes ]; then
+            warning "can't find debconf-get-selections in vserver $vserver, skipping package selection states. You may want to install the debconf-utils package."
          else
             debug "$VSERVER $vserver exec $debconfgetselections > $VROOTDIR/$vserver$selectionsfile"
             $VSERVER $vserver exec $debconfgetselections > $VROOTDIR/$vserver$selectionsfile || fatal "can not save debconf-get-selections info to $selectionsfile"
          fi
+         unset found
       done
    fi
-   
+
    # We want to perform this on the host as well
-   if [ -z "$packagemgr" -o ! -x "$packagemgr" ]; then 
+   if [ -z "$packagemgr" -o ! -x "$packagemgr" ]; then
       warning "can't find ${packagemgr}, skipping installed packages report."
    else
       # don't expand * since it can be used in $packagemgroptions
@@ -146,7 +197,7 @@ if [ "$packages" == "yes" ]; then
       set +o noglob
    fi
    if [ -z "$debconfgetselections" ]; then
-      warning "can't find ${debconfgetselections}, skilling package selection states."
+      warning "can't find debconf-get-selections, skipping package selection states. You might want to install the debconf-utils package."
    else
       debug "$debconfgetselections > $selectionsfile"
       $debconfgetselections > $selectionsfile || fatal "can not save $debconfgetselections info to $selectionsfile"
@@ -185,7 +236,7 @@ catiffile () {
       done
    fi
    echo $DASHES >> $sysreportfile
-} 
+}
 
 catifexec () {
    if [ -x $1 ]; then
@@ -195,12 +246,12 @@ catifexec () {
       $*  >> $sysreportfile 2>&1 || info "executing of $1 failed"
    fi
 }
-   
+
 
 STATUS="Determining $os version:"
 catiffile $osversion
 
-STATUS="Determinding your current hostname: " 
+STATUS="Determinding your current hostname: "
 catifexec "/bin/hostname"
 
 STATUS="Getting the date:"
@@ -217,58 +268,58 @@ catifexec "/bin/df" "-al"
 
 STATUS="Collecting what services run at what run level:"
 if [ $os = "redhat" ]; then
-   catifexec "/sbin/chkconfig --list"
+   catifexec "/sbin/chkconfig" "--list"
    STATUS="Collecting information about /etc/rc.d:"
    catiffile "/bin/ls /etc/rc.d/rc*.d/"
 
 elif [ $os = "debian" ]; then
-    for level in 0 1 2 3 4 5 6 S; do
-       echo "Level: $level" >> $sysreportfile
-       for f in /etc/rc${level}.d/*; do
-       # Remove /etc/Knn or Snn from beginning
-          ff=$(echo $f | @SED@ 's_/etc/rc..d/[KS][0-9][0-9]__')
-          if [ $f != $ff ]; then
-             echo $ff >> $sysreportfile
-          fi
-       done
-       echo "" >> $sysreportfile
-    done
+   for level in 0 1 2 3 4 5 6 S; do
+      echo "Level: $level" >> $sysreportfile
+      for f in /etc/rc${level}.d/*; do
+         # Remove /etc/Knn or Snn from beginning
+         ff=$(echo $f | @SED@ 's_/etc/rc..d/[KS][0-9][0-9]__')
+         if [ $f != $ff ]; then
+            echo $ff >> $sysreportfile
+         fi
+      done
+      echo "" >> $sysreportfile
+   done
 fi
 
 STATUS="Getting bootloader information:"
-catifexec "/bin/ls -alR /boot"
+catifexec "/bin/ls" "-alR /boot"
 
 # This covers sparc, alpha, and intel (respectively)
 # updated for grub -mpg
 if [ -f /etc/silo.conf ]; then
-  STATUS="Collecting information about the boot process (silo):"
-  catiffile "/etc/silo.conf"
+   STATUS="Collecting information about the boot process (silo):"
+   catiffile "/etc/silo.conf"
 fi
 if [ -f /etc/milo.conf ]; then
-  STATUS="Collecting information about the boot process (milo):"
-  catiffile "/etc/milo.conf"
+   STATUS="Collecting information about the boot process (milo):"
+   catiffile "/etc/milo.conf"
 fi
 if [ -f /etc/lilo.conf ]; then
-  STATUS="Collecting information about the boot process (lilo):"
-  catiffile "/etc/lilo.conf"
-  catifexec "/sbin/lilo -q"
+   STATUS="Collecting information about the boot process (lilo):"
+   catiffile "/etc/lilo.conf"
+   catifexec "/sbin/lilo" "-q"
 fi
 if [ -d /boot/grub -a -f /boot/grub/grub.conf -a -f /boot/grub/device.map ]; then
-  STATUS="Collecting information about the boot process (grub.conf):"
-  catiffile "/boot/grub/grub.conf"
-  STATUS="Collecting information about the boot process (grub.map):"
-  catiffile "/boot/grub/device.map"
+   STATUS="Collecting information about the boot process (grub.conf):"
+   catiffile "/boot/grub/grub.conf"
+   STATUS="Collecting information about the boot process (grub.map):"
+   catiffile "/boot/grub/device.map"
 fi
 if [ -f /etc/cluster.conf -o -f /etc/cluster.xml ] ; then
-  STATUS="Gathering information on cluster setup"
-  # 2.1 AS
-  if [ -f /etc/cluster.conf ] ; then
-    catiffile "/etc/cluster.conf"
-  fi
-  # Taroon
-  if [ -f /etc/cluster.xml ] ; then
-    catiffile "/etc/cluster.xml"
-  fi
+   STATUS="Gathering information on cluster setup"
+   # 2.1 AS
+   if [ -f /etc/cluster.conf ] ; then
+      catiffile "/etc/cluster.conf"
+   fi
+   # Taroon
+   if [ -f /etc/cluster.xml ] ; then
+      catiffile "/etc/cluster.xml"
+   fi
 fi
 
 STATUS="Gathering sysctl information (sysctl -a):"
@@ -277,13 +328,13 @@ STATUS="Gathering sysctl information (/etc/sysctl.conf):"
 catiffile "/etc/sysctl.conf"
 
 STATUS="Gathering IP information (/sbin/ifconfig):"
-catifexec "/sbin/ifconfig -a"
+catifexec "/sbin/ifconfig" "-a"
 
 STATUS="Gathering additional IP information (/bin/ip addr list):"
-catifexec "/bin/ip addr list"
+catifexec "/bin/ip" "addr list"
 
 STATUS="Checking network routes:"
-catifexec "/sbin/route -n"
+catifexec "/sbin/route" "-n"
 
 STATUS="Collecting Name Service Switch config information:"
 catiffile "/etc/nsswitch.conf"
@@ -299,10 +350,10 @@ STATUS="Getting kernel version:"
 catifexec "/bin/uname" "-a"
 STATUS="Checking module information:"
 catifexec "/sbin/lsmod"
-for x  in $(/sbin/lsmod | /bin/cut -f1 -d" " 2>/dev/null | /bin/grep -v Module 2>/dev/null 
+for x  in $(/sbin/lsmod | /bin/cut -f1 -d" " 2>/dev/null | /bin/grep -v Module 2>/dev/null
 ) ; do
-  STATUS="Checking module information $x:"
-  catifexec "/sbin/modinfo  $x"
+   STATUS="Checking module information $x:"
+   catifexec "/sbin/modinfo" "$x"
 done
 
 STATUS="Gathering information about your filesystems:"
@@ -325,27 +376,27 @@ STATUS="Collecting information regarding kernel modules"
 VER=`uname -r`
 catiffile "/lib/modules/$VER/modules.dep"
 if [ -f /etc/conf.modules ]; then
-  STATUS="Collecting information regarding kernel modules (conf.modules)"
-  catiffile "/etc/conf.modules"
+   STATUS="Collecting information regarding kernel modules (conf.modules)"
+   catiffile "/etc/conf.modules"
 fi
 if [ -f /etc/modules.conf ]; then
-  STATUS="Collecting information regarding kernel modules (modules.conf)"
-  catiffile "/etc/modules.conf"
+   STATUS="Collecting information regarding kernel modules (modules.conf)"
+   catiffile "/etc/modules.conf"
 fi
 if [ -f /etc/modprobe.conf ]; then
-  STATUS="Collecting information regarding kernel modules (modeprobe.conf)"
-  catiffile "/etc/modprobe.conf"
+   STATUS="Collecting information regarding kernel modules (modeprobe.conf)"
+   catiffile "/etc/modprobe.conf"
 fi
 
 # dkms status
 if [ -x /usr/sbin/dkms ] ; then
    STATUS="Gathering current status of modules, versions and kernels (dkms):"
-  catifexec "/usr/sbin/dkms" "status"
+   catifexec "/usr/sbin/dkms" "status"
 fi
 
 if [ -f /etc/sysconfig/isdncard ] ; then
-  STATUS="Gathering information about ISDN:"
-  catiffile "/etc/sysconfig/isdncard"
+   STATUS="Gathering information about ISDN:"
+   catiffile "/etc/sysconfig/isdncard"
 fi
 
 STATUS="Collecting information from the proc directory:"
@@ -393,7 +444,7 @@ STATUS="Collecting information from /etc/fstab:"
 catiffile "/etc/fstab"
 
 STATUS="Collecting disk partition information:"
-catifexec "/sbin/fdisk -l"
+catifexec "/sbin/fdisk" "-l"
 
 STATUS="Checking mounted file systems (mount) "
 catifexec "/bin/mount"
@@ -428,18 +479,21 @@ if [ $os = "redhat" ]; then
 elif [ $os = "debian" ]; then
    catifexec "/sbin/vgdisplay" "-vv"
 fi
-   
+
+STATUS="Collecting device-mapper (dm) information:"
+catifexec '/sbin/dmsetup' 'info'
+
 STATUS="Collecting SCSI Tape information (/etc/stinit.def)"
 catiffile "/etc/stinit.def"
 
 if [ -x /sbin/lsusb ] ; then
-  STATUS="Collecting USB devices list (lsusb):"
-  catifexec "/sbin/lsusb"
+   STATUS="Collecting USB devices list (lsusb):"
+   catifexec "/sbin/lsusb"
 fi
 
 if [ -x /usr/bin/lshal ] ; then
-  STATUS="Collecting global devices list (lshal):"
-  catifexec "/usr/bin/lshal"
+   STATUS="Collecting global devices list (lshal):"
+   catifexec "/usr/bin/lshal"
 fi
 
 
@@ -458,24 +512,24 @@ fi
 
 if [ "$partitions" == "yes" ]; then
    if [ "$dosfdisk" == "yes" ]; then
-       if [ ! -x "$SFDISK" ]; then
-               warning "can't find sfdisk, skipping sfdisk report."
-               partitions="no"
-       fi
+      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
+      if [ ! -x "$HWINFO" ]; then
+    warning "can't find hwinfo, skipping partition report."
+    partitions="no"
+      fi
    fi
 fi
 
 if [ "$hardware" == "yes" ]; then
-       if [ ! -x "$HWINFO" ]; then
-               warning "can't find hwinfo, skipping hardware report."
-               hardware="no"
-       fi
+   if [ ! -x "$HWINFO" ]; then
+      warning "can't find hwinfo, skipping hardware report."
+      hardware="no"
+   fi
 fi
 
 ## HARDWARE #############################
@@ -483,48 +537,47 @@ fi
 #
 # 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
+    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
+    echo -e "\n\n====================== $flag ======================\n" >>  $hardwarefile
+    $HWINFO --$flag >> $hardwarefile
       done
    fi
 fi
 
-
 ## PARTITIONS #############################
 
-# here we use sfdisk to dump a listing of all the partitions. 
+# here we use sfdisk to dump a listing of all the partitions.
 # these files can be used to directly partition a disk of the same size.
 
 if [ "$partitions" == "yes" ]; then
    if [ "$dosfdisk" == "yes" ]; then
       devices=`LC_ALL=C $SFDISK -l 2>/dev/null | grep "^Disk /dev" | @AWK@ '{print $2}' | cut -d: -f1`
-       if [ "$devices" == "" ]; then 
-          warning "No harddisks found" 
-       fi
-       for dev in $devices; do
-                debug "$SFDISK will try to backup partition tables for device $dev"
-               [ -b $dev ] || continue
-               label=${dev#/dev/}
-               label=${label//\//-}
-               outputfile=${partitionsfile//__star__/$label}
-               debug "$SFDISK $sfdisk_options -d $dev > $outputfile 2>/dev/null"
-               $SFDISK $sfdisk_options -d $dev > $outputfile 2>/dev/null
-                if [ $? -ne 0 ]; then
-                   warning "The partition table for $dev could not be saved."
-                fi
-       done
+   if [ "$devices" == "" ]; then
+      warning "No harddisks found"
+   fi
+   for dev in $devices; do
+      debug "$SFDISK will try to backup partition tables for device $dev"
+      [ -b $dev ] || continue
+      label=${dev#/dev/}
+      label=${label//\//-}
+      outputfile=${partitionsfile//__star__/$label}
+      debug "$SFDISK $sfdisk_options -d $dev > $outputfile 2>/dev/null"
+      $SFDISK $sfdisk_options -d $dev > $outputfile 2>/dev/null
+      if [ $? -ne 0 ]; then
+         warning "The partition table for $dev could not be saved."
+      fi
+   done
    fi
    if [ "$dohwinfo" == "yes" ]; then
       debug "Using $HWINFO to get all available disk information"
@@ -532,3 +585,99 @@ if [ "$partitions" == "yes" ]; then
       $HWINFO --disk >> $hardwarefile
    fi
 fi
+
+if [ "$luksheaders" == "yes" ]; then
+   devices=`LC_ALL=C $SFDISK -l 2>/dev/null | grep "^Disk /dev" | @AWK@ '{print $2}' | cut -d: -f1`
+   [ -n "$devices" ] || warning "No block device found"
+   targetdevices=""
+   for dev in $devices; do
+      [ -b $dev ] || continue
+      debug "$CRYPTSETUP isLuks $dev"
+      $CRYPTSETUP isLuks $dev
+      [ $? -eq 0 ] && targetdevices="$targetdevices $dev"
+   done
+   for dev in $targetdevices; do
+      label=${dev#/dev/}
+      label=${label//\//-}
+      outputfile=${luksheadersfile//__star__/$label}
+      # the following sizes are expressed in terms of 512-byte sectors
+      debug "Let us find out the Luks header size for $dev"
+      debug "$CRYPTSETUP luksDump \"$dev\" | grep '^Payload offset:' | @AWK@ '{print $3}'"
+      headersize=`$CRYPTSETUP luksDump "$dev" | grep '^Payload offset:' | @AWK@ '{print $3}'`
+      if [ $? -ne 0 ]; then
+         warning "Could not compute the size of Luks header, skipping device $dev"
+         continue
+      elif [ -z "$headersize" -o -n "`echo \"$headersize\" | sed 's/[0-9]*//g'`" ]; then
+         warning "The computed size of Luks header is not an integer, skipping device $dev"
+         continue
+      fi
+      debug "Let us backup the Luks header of device $dev"
+      debug "$DD if=\"${dev}\" of=\"${outputfile}\" bs=512 count=\"${headersize}\""
+      output=`$DD if="${dev}" of="${outputfile}" bs=512 count="${headersize}" 2>&1`
+      exit_code=$?
+      if [ $exit_code -eq 0 ]; then
+         debug $output
+         info "The Luks header of $dev was saved to $outputfile."
+      else
+         debug $output
+         fatal "The Luks header of $dev could not be saved."
+      fi
+   done
+fi
+
+## LVM ####################################
+
+# returns 0 on success, 1 on error, 2 if not tried
+# outputs error message if error, reason if not tried
+function doLvmBackup () {
+   local lvmdir="$1"
+   if [ ! -d "$lvmdir" ]; then
+      if ! mkdir "$lvmdir"; then
+         echo "could not create $lvmdir"
+         return 2
+      else
+         info "successfully created $lvmdir"
+      fi
+   fi
+   if [ ! -w "$lvmdir" ]; then
+      echo "can not write to directory $lvmdir"
+      return 2
+   fi
+   debug "Let's try to gather the list of LVM volume groups"
+   debug "$VGS --options vg_name --noheadings | @SED@ 's/^[ ]*//' | @SED@ 's/[ ]*$//' | tr '\n' ' '"
+   vgs=`$VGS --options vg_name --noheadings | @SED@ 's/^[ ]*//' | @SED@ 's/[ ]*$//' | tr '\n' ' '`
+   debug "Let's try to backup LVM metadata for detected volume groups: $vgs"
+   debug "$VGCFGBACKUP --file \"${lvmdir}\"/\'%s\' $vgs"
+   output=`$VGCFGBACKUP --file "${lvmdir}"/'%s' $vgs`
+   exit_code=$?
+   debug $output
+   case $exit_code in
+      0)
+         info "LVM metadata was saved to $lvmdir for volume groups: $vgs"
+         return 0
+         ;;
+      *)
+         echo "LVM metadata could not be saved for at least one of these volume groups: $vgs"
+         return 1
+         ;;
+   esac
+}
+
+if [ "$lvm" == "yes" ]; then
+   output=`doLvmBackup "${parentdir}/lvm"`
+   exit_code=$?
+   case $exit_code in
+      0) # success. info message has already been displayed
+         true
+         ;;
+      1) # error
+         fatal "$output"
+         ;;
+      2) # could not even try
+         fatal "LVM metadata backup was not tried: $output"
+         ;;
+      *) # should never happen
+         fatal "Unhandled error ($exit_code) while trying to backup LVM metadata, please report a bug"
+         ;;
+   esac
+fi