#!/bin/sh
#
# bootcd2disk
#
# DISK=auto, we will build an boot partition with size defined in BOOTS
BOOTS=50

VERBOSE=""
SCRIPT=""
CONFDIR="/etc/bootcd"
while [ $# -gt 0 ]; do
  if [ "$1" = "-v" ]; then
    VERBOSE="$1"
    shift
  elif [ "$1" = "-c" -a $# -gt 1 ]; then
    CONFDIR=$2
    shift 2
  elif [ "$1" = "-s" ]; then
    SCRIPT="$1"
    shift
  else
    echo "Usage: bootcd2disk [-v]"
    echo "  use man bootcd2disk to get help"
    echo "  and see $CONFDIR/bootcd2disk.conf"
    exit 1
  fi
done

CONFVARS="DISK SFDISK EXT2FS EXT3 SWAP MOUNT UMOUNT FSTAB LILO SSHHOSTKEY \
  VFAT ELILO TRYFIRST"
CREATEVARS="KERNEL INITRD DISABLE_CRON ARCH"
unset $CONFVARS $CREATEVARS

[ $CONFDIR/bootcd2disk.conf ] && . $CONFDIR/bootcd2disk.conf
[ /etc/bootcd/thisbootcd.conf ] && . /etc/bootcd/thisbootcd.conf
[ /usr/share/bootcd/bootcd-run.lib ] && . /usr/share/bootcd/bootcd-run.lib

[ ! -f /etc/bootcd/thisbootcd.conf ] &&
  err "No file /etc/bootcd/thisbootcd.conf"
[ ! -f $CONFDIR/bootcd2disk.conf ] && err "No file $CONFDIR/bootcd2disk.conf"

for i in $CONFVARS; do
  [ "`set | grep ^$i=`" ] || err "$i is not set in $CONFDIR/bootcd2disk.conf"
done

for i in $CREATEVARS; do
  [ "`set | grep ^$i=`" ] || err "$i is not set in /etc/bootcd/thisbootcd.conf"
done

KERN_YES="y"
[ "$INITRD" ] && KERN_YES="[m|y]" # if initrd is used, a kernel-module is enough

cleanup()
{
  echo "ignoring trap"
}

check_ext3()
{
  [ "$EXT3" = "no" ] && return

PROBLEM="
To use EXT3 some kernel options are needed. It seems not all needed
Options are build in the kernel."
  if [ "$KCONF" ]; then
    for i in \
      "CONFIG_EXT3_FS=$KERN_YES"
    do
      grep -q "^$i" $KCONF
      if [ $? != 0 ]; then
        if [ "$EXT3" = "yes" ]; then
	  warn "CONFIG_EXT3_FS is not configured.$PROBLEM"
        else
	  echo "CONFIG_EXT3_FS is not configured.$PROBLEM" >>$ERRLOG
          echo " => EXT3=no" >>$ERRLOG
	  EXT3=no
	  return
	fi
      fi
    done
  fi

PROBLEM="
To use EXT3 a new version of e2fsprogs has to be installed. For example
the file /sbin/mkfs.ext3 must exist."
  if [ ! -f "/sbin/mkfs.ext3" ]; then
    if [ "$EXT3" = "yes" ]; then
      warn "/sbin/mkfs.ext3 not found.$PROBLEM"
    else
      echo "/sbin/mkfs.ext3 not found.$PROBLEM" >>$ERRLOG
      echo " => EXT3=no" >>$ERRLOG
      EXT3=no
      return
    fi
  fi

  [ "$EXT3" = "auto" ] && EXT3="yes"
}

# replace parameter DISK to the real disk-device
function disk2real()
{
  local param="$1"

  if [ $# -gt 1 ]; then
    local file="$2"
  else
    local file=""
  fi

  if [ "$file" = "" ]; then
    echo $(eval echo \'$param\' | 
      sed -e "s|DISK\>|${DISK}|g" -e "s|DISK|${DISK}${P}|g")
  else
    sed -e "s|DISK\>|${DISK}|g" -e "s|DISK|${DISK}${P}|g" $file >$file.tmp
    mv $file.tmp $file
  fi
}
#echo "Expected Result: /dev/hda /dev/hda1 /dev/hda3"
#P="" DISK=/dev/hda disk2real "Test Result....: DISK DISK1 DISK2"
#echo 
#echo "Expected Result: /dev/cciss/p0d0 /dev/cciss/p0d0p1 /dev/cciss/p0d0p3"
#P="p" DISK=/dev/cciss/p0d0 disk2real "Test Result....: DISK DISK1 DISK2"
#echo
#exit 0

get_disk()
{
  # sfsidk -l does not allways show all disks but /proc/partitions works
  PARTIMAJOR=$(cat /proc/partitions | 
    tail +2 |				# ignore header line
    grep -v "^[[:space:]]*$" |		# ignore empty lines
    awk '{print $1}' |			# show only major numbers
    sort -u				# each major only one time
  )
  echo "PARTIMAJOR=<$PARTIMAJOR>" >>$ERRLOG

  PARTIDISK=""
  # find devicefile with given major number and minor number 0
  for i in $PARTIMAJOR; do
    PARTIDISK="$PARTIDISK $(find /dev -type b -follow 2>/dev/null | 	
    					# find all blockdevices 
      xargs /bin/ls -l | 		# 
      grep "\<$i,[[:space:]]\+0\>" | 	# search for major and minor
      awk '{print $NF}'			# print device path
    )"
  done
  echo "PARTIDISK=<$PARTIDISK>" >>$ERRLOG

  AUTODISK=$( 
    ( for i in $TRYFIRST $PARTIDISK; do
        sfdisk -l $i
      done
    ) 2>&1 |
    grep "^Disk.*cylinders" |	# Disk /dev/cciss/c0d0: 17433 cylinders, ...
    grep -v ": 0 cylinders" |		# Filter out CDROMS
    head -1|                    	# Use only the first disk
    sed "s/:/ /g"|awk '{print $2}'
  )
  echo "$AUTODISK"
}
#get_disk
#exit 0

date "+--- $0 %d.%m.%Y ---" > $ERRLOG
echo "To see full output: tail -f $ERRLOG" | tee -a $ERRLOG

# only call the function, if it is defined
doit=$(egrep "^[[:space:]]*(function)*[[:space:]]*do_first" $CONFDIR/bootcd2disk.conf)
if [ ! -z "$doit" ]; then
  echo "--- do function do_first ---" | tee -a $ERRLOG
  do_first
fi

KCONF=`echo "$KERNEL" | sed "s/vmlinu./config/"`

if [ "$SFDISK" != "auto" ]; then
  [ "$EXT2FS" = "auto" ] && warn "To define EXT2FS=auto makes only sence if you define SFDISK=auto too"
  [ "$SWAP" = "auto" ] && warn "To define SWAP=auto makes only sence if you define SFDISK=auto too"
fi

if [ "$EXT2FS" != "auto" ]; then
  [ "$MOUNT" = "auto" ] && warn "To define MOUNT=auto makes only sence if you define EXT2FS=auto too"
  [ "$UMOUNT" = "auto" ] && warn "To define UMOUNT=auto makes only sence if you define EXT2FS=auto too"
  [ "$FSTAB" = "auto" ] && warn "To define FSTAB=auto makes only sence if you define EXT2FS=auto too"
  [ "$LILO" = "auto" ] && warn "To define LILO=auto makes only sence if you define EXT2FS=auto too"
fi

if [ "$DISK" = "auto" ]; then
  DISK=$(get_disk)
  [ "$DISK" ] || err "Could not automatically calculate DISK"
  echo "auto DISK=<$DISK>" >>$ERRLOG
  [ "$VERBOSE" ] && echo "DISK=<$DISK>"
fi

# /dev/hda has partitions named /dev/hda1 /dev/hda2 ...
# /dev/sda has partitions named /dev/sda1 /dev/sda2 ...
# /dev/ida/c0d0 has partitions named /dev/ida/c0d0p1 /dev/ida/c0d0p2 ...
P=""
[ -b ${DISK}p1 ] && P="p"

if [ "$SFDISK" = "auto" ]; then
  [ -b "$DISK" ] || err \
    "If you define SFDISK=auto, please define DISK as auto or <block-device>"
  MEMS=`free | grep Mem | awk '{print $2}'`
  SWAPS=$(expr 2 \* $MEMS / 1024)
  SFDISK="
,$BOOTS
,$SWAPS,S
;
"
  echo "auto SFDISK=<$SFDISK>" >>$ERRLOG
  [ "$VERBOSE" ] && echo "SFDISK=<$SFDISK>"
fi

if [ "$EXT2FS" = "auto" ]; then
  [ -b "$DISK" ] || err "If you define EXT2FS=auto, please define DISK as auto or <block-device>"
  EXT2FS="DISK1 DISK3"
  echo "auto EXT2FS=<$EXT2FS>" >>$ERRLOG
  [ "$VERBOSE" ] && echo "EXT2FS=<$EXT2FS>"
fi
EXT2FS=$(disk2real "$EXT2FS")

check_ext3

if [ "$SWAP" = "auto" ]; then
  [ -b "$DISK" ] || err "If you define SWAP=auto, please define DISK as auto or <block-device>"
  SWAP="DISK2"
  echo "auto SWAP=<$SWAP>" >>$ERRLOG
  [ "$VERBOSE" ] && echo "SWAP=<$SWAP>"
fi
SWAP=$(disk2real "$SWAP")

if [ "$MOUNT" = "auto" ]; then
  [ -b "$DISK" ] || err "If you define MOUNT=auto, please define DISK as auto or <block-device>"
  MOUNT="mount DISK3 /mnt; mkdir /mnt/boot; mount DISK1 /mnt/boot"
  echo "auto MOUNT=<$MOUNT>" >>$ERRLOG
  [ "$VERBOSE" ] && echo "MOUNT=<$MOUNT>"
fi
MOUNT=$(disk2real "$MOUNT")

if [ "$UMOUNT" = "auto" ]; then
  [ -b "$DISK" ] || err "If you define UMOUNT=auto, please define DISK as auto or <block-device>"
  UMOUNT="umount /mnt/boot; umount /mnt"
  echo "auto UMOUNT=<$UMOUNT>" >>$ERRLOG
  [ "$VERBOSE" ] && echo "UMOUNT=<$UMOUNT>"
fi

VFAT=$(disk2real "$VFAT")

OPT="ext2"
[ "$EXT3" = "yes" ] && OPT="ext3"
if [ "$FSTAB" = "auto" ]; then
  [ -b "$DISK" ] || err "If you define FSTAB=auto, please define DISK as auto or <block-device>"
  DEVFSMOUNT=""
  [ -c /dev/.devfsd ] && DEVFSMOUNT="none	/dev devfs defaults 0 0"
  FSTAB="
DISK1 /boot $OPT defaults 0 1
DISK2 none  swap sw 0 0
DISK3 /     $OPT defaults,errors=remount-ro 0 1
proc      /proc proc defaults 0 0
$DEVFSMOUNT
"
  echo "auto FSTAB=<$FSTAB>" >>$ERRLOG
  [ "$VERBOSE" ] && echo "FSTAB=<$FSTAB>"
fi

if [ "$LILO" = "auto" ]; then
  [ -b "$DISK" ] || err "If you define LILO=auto, please define DISK as auto or <block-device>"

LILOINITRD=""
[ "$INITRD" ] && LILOINITRD="initrd=$INITRD"

LILO="
boot=DISK
delay=20
vga=0
lba32
read-only

image=/vmlinuz
  label=linux
  root=DISK3
  $LILOINITRD
"
  echo "auto LILO=<$LILO>" >>$ERRLOG
  [ "$VERBOSE" ] && echo LILO="<$LILO>"
fi

echo ""
OPT="EXT2FS"
[ "$EXT3" = "yes" ] && OPT="EXT3FS"
A=""
while [ "$A" != "y" -a "$A" != "n" ]
do
  [ "$DISK" ] && echo "Harddisk $DISK will be erased!!!" | tee -a $ERRLOG
  [ "$SWAP" ] && echo "Partition $SWAP will be newly created as SWAP !!!" | tee -a $ERRLOG
  [ "$EXT2FS" ] && echo "Partition $EXT2FS will be newly created as $OPT !!!" | tee -a $ERRLOG
  [ "$VFAT" ] && echo "Partition $VFAT will be newly created as vfat !!!" | tee -a $ERRLOG
  echo -n "(y/n) " | tee -a $ERRLOG
  if [ "$SCRIPT" ]; then
    A="y"
  else
    read A
  fi
  echo "$A" >> $ERRLOG
done
if [ "$A" = "n" ]; then
  exit 1
fi

trap cleanup 2

if [ "$SFDISK" ]; then
  echo "--- Partitioning Disk $DISK ---" | tee -a $ERRLOG
  stdout "^ $DISK: "
  stdout "^sfdisk: ERROR: sector .* does not have an msdos signature"
  run "echo \"$SFDISK\" | sfdisk -qL -uM $DISK >/dev/null"
fi

for i in $VFAT; do
  echo "--- Building Filesystem $i with mkdosfs ---" | tee -a $ERRLOG
  stdout "^mkdosfs "
  run "mkdosfs $i"
done

OPT=""
[ "$EXT3" = "yes" ] && OPT="-j"
for i in $EXT2FS; do
  echo "--- Building Filesystem $i with mke2fs $OPT ---" | tee -a $ERRLOG
  stdout "^mke2fs "
  run "mke2fs $OPT -q $i"
done

for i in $SWAP; do
  echo "--- making SWAP $i ---" | tee -a $ERRLOG
  stdout "^Setting up swapspace"
  run "mkswap $i"
done

echo "--- mounting DISK ---" | tee -a $ERRLOG
run "$MOUNT"

echo "--- copying CD and RAM ---" | tee -a $ERRLOG
run "find / -mount|grep -v -e '^/var.ro\>' -e '^/var\>'|cpio --quiet -pdum /mnt"
run "cd /var.ro; find . -mount | cpio --quiet -pdum /mnt/var"
run rm /mnt/etc /mnt/tmp /mnt/dev /mnt/home /mnt/root
run rm -r /mnt/etc.ro /mnt/tmp.ro /mnt/dev.ro /mnt/home.ro /mnt/root.ro
run cp -a -x /ram1/etc /ram1/tmp /ram1/dev /ram1/home /ram1/root /mnt
run rm -f /mnt/fastboot /mnt/cdboot.catalog /mnt/cdboot.img /mnt/ram1.cpio.gz /mnt/ram2.cpio.gz
run rm -rf /mnt/rr_moved/ /mnt/isolinux/
run rm /mnt/etc/rcS.d/S12bootcdram.sh \
  /mnt/etc/rcS.d/S13bootcdflop.sh \
  /mnt/usr/bin/bootcd2disk \
  /mnt/usr/bin/bootcdflopcp \
  /mnt/etc/bootcd/bootcd2disk.conf \
  /mnt/etc/bootcd/thisbootcd.conf
run rmdir /mnt/ram1 /mnt/ram2

echo "--- deleting NOT_TO_RAM symlinks ---" 
NOT_TO_RAM_RO=$(find /ram1 /ram2 -xdev -type l | xargs /bin/ls -l | grep -e " -> /etc.ro/" -e " -> /home.ro/" -e " -> /root.ro/" | awk '{ print $(NF) }')
for i in $NOT_TO_RAM_RO; do     # exp: i=/etc.ro/X11
  j=$(echo $i | sed "s/\.ro//") #   => j=/etc/X11
  run rm /mnt/$j                #   => /mnt/etc/X11 -> /etc.ro/X11
  run cp -a $i /mnt/$j
done

# only call the function, if it is defined
doit=$(egrep "^[[:space:]]*(function)*[[:space:]]*after_copy" $CONFDIR/bootcd2disk.conf)
if [ ! -z "$doit" ]; then
  echo "--- do function after_copy ---" | tee -a $ERRLOG
  after_copy
fi

echo "--- Building fstab ---" | tee -a $ERRLOG
run "echo \"$FSTAB\" > /mnt/etc/fstab"
disk2real "$FSTAB" /mnt/etc/fstab

echo "--- Resetting mtab ---" | tee -a $ERRLOG
run "rm -f /mnt/etc/mtab"

if [ "$LILO" ]; then
  echo "--- Building lilo.conf ---" | tee -a $ERRLOG
  run "echo \"$LILO\" > /mnt/etc/lilo.conf"
  disk2real "$LILO" /mnt/etc/lilo.conf
fi

if [ "$ELILO" ]; then
  echo "--- Building elilo.conf ---" | tee -a $ERRLOG
  run "echo \"$ELILO\" > /mnt/etc/elilo.conf"
  disk2real "$ELILO" /mnt/etc/elilo.conf
fi

if [ "$SSHHOSTKEY" = "yes" ]; then
  # each installed PC gets a unique hostkey (only if hostkey already existed)
  create_host_keys /mnt/etc/ssh

elif [ "$SSHHOSTKEY" != "no" ]; then
  warn 'SSHHOSTKEY is not defined as "yes" or "no".' \
       'It will be treated as "no".'
fi

echo "--- Enabling turned off stuff ---" | tee -a $ERRLOG
for f in $DISABLE_CRON; do
  if [ -f /mnt/$f.no_run_on_bootcd ]; then 
    run rm /mnt/$f
    run mv /mnt/$f.no_run_on_bootcd /mnt/$f
  fi
done

if [ "$LILO" ]; then
  echo "--- Running lilo ---" | tee -a $ERRLOG
  run "chroot /mnt mount /proc"
  stdout "^Added "
  run "chroot /mnt lilo -w"
  run "chroot /mnt umount /proc"
fi

if [ "$ELILO" ]; then
  echo "--- Running elilo ---" | tee -a $ERRLOG
  run "chroot /mnt elilo"
fi

echo "--- unmounting DISK ---" | tee -a $ERRLOG
run cp $ERRLOG /mnt/var/log
run "$UMOUNT"

echo "Please Reboot now !" | tee -a $ERRLOG
