#!/bin/sh
# Filename:      grml2usb
# Purpose:       install grml-system to usb-device
# Authors:       grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
# Bug-Reports:   see http://grml.org/bugs/
# License:       This file is licensed under the GPL v2.
# Latest change: Sun May 25 01:37:43 CEST 2008 [mika]
################################################################################

# colors {{{
  CRE="
[K"
  NORMAL="[0;39m"
  RED="[1;31m"
  GREEN="[1;32m"
  YELLOW="[1;33m"
  BLUE="[1;34m"
  MAGENTA="[1;35m"
  CYAN="[1;36m"
  WHITE="[1;37m"
# }}}

# usercheck {{{
  if ! [ -x "$(which syslinux)" ] ; then
    echo "${RED}Error: syslinux is not available. Please install it before running this script.${NORMAL}" >&2; exit 2
  fi

  if [ "$(id -u)" != 0 ];  then
    echo "${RED}Error: please run this script with uid 0 (root).${NORMAL}" >&2 ; exit 1
  fi
# }}}

# set variables  {{{
  if [ -n "$DEBUG" ]; then
    # set -x
    debugit(){
      echo $*
    }
  else
    debugit(){
      echo >/dev/null
    }
  fi

  if [ "$1" = "uninstall" ] ; then
     UNINSTALL=1
  fi

  LANG='C'
  LANGUAGE='C'
  LC_ALL='C'
  PROGRAMNAME=${0##*/}
  VERSION='0.9.1'
  ISO="$1"
  DEVICE="$2"

  [ -n "$TMPMNT" ] || TMPMNT='/mnt/test/'
  [ -d "$TMPMNT" ] || mkdir -p $TMPMNT
# }}}

# helper functions {{{
bailout(){
  echo
  echo "Exiting - umounting /mnt/test and $DEVICE"
  umount $TMPMNT 2>/dev/null
  umount $DEVICE 2>/dev/null
  exit 2
}

usage()
{
  echo 1>&2 "$PROGRAMNAME $VERSION - install grml-system to usb-device

This program installs a grml-iso to an usb-device to be able to boot
from usb. Make sure you have a grml-iso, syslinux (just run
'apt-get install syslinux' on Debian-based systems) and root access.

Usage:
  $PROGRAMNAME grml.iso /mount/point

  Notice: /mount/point is the mountpoint set up for your USB device in /etc/fstab
          /mount/point should not be mounted at the time running $PROGRAMNAME

Usage example - install grml-small to usb-device on /mnt/usb-sdb1:
  $PROGRAMNAME grml_1.1.iso /mnt/usb-sdb1

Usage example - install currently running grml to usb-device on /mnt/usb-sdb1:
  $PROGRAMNAME /live/image /mnt/usb-sdb1

Usage example - delete grml-installation from /mnt/usb-sdb1:
  $PROGRAMNAME uninstall /mnt/usb-sdb1

For more information take a look at http://wiki.grml.org/doku.php?id=usb
Report bugs, send wishes and feedback to the grml team:
http://grml.org/bugs/ - contact (at) grml.org
"
}

notice(){
  echo "
Installing grml to $DEVICE should have been successful!

Please take a look at http://wiki.grml.org/doku.php?id=usb
for more information or if you have problems with booting from usb."
}

info(){
  echo "$PROGRAMNAME ${VERSION} - install grml-system to usb-device"
  echo
}

vfat_warning(){
  DEV=$(echo ${DEVICE%/})
  TMPDEV=$(grep "[[:space:]]${DEV}[[:space:]]" /etc/fstab | grep -vh '^[[:space:]]*#' | awk '{print $1}')
  SYSDEV=$(echo ${TMPDEV%/})
  if [ -x /lib/udev/vol_id ] ; then
     /lib/udev/vol_id $SYSDEV | grep -q 'FS_TYPE=vfat' || VFAT=1
     /lib/udev/vol_id $SYSDEV | grep -q 'ID_FS_VERSION=FAT16' || VFAT=1
  else
     VFAT=1
  fi
  if [ -n "$VFAT" ] ; then
     echo 'WARNING: make sure that your usb-device is preformated with vfat.'
     echo "Format your device (erases all data) via:  mkfs.vfat -F 16 -v $SYSDEV"
     echo
  fi
}

mount_device(){
  if grep -q ${DEVICE} /proc/mounts ; then
    echo "Notice: ${WHITE}${DEVICE} already mounted - continuing anyway${NORMAL}" >&2
  else
    echo -n "Mounting ${DEVICE}: "
    debugit "debug: mount $DEVICE"
    mount $DEVICE && echo "${WHITE}done${NORMAL}" || bailout
  fi
}

mount_iso(){
  echo -n "Mounting ${ISO} to ${TMPMNT}: "
  local mount_opts_="-o loop"
  if [ -d $ISO ]; then
      mount_opts_="--bind"
  elif [ -b $ISO ]; then
      mount_opts_=""
  fi
  debugit "debug: mount $mount_opts_ ${ISO} ${TMPMNT}"
  if mount $mount_opts_ "${ISO}" ${TMPMNT} ; then
     echo "${WHITE}done${NORMAL}"
  else
     echo "${RED}Problem? You got an error saying 'mount: could not find any free loop device'?
Possible solution: losetup -d /dev/loop/0${NORMAL}" >&2
    exit 3
  fi
}

unmount(){
  echo -n "Unmounting ${DEVICE} and ${TMPMNT}: "
  umount ${TMPMNT}
  umount ${DEVICE} && echo "done" || echo "failed"
}

copyit(){
  echo -n "Installing data from ${ISO} to ${DEVICE} (will take some time): "
  debugit "debug: cp -dR --preserve=mode,timestamps ${TMPMNT}/* ${DEVICE}"
  debugit "debug: mv ${DEVICE}/boot/isolinux/* ${DEVICE}/"

  if cp -dR --preserve=mode,timestamps ${TMPMNT}/* ${DEVICE} ; then
    echo "# filelist of $PROGRAMNAME on $(date) using $ISO on ${DEVICE}:" > $DEVICE/grml2usb.filelist

    find  ${TMPMNT} -type f | sed "s#${TMPMNT}##" | \
          sed "s#boot/## ; s#isolinux/## ; s#.*initrd.gz#initrd.gz# ; s#.*linux26#linux26#" | \
          tr A-Z a-z >> $DEVICE/grml2usb.filelist

    # make sure we have a valid syslinux.cfg, if not use isolinux.cfg as base
    if ! [ -f "${DEVICE}"/boot/isolinux/syslinux.cfg ] ; then
       cp ${DEVICE}/boot/isolinux/isolinux.cfg ${DEVICE}/boot/isolinux/syslinux.cfg && \
       echo 'syslinux.cfg' >> $DEVICE/grml2usb.filelist
    fi

    if mv ${DEVICE}/boot/isolinux/* ${DEVICE}/ ; then
       rmdir ${DEVICE}/boot/isolinux
    fi
    echo boot >> $DEVICE/grml2usb.filelist

    # syslinux creates a file named ldlinux.sys:
    echo "ldlinux.sys" >> ${DEVICE}/grml2usb.filelist

    if ! [ -r ${DEVICE}/live/filesystem.module ] ; then
       GRML_NAME=grml
    else
       GRML_NAME=$(cat ${DEVICE}/live/filesystem.module)
       GRML_NAME=${GRML_NAME%%.squashfs}
       GRML_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
    fi

    KERNEL=$(find ${TMPMNT}/boot/ -maxdepth 2 -name linux26)
    INITRD=$(find ${TMPMNT}/boot/ -maxdepth 2 -name initrd.gz)

    case $KERNEL in
      */boot/${GRML_NAME}/linux26*)   mv ${DEVICE}/boot/${GRML_NAME}/linux26 ${DEVICE}/
      ;;
    esac

    case $INITRD in
      */boot/${GRML_NAME}/initrd.gz*) mv ${DEVICE}/boot/${GRML_NAME}/initrd.gz ${DEVICE}/
      ;;
    esac

    if [ -d "${DEVICE}"/boot/addons ] ; then
       [ -d "${DEVICE}/addons" ] || mkdir ${DEVICE}/addons
       mv ${DEVICE}/boot/addons/* ${DEVICE}/addons/
    fi

    if [ -d "${DEVICE}"/boot/grub ] ; then
       [ -d "${DEVICE}/grub" ] || mkdir ${DEVICE}/grub
       mv ${DEVICE}/boot/grub/* ${DEVICE}/grub/
    fi

    rmdir ${DEVICE}/boot 2>/dev/null

    sync && echo "${WHITE}done${NORMAL}"
  else
    unmount
    return 1
  fi
}

run_syslinux(){
  DEV=$(echo ${DEVICE%/})
  TMPDEV=$(grep "[[:space:]]${DEV}[[:space:]]" /etc/fstab | grep -vh '^[[:space:]]*#' | awk '{print $1}')
  SYSDEV=$(echo ${TMPDEV%/})
  echo -n "Running syslinux on ${SYSDEV}: "
  debugit "debug: syslinux ${SYSDEV}"

  if syslinux ${SYSDEV} ; then
     echo "${WHITE}done${NORMAL}"
  else
     echo "${RED}Problem when running syslinux?" >&2
     echo "Try to call it manually via 'syslinux $SYSDEV' if you installed grml to ${SYSDEV}${NORMAL}" >&2
     return 1
  fi
}

# }}}

# main program {{{
trap bailout 1 2 3 15

if [ "$#" != 2 ]; then
  usage ; exit 4
fi

if [ -n "$UNINSTALL" ] ; then
   echo "$PROGRAMNAME - ${VERSION}"
   echo

   echo -n "Are you sure you want to erase all grml related data on ${DEVICE}? [y/N] "
   read a
   if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
      echo "Exiting as requested."
      exit 1
   fi

   echo "Uninstalling grml from ${DEVICE} based on ${DEVICE}/grml2usb.filelist${NORMAL}"
   if mount_device ; then
      if ! [ -f "${DEVICE}"/grml2usb.filelist ] ; then
         echo "${RED}File ${DEVICE}/grml2usb.filelist not found."
         echo "I have nothing to delete therefor. Exiting.${NORMAL}"
         bailout
      else
         echo
         for file in $(grep -v '^#' "${DEVICE}/grml2usb.filelist") ; do
             if [ -f "${DEVICE}/${file}" ] ; then
                echo -n "removing file ${file} on ${DEVICE}: "
                rm ${DEVICE}/${file} && echo "${WHITE}done${NORMAL}" || echo "${RED}error${NORMAL}"
             fi
         done

         for dir in $(grep -v '^#' "${DEVICE}/grml2usb.filelist" | sed 's#/.*##' | sort -u) ; do
             if [ -d "${DEVICE}/$dir" ] ; then
                echo -n "removing directory ${dir} on ${DEVICE}: "
                rmdir "${DEVICE}/${dir}"/* 2>/dev/null
                rmdir "${DEVICE}/${dir}" && echo "${WHITE}done${NORMAL}" || echo "${RED}error${NORMAL}"
             fi
         done

         echo -n "removing filelist grml2usb.filelist on ${DEVICE}: "
         rm ${DEVICE}/grml2usb.filelist && echo "${WHITE}done${NORMAL}" || echo "${RED}error${NORMAL}"

         echo

         echo -n "Unmounting ${DEVICE}: "
         umount $DEVICE && echo "${WHITE}done${NORMAL}" || echo "${RED}error${NORMAL}"
      fi
   fi
else
   info
   vfat_warning && \
   mount_iso    && \
   mount_device && \
   copyit       && \
   unmount      && \
   run_syslinux && \
   notice
fi
# }}}

## END OF FILE #################################################################
# vim:foldmethod=marker ts=2 ft=sh ai expandtab sw=3
