#!/bin/sh

# This script creates a ramdisk containing XenServer install sources
# from the customer/service partition. There are two modes of operation:
#
# 1. Original Bodie mode - the contents of the entire device are copied
#    to the ramdisk in a recursive file copy.
#
# 2. ISO mode - if the filesystem on the device contains a top level
#    directory named "xsinst" then the ramdisk will be populated with
#    the unpacked contents of any *.iso file in xsinst as well as
#    a recursize copy of any other files/directories in xsinst. A non-ISO
#    file/dir in xsinst gets copied to the top level of the filesystem in
#    the ramdisk. Typically xsinst will contain a XenServer main.iso,
#    zero or more supplemental pack ISOs, an answerfile generator and
#    a post install script. When using this mode with FATx filesystems it
#    is recommended to use 8.3 naming of the files in xsinst (note that
#    the ISOs themselves are unpacked to the tmpfs ramdisk so can have
#    long filenames). You can override "xsinst" with installer param
#    xsinst=path

start()
{
  ret=0
  xsinst="xsinst"
  for arg in `cat /proc/cmdline | sed -e 's/ $//; y/ /\n/'`; do
    case "$arg" in
      xsinst=*)
        xsinst=${arg#xsinst=}
        ;;
      make-ramdisk=*)
        src=${arg#make-ramdisk=}
        [ -d /tmp/ramdisk ] && continue
        copied=0
        errors=0
        echo -n "Copying installation image from $src to ramdisk..."

        # hang around a while for USB devices to settle
        for n in `seq 1 5`; do
          [ -b $src ] && break
          sleep 5
        done
        if ! [ -b $src ]; then
            echo " failed"
            continue
        fi

        # mount the source
        mkdir /tmp/src
        for fs in iso9660 vfat ext3; do
          mount -t $fs -o ro $src /tmp/src 2>/dev/null && break
        done
        if grep -q ' /tmp/src ' /proc/mounts; then 

          # create appropriately sized ramdisk and populate
          if [ -d /tmp/src/$xsinst ]; then
            # ISO mode, assume the ISOs unpack to less than 110% of the
            # ISO size. We'll also add 1000k headroom later.
            fssize=`du -ks /tmp/src/$xsinst | awk '{print $1}'`
          else
            # Original mode
            fssize=`df -k /tmp/src | sed -ne 's#^/[^ ]\+ \+[0-9]\+ \+\([0-9]\+\).*#\1#p'`
          fi
          mkdir /tmp/ramdisk
          shopt -s dotglob
          mount -t tmpfs -o size=$((fssize * 11/10 + 2000))k tmpfs /tmp/ramdisk
          if [ -d /tmp/src/$xsinst ]; then
            # ISO mode. Iterate through ISOs in the $xsinst directory
            # unpacking each one to the ramdisk
            for isofile in /tmp/src/$xsinst/*.iso; do
              if [ -f $isofile ]; then
                basedir=$(basename $isofile .iso)
                mkdir -p /tmp/srciso
                mount -oloop,ro -t iso9660 $isofile /tmp/srciso
                if grep -q ' /tmp/srciso ' /proc/mounts; then
                  if [ -f /tmp/srciso/.treeinfo ]; then
                    # This is the main product ISO
                    if ! cp -a /tmp/srciso/* /tmp/ramdisk; then
                      errors=$(($errors + 1))
                    fi
                  else
                    # an update ISO
                    mkdir -p /tmp/ramdisk/$basedir
                    if ! cp -a /tmp/srciso/* /tmp/ramdisk/$basedir; then
                      errors=$(($errors + 1))
                    fi
                  fi
                  umount /tmp/srciso
                fi
              fi
            done
            # Copy any remaining files/dirs recursively (these may be
            # answerfile or hook scripts)
            for f in /tmp/src/$xsinst/*; do
              if [ $f = "/tmp/src/$xsinst/factory.tar" ]; then
                continue
              fi
              if [ ${f: -4} = ".iso" ]; then
                continue
              fi
              if ! cp -a $f /tmp/ramdisk; then
                errors=$(($errors + 1))
              fi
            done
            if [ $errors -eq 0 ]; then
              copied=1
            fi
          else
            # Original recursive copy mode
            if cp -a /tmp/src/* /tmp/ramdisk; then
              copied=1
            fi
          fi
          if [ $copied -eq 1 ] ; then
            echo " done"
          else
            umount /tmp/ramdisk
            rmdir /tmp/ramdisk
          fi
          umount /tmp/src
        fi
        rmdir /tmp/src
        if [ $copied -eq 0 ]; then
          echo " failed"
          ret=1
        fi;;
    esac
  done
  return $ret
}

stop()
{
  grep -q ' /tmp/ramdisk ' && umount /tmp/ramdisk
  return 0
}


RET=0
case "$1" in
  start)
    start
    RET=$?;;
  stop)
    stop
    RET=$?;;
  *)
    echo "Usage: $0 start|stop"
    RET=1
esac

exit $RET
