Last active
May 6, 2016 22:20
-
-
Save hankcs/976d8a5fb6383f15af06d31a745017f6 to your computer and use it in GitHub Desktop.
Bootable ISO to USB disk for Mac OSX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
## | |
# AUTHOR: Andy Savage <[email protected]> | |
# GITHUB: www.github.com/hongkongkiwi | |
# DESCRIPTION: This script is for converting ISO files and burning them to a USB drive | |
## | |
HELP="USAGE: iso2usb blah.iso /dev/disk#" | |
ISOPATH="$1" | |
DEVPATH="$2" | |
# Check if a value exists in an array | |
# @param $1 mixed Needle | |
# @param $2 array Haystack | |
# @return Success (0) if value exists, Failure (1) otherwise | |
# Usage: in_array "$needle" "${haystack[@]}" | |
# See: http://fvue.nl/wiki/Bash:_Check_if_array_element_exists | |
in_array() { | |
local hay needle=$1 | |
shift | |
for hay; do | |
[[ $hay == $needle ]] && return 0 | |
done | |
return 1 | |
} | |
## If the user didn't pass a device to write to, we offer a selection | |
if [[ "$DEVPATH" == "" ]]; then | |
DEVICES=`diskutil list | grep "/dev" | cut -d'(' -f1` | |
OPTIONS=() | |
OPTION_DEVICES=() | |
while read -r DEVICE; do | |
PROTOCOL=`diskutil info "$DEVICE" | grep 'Protocol:' | tr -d ' ' | cut -d':' -f2` | |
if [[ "$PROTOCOL" == "USB" ]]; then | |
DEVICE_SIZE=`diskutil info "$DEVICE" | grep 'Total Size:' | tr -d ' ' | cut -d':' -f2 | cut -d'(' -f1` | |
DEVICE_NAME=`diskutil info "$DEVICE" | grep "Device / Media Name:" | cut -d':' -f2 | sed -e 's/^[[:space:]]*//'` | |
OPTIONS+=("$DEVICE_NAME ($DEVICE_SIZE)") | |
OPTION_DEVICES+=("$DEVICE") | |
fi | |
done <<< "$DEVICES" | |
# Check if our devices list is empty | |
if [ ${#OPTIONS[@]} -eq 0 ]; then | |
echo "ERROR: Looks like there are no USB devices plugged in" | |
exit 0 | |
fi | |
OPTIONS+=("Quit") | |
PS3='Please select USB device: ' | |
select CHOICE in "${OPTIONS[@]}"; do | |
if [[ "$CHOICE" == "Quit" ]]; then | |
exit 0 | |
elif [[ "$CHOICE" == "" ]]; then | |
echo "Invalid Selection" | |
elif [[ "$CHOICE" == "" ]]; then | |
exit 0 | |
else | |
in_array "$CHOICE" "$OPTIONS" | |
DEVPATH=${OPTION_DEVICES[${?}]} | |
break | |
fi | |
done | |
fi | |
if [[ ! -b "$DEVPATH" ]]; then | |
echo "ERROR: Device not found. Aborting" | |
echo | |
echo "$HELP" | |
exit 1 | |
fi | |
# trap ctrl-c and call ctrl_c() | |
trap ctrl_c INT | |
# This just does some cleanup if necessary | |
function ctrl_c() { | |
# Get rid of that pesky disk inserted is not readable error | |
NOTIFICATION_PID=`ps axww | grep -i "[u]ser[n]otification[c]enter" | awk '{print $1}'` | |
if [[ "$NOTIFICATION_PID" != "" ]]; then | |
kill "$NOTIFICATION_PID" | |
fi | |
if [[ "$CONVERTED" == "YES" && -f "$DMGPATH" ]]; then | |
rm "$DMGPATH" | |
fi | |
echo "ERROR: User Quit" | |
exit 255 | |
} | |
#### Some Useful Variables #### | |
#DEBUG="YES" # Set to Yes to avoid non-destructive actions | |
DEVINFO=`diskutil info "$DEVPATH" | grep 'Protocol' | tr -d ' ' | cut -d':' -f2` | |
DMGPATH=`mktemp -t 'iso2usb'` | |
ISOFILENAME=$(basename "$ISOPATH") | |
ISOEXT="${ISOFILENAME##*.}" | |
ISONAME="${ISOFILENAME%.*}" | |
DISKNUMBER=`basename "$DEVPATH"` | |
#add an 'r' to the beginning of the device name | |
#rdisk or raw disks write much faster | |
RDISKPATH="/dev/r$DISKNUMBER" | |
DISKSIZE=`diskutil info "$DEVPATH" | grep 'Total Size:' | tr -d ' ' | cut -d':' -f2 | cut -d'(' -f1` | |
DISKNAME=`diskutil info "$DEVPATH" | grep "Device / Media Name:" | cut -d':' -f2 | sed -e 's/^[[:space:]]*//'` | |
DDBSSIZE="1m" | |
PV_BIN=`which pv` | |
#### DO SOME SANITY CHECKING ### | |
PLATFORM='unknown' | |
UNAMESTR=`uname` | |
if [[ "$UNAMESTR" == 'Linux' ]]; then | |
PLATFORM='linux' | |
elif [[ "$UNAMESTR" == 'FreeBSD' ]]; then | |
PLATFORM='freebsd' | |
elif [[ "$UNAMESTR" == "Darwin" ]]; then | |
PLATFORM="mac" | |
fi | |
if [[ "$PLATFORM" != "mac" ]]; then | |
echo "ERROR: This script is designed only to run on Mac OSX" | |
echo " if you have some time, please help to improve it" | |
echo " and submit a pull request. I would appreciate it!" | |
fi | |
if [[ "$PV_BIN" == "" ]]; then | |
echo "WARNING: pv is not installed. I recommend you install it to get better transfer progress info" | |
echo " if you have homebrew you can use 'brew install pv'" | |
fi | |
#check is script has been run as root /sudo | |
if [[ $UID != 0 ]]; then | |
echo "Looks like your not running the script using sudo, we will do it for you" | |
RESULT=`sudo -p "Please enter your user password so we can gain root privileges: " echo > /dev/null` | |
if [[ $? != 0 ]]; then | |
echo "ERROR: We were unable to get root privileges!" | |
echo " try running the script with sudo" | |
exit 1 | |
fi | |
fi | |
if [[ ! -f "$ISOPATH" ]]; then | |
echo "ERROR: ISO not found." | |
echo "$HELP" | |
exit 1 | |
fi | |
if [[ `echo $ISOEXT | tr '[:upper:]' '[:lower:]'` != 'dmg' && `echo $ISOEXT | tr '[:upper:]' '[:lower:]'` != 'iso' ]]; then | |
echo "ERROR: Accepted input ISO types are .iso or .dmg, anything else is not supported" | |
exit 1 | |
fi | |
#check if device is USB. Exit if device is not USB. | |
if [[ $DEVINFO != "USB" ]]; then | |
echo "Non-USB device specified. This is dangerous and I assume a mistake." | |
echo "Aborting." | |
exit 1 | |
fi | |
echo "Are you sure you want to write \"$ISONAME.$ISOEXT\" to \"$DISKNAME\" ($DISKSIZE)?" | |
read -p "WARNING: This is a destructive action! Proceed? (y/n)? " -n 1 -r | |
echo # (optional) move to a new line | |
if [[ ! $REPLY =~ ^[Yy]$ ]]; then | |
echo "ERROR: User Quit" | |
exit 1 | |
fi | |
if [[ "$DEBUG" == "YES" ]]; then | |
echo "WARNING: Running in Debug mode! We won't actually do any destructive actions" | |
fi | |
if [[ `echo $ISOEXT | tr '[:upper:]' '[:lower:]'` == 'dmg' ]]; then | |
echo "-> ISO file is actually a DMG file, skipping convert" | |
DMGPATH="$ISOPATH" | |
else | |
echo "-> Converting ISO to DMG file..." | |
#convert the ISO to Mac format | |
if [[ "$DEBUG" == "YES" ]]; then | |
echo "hdiutil convert -format UDRW -o $DMGPATH $ISOPATH" | |
fi | |
if [[ -f "$DMGPATH" ]]; then | |
rm "$DMGPATH" | |
fi | |
RESULT=`hdiutil convert -format UDRW -o "$DMGPATH" "$ISOPATH"` | |
DMGPATH="$DMGPATH.dmg" | |
#change the ownership of the new file to match the owner of the | |
#current directory | |
OWNER=$(ls -dl . | cut -d' ' -f4) | |
GROUP=$(ls -dl . | cut -d' ' -f6) | |
chown ${OWNER}:${GROUP} "$DMGPATH" | |
CONVERTED="YES" | |
fi | |
# Unmount the device target device | |
if [[ $(mount | grep $DEVPATH) ]]; then | |
RESULT=`diskutil unmountDisk $DEVPATH` | |
echo "-> Unmounted disk $DEVPATH" | |
sleep 2 | |
if [[ $(mount | grep $DEVPATH) ]]; then | |
echo "ERROR: Unable to unmount target device." | |
echo "Aborting." | |
exit 1 | |
fi | |
fi | |
echo "-> Writing DMG file to device. This may take a while..." | |
#start the image writing process in the background | |
if [[ "$PV_BIN" == "" ]]; then | |
if [[ "$DEBUG" == "YES" ]]; then | |
echo "sudo dd if=$DMGPATH of=$RDISKPATH bs=1m &" | |
else | |
sudo dd if="$DMGPATH" of="$RDISKPATH" bs=1m & | |
fi | |
# This is the awkward way of getting dd progress | |
PID=$(ps | grep dd | grep -v grep) | |
PID=$(echo $PID | cut -d' ' -f1) | |
while [[ $(ps | grep $PID | grep -v grep) ]] | |
do | |
kill -INFO $PID | |
sleep 10 | |
done | |
else | |
# Progress using pv is much more interesting | |
DMGSIZE=`ls -nl "$DMGPATH" | awk '{print $5}'` | |
if [[ "$DEBUG" == "YES" ]]; then | |
echo "dd if=$DMGPATH 2> /dev/null | pv --size $DMGSIZE -e -N 'Burning USB Drive' | sudo dd of=$RDISKPATH bs=1m >/dev/null 2>&1" | |
else | |
dd if="$DMGPATH" | pv --size $DMGSIZE -e -N 'Burning USB Drive' | sudo dd of="$RDISKPATH" bs="$DDBSSIZE" >/dev/null 2>&1 | |
fi | |
fi | |
# Get rid of that pesky disk inserted is not readable error | |
NOTIFICATION_PID=`ps axww | grep -i "[u]ser[n]otification[c]enter" | awk '{print $1}'` | |
if [[ "$NOTIFICATION_PID" != "" ]]; then | |
sudo kill "$NOTIFICATION_PID" | |
fi | |
DISK_IS_MOUNTED=`diskutil list | grep "$DEVPATH"` | |
if [[ "$DISK_IS_MOUNTED" == "$DEVPATH" ]]; then | |
# Eject the DISK | |
RESULT=`diskutil eject "$DEVPATH"` | |
echo "-> Finished. Disk is Ejected and is safe to remove." | |
fi | |
# Clear up converted DMG file if necessary | |
if [[ "$CONVERTED" == "YES" && -f "$DMGPATH" ]]; then | |
if [[ "$DEBUG" != "YES" ]]; then | |
rm "$DMGPATH" | |
fi | |
echo "-> Cleaned up temp dmg file" | |
fi | |
echo | |
echo "Note: If you want to use the disk now, please unplug and plug back in" | |
echo | |
echo "Have a nice day :-)" | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment