#!/bin/bash # Convert a Install iso so that it's bootable off of a USB stick # Copyright 2008 Jerry Vonau. # Jerry Vonau # base on livecd-iso-to-disk # by: # Jeremy Katz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. export PATH=/sbin:/usr/sbin:$PATH usage() { echo "$0 [--reset-mbr] [--noverify] " exit 1 } cleanup() { [ -d "$CDMNT" ] && umount $CDMNT && rmdir $CDMNT [ -d "$USBMNT" ] && umount $USBMNT && rmdir $USBMNT } exitclean() { echo "Cleaning up to exit..." cleanup exit 1 } getdisk() { DEV=$1 p=$(udevadm info -q path -n $DEV) if [ -e /sys/$p/device ]; then device=$(basename /sys/$p) else device=$(basename $(readlink -f /sys/$p/../)) fi if [ ! -e /sys/block/$device -o ! -e /dev/$device ]; then echo "Error finding block device of $DEV. Aborting!" exitclean fi device="/dev/$device" } resetMBR() { getdisk $1 if [ -f /usr/lib/syslinux/mbr.bin ]; then cat /usr/lib/syslinux/mbr.bin > $device elif [ -f /usr/share/syslinux/mbr.bin ]; then cat /usr/share/syslinux/mbr.bin > $device else exitclean fi } checkMBR() { getdisk $1 bs=$(mktemp /tmp/bs.XXXXXX) dd if=$device of=$bs bs=512 count=1 2>/dev/null || exit 2 mbrword=$(hexdump -n 2 $bs |head -n 1|awk {'print $2;'}) rm -f $bs if [ "$mbrword" = "0000" ]; then echo "MBR appears to be blank." echo "Do you want to replace the MBR on this device?" echo "Press Enter to continue or ctrl-c to abort" read resetMBR $1 fi return 0 } checkPartActive() { dev=$1 getdisk $dev # if we're installing to whole-disk and not a partition, then we # don't need to worry about being active if [ "$dev" = "$device" ]; then return fi if [ "$(/sbin/fdisk -l $device 2>/dev/null |grep $dev |awk {'print $2;'})" != "*" ]; then echo "Partition isn't marked bootable!" echo "You can mark the partition as bootable with " echo " # /sbin/parted $device" echo " (parted) toggle N boot" echo " (parted) quit" exitclean fi } checkFilesystem() { dev=$1 # USBFS=$(/lib/udev/vol_id -t $dev) #modified for use of blkid replacing vol_id USBFS=$(/sbin/blkid -s TYPE $dev | cut -d '"' -f2) if [ "$USBFS" != "vfat" -a "$USBFS" != "msdos" -a "$USBFS" != "ext2" -a "$USBFS" != "ext3" ]; then echo "USB filesystem must be vfat or ext[23]" exitclean fi } checkLABEL() { dev=$1 # USBLABEL=$(/lib/udev/vol_id -l $dev) USBLABEL=$(/sbin/blkid -s LABEL $dev | cut -d '"' -f2) if [ "$USBLABEL" != "XSRepo" ]; then USBLABEL="XSRepo" echo "Need to have a filesystem label for your USB device" if [ "$USBFS" = "vfat" -o "$USBFS" = "msdos" ]; then echo "Label will be set with /sbin/dosfslabel" dosfslabel $dev $USBLABEL elif [ "$USBFS" = "ext2" -o "$USBFS" = "ext3" ]; then echo "Label will be set with /sbin/e2label" e2label $dev $USBLABEL fi fi } checkSyslinuxVersion() { if [ ! -x /usr/bin/syslinux ]; then echo "You need to have syslinux installed to run this script" exit 1 fi if ! syslinux 2>&1 | grep -qe -d; then SYSLINUXPATH="" else SYSLINUXPATH="syslinux" fi } checkMounted() { dev=$1 if grep -q "^$dev " /proc/mounts ; then echo "$dev is mounted, please unmount for safety" exitclean fi if grep -q "^$dev " /proc/swaps; then echo "$dev is in use as a swap device, please disable swap" exitclean fi } if [ $(id -u) != 0 ]; then echo "You need to be root to run this script" exit 1 fi while [ $# -gt 2 ]; do case $1 in --noverify) noverify=1 shift; ;; --reset-mbr|--resetmbr) resetmbr=1 shift; ;; *) usage ;; esac done ISO=$(readlink -f "$1") USBDEV=$2 if [ -z "$ISO" ]; then usage fi if [ ! -b "$ISO" -a ! -f "$ISO" ]; then usage fi if [ -z "$USBDEV" -o ! -b "$USBDEV" ]; then usage fi if [ -z "$noverify" ]; then # verify the image echo "Verifying image..." checkisomd5 --verbose "$ISO" if [ $? -ne 0 ]; then echo "Are you SURE you want to continue?" echo "Press Enter to continue or ctrl-c to abort" read fi fi # do some basic sanity checks. checkSyslinuxVersion checkFilesystem $USBDEV checkPartActive $USBDEV checkMBR $USBDEV checkMounted $USBDEV checkLABEL $USBDEV [ -n $resetmbr ] && resetMBR $USBDEV # FIXME: would be better if we had better mountpoints CDMNT=$(mktemp -d /media/cdtmp.XXXXXX) mount -o loop,ro "$ISO" $CDMNT || exitclean USBMNT=$(mktemp -d /media/usbdev.XXXXXX) mount $USBDEV $USBMNT || exitclean trap exitclean SIGINT SIGTERM ## let's try to make sure there's enough room on the stick check=$CDMNT # let's try to make sure there's enough room on the stick tbd=0 if [ -d $USBMNT/iso ]; then tbd=$(du -s -B 1M $USBMNT/iso | awk {'print $1;'}) fi livesize=$(du -s -B 1M $check | awk {'print $1;'}) free=$(df -B1M $USBDEV |tail -n 1 |awk {'print $4;'}) if [ $livesize -gt $(($free + $tbd)) ]; then echo "Unable to fit installer on available space on USB stick" echo "Size of live image: $livesize" echo "Available space: $(($free + $tbd))" exitclean fi ############### if [ -d $USBMNT/iso ]; then echo "Already set up as installer image. Deleting old in fifteen seconds..." sleep 15 if [ -d $USBMNT/iso ]; then echo "Removing old directory iso" rm -fr $USBMNT/iso fi if [ -d $USBMNT/images ]; then echo "Removing old directory images" rm -fr $USBMNT/images fi if [ -d $USBMNT/boot ]; then echo "Removing old directory boot" rm -fr $USBMNT/boot fi fi echo "Copying install image to USB stick" if [ ! -d $USBMNT/$SYSLINUXPATH ]; then mkdir $USBMNT/$SYSLINUXPATH ; fi if [ ! -d $USBMNT/iso ]; then mkdir $USBMNT/iso ; fi if [ ! -d $USBMNT/images ]; then mkdir $USBMNT/images ; fi if [ ! -d $USBMNT/boot ]; then mkdir $USBMNT/boot ; fi cat > $USBMNT/boot/olpc.fth << EOF \ Boot script for USB boot hex rom-pa fffc7 + 4 $number drop h# 2e19 < [if] patch 2drop erase claim-params : high-ramdisk ( -- ) cv-load-ramdisk h# 22c +lp l@ 1+ memory-limit umin /ramdisk - ffff.f000 and ( new-ramdisk-adr ) ramdisk-adr over /ramdisk move ( new-ramdisk-adr ) to ramdisk-adr ; ' high-ramdisk to load-ramdisk [then] : set-bootpath-dev ( -- ) " /chosen" find-package if ( phandle ) " bootpath" rot get-package-property 0= if ( propval$ ) get-encoded-string ( bootpath$ ) [char] \ left-parse-string 2nip ( dn$ ) dn-buf place ( ) then then " /sd" dn-buf count sindex 0>= if " sd:" else " u:" then " BOOTPATHDEV" \$set-macro ; set-bootpath-dev " text ks=hd:LABEL=XSRepo:/ks.cfg method=hd:LABEL=XSRepo:/iso " to boot-file " \${BOOTPATHDEV}\\$SYSLINUXPATH\initrd.img" expand$ to ramdisk " \${BOOTPATHDEV}\\$SYSLINUXPATH\vmlinuz" expand$ to boot-device unfreeze boot EOF # Copy the iso if [ -f "$ISO" ]; then cp $CDMNT/images/* $USBMNT/images/ cp "$ISO" $USBMNT/iso/ || exitclean fi cp $CDMNT/isolinux/* $USBMNT/$SYSLINUXPATH if [ -e $CDMNT/ks.cfg ];then cp $CDMNT/ks.cfg $USBMNT/ fi echo "Updating boot config file" # adjust ks label and fstype if grep -q method $USBMNT/$SYSLINUXPATH/isolinux.cfg ;then sed -i -e 's/cdrom:/hd:LABEL=XSRepo:/g' -e 's|method=cdrom|method=hd:sdb1:/iso|' $USBMNT/$SYSLINUXPATH/isolinux.cfg else sed -i -e 's/cdrom:/hd:LABEL=XSRepo:/g' -e 's|cfg|cfg method=hd:sdb1:/iso|' $USBMNT/$SYSLINUXPATH/isolinux.cfg fi echo "Installing boot loader" if [ "$USBFS" = "vfat" -o "$USBFS" = "msdos" ]; then # syslinux expects the config to be named syslinux.cfg # and has to run with the file system unmounted mv $USBMNT/$SYSLINUXPATH/isolinux.cfg $USBMNT/$SYSLINUXPATH/syslinux.cfg cleanup if [ -n "$SYSLINUXPATH" ]; then syslinux -d $SYSLINUXPATH $USBDEV else syslinux $USBDEV fi elif [ "$USBFS" = "ext2" -o "$USBFS" = "ext3" ]; then # extlinux expects the config to be named extlinux.conf # and has to be run with the file system mounted mv $USBMNT/$SYSLINUXPATH/isolinux.cfg $USBMNT/$SYSLINUXPATH/extlinux.conf extlinux -i $USBMNT/syslinux cleanup fi echo "USB stick set up as installer image!"