#!/bin/bash
#
# Create a partitioned bochs-disk.
# 
# $Author: bablokb $
# $Revision: 1.17 $
#
# License: GPL2
# -----------------------------------------------------------------------------

. `dirname $0`/bxtfuncs.inc

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

usage() {
  echo -e "\n`basename $0`: create a partitioned bochs-hd-image\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\
    -o       overwrite existing file\n\
    -H heads number of heads (default: 16)\n\
    -S spt   number of sectors-per track (default: 63)\n\
    -1 size  create partition 1 with given size\n\
    -2 size  create partition 2 with given size\n\
    -3 size  create partition 3 with given size\n\
    -4 size  create partition 4 with given size\n\
    -t size  create image with total given total size\n\
"
  exit 3
}

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

setDefaults() {
  imageName=hda.img
  quiet=1; simulate=0; overwrite=0; debug=0
  hda1Blocks=0; hda2Blocks=0; hda3Blocks=0; hda4Blocks=0
  sizeLimit=-1; maxCyl=65535
}

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

parseArguments() {

  while getopts ":H:S:1:2:3:4:t:Vhqvsdo" opt; do
    case $opt in
      1) hda1Blocks=`getSize $OPTARG`;;
      2) hda2Blocks=`getSize $OPTARG`;;
      3) hda3Blocks=`getSize $OPTARG`;;
      4) hda4Blocks=`getSize $OPTARG`;;
      t) sizeLimit=`getSize $OPTARG`;;
      H) heads=$OPTARG;;
      S) spt=$OPTARG;;
      V) showCopyright `basename $0` "create a partitioned bochs-hd-image";;
      h) usage;;
      q) quiet=1;;
      v) quiet=0;;
      s) simulate=1;;
      d) debug=1;;
      o) overwrite=1;;
      ?) echo "illegal option: $OPTARG" >&2
           usage;;
    esac
  done
  if [ $# -eq $OPTIND ]; then
    imageName=${!OPTIND}
  fi
  if [ $# -gt $OPTIND ]; then
    echo "illegal argument ${!#}" >&2
    usage
  fi
}

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

checkArguments() {
  if [ -f $imageName -a ! $overwrite -eq 1 ]; then
    echo "error: image $imageName exists. Use option -o to overwrite existing image" >&2
    exit 3
  fi
  if [ $sizeLimit -gt `getSize 2g` ]; then
    echo "error: requested size $sizeLimit blocks is too large" >&2
    exit 3
  fi
}

# calculate partition sizes   -------------------------------------------------

calcSizes() {
  if [ $sizeLimit -ne -1 ]; then
    let maxCyl=sizeLimit/blocksPerCyl
    if [[ sizeLimit%blocksPerCyl -ne 0 ]]; then
      let maxCyl+=1
    fi
  fi
  if [ $maxCyl -lt 1 ]; then
    echo "error: requested size limit $sizeLimit blocks results in image with 0 cylinders" >&2
    exit 3
  fi

  let totalCyl=1

  if [ $hda1Blocks -eq 0 ]; then
    [ $sizeLimit -ne -1 ] && let totalCyl=maxCyl
    return
  fi
  let hda1Cyl=hda1Blocks/blocksPerCyl
  if [[ hda1Blocks%blocksPerCyl -ne 0 ]]; then
    let hda1Cyl+=1
  fi
  if [[ totalCyl+hda1Cyl -gt maxCyl ]]; then
    let hda1Cyl=maxCyl-totalCyl
    let hda2Blocks=0
  fi
  let totalCyl+=hda1Cyl
  let hda1Sectors=hda1Cyl*sectPerCyl
  let hda1SectOffset=sectPerCyl

  if [ $hda2Blocks -eq 0 ]; then
    [ $sizeLimit -ne -1 ] && let totalCyl=maxCyl
    return
  fi
  let hda2Cyl=hda2Blocks/blocksPerCyl
  if [[ hda2Blocks%blocksPerCyl -ne 0 ]]; then
    let hda2Cyl+=1
  fi
  if [[ totalCyl+hda2Cyl -gt maxCyl ]]; then
    let hda2Cyl=maxCyl-totalCyl
    let hda3Blocks=0
  fi
  let totalCyl+=hda2Cyl
  let hda2Sectors=hda2Cyl*sectPerCyl
  let hda2SectOffset=hda1SectOffset+hda1Sectors

  if [ $hda3Blocks -eq 0 ]; then
    [ $sizeLimit -ne -1 ] && let totalCyl=maxCyl
    return
  fi
  let hda3Cyl=hda3Blocks/blocksPerCyl
  if [[ hda3Blocks%blocksPerCyl -ne 0 ]]; then
    let hda3Cyl+=1
  fi
  if [[ totalCyl+hda3Cyl -gt maxCyl ]]; then
    let hda3Cyl=maxCyl-totalCyl
    let hda4Blocks=0
  fi
  let totalCyl+=hda3Cyl
  let hda3Sectors=hda3Cyl*sectPerCyl
  let hda3SectOffset=hda2SectOffset+hda2Sectors

  if [ $hda4Blocks -eq 0 ]; then
    [ $sizeLimit -ne -1 ] && let totalCyl=maxCyl
    return
  fi
  let hda4Cyl=hda4Blocks/blocksPerCyl
  if [[ hda4Blocks%blocksPerCyl -ne 0 ]]; then
    let hda4Cyl+=1
  fi
  if [[ totalCyl+hda4Cyl -gt maxCyl ]]; then
    let hda4Cyl=maxCyl-totalCyl
  fi
  let totalCyl+=hda4Cyl
  let hda4Sectors=hda4Cyl*sectPerCyl
  let hda4SectOffset=hda3SectOffset+hda3Sectors
  [ $sizeLimit -ne -1 ] && let totalCyl=maxCyl
}


# show partition sizes   ------------------------------------------------------

showSizes() {
  if [ $debug -eq 1 ]; then
    echo -e "hda1: blocks=$hda1Blocks, sectors=$hda1Sectors, cyl=$hda1Cyl" >&2
    echo -e "hda2: blocks=$hda2Blocks, sectors=$hda2Sectors, cyl=$hda2Cyl" >&2
    echo -e "hda3: blocks=$hda3Blocks, sectors=$hda3Sectors, cyl=$hda3Cyl" >&2
    echo -e "hda4: blocks=$hda4Blocks, sectors=$hda4Sectors, cyl=$hda4Cyl" >&2
    echo -e "total cylinders: $totalCyl" >&2
  fi
}

# create bochs disk-image -- --------------------------------------------------

createDisk() {
  if [ $totalCyl -eq 1 ]; then
    echo "warning: number of cylinders is 1! Check arguments!" >&2
  fi
  if [ $quiet -eq 0 ]; then
    let totalSize=totalCyl*bytesPerCyl/1024/1024
    echo "total size is: ${totalSize} MB"
  fi
  if ! do_cmd "dd if=/dev/zero of=$imageName count=$totalCyl bs=$bytesPerCyl 2>/dev/null";
    then
      echo "error: creation of disk-image $imageName failed!" >&2
      exit 1
  fi
}

# create partition table   ----------------------------------------------------

createTable() {
  createTempFile sfdiskInput || exit 1
  if [ $hda1Blocks -gt 0 ]; then
     cat > $sfdiskInput <<EOF
# partition table of $imageName
unit: sectors

${imageName}1 : start=$hda1SectOffset, size=$hda1Sectors, Id=83
EOF
  fi

  if [ $hda2Blocks -eq 0 ]; then
    return
  fi
  cat >> $sfdiskInput <<EOF
${imageName}2 : start=$hda2SectOffset, size=$hda2Sectors, Id=82
EOF
  if [ $hda3Blocks -eq 0 ]; then
    return
  fi
  cat >> $sfdiskInput <<EOF
${imageName}3 : start=$hda3SectOffset, size=$hda3Sectors, Id=83
EOF
  if [ $hda4Blocks -eq 0 ]; then
    return
  fi
  cat >> $sfdiskInput <<EOF
${imageName}4 : start=$hda4SectOffset, size=$hda4Sectors, Id=83
EOF
}

# show partition table   ------------------------------------------------------

showTable() {
  if [ $debug -eq 1 ]; then
    echo "sfdisk input file:" >&2
    cat $sfdiskInput >&2
  fi
}

# partition disk-image   ------------------------------------------------------

partitionDisk() {
  [ $hda1Blocks -eq 0 ] && return
  createTable
  showTable
  if ! do_cmd "sfdisk -q -L -C $totalCyl -H $heads -S $spt $imageName < $sfdiskInput > /dev/null 2>/dev/null";
    then
      echo "error: partitioning of disk-image $imageName failed!" >&2
      rm -f $sfdiskInput
      exit 1
  fi
  rm -f $sfdiskInput
}

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

setDefaults
parseArguments "$@"
checkSfdisk
checkArguments
setGeometry
calcSizes
showSizes
createDisk
partitionDisk
exit 0