#!/bin/bash
#
# Make a bochs-disk bootable.
# 
# $Author: bablokb $
# $Revision: 1.12 $
#
# License: GPL2
# -----------------------------------------------------------------------------

. `dirname $0`/bxtfuncs.inc

# usage message   -------------------------------------------------------------

usage() {
  echo -e "\n`basename $0`: make a bochs-hd-image bootable with lilo\n\
  \nusage: `basename $0` [options] image-name\n\
  possible options:\n\
    -V       show version\n\
    -h       show this help\n\
    -q       run quiet (default)\n\
    -v       verbose messages\n\
    -s       only simulate\n\
    -r root  root-partition (default: autodetected)\n\
    -b boot  boot-partition (default: autodetected)\n\
    -k path  path to kernel, relative to partition-root\n\
"
  exit 3
}

# set system defaults   -------------------------------------------------------

setDefaults() {
  quiet=1; simulate=0; debug=0
  [ -z "$EDITOR" ] && EDITOR=vi
}

# parse arguments and set variables -------------------------------------------

parseArguments() {

  while getopts ":r:b:k:Vhqvsd" opt; do
    case $opt in
      r) rootPartition=$OPTARG;;
      b) bootPartition=$OPTARG;;
      k) kernelPath=$OPTARG;;
      V) showCopyright `basename $0` " make a bochs-hd-image bootable with lilo";;
      h) usage;;
      q) quiet=1;;
      v) quiet=0;;
      s) simulate=1;;
      d) debug=1;;
      ?) echo "illegal option: $OPTARG" >&2
           usage;;
    esac
  done
  if [ $# -eq $OPTIND ]; then
    imageName=${!OPTIND}
  elif [ $# -gt $OPTIND ]; then
    echo "error: illegal argument ${!#}"
    usage
  else
    echo "error: missing argument image-name"
    usage
  fi
}

# check arguments   -----------------------------------------------------------

checkArguments() {
  if [ ! -f $imageName ]; then
    echo "error: image $imageName does not exist!" >&2
    exit 1
  fi
}

# check for linux boot-partition ----------------------------------------------

checkLinux() {

  # check explicit imagePath

  if [ -n "$kernelPath" ]; then
    if [ -f $mountPathBoot/$kernelPath ]; then
      imagePath=$kernelPath
      return 0
    else
      return 1
    fi
  fi

  # search boot-directory for kernel

  if [ ! -d $mountPathBoot/boot ]; then
    return 1
  fi
  pushd $mountPathBoot/boot > /dev/null
  for f in *; do
    if file -k $f | grep -qi "Linux.*Kernel"; then
      [ $debug -eq 1 ] && echo "found kernel: $f" >&2
      kernelPath=/boot/$f
      imagePath=boot/$f
      popd > /dev/null
      return 0
    fi
  done
  popd > /dev/null
  return 1
}

# check for other boot-partition ----------------------------------------------

checkOther() {
  if [ -f $mountPathBoot/io.sys ]; then
    if [ `find $mountPathBoot -type d -maxdepth 1 -name "dos*" | 
                                          wc -l | sed -e's/ //g'` -gt 0 ]; then
      otherType="DOS"
    elif  [ `find $mountPathBoot -type d -maxdepth 1 -name "win*" |
                                          wc -l | sed -e's/ //g'` -gt 0 ]; then
      otherType="Windows"
    else
      otherType="Unknown"
    fi
  elif [ -f $mountPathBoot/kernel.sys ]; then
      otherType="FreeDOS"
  fi
  if [ -z "$otherType" ]; then
    return 1
  else
    return 0
  fi
}

# scan Partitions -------------------------------------------------------------
#
# search for (first) linux partition and legacy partitions

scanPartitions() {
  if [ -n "$bootPartition" ]; then
    partitionNumbers="$bootPartition"
  else
    partitionNumbers="1 2 3 4"
  fi
  createMountPoint mountPathBoot || cleanupAndExit 1 
  for i in $partitionNumbers; do
    do_cmd "umount $mountPathBoot 1>/dev/null 2>&1"
    doMount $imageName:$i $mountPathBoot || break
    if checkLinux; then
      linuxPartition=$i;
      break;
    elif [ -z "$otherPartition" ]; then
      checkOther && otherPartition=$i
    fi
  done
  doUmount $mountPathBoot
  mountPathBoot=""
  if [ -z "$linuxPartition" -a -n "$kernelPath" ]; then
    echo "error: could not find $kernelPath on any partition" >&2
    exit 1
  fi
  if [ -z "$linuxPartition" -a -z "$otherPartition" ]; then
    echo "error: could not find neither linux nor legacy-partition" >&2
    exit 1
  fi
}

# setup loop-devices ----------------------------------------------------------

setupLoops() {
 if ! loopDevice=`getLoopDevice`; then
   echo "error: no free loop-device" >&2
   cleanupAndExit 1
 fi
 if ! do_cmd "losetup $loopDevice $imageName"; then
   echo "error: could not setup loop-device for image" >&2
   cleanupAndExit 1
 fi

 if [ -n "$linuxPartition" ]; then
   createMountPoint mountPathLinux || cleanupAndExit 1
   doMount $imageName:$linuxPartition $mountPathLinux || cleanupAndExit 1
   loopDeviceLinux=`mount | grep $mountPathLinux | sed -e 's/.*loop=\([^,]*\),.*/\1/'`
   [ $debug -eq 1 ] && echo "loopDeviceLinux=$loopDeviceLinux" >&2
   mountPathBoot=$mountPathLinux
  let linuxPartitionStart=`bxtptinfo -p $linuxPartition $imageName`
  let linuxPartitionStart/=512
 fi
 if [ -n "$otherPartition" ]; then
   createMountPoint mountPathOther || cleanupAndExit 1
   doMount $imageName:$otherPartition $mountPathOther || cleanupAndExit 1
   loopDeviceOther=`mount | grep $mountPathOther | sed -e 's/.*loop=\([^,]*\),.*/\1/'`
   [ $debug -eq 1 ] && echo "loopDeviceOther=$loopDeviceOther" >&2
   [ -z "$mountPathBoot" ] && mountPathBoot=$mountPathOther
  let otherPartitionStart=`bxtptinfo -p $otherPartition $imageName`
  let otherPartitionStart/=512
 fi
}

# createLiloMsg ---------------------------------------------------------------

createLiloMsg() {
  createTempFile liloMsgFile || cleanupAndExit 1
  [ -n "$linuxPartition" ] &&
                       linuxLine="/dev/hda$linuxPartition: linux ($kernelPath)"
  [ -n "$otherPartition" ] &&
                       otherLine="/dev/hda$otherPartition: other ($otherType)"

  cat > $liloMsgFile <<EOF
This boot-configuration was created by bxtlilo version $version

Available Operating-Systems:

$linuxLine
$otherLine

EOF
  [ $debug -eq 1 ] && $EDITOR $liloMsgFile
}

# createLiloConf --------------------------------------------------------------

createLiloConf() {
  createTempFile liloConfFile || cleanupAndExit 1
  [ -z "$rootPartition" ] && rootPartition=$linuxPartition

  if lilo -X | grep -q LCF_BUILTIN 1>/dev/null 2>&1; then
    installFile=menu
  elif [ -f /boot/boot-menu.b ]; then
    installFile=/boot/boot-menu.b
  elif [ -f /boot/boot.b ]; then
    installFile=/boot/boot.b
  else
   echo "error: could not find lilo support file boot-menu.b or boot.b" >&2
   cleanupAndExit 1
  fi
  do_cmd "mkdir -p $mountPathBoot/boot"

  cat > $liloConfFile <<EOF
boot       = $loopDevice
backup     = /dev/null
map        = $mountPathBoot/boot/map
install    = $installFile
menu-title = "The Bochs-Emulator: $imageName"
message    = $liloMsgFile

lba32
read-only
prompt
timeout=100
vga = normal

disk=$loopDevice
  bios=0x80
  sectors=$spt
  heads=$heads
EOF

 if [ -n "$linuxPartition" ]; then
   cat >>  $liloConfFile <<EOF
  partition=$loopDeviceLinux
    start=$linuxPartitionStart
EOF
 fi
  
 if [ -n "$otherPartition" ]; then
   cat >>  $liloConfFile <<EOF
  partition=$loopDeviceOther
    start=$otherPartitionStart
EOF
 fi

  cat >>  $liloConfFile <<EOF

# End LILO global section

EOF

  if [ -n "$linuxPartition" ]; then
    cat >>  $liloConfFile <<EOF
image = $mountPathLinux/$imagePath
  label = linux
  root=/dev/hda$rootPartition
#
EOF
  fi

  if [ -n "$otherPartition" ]; then
    cat >>  $liloConfFile <<EOF

other = $loopDeviceOther
  table = $loopDevice
  label = other
#
EOF
  fi

  [ $debug -eq 1 ] && $EDITOR $liloConfFile
}

# cleanup and exit script   ---------------------------------------------------

cleanupAndExit() {
  [ -n "$mountPathLinux" -a -d "$mountPathLinux" ] && doUmount $mountPathLinux 
  [ -n "$mountPathOther" -a -d "$mountPathOther" ] && doUmount $mountPathOther 
  [ -n "$loopDevice" ] && do_cmd "losetup -d $loopDevice"
  if [ $debug -eq 0 ]; then
    [ -n "$liloMsgFile" -a -f "$liloMsgFile" ] && do_cmd  "rm -f $liloMsgFile"
    [ -n "$liloConfFile" -a -f "$liloConfFile" ] && do_cmd  "rm -f $liloConfFile"
  fi
  exit $1
}

# main program   --------------------------------------------------------------

setDefaults
parseArguments "$@"
checkArguments
setGeometry $imageName
scanPartitions
setupLoops
createLiloMsg
createLiloConf
do_cmd "lilo -v -C $liloConfFile"
cleanupAndExit 0
