summaryrefslogblamecommitdiffstats
path: root/usb-and-pxe-installers/usbimg2disk.sh
blob: d98e21de42a7ff9f2a6253326edfdd153e087f1c (plain) (tree)





















































































































































































































































































                                                                                 
#!/bin/sh
# $Id: usbimg2disk.sh,v 1.2 2009/05/14 10:29:38 eha Exp eha $
#
# Copyright 2009  Eric Hameleers, Eindhoven, NL
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Paranoid as usual:
set -e

showhelp() {
  echo "# "
  echo "# Purpose: to use the content of Slackware's usbboot.img and transform"
  echo "#   a standard USB thumb drive with a single vfat partition"
  echo "#   into an alternative USB boot device for the Slackware installer."
  echo "# "
  echo "# Reason: some computers refuse to boot from a USB thumb drive if it was"
  echo "#   made bootable by dumping 'usbboot.img' onto it."
  echo "# "
  echo "# Your USB thumb drive may contain data!"
  echo "# This data will *not* be overwritten, unless you have"
  echo "#   explicitly chosen to format the drive by using the '-f' parameter."
  echo "# "
  echo "# $(basename $0) accepts the following parameters:"
  echo "#   -h|--help                  This help"
  echo "#   -f|--format                Format the USB drive before use"
  echo "#   -i|--infile <filename>     Full path to the usbboot.img file"
  echo "#   -l|--logfile <filename>    Optional logfile to catch fdisk output"
  echo "#   -o|--outdev <filename>     The device name of your USB drive"
  echo "#   -u|--unattended            Do not ask any questions"
  echo "# "
  echo "# Example:"
  echo "# "
  echo "# $(basename $0) -i ~/download/usbboot.img -o /dev/sdX"
  echo "# "
}

reformat() {
  # Commands to re-create a functional USB stick with VFAT partition:
  # Only parameter: the name of the USB device to be formatted:
  TOWIPE="$1"

  # Sanity checks:
  if [ ! -b $TOWIPE ]; then
    echo "*** Not a block device: '$TOWIPE' !"
    exit 1
  fi

  # Wipe the MBR:
  dd if=/dev/zero of=$TOWIPE bs=512 count=1

  # create a FAT32 partition (type 'b')
  /sbin/fdisk $TOWIPE <<EOF
n
p
1


t
b
w
EOF

  # Format with a vfat filesystem:
  /sbin/mkdosfs -F32 ${TOWIPE}1
}

makebootable() {
  # Only parameter: the name of the USB device to be set bootable:
  USBDRV="$1"

  # Sanity checks:
  if [ ! -b $USBDRV ]; then
    echo "Not a block device: '$USBDRV' !"
    exit 1
  fi

  # Set the bootable flag for the first (and only...) partition:
  /sbin/sfdisk $USBDRV -N1 <<EOF
,,,*
EOF
}

# Parse the commandline parameters:
if [ -z "$1" ]; then
  showhelp
  exit 1
fi
while [ ! -z "$1" ]; do
  case $1 in
    -f|--format)
      REFORMAT=1
      shift
      ;;
    -h|--help)
      showhelp
      exit
      ;;
    -i|--infile)
      USBIMG="$(cd $(dirname $2); pwd)/$(basename $2)"
      shift 2
      ;;
    -l|--logfile)
      LOGFILE="$(cd $(dirname $2); pwd)/$(basename $2)"
      shift 2
      ;;
    -o|--outdev)
      TARGET="$2"
      TARGETPART="${TARGET}1"
      shift 2
      ;;
    -u|--unattended)
      UNATTENDED=1
      shift
      ;;
    *)
      echo "Unknown parameter '$1'!"
      exit 1
      ;;
  esac
done

# Before we start:
[ -x /bin/id ] && CMD_ID="/bin/id" || CMD_ID="/usr/bin/id"
if [ "$($CMD_ID -u)" != "0" ]; then
  echo "You need to be root to run $(basename $0)."
  exit 1
fi

# Prepare the environment:
UNATTENDED=${UNATTENDED:-0}   # unattended means: never ask questions.
REFORMAT=${REFORMAT:-0}       # do not try to reformat by default
LOGFILE=${LOGFILE:-/dev/null} # silence by default

# Sanity checks:
if [ -z "$TARGET" -o -z "$USBIMG" ]; then
  echo "*** You must specify both the names of usbboot.img and the USB device!"
  exit 1
fi

if [ ! -f $USBIMG ]; then
  echo "*** This is not a useable file: '$USBIMG' !"
  exit 1
fi

if [ $REFORMAT -eq 0 ]; then
  if ! /sbin/blkid -t TYPE=vfat $TARGETPART 1>/dev/null 2>/dev/null ; then
    echo "*** I fail to find a 'vfat' partition: '$TARGETPART' !"
    echo "*** If you want to format the USB thumb drive, add the '-f' parameter."
    exit 1
  fi
else
  if [ ! -b $TARGET ]; then
    echo "*** Not a block device: '$TARGET' !"
    exit 1
  fi
fi

if mount | grep -q $TARGETPART ; then
  echo "***"
  echo "*** Please un-mount $TARGETPART first, then re-run this script!"
  echo "***"
  exit 1
fi

# Check for prerequisites:
if [ ! -r /usr/lib/syslinux/mbr.bin -o ! -x /usr/bin/syslinux ]; then
  echo "This script requires that the syslinux package is installed!"
  exit 1
fi

# Show the USB device's information to the user:
if [ $UNATTENDED -eq 0 ]; then
  [ $REFORMAT -eq 1 ] && DOFRMT="format and " || DOFRMT="" 

  echo ""
  echo "# We are going to ${DOFRMT}use this device - '$TARGET'."
  /sbin/fdisk -l $TARGET | while read LINE ; do echo "# $LINE" ; done
  echo ""

  echo "***                                                       ***"
  echo "*** If this is the wrong drive, then press CONTROL-C now! ***"
  echo "***                                                       ***"

  read -p "Or press ENTER to continue: " JUNK
  # OK... the user was sure about the drive...
fi

# Initialize the logfile:
cat /dev/null > $LOGFILE

# If we need to format the USB drive, do it now:
if [ $REFORMAT -eq 1 ]; then
  echo "--- Formatting $TARGET and creating VFAT partition..."
  if [ $UNATTENDED -eq 0 ]; then
    echo "--- Last chance! Press CTRL-C to abort!"
    read -p "Or press ENTER to continue: " JUNK
  fi
  ( reformat $TARGET ) 1>>$LOGFILE 2>&1
fi

# Create a temporary mount point for the image file:
mkdir -p /mnt
MNTDIR1=$(mktemp -d -p /mnt -t img.XXXXXX)
if [ ! -d $MNTDIR1 ]; then
  echo "*** Failed to create a temporary mount point for the image!"
  exit 1
else
  chmod 700 $MNTDIR1
fi

# Create a temporary mount point for the USB thumb drive partition:
MNTDIR2=$(mktemp -d -p /mnt -t usb.XXXXXX)
if [ ! -d $MNTDIR2 ]; then
  echo "*** Failed to create a temporary mount point for the usb thumb drive!"
  exit 1
else
  chmod 700 $MNTDIR2
fi

# Mount the image file:
mount -o loop $USBIMG $MNTDIR1

# Mount the vfat partition
mount $TARGETPART $MNTDIR2

# Check available space:
USBFREE=$(df -k $TARGETPART | grep "^$TARGETPART" |tr -s ' ' | cut -d' ' -f4)
IMGSIZE=$(du -k $USBIMG | cut -f1)
echo "--- Available free space on the the USB drive is $USBFREE KB"
echo "--- Required free space: $IMGSIZE KB"

# Exit when the image size appears larger than available space:
if [ $IMGSIZE -gt $USBFREE ]; then
  echo "*** The USB thumb drive does not have enough free space!"
  # Cleanup and exit:
  umount -f $MNTDIR1
  umount -f $MNTDIR2
  rmdir $MNTDIR1 $MNTDIR2
  exit 1
fi

# Copy files to the USB disk in it's own subdirectory '/syslinux'
echo "--- Copying files to the USB drive..."
mkdir -p $MNTDIR2/syslinux
cp -a $MNTDIR1/* $MNTDIR2/syslinux/
rm -f $MNTDIR2/syslinux/ldlinux.sys

# Unmount everything:
umount -f $MNTDIR1
umount -f $MNTDIR2

# Remove the temporary directories:
rmdir $MNTDIR1 $MNTDIR2

# Run syslinux and write a good MBR:
echo "--- Making the USB drive '$TARGET' bootable..."
( makebootable $TARGET ) 1>>$LOGFILE 2>&1
/usr/bin/syslinux -s -d /syslinux $TARGETPART 1>>$LOGFILE 2>&1
dd if=/usr/lib/syslinux/mbr.bin of=$TARGET 1>>$LOGFILE 2>&1

# THE END