diff options
Diffstat (limited to 'usb-and-pxe-installers/usbimg2disk.sh')
-rw-r--r-- | usb-and-pxe-installers/usbimg2disk.sh | 214 |
1 files changed, 176 insertions, 38 deletions
diff --git a/usb-and-pxe-installers/usbimg2disk.sh b/usb-and-pxe-installers/usbimg2disk.sh index d98e21de..aed32c51 100644 --- a/usb-and-pxe-installers/usbimg2disk.sh +++ b/usb-and-pxe-installers/usbimg2disk.sh @@ -1,7 +1,7 @@ #!/bin/sh -# $Id: usbimg2disk.sh,v 1.2 2009/05/14 10:29:38 eha Exp eha $ +# $Id: usbimg2disk.sh,v 1.9 2010/04/24 18:21:53 eha Exp eha $ # -# Copyright 2009 Eric Hameleers, Eindhoven, NL +# Copyright 2009, 2010 Eric Hameleers, Eindhoven, NL # All rights reserved. # # Redistribution and use of this script, with or without modification, is @@ -24,14 +24,29 @@ # Paranoid as usual: set -e +# Clean up in case of failure: +cleanup() { + # Clean up by unmounting our loopmounts, deleting tempfiles: + echo "--- Cleaning up the staging area..." + sync + umount -f ${MNTDIR1} 2>/dev/null || true + umount -f ${MNTDIR2} 2>/dev/null || true + rm -rf ${MNTDIR3} + rmdir $MNTDIR1 $MNTDIR2 +} +trap "echo \"*** $0 FAILED at line $LINENO ***\"; cleanup; exit 1" ERR INT TERM + 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 "# Purpose #1: to use the content of Slackware's usbboot.img and" + echo "# transform a standard USB thumb drive with a single vfat partition" + echo "# into a bootable medium containing the Slackware Linux installer." + echo "# " + echo "# Purpose #2: to use the contents of a Slackware directory tree" + echo "# and transform a standard USB thumb drive with" + echo "# a single vfat partition and 2GB of free space into" + echo "# a self-contained USB installation medium for Slackware Linux." 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" @@ -43,18 +58,28 @@ showhelp() { 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 "# -s|--slackdir <dir> Use 'dir' as the root of Slackware tree" echo "# -u|--unattended Do not ask any questions" + echo "# -L|--label FAT label when formatting the USB drive" + echo "# " - echo "# Example:" + echo "# Examples:" echo "# " echo "# $(basename $0) -i ~/download/usbboot.img -o /dev/sdX" + echo "# $(basename $0) -f -s /home/ftp/pub/slackware-13.0 -o /dev/sdX" + echo "# " + echo "# The second example shows how to create a fully functional Slackware" + echo "# installer on a USB stick (it needs a Slackware tree as the source)." 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" + # two parameters: + # (1) the name of the USB device to be formatted: + # (2) FAT label to use when formatting the USB device: + local TOWIPE="$1" + local THELABEL="$2" # Sanity checks: if [ ! -b $TOWIPE ]; then @@ -77,8 +102,11 @@ b w EOF + # We set the fat label to '$THELABEL' when formatting. + # It will enable the installer to mount the fat partition automatically + # and pre-fill the correct pathname for the "SOURCE" dialog. # Format with a vfat filesystem: - /sbin/mkdosfs -F32 ${TOWIPE}1 + /sbin/mkdosfs -F32 -n ${THELABEL} ${TOWIPE}1 } makebootable() { @@ -125,10 +153,19 @@ while [ ! -z "$1" ]; do TARGETPART="${TARGET}1" shift 2 ;; + -s|--slackdir) + REPOSROOT="$(cd $(dirname $2); pwd)/$(basename $2)" + FULLINSTALLER="yes" + shift 2 + ;; -u|--unattended) UNATTENDED=1 shift ;; + -L|--label) + FATLABEL="$2" + shift 2 + ;; *) echo "Unknown parameter '$1'!" exit 1 @@ -143,12 +180,46 @@ if [ "$($CMD_ID -u)" != "0" ]; then exit 1 fi +# Check FAT label: +if [ -n "${FATLABEL}" ]; then + if [ "x$(echo '${FATLABEL}'| tr -d '[:alnum:]_-.')" != "x" ]; then + echo "FAT label '${FATLABEL}' is not an acceptible name!" + exit 1 + elif [ ${#FATLABEL} gt 11 ]; then + echo "FAT label '${FATLABEL}' must be less than 12 characters!" + exit 1 + fi +else + FATLABEL="USBSLACKINS" +fi + # Prepare the environment: +MININSFREE=2000 # minimum in MB required for a Slackware tree 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 +EXCLUDES=${EXCLUDES:-"--exclude=source \ + --exclude=extra/aspell-word-lists \ + --exclude=isolinux \ + --exclude=usb-and-pxe-installers \ + --exclude=pasture"} # not copied onto the stick + +# If we have been given a Slackware tree, we will create a full installer: +if [ -n "$REPOSROOT" ]; then + if [ -d "$REPOSROOT" -a -f "$REPOSROOT/PACKAGES.TXT" ]; then + USBIMG=${USBIMG:-"$REPOSROOT/usb-and-pxe-installers/usbboot.img"} + PKGDIR=$(head -40 $REPOSROOT/PACKAGES.TXT | grep 'PACKAGE LOCATION: ' |head -1 |cut -f2 -d/) + if [ -z "$PKGDIR" ]; then + echo "*** Could not find the package subdirectory in '$REPOSROOT'!" + exit 1 + fi + else + echo "*** Directory '$REPOSROOT' does not look like a Slackware tree!" + exit 1 + fi +fi -# Sanity checks: +# More 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 @@ -162,7 +233,7 @@ 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." + echo "*** If you want to format the USB thumb drive, add the '-f' parameter" exit 1 fi else @@ -173,15 +244,20 @@ else 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!" +MBRBIN="/usr/lib/syslinux/mbr.bin" +if [ ! -r $MBRBIN ]; then MBRBIN="/usr/share/syslinux/mbr.bin"; fi +if [ ! -r $MBRBIN -o ! -x /usr/bin/syslinux ]; then + echo "*** This script requires that the 'syslinux' package is installed!" + exit 1 +fi + +if [ ! -x /usr/bin/mtools ]; then + echo "*** This script requires that the 'floppy' (mtools) package is installed!" exit 1 fi @@ -190,7 +266,7 @@ if [ $UNATTENDED -eq 0 ]; then [ $REFORMAT -eq 1 ] && DOFRMT="format and " || DOFRMT="" echo "" - echo "# We are going to ${DOFRMT}use this device - '$TARGET'." + echo "# We are going to ${DOFRMT}use this device - '$TARGET':" /sbin/fdisk -l $TARGET | while read LINE ; do echo "# $LINE" ; done echo "" @@ -212,7 +288,7 @@ if [ $REFORMAT -eq 1 ]; then echo "--- Last chance! Press CTRL-C to abort!" read -p "Or press ENTER to continue: " JUNK fi - ( reformat $TARGET ) 1>>$LOGFILE 2>&1 + ( reformat $TARGET ${FATLABEL} ) 1>>$LOGFILE 2>&1 fi # Create a temporary mount point for the image file: @@ -234,45 +310,107 @@ else chmod 700 $MNTDIR2 fi +# Create a temporary directory to extract the initrd if needed: +MNTDIR3=$(mktemp -d -p /mnt -t initrd.XXXXXX) +if [ ! -d $MNTDIR3 ]; then + echo "*** Failed to create a temporary directory to extract the initrd!" + exit 1 +else + chmod 700 $MNTDIR3 +fi + # Mount the image file: -mount -o loop $USBIMG $MNTDIR1 +mount -o loop,ro $USBIMG $MNTDIR1 + +# Mount the vfat partition: +mount -t vfat -o shortname=mixed $TARGETPART $MNTDIR2 -# Mount the vfat partition -mount $TARGETPART $MNTDIR2 +# Do we have space to create a full Slackware USB install medium? +if [ "$FULLINSTALLER" = "yes" ]; then + if [ $(df --block=1MB $TARGETPART |grep "^$TARGETPART" |tr -s ' ' |cut -f4 -d' ') -le $MININSFREE ]; then + echo "*** The partition '$TARGETPART' does not have enough" + echo "*** free space (${MININSFREE} MB) to create a Slackware installation medium!" + cleanup + exit 1 + fi +fi -# Check available space: -USBFREE=$(df -k $TARGETPART | grep "^$TARGETPART" |tr -s ' ' | cut -d' ' -f4) -IMGSIZE=$(du -k $USBIMG | cut -f1) +# Check available space for a Slackware USB setup bootdisk: +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" +echo "--- Required free space for installer: $IMGSIZE KB" -# Exit when the image size appears larger than available space: +# Exit when the installer image's size does not fit in 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 + cleanup exit 1 fi -# Copy files to the USB disk in it's own subdirectory '/syslinux' -echo "--- Copying files to the USB drive..." +if [ $UNATTENDED -eq 0 ]; then + # if we are running interactively, warn about overwriting files: + if [ -n "$REPOSROOT" ]; then + if [ -d $MNTDIR2/syslinux -o -d $MNTDIR2/$(basename $REPOSROOT) ]; then + echo "--- Your USB drive contains directories 'syslinux' and/or '$(basename $REPOSROOT)'" + echo "--- These will be overwritten. Press CTRL-C to abort now!" + read -p "Or press ENTER to continue: " JUNK + fi + else + if [ -d $MNTDIR2/syslinux ]; then + echo "--- Your USB drive contains directory 'syslinux'" + echo "--- This will be overwritten. Press CTRL-C to abort now!" + read -p "Or press ENTER to continue: " JUNK + fi + fi +fi + +# Copy boot image files to the USB disk in its own subdirectory '/syslinux': +echo "--- Copying boot 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 +# If we are creating a full Slackware installer, there is a lot more to do: +if [ "$FULLINSTALLER" = "yes" ]; then + # Extract the Slackware initrd for modifications we have to do: + echo "--- Extracting Slackware initrd.img..." + ( cd ${MNTDIR3}/ + gunzip -cd ${MNTDIR2}/syslinux/initrd.img | cpio -i -d -H newc --no-absolute-filenames + ) 2>>$LOGFILE + + # Modify installer files so that installing from USB stick will be easier: + echo "--- Modifying installer files..." + ( cd ${MNTDIR3}/ + # Try to automatically mount the installer partition: + mkdir usbinstall + echo "mount -t vfat -o ro,shortname=mixed \$(/sbin/blkid -t LABEL=$FATLABEL | cut -f1 -d:) /usbinstall 1>/dev/null 2>&1" >> etc/rc.d/rc.S + # Adapt the dialogs so that pressing [OK] will be all there is to it: + sed -i -e 's# --menu# --default-item 6 --menu#' usr/lib/setup/SeTmedia + sed -i -e "s# 2> \$TMP/sourcedir# /usbinstall/$(basename $REPOSROOT)/$PKGDIR 2> \$TMP/sourcedir#" usr/lib/setup/INSdir + ) 2>>$LOGFILE + + # Recreate the initrd: + echo "--- Gzipping the initrd image again:" + ( cd ${MNTDIR3}/ + find . |cpio -o -H newc |gzip > ${MNTDIR2}/syslinux/initrd.img + ) 2>>$LOGFILE + + # Copy Slackware package tree (no sources) to the USB disk - + # we already made sure that ${REPOSROOT} does not end with a '/' + echo "--- Copying Slackware package tree to the USB drive..." + rsync -rptHDL $EXCLUDES $REPOSROOT $MNTDIR2/ +fi -# Remove the temporary directories: -rmdir $MNTDIR1 $MNTDIR2 +# Unmount/remove stuff: +sync +cleanup # 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 +dd if=$MBRBIN of=$TARGET 1>>$LOGFILE 2>&1 # THE END |