#!/bin/bash
# Filename:      grml2iso
# Purpose:       create a multiboot grml ISO using grml2usb
# Authors:       Michael Prokop <mika@grml.org>,
#                Thorsten Glaser <tg@mirbsd.org>
# Bug-Reports:   see http://grml.org/bugs/
# License:       This file is licensed under the GPL v2 or any later version.
################################################################################
# TODO:
# * support isolinux as bootloader on the ISO
# * support setting grml2usb options (e.g. --bootoptions=...)
################################################################################

# define function getfilesize before "set -e" {{{
  if stat --help >/dev/null 2>&1; then
    getfilesize='stat -c %s'        # GNU stat
  else
    getfilesize='stat -f %z'        # BSD stat
  fi
# }}}

# adjust variables if necessary through environment {{{
# path to the grml2usb script you'd like to use
  [ -n "$GRML2USB" ] || GRML2USB='grml2usb'
# work directory for creating the filesystem
  [ -n "$WRKDIR" ]   || WRKDIR='/tmp/grml2iso.tmp'
# }}}

# helper stuff {{{
  set -e

  usage() {
    echo >&2 "Usage: $0 -o target.iso source1.iso [source2.iso ...]"
    [ -n "$1" ] && exit $1 || exit 1
  }
# }}}

# command line handling {{{
  [[ $# -gt 2 ]] || usage 1

  ISOFILE=''
  while getopts ao: name; do
    case $name in
      o)   ISOFILE="$OPTARG";;
      ?)   usage 2;;
    esac
  done

# make sure -o is specified
  [ -n "$ISOFILE" ] || usage 1

# we don't to override any files by accident
  if [ -e "$ISOFILE" ]; then
    echo "Error: target file $ISOFILE exists already." >&2
    exit 1
  fi

  shift $(($OPTIND - 1))
# }}}

# we need root permissions for executing grml2usb {{{
  if [[ $(id -u) != 0 ]]; then
    echo >&2 "Error: please run $0 as root."
    exit 1
  fi
# }}}

# variables {{{
  ORIG_DIR="$(pwd)"
  # note: grub-pc_1.96+20090603-1 seems to be b0rken
  GRUB_VERSION="grub-pc_1.96+20080724-16"

# normalise path
  case $ISOFILE in
    /*) ;;
    *) ISOFILE=$ORIG_DIR/$ISOFILE ;;
  esac
# }}}

# create necessary stuff under WRKDIR {{{
  [ -d "$WRKDIR" ] && WRKDIR_EXISTED='true' || WRKDIR_EXISTED='false'
  rm -rf "$WRKDIR/cddir" "$WRKDIR/grub_tmp"
  mkdir -p "$WRKDIR/cddir" "$WRKDIR/grub_tmp"
# }}}}

# execute grml2usb with all ISOs you'd like to install {{{
  $GRML2USB "$@" "$WRKDIR/cddir"
# }}}

# install grub2 files {{{
# as we don't want to rely on a grub2 installation on the
# running system let's grab it from the net
  if which dpkg >/dev/null 2>&1 ; then
     ARCH="$(dpkg --print-architecture)"
  else
    [[ $(uname -m) == x86_64 ]] && ARCH=amd64 || ARCH=i386
  fi
  GRUB_DEB="${GRUB_VERSION}_${ARCH}.deb"

  cd "$WRKDIR"/grub_tmp/
  wget http://ftp.de.debian.org/debian/pool/main/g/grub2/"$GRUB_DEB"
  ar x "$GRUB_DEB"
  tar xzf data.tar.gz
  ./usr/bin/grub-mkimage -d usr/lib/grub/i386-pc \
    -o "$WRKDIR"/cddir/boot/grub/core.img biosdisk iso9660

  for a in usr/lib/grub/i386-pc/{*.mod,efiemu??.o,command.lst,moddep.lst,fs.lst,handler.lst,parttool.lst}; do
    test -e $a && cp $a "$WRKDIR"/cddir/boot/grub/
  done

  cat usr/lib/grub/i386-pc/cdboot.img "$WRKDIR"/cddir/boot/grub/core.img \
    > "$WRKDIR"/cddir/boot/grub/eltorito.img
  cd "$WRKDIR/cddir"
# }}}

# generate the CD/DVD ISO {{{
  mkisofs -V 'grml-multiboot' -l -r -J -no-pad \
    -no-emul-boot -boot-load-size 4 -boot-info-table \
    -b boot/grub/eltorito.img -c boot/grub/eltorito.cat \
    -o "$ISOFILE" .
# }}}

# pad the output ISO to multiples of 256 KiB for partition table support {{{
  siz=$($getfilesize "$ISOFILE")
  cyls=$(echo "$siz / 512 / 32 / 16 + 1" | bc)  # C=$cyls H=16 S=32
  ofs=$(echo "$cyls * 16 * 32 * 512 - 1" | bc)  # padding offset (size - 1)
  dd if=/dev/zero bs=1 count=1 seek=$ofs of="$ISOFILE" 2>/dev/null
# }}}

# create a manifold-boot image with a partition table, if possible {{{
  if mksh -c true 2>/dev/null && \
    test -e /usr/share/grml-live/scripts/bootgrub.mksh; then
      echo "Creating a manifold-boot ISO image"
      echo 1 63 | \
        mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 1 -p 0x83 -g $cyls:16:32 | \
        cat - boot/grub/core.img | \
        dd conv=notrunc of="$ISOFILE" conv=notrunc 2>/dev/null
  else
      echo "Cannot find mksh or bootgrub.mksh, not generating manifold-boot ISO image"
  fi
# }}}

# cleanup {{{
  cd "$ORIG_DIR"
  sync
  rm -rf "$WRKDIR/cddir" "$WRKDIR/grub_tmp"
  [[ $WRKDIR_EXISTED = 'false' ]] && rmdir "$WRKDIR"
  echo "Generated $ISOFILE"
# }}}

## EOF #########################################################################
# vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3
