#!/bin/sh
set -u # exit on using unset var

#        name = bootcdmk2diskconf - create bootcd2disk.conf for backup
#       autor = Bernd Schumacher 
#   startdate = 08.05.2007

WARNING="
#
#  bootcdmk2diskconf and generated bootcd2disk.conf are 
#
#                E X P E R I M E N T A L
#
#  bootcdmk2diskconf is used to create bootcd2disk.conf for backup purposes.
#  
#  Please dobule check bootcd2disk.conf if bootcdmk2diskconf has been used
#  to create it.
#
#  It is very likely, that bootcdmk2diskconf has to be changed
#
"

USAGE="
Usage: bootcdmk2diskconf [-v] [-d]
   -v 	verbose 
   -d   debug
   -s   same; same size for last partition. If this option is not used 
        the last partition will be adjusted to actual disk size.
   -e   exact; exact disks will be used. Normally only the disk order will
        be used.
   -b   This option is needed to create a bootcd2disk.conf that can be 
        used to restore an offline backup.
   -f <fstabdev>
        Not the actual running system is used, but a system described by 
	the fstab that can be found on device <fstabdev>.
	<fstabpath>. example: -f /dev/sde7
"

debug()
{
  if [ "$DEBUG" ]; then
    echo "DEBUG $*" >&2
  fi
}

# label2dev <label>
label2dev()
{
  mount -vnf LABEL=$1 | # -> /ram1/dev/sda1 on /mnt/boot type ext3 (rw)
    awk '{print $1}' | # -> /ram1/dev/sda1
    sed "s|/ram[^/]*||" # /dev/sda1
}

#labelsed 
labelsed()
{
  local T T1 L j i
  T="$(cat)"
  debug "labelsed INPUT=<$T>"
  L="$(echo "$T" | sed -n "s/.*LABEL=\([^:[:space:]]\+\).*/\1/p" | sort -n)"
  for i in $L; do
    debug "labelsed search for label <$i>"
    j="$(echo "$RILABEL" | grep ":$i$" | awk -F: '{print $1}')"
    debug "labelsed found <$j>"
    T1="$(echo "$T" | sed "s|LABEL=$i|$j|")"
    T="$T1"
  done
  debug "labelsed OUTPUT=<$T>"
  echo "$T"
}

# rmvg()
rmvg()
{
  T="$(cat)"
  debug "rmvg INPUT=<$T>"
  for i in $CIVG; do
    debug "rmvg $i"
    T1="$(echo "$T" | grep -v -e "/dev/$i\>")"
    T="$T1"
  done
  debug "rmvg OUTPUT=<$T>"
  echo "$T"
}

# readinfo [/mnt]
readinfo()
{
  MNT=""
  [ $# -gt 0 ] && local MNT="$1"  

  RIFSTAB="$(cat $MNT/etc/fstab)"
  RIGRUB="$(for i in $MNT/boot/grub/menu.lst $MNT/boot/grub/grub.conf $MNT/boot/boot/grub/menu.lst \
    $MNT/boot/boot/grub/grub.conf; do if [ -s $i ]; then cat $i; break; fi; done)"
  RILV="$([ "$(type lvdisplay 2>/dev/null)" ] && (lvdisplay --units m -C | tail -n +2 | 
    sed "s/^[[:space:]]*//" | awk '{printf("%s:%s:%d\n",$1,$2,$4)}'))"
  RIPV="$([ "$(pvdisplay 2>/dev/null)" ] && (pvdisplay -C | tail -n +2 |
    awk '{printf("%s:%s\n",$1,$2)}'))"
  RIDF="$(df -lPm | grep -e "^/dev/" -e "^LABEL=" | 
    awk '{printf("%s:%s\n",$1,$2)}')"
  RILABEL="$(for i in $(echo "$RIFSTAB" | 
    sed -n "s/.*LABEL=\([^[:space:]]\+\).*/\1/p" | sort -n); do
      echo "$(label2dev $i):$i"
    done)"
  RIPARTITION="$(cat /proc/partitions | tail -n +3|
    awk '{printf("/dev/%s:%d\n",$4,$3/1024)}')"
}

readinfo_t1()
{
RIFSTAB="# This file is edited by fstab-sync - see 'man fstab-sync' for details
/dev/VolGroup00/LogVol00 /                       ext3    defaults        1 1
LABEL=/boot             /boot                   ext3    defaults        1 2
none                    /dev/pts                devpts  gid=5,mode=620  0 0
none                    /dev/shm                tmpfs   defaults        0 0
none                    /proc                   proc    defaults        0 0
none                    /sys                    sysfs   defaults        0 0
/dev/VolGroup00/LogVol01 swap                    swap    defaults        0 0
/dev/hda                /media/cdrom            auto    pamconsole,exec,noauto,managed 0 0
/dev/fd0                /media/floppy           auto    pamconsole,exec,noauto,managed 0 0"
RIGRUB="# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00
#          initrd /initrd-version.img
#boot=/dev/cciss/c0d0
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Red Hat Enterprise Linux AS (2.6.9-42.ELsmp)
	root (hd0,0)
	kernel /vmlinuz-2.6.9-42.ELsmp ro root=/dev/VolGroup00/LogVol00 rhgb quiet
	initrd /initrd-2.6.9-42.ELsmp.img
title Red Hat Enterprise Linux AS-up (2.6.9-42.EL)
	root (hd0,0)
	kernel /vmlinuz-2.6.9-42.EL ro root=/dev/VolGroup00/LogVol00 rhgb quiet
	initrd /initrd-2.6.9-42.EL.img"
RILV="LogVol00:VolGroup00:34124
LogVol01:VolGroup00:2080"
RIPV="/dev/cciss/c0d0p2:VolGroup00"
RIDF="/dev/mapper/VolGroup00-LogVol00:32033
/dev/cciss/c0d0p1:99"
RILABEL="/dev/cciss/c0d0p1:/boot"
RIPARTITION="/dev/cciss/c0d0:34727
/dev/cciss/c0d0p1:101
/dev/cciss/c0d0p2:34624
/dev/dm-0:32544
/dev/dm-1:1984"
}


calcinfo()
{
  local i j

  CIVG="$(echo "$RILV" | awk -F: '{print $2}' | sort -u)" 

  CISWAP="$(echo "$RIFSTAB" | grep -e "^/dev/" -e "^LABEL=" | 
    grep "\<swap\>" |awk '{print $1}' | labelsed)"

  CIFS="$(echo "$RIFSTAB"| eval "$MOUNTGREP" | awk '{printf("%s:%s\n",$1,$2)}' | labelsed )"

  CIPART="$((echo "$CIFS" | awk -F: '{print $1}'; echo "$CISWAP"; 
    echo "$RIPV" | awk -F: '{print $1}') | rmvg | sort -u)"

  CIDISK="$(
    j=0
    for i in $(echo "$CIPART" | sed "s/p*[123456789][[:digit:]]*//"|uniq); do
      echo "$i:DISK$j"
      let j=j+1
    done
  )"
}

showinfo()
{
  echo "RILV=\"$RILV\"" >&2
  echo "RIPV=\"$RIPV\"" >&2
  echo "RIDF=\"$RIDF\"" >&2
  echo "RILABEL=\"$RILABEL\"" >&2
  echo "RIPARTITION=\"$RIPARTITION\"" >&2

  echo "CIVG=\"$CIVG\"" >&2
  echo "CISWAP=\"$CISWAP\"" >&2
  echo "CIFS=\"$CIFS\"" >&2
  echo "CIPART=\"$CIPART\"" >&2
  echo "CIDISK=\"$CIDISK\"" >&2
}

parttrans()
{
  local i dev dsk

  T="$(cat)"
  for i in $CIDISK; do
    # i=/dev/sda:DISK1 -> dev=/dev/sda dsk=DISK1
    dev="$(echo "$i" | awk -F: '{print $1}')"
    dsk="$(echo "$i" | awk -F: '{print $2}')"

    T1="$(echo "$T" | sed "s|${dev}p*\>|$dsk|")"
    T="$(echo "$T1" | sed "s|${dev}p*\([[:digit:]]\+\)|${dsk}P\1|")"
  done
  echo "$T"
}

trans()
{
  echo "$1"  | sed "$PARTTRANS"
}

mapperlv2lv()
{
   T="$1"
   for i in $VG; do
     T1="$(echo "$T" | sed "s|/dev/mapper/$i-|/dev/$i/|")"
     T="$T1"
   done
   echo "$T"
}

print2diskconf()
{
  cat <<END
# bootcd2disk.conf - automatically created by bootcdmk2diskconf
$WARNING
ERRLOG=/var/log/bootcd2disk.log
END

  for i in $CIDISK; do 
    # i=/dev/sda:DISK1 -> dev=/dev/sda dsk=DISK1
    dev="$(echo "$i" | awk -F: '{print $1}')"
    dsk="$(echo "$i" | awk -F: '{print $2}')"
    if [ "$EXACTDISKS" ]; then
      echo "$dsk=\"$dev\""
    else
      echo "$dsk=\"auto\""
    fi
  done

  echo "LVMGRP=\""
  for i in $RIPV; do
    echo "$(echo "$i" | awk -F: '{print $2}' 
      ) $(echo "$i" | awk -F: '{print $1}' | parttrans)"
  done
  echo "\""

  echo "LVMVOL=\""

  for i in $RILV; do
    echo "$(echo "$i" | awk -F: '{printf("%s %s %s\n", $1,$3,$2)}')"
  done
  echo "\""

  for i in $CIDISK; do                                 
    # i=/dev/cciss/c0d0:DISK0 -> x=/dev/cciss/c0d0 y=0
    x="$(echo "$i" | awk -F: '{print $1}')"                
    y="$(echo "$i" | awk -F: '{print $2}' | sed "s/DISK//")"  
    echo "SFDISK$y=\""
    n=0
    while :; do
      # RIPARTITION="/dev/cciss/c0d0p1:101\n/dev/cciss/c0d0p2:34624" 
      # -> n=1, m=2, pn=101, pm=34624  -> n=2, m=3, pn=34624 pm=
      let n=n+1
      let m=n+1
      pn="$(echo "$RIPARTITION" | grep "^${x}p*${n}:" | awk -F: '{print $2}')"
      if [ "$pn" -eq 0 -a "$n" -lt 5 ]; then
        echo ",,E"
        n=5 
	m=6
        pn="$(echo "$RIPARTITION" | grep "^${x}p*${n}:" | awk -F: '{print $2}')"
      fi
      pm="$(echo "$RIPARTITION" | grep "^${x}p*${m}:" | awk -F: '{print $2}')"
      if [ "$pm" ]; then
        echo ",$pn"
      else
        if [ "$SAMESIZE" ]; then
          echo ",$pn"
	else
          echo ";"
        fi
        break
      fi
    done
    echo "\""
  done

  echo "EXT2FS=\""
  echo "$CIFS" | awk -F: '{print $1}' | parttrans
  echo "\""

  echo "SWAP=\"$(echo "$CISWAP" | parttrans)\""

  # CIFS="<devpath>:<mountpoint>\n..."
  # Sort it with length of <mountpoint> for right mount order
  SORTCIFS=$(for i in $CIFS; do
    echo "$(echo "$i" | awk -F: '{print $2}'|wc -c):$i" | sort -n
  done)
  
  echo "MOUNT=\""
  # RILABEL="/dev/cciss/c0d0p1:/boot"
  for i in $RILABEL; do
    x="$(echo "$i" | awk -F: '{print $1}')"
    y="$(echo "$i" | awk -F: '{print $2}')"
    echo "tune2fs -L $y $x >/dev/null 2>&1" | parttrans
  done
  # SORTCIFS="<mountpointlen>:<devpath>:<mountpoint>\n..."
  for i in $SORTCIFS; do
    x="$(echo "$i" | awk -F: '{print $2}')"
    y="$(echo "$i" | awk -F: '{print $3}')"
    echo "mkdir -p /mnt$y; mount $x /mnt$y"
  done
  echo "\""

  UMOUNT=""
  echo "UMOUNT=\""
  for i in $(echo "$SORTCIFS" | sort -nr); do
    x="$(echo "$i" | awk -F: '{print $3}')"
    echo "umount /mnt$x"
    UMOUNT="$UMOUNT umount /mnt$x;"
  done
  echo "\""
  
  if [ ! "$BACKUP" ]; then
    echo "FSTAB=\""
    echo "$RIFSTAB"
    echo "\""

    echo "GRUB=\""
    echo "$RIGRUB"
    echo "\""
  else
    echo "FSTAB=\"fstab is used, as defined in backup\""
    echo "GRUB=\"grub is used, as defined in backup\""
  fi

  if [ "$BACKUP" ]; then
    # default directory structure for backup called <name>:
    #   /<name>/backup.tgz
    #   /etc/bootcd/<name>/bootcd2disk.conf (this file)

    echo "RESTORECMD=\"(cd /mnt; tar xzf /\\\$(basename \\\$CONFDIR)/backup.tgz)\""
  fi

  cat <<END
# Default values
TRYFIRST=""
VFAT=""
EXT3="auto"
GRUBBOOTDISK="hd0"
LILO=""
ELILO=""
SSHHOSTKEY=yes
UDEV_FIXNET="no"
USEIMAGESERVER="no"
IMAGEURL=""
END

}

# Const 
MOUNTGREP='grep -e "^/dev/" -e "^LABEL=" | grep -v -e "\<noauto\>" -e "\<auto\>" -e "\<swap\>"'

SAMESIZE=""
VERBOSE=""
DEBUG=""
EXACTDISKS=""
BACKUP=""
FSTABDEV=""
while [ "$*" ]; do
  if [ "$1" = "-v" ]; then
    VERBOSE="1"
    shift
  elif [ "$1" = "-d" ]; then
    DEBUG="1"
    shift
  elif [ "$1" = "-s" ]; then
    SAMESIZE="$1"
    shift
  elif [ "$1" = "-e" ]; then
    EXACTDISKS="$1"
    shift
  elif [ "$1" = "-b" ]; then
    BACKUP="$1"
    shift 1
  elif [ "$1" = "-f" ]; then
    FSTABDEV="$2"
    shift 2
  else
    echo "$USAGE" >&2
    exit 1
  fi
done

if [ "$FSTABDEV" ]; then

  if [ "$(/bin/ls /mnt)" ]; then
    echo "/mnt is not emply; please empty it, (rm or umount)" >&2
    exit 1
  fi
  mount $FSTABDEV /mnt 
  if [ $? -ne 0 ]; then
    echo "Problem mounting $FSTABDEV /mnt" >&2
    exit 1
  fi

  if [ ! "$(grep "# bootcdmk2diskconf entries" /etc/fstab)" ]; then
    echo "# bootcdmk2diskconf entries" >>/etc/fstab

    if [ -f /etc/fstab ]; then
      FSTABPATH="/etc/fstab"
    elif [ -f /fstab ]; then
      FSTABPATH="/fstab"
    else
      echo "Can not find fstab" >&2
      exit 1
    fi
    ADDMNT="$(cat /mnt/$FSTABPATH | eval "$MOUNTGREP" | awk '{$2="/mnt/"$2; print}')"
    [ "$VERBOSE" ] && echo "Additional mounts: <$ADDMNT>" >&2
    echo "$ADDMNT" >> /etc/fstab
  fi
  mount -a
  readinfo /mnt


else
  readinfo
  #readinfo_t1
fi

calcinfo
[ "$VERBOSE" ] && showinfo
print2diskconf


if [ "$FSTABDEV" ]; then

  cp /etc/fstab /etc/fstab.tmp
  cat /etc/fstab.tmp | awk 'BEGIN {p=1} /# bootcdmk2diskconf entries/ {p=0} {if(p) print}' >/etc/fstab
  rm /etc/fstab.tmp

  [ "$VERBOSE" ] && echo "Doing umount: <$UMOUNT>" >&2
  eval "$UMOUNT"

  if [ "$(/bin/ls /mnt)" ]; then
    echo "ERROR: /mnt is not emply; calculated umount <$UMOUNT> did not work !!!"
    exit 1
  fi

fi
