Difference between revisions of "Mac Build Scripts"

From FreekiWiki
Jump to navigation Jump to search
(hacked for host-to-disk operation)
Line 570: Line 570:
  
 
==Replicate Mac Ubuntu Disk: Host to Disk==
 
==Replicate Mac Ubuntu Disk: Host to Disk==
This is the same script as above, but hacked to use a bootpartition image and a copy of the root filesystem, both resident on the host in directory '''/root/rootdir'''.  The only 'bug' I've seen so far (incompleteness notwithsanding) is that the UUID of the swap partition cannot be discovered with '''tune2fs''' (doh!).  Still needs boot partition mods for correct UUIDs ('''ybin'''  or '''mkofboot'''), and fstab replacement.
+
This is the same script as above, but hacked to use a bootpartition image and a copy of the root filesystem, both resident on the host in directory '''/root/rootdir'''.  Still needs boot partition mods for correct UUIDs ('''ybin'''  or '''mkofboot'''), and fstab replacement.
  
 
------------------------------------------------------------
 
------------------------------------------------------------
Line 852: Line 852:
 
     fi
 
     fi
 
     mkfs.ext3 $targetlinuxpart
 
     mkfs.ext3 $targetlinuxpart
 +
    # rumor has it that 'mkswap' creates a new UUID
 +
    mkswap $targetswappart
 
  }
 
  }
 
   
 
   
Line 933: Line 935:
 
    
 
    
 
     # UUID of targetlinux and targetswap partitions
 
     # UUID of targetlinux and targetswap partitions
     linuxuuid=$(tune2fs -l /dev/$(basename ${targetlinuxpart}) | grep -i uuid | awk '{print $3}')
+
     linuxuuid=$(vol_id ${targetlinuxpart} | grep -i uuid | cut -d'=' -f2)
     swapuuid=$(tune2fs -l /dev/$(basename ${targetswappart}) | grep -i uuid | awk '{print $3}')
+
     swapuuid=$(vol_id ${targetswappart} | grep -i uuid | cut -d'=' -f2)
 
   
 
   
 
     genYbConf $bootDevice
 
     genYbConf $bootDevice

Revision as of 19:58, 27 February 2007

Generate fdisk script

This script takes a raw device argument like /dev/hda and writes out a set of commands that can be fed to fdisk to automatically define a partition table for a Mac. The commands are written to a file named fdisk.script, but that can be changed to stdout, if this script needs to called from another script, for example. It is currently only tested for G3 towers, and needs more work and testing


#!/bin/sh
#
# create a set of input commands for fdisk to use to partition a blank
# drive for Macintosh machines.
#
# Partitions are created in the same order that an Ubuntu installation creates
# them: 
#   1. partition map
#   2. boot partition
#   3. linux partition
#   4. swap partition
# The partition map is automatically created with length 63.  The boot
# partition start block (64) and size (1954) are known (from the Ubuntu model). 
# The swap partition size is fixed arbitrary size, chosen to support 512Mb
# of ram and to allow the swap and linux partition lengths to be even.
 
 scriptName="fdisk.script"
 
 genScript () {
     # generate and write the commands, creating the script file
     #
  
     local target scriptName
 
     # initialize partition table, answer disk length query, and show the result
     echo i > $scriptName
     echo "" >>  $scriptName
     echo p >> $scriptName
     
     # create a boot partition with explicit partition size/type, and show result
     echo C >> $scriptName
     echo $bootstart >> $scriptName
     echo $bootlen >> $scriptName
     echo untitled >> $scriptName
     echo Apple_Bootstrap >> $scriptName
     echo p >> $scriptName
    
     # create a linux native partition, and show result
     echo c >> $scriptName
     echo $linuxstart >> $scriptName
     echo $linuxlen >> $scriptName
     echo c >> $scriptName
     echo p >> $scriptName
     
     # create the swap partition. and show result
     echo $swapstart >> $scriptName
     echo $swaplen >> $scriptName
     echo swap >> $scriptName
     echo p >> $scriptName
    
     # write out the partition map and confirm
     echo w >> $scriptName
     echo "" >> $scriptName
    
     # we done partishin' now
     echo q >> $scriptName
}
    
# first of all, best be root to do this
if [ $(whoami) != 'root' ]; then
    echo "You must be root to run this script; try using sudo"
    exit 1
fi

# need one argument
# target device
if [ -z $1 ]; then
    echo "no target specified"
    exit 2
else
    target=$1
fi

# target device has to exist
hdparm -g $target > /dev/null 2>&1
status=$?
if [ $status -ne 0 ]; then
    echo "device $target does not seem to exist"
    exit 3
fi

# target device must have no partitions
n_partitions=$(( $(fdisk -l $target | grep $target | wc -l) ))
if [ $n_partitions -ne 0 ]; then
    echo "There appear to be existing partitions on $target"
    echo "Quitting"
    exit 4
fi

# length of target drive
## get the hd geometry (hdparm), from that get (awk) the line that has 
## "sectors" in it, and spit out the number of sectors from that line 
## (sixth field); then remove (cut) the ',' from the end of the number;
## The hd length used for partition length calculations is actually one
## less that the true disk length, since block zero is ignored.
hdlen=$(hdparm -g $target | awk '/sector/ {print $6}' | cut -d ',' -f 1)
hdlen=$(($hdlen - 1))

# starts and lengths for boot, linux and swap partitions
#
# known values
mapstart=1
maplen=63
bootlen=1954
swaplen=1494848

#calculated values
bootstart=$(($mapstart + $maplen))
linuxstart=$(($bootstart + $bootlen))
linuxlen=$(($hdlen-($maplen + $bootlen + $swaplen)))
swapstart=$(($linuxstart+$linuxlen))

# debug
#echo "target=           $target"
#echo "hdlen=            $hdlen"
#echo "bootstart=        $bootstart"
#echo "bootlen=          $bootlen"
#echo "linuxstart=       $linuxstart"
#echo "linuxlen=         $linuxlen"
#echo "swapstart=        $swapstart"
#echo "swaplen=          $swaplen"
#calclen=$((63+$bootlen+$linuxlen+$swaplen))
#echo "calculated hdlen= $calclen"

genScript
exit 0

Replicate Mac Ubuntu Disk: Disk to Disk

This script is in-work.

The current version assumes a configuration that has three drives: a boot drive, a replication source and a replication target. It's not really practical solution unless the boot drive is the CD, and the media a bootable CD with all of the necessary software. I'm thinking customized rescue type CD, like the finnix (knoppix based) I currently use in Mac Build. Another possibility would be a netboot configuration (unknown PPC implementation at this point).

The current version is not completely tested as of 26feb07.


#!/bin/sh
#
# usage:
#       copyMacDisk [-t macType] source-device  target-device
#       -t macType     tweak the relevant files for the target environment
#
# Replicate a Mac Ubuntu disk onto a 'clean' disk; this script assumes
#   that the source is a fully installed disk device in its own right and not
#   the host on which this script is running.  The target device is expected
#   to be a 'clean' disk with no partition map.
#   [There is an alternate implentation in my mind's eye that has the
#   entire rooted file system, or install image, in a directory or partition
#   of it's own on the host machine - tr]
#
# 1. Take two arguments, a source device and a target device, and possibly
#    an option specifying the target platform
# 2. Verify that the source device has a Mac Ubuntu installation
# 3. Verify that the target device is a 'clean' disk
# 4. Create partitions on the target device
# 5. Create an ext3 filesystem on the linux partition of the target device
# 6. Use dd to copy the source boot partition to the target boot partition
#    [There is an alternative: use 'mkofboot' to create an populate the
#    target boot partition. In that case this step woujldn't happen until
#    until after fstab and yaboot.conf are modified.]
# 7. Use rsync to copy the source linux image to the target linux partition
# 8. modify fstab and yaboot.conf files for target machine environment
#    [see step 6]

errExit () {
# expect an error number and message string
# show the message, exit with the error number as exit status
    local errno msg
    errno=$1
    msg=$2
    echo $msg
    exit $errno
}

genScript () {
# expect a filename string as an argument;
# create an fdisk script file with the argument filename, overwriting 
# existing file of same name
    local scriptName
    scriptName=$1

    # length of target drive
    ## get the hd geometry (hdparm), from that get (awk) the line that has 
    ## "sectors" in it, and spit out the number of sectors from that line 
    ## (sixth field); then remove (cut) the ',' from the end of the number;
    ## The hd length used for partition length calculations is actually one
    ## less that the true disk length, since block zero is ignored.
    hdlen=$(hdparm -g /dev/$target | awk '/sector/ {print $6}' | cut -d ',' -f 1)
    hdlen=$(($hdlen - 1))
    
    # starts and lengths for boot, linux and swap partitions
    #
    # known values
    mapstart=1
    maplen=63
    bootlen=1954
    swaplen=1494848
    
    #calculated values
    bootstart=$(($mapstart + $maplen))
    linuxstart=$(($bootstart + $bootlen))
    linuxlen=$(($hdlen-($maplen + $bootlen + $swaplen)))
    swapstart=$(($linuxstart+$linuxlen))

    # generate and write the commands, creating the script file
    #
    # initialize partition table, answer disk length query, and show the result
    echo i > $scriptName
    echo "" >>  $scriptName
    echo p >> $scriptName
    
    # create a boot partition with explicit partition size/type, and show result
    echo C >> $scriptName
    echo $bootstart >> $scriptName
    echo $bootlen >> $scriptName
    echo untitled >> $scriptName
    echo Apple_Bootstrap >> $scriptName
    echo p >> $scriptName
    
    # create a linux native partition, and show result
    echo c >> $scriptName
    echo $linuxstart >> $scriptName
    echo $linuxlen >> $scriptName
    echo c >> $scriptName
    echo p >> $scriptName
    
    # create the swap partition. and show result
    echo $swapstart >> $scriptName
    echo $swaplen >> $scriptName
    echo swap >> $scriptName
    echo p >> $scriptName
    
    # write out the partition map and confirm
    echo w >> $scriptName
    echo "" >> $scriptName
    
    # we done partishin' now
    echo q >> $scriptName
}

genYbConf () {
# expect a boot-device string formatted as an OF device-tree name;
# write a candidate yaboot.conf file using target platform values for boot device,
# boot partition and linux root partition.
    local bootdev
    bootdev=$1

    echo '## yaboot.conf generated by the Ubuntu installer' > $ybconfName
    echo '##' >> $ybconfName
    echo '## run: "man yaboot.conf" for details. Do not make changes until you have!!' >> $ybconfName
    echo '## see also: /usr/share/doc/yaboot/examples for example configurations.' >> $ybconfName
    echo '##' >> $ybconfName
    echo '## For a dual-boot menu, add one or more of:' >> $ybconfName
    echo '## bsd=/dev/hdaX, macos=/dev/hdaY, macosx=/dev/hdaZ' >> $ybconfName
    echo  >> $ybconfName
    echo "boot=${actualbootpart}" >> $ybconfName
    echo "device=${bootdev}" >> $ybconfName
    echo 'partition=3' >> $ybconfName
    echo "root=${actuallinuxpart}" >> $ybconfName
    echo 'timeout=50' >> $ybconfName
    echo 'install=/usr/lib/yaboot/yaboot' >> $ybconfName
    echo 'magicboot=/usr/lib/yaboot/ofboot' >> $ybconfName
    echo 'enablecdboot' >> $ybconfName
    echo  >> $ybconfName
    echo 'image=/boot/vmlinux' >> $ybconfName
    echo '        label=Linux' >> $ybconfName
    echo '        read-only' >> $ybconfName
    echo '        initrd=/boot/initrd.img' >> $ybconfName
    echo '        append="quiet splash"' >> $ybconfName
    echo  >> $ybconfName
    echo 'image=/boot/vmlinux.old' >> $ybconfName
    echo '        label=old' >> $ybconfName
    echo '        read-only' >> $ybconfName
    echo '        initrd=/boot/initrd.img.old' >> $ybconfName
    echo '        append="quiet splash"' >> $ybconfName
}

genFstab () {
# expect linux partition uuid and swap partition UUIDs as arguments;
# write a candidate /etc/fstab file using the target platform values for
# swap partition device name and uuid, and linux root partition device
# name and uuid.
    local linuxuuid swapuuid
    linuxuuid=$1
    swapuuid=$2

    echo '# /etc/fstab: static file system information.' > $fstabName
    echo '#' >> $fstabName
    echo '# <file system> <mount point>   <type>  <options>       <dump>  <pass>' >> $fstabName
    echo 'proc            /proc           proc    defaults        0       0' >> $fstabName
    echo "# $actuallinuxpart" >> $fstabName
    echo "UUID=$linuxuuid /               ext3    defaults,errors=remount-ro 0       1" >> $fstabName
    echo "# $actualswappart" >> $fstabName
    echo "UUID=$swapuuid none            swap    sw              0       0" >> $fstabName
    echo "$actualcdrom        /media/cdrom0   udf,iso9660 user,noauto     0       0" >> $fstabName
}

usage () {
# print error message and exit
    errExit 2 "usage: copyMacDisk [-t macType] srcdev targetdev"
}

getArgs () {
# parse command line options and arguments
# set values for globals: src, target, macType
    while getopts t: f; do
        case $f in
        t)  case $OPTARG in
               imac) macType=$OPTARG;;
               g3)   macType=$OPTARG;;
               g4)   macType=$OPTARG;;
               *)    errExit 1 "unrecognized target machine type $OPTARG";;
            esac;;
        *)  usage;;
        esac
    done
    shift `expr $OPTIND - 1`

    if [ $# -lt 2 ]; then
        usage
    else
        src=$(basename $1)
        target=$(basename $2)
    fi
}

verifySource () {
# expect a device name (e.g. hda) as argument;
# test for presence of partition map, and three partitions: boot, linux, swap
# fail/exit if any of these is not there
    local src
    src=$1
    # test: exactly four partitions; successful fdisk has one extra match
    n_partitions=$(( $(fdisk -l /dev/$src | grep $src | wc -l) ))
    if [ $n_partitions -ne 5 ]; then
        errExit 3 "error: $src does not contain 4 partitions"
    fi

    # test: partition 1 is partition map
    part1=$(fdisk -l /dev/$src | grep ${src}1)
    if [ -z "$part1" ]; then
        errExit 4 "error: no partition map found on $src"
    else
        if [ -z "`echo $part1 | grep -i map`" ]; then
            errExit 4 "error: no partition map found on $src"
        fi
    fi

    # test: partition 2 is boot partition
    part2=$(fdisk -l /dev/$src | grep ${src}2)
    if [ -z "$part2" ]; then
        errExit 5 "error: no boot partition found on $src"
    else
        if [ -z "`echo $part2 | grep -i bootstrap`" ]; then
            errExit 5 "error: no boot partition found on $src"
        fi
    fi

    # test: partition 3 is linux partition
    part3=$(fdisk -l /dev/$src | grep ${src}3)
    if [ -z "$part3" ]; then
        errExit 6 "error: no linux partition found on $src"
    else
        if [ -z "`echo $part3 | grep -i native`" ]; then
            errExit 6 "error: no linux partition found on $src"
        fi
    fi

    # test: partition 4 is swap partition
    part4=$(fdisk -l /dev/$src | grep ${src}4)
    if [ -z "$part4" ]; then
        errExit 7 "error: no swap partition found on $src"
    else
        if [ -z "`echo $part4 | grep -i swap`" ]; then
            errExit 7 "error: no swap partition found on $src"
        fi
    fi
}

verifyTarget () {
# expect a device name argument;
# the device is expected to be a 'clean' drive with no partition map
# fail/exit if device does not exist (hdpar failure) or has partitions.
    local target
    target=$1
    # target device has to exist
    hdparm -g $target > /dev/null 2>&1
    status=$?
    if [ $status -ne 0 ]; then
        errExit 8 "error: device $target does not seem to exist"
    fi

    # target device must have no partitions
    n_partitions=$(( $(fdisk -l /dev/$target | grep $target | wc -l) ))
    if [ $n_partitions -ne 0 ]; then
        errExit 9 "error: there appear to be existing partitions on $target"
    fi
}

createPartitions () {
# expect no arguments;
# create an fdisk script, run it, verify that the target linux partition 
# was created and create an ext3 filesystem on it.

    # run the fdisk script
    genScript $script
    fdisk /dev/$target < $script
    # create an ext3 partition on target linux partition
    ## make sure it's there
    n_partitions=$(( $(fdisk -l /dev/$target | grep $targetlinuxpartition | wc -l) ))
    if [ $n_partitions -ne 1 ]; then
        errExit 10 "error: no linux partition $target for fs creation"
    fi
    mkfs.ext3 $targetlinuxpart
}

setupForCopy () {
# verify/create all the necessary mount points using global values
    # create mount points as necessary
    ## linux src
    if [ ! -d /mnt/${srclinuxpart} ]; then
        mkdir /mnt/${srclinuxpart}
    fi
    ## linux target
    if [ ! -d /mnt/${targetlinuxpart} ]; then
        mkdir /mnt/${targetlinuxpart}
    fi
    ## boot target
    if [ ! -d /mnt/${targetbootpart} ]; then
        mkdir /mnt/${targetbootpart}
    fi

    # mount source and target linux partitions
    mount -t ext3 /dev/${srclinuxpart} /mnt/${srclinuxpart}
    status=$?
    if [ $status -ne 0 ]; then
        errExit 11 "error: mount src linux partition failed: /dev/${srclinuxpart} to /mnt/${srclinuxpart}"
    fi
    mount -t ext3 /dev/${targetlinuxpart} /mnt/${targetlinuxpart}
    if [ $status -ne 0 ]; then
        errExit 12 "error: mount target linux partition failed: /dev/${targetlinuxpart} to /mnt/${targetlinuxpart}"
    fi
}

copyPartitions () {
# expect no arguments;
# using global partition names, copy boot partition with dd, and copy 
# linux install image with rsync; verify boot partition by mounting it
# as an hfs filesystem

    # dd source boot partition to target boot partition
    dd if=/dev/${srcbootpart} of=/dev/${targetbootpart}
    # verify boot partition copy
    mount -t hfs /dev/${targetbootpart} /mnt/${targetbootpart}
    if [ $status -ne 0 ]; then
        errExit 13 "error: mount target boot partition failed: /dev/${targetbootpart} to /mnt/${targetbootpart}"
    else
        umount /mnt/${targetbootpart}
    fi
    

    # rsync linux source root to linux target 
    rsync -a /mnt/${src}/ /mnt/${target}/
    status=$?
    if [ $status -ne 0 ]; then
        errExit 14 "error: linux partition copy failed"
    fi
}

tweakFilesForTargetMachine () {
# expect a platform selector as an argument;
# select an OF device-tree definition for the target platform boot-device,
# and capture the UUIDs of the target drive's linux and swap partitions;
# use those values to generate yaboot.conf and fstab files.
    local macType
    macType=$1
#    echo "target machine is $macType"
    
    # OF path to target boot partition.  This must be explicit, since the
    # assumption is that this host is not, in general, the target
    case $mactype in
        imac) bootDevice="/pci@f2000000/mac-io@17/ata-4@1f000/disk@0:";;
        g3)   bootDevice="hd:";;
        g4)   bootDevice="hd:";;
        *)    bootDevice="hd:";;
    esac
 
    # UUID of target and swap partitions
    linuxuuid=$(tune2fs -l /dev/${srclinuxpart} | grep -i uuid | awk '{print $3}')
    swapuuid=$(tune2fs -l /dev/${srcswappart} | grep -i uuid | awk '{print $3}')

    genYbConf $bootDevice
    genFstab $linuxuuid $swapuuid
}

###########################
# main                    #
###########################
# first of all, best be root to do this
if [ $(whoami) != 'root' ]; then
    errExit 1 "You must be root to run this script; try using sudo"
fi

# now get commandline options
# ignore -t for now; if it is ever used, its argument will be
# qualified as a legal specifier.  An illegal specifier is grounds
# for early exit.
while getopts t: f; do
    case $f in
    t)  case $OPTARG in
           imac) macType=$OPTARG;;
           g3)   macType=$OPTARG;;
           g4)   macType=$OPTARG;;
           *)    errExit 1 "unrecognized target machine type $OPTARG";;
        esac;;
    *)  usage;;
    esac
done
shift `expr $OPTIND - 1`

# var defs
script="/tmp/fdisk.script"
ybconfName="/tmp/yaboot.conf"
fstabName="/tmp/fstab"
bootpart=2
linuxpart=3
swappart=4
getArgs $@
srcbootpart=/dev/${src}${bootpart}
srcswappart=/dev/${src}${swappart}
targetbootpart=/dev/${target}${bootpart}
targetswappart=/dev/${target}${swappart}
srclinuxpart=/dev/${src}${linuxpart}
targetlinuxpart=/dev/${target}${linuxpart}
case $macType in
    imac) actuallinuxpart=/dev/hda3 ;
          actualswappart=/dev/hda4 ;
          actualbootpart=/dev/hda2 ;
          actualcdrom=/dev/hdb ;;
    g3)   actuallinuxpart=/dev/hdc3 ;
          actualswappart=/dev/hdc4 ;
          actualbootpart=/dev/hdc2 ;
          actualcdrom=/dev/hda ;;
    g4)   actuallinuxpart=/dev/hda3 ;
          actualswappart=/dev/hda4 ;
          actualbootpart=/dev/hda2 ;
          actualcdrom=/dec/hdc ;;
    *)    actuallinuxpart=/dev/hda3 ;
          actualswappart=/dev/hda4 ;
          actualbootpart=/dev/hda2 ;
          actualcdrom=/dev/hdc ;;
esac

verifySource ${src}
verifyTarget ${target}
createPartitions
setupForCopy
copyPartitions
if [ $macType ]; then 
    tweakFilesForTargetMachine $macType
fi
exit 0



Replicate Mac Ubuntu Disk: Host to Disk

This is the same script as above, but hacked to use a bootpartition image and a copy of the root filesystem, both resident on the host in directory /root/rootdir. Still needs boot partition mods for correct UUIDs (ybin or mkofboot), and fstab replacement.


#!/bin/sh
#
# usage:
#       copyMacDisk [-t macType] source-device  target-device
#       -t macType     tweak the relevant files for the target environment
#
# Replicate a Mac Ubuntu disk onto a 'clean' disk; this script assumes
#   that the source is a fully installed disk device in its own right and not
#   the host on which this script is running.  The target device is expected
#   to be a 'clean' disk with no partition map.
#   [There is an alternate implentation in my mind's eye that has the
#   entire rooted file system, or install image, in a directory or partition
#   of it's own on the host machine - tr]
#
# 1. Take two arguments, a source device and a target device, and possibly
#    an option specifying the target platform
# 2. Verify that the source device has a Mac Ubuntu installation
# 3. Verify that the target device is a 'clean' disk
# 4. Create partitions on the target device
# 5. Create an ext3 filesystem on the linux partition of the target device
# 6. Use dd to copy the source boot partition to the target boot partition
#    [There is an alternative: use 'mkofboot' to create an populate the
#    target boot partition. In that case this step woujldn't happen until
#    until after fstab and yaboot.conf are modified.]
# 7. Use rsync to copy the source linux image to the target linux partition
# 8. modify fstab and yaboot.conf files for target machine environment
#    [see step 6]

errExit () {
# expect an error number and message string
# show the message, exit with the error number as exit status
    local errno msg
    errno=$1
    msg=$2
    echo $msg
    exit $errno
}

genScript () {
# expect a filename string as an argument;
# create an fdisk script file with the argument filename, overwriting 
# existing file of same name
    local scriptName
    scriptName=$1

    # length of target drive
    ## get the hd geometry (hdparm), from that get (awk) the line that has 
    ## "sectors" in it, and spit out the number of sectors from that line 
    ## (sixth field); then remove (cut) the ',' from the end of the number;
    ## The hd length used for partition length calculations is actually one
    ## less that the true disk length, since block zero is ignored.
    hdlen=$(hdparm -g /dev/$target | awk '/sector/ {print $6}' | cut -d ',' -f 1)
    hdlen=$(($hdlen - 1))
    
    # starts and lengths for boot, linux and swap partitions
    #
    # known values
    mapstart=1
    maplen=63
    bootlen=1954
    swaplen=1494848
    
    #calculated values
    bootstart=$(($mapstart + $maplen))
    linuxstart=$(($bootstart + $bootlen))
    linuxlen=$(($hdlen-($maplen + $bootlen + $swaplen)))
    swapstart=$(($linuxstart+$linuxlen))

    # generate and write the commands, creating the script file
    #
    # initialize partition table, answer disk length query, and show the result
    echo i > $scriptName
    echo "" >>  $scriptName
    echo p >> $scriptName
    
    # create a boot partition with explicit partition size/type, and show result
    echo C >> $scriptName
    echo $bootstart >> $scriptName
    echo $bootlen >> $scriptName
    echo untitled >> $scriptName
    echo Apple_Bootstrap >> $scriptName
    echo p >> $scriptName
    
    # create a linux native partition, and show result
    echo c >> $scriptName
    echo $linuxstart >> $scriptName
    echo $linuxlen >> $scriptName
    echo untitled >> $scriptName
    echo p >> $scriptName
    
    # create the swap partition. and show result
    echo c >> $scriptName
    echo $swapstart >> $scriptName
    echo $swaplen >> $scriptName
    echo swap >> $scriptName
    echo p >> $scriptName
    
    # write out the partition map and confirm
    echo w >> $scriptName
    echo yes >> $scriptName
    
    # we done partishin' now
    echo q >> $scriptName
}

genYbConf () {
# expect a boot-device string formatted as an OF device-tree name;
# write a candidate yaboot.conf file using target platform values for boot device,
# boot partition and linux root partition.
    local bootdev
    bootdev=$1

    echo '## yaboot.conf generated by the Ubuntu installer' > $ybconfName
    echo '##' >> $ybconfName
    echo '## run: "man yaboot.conf" for details. Do not make changes until you have!!' >> $ybconfName
    echo '## see also: /usr/share/doc/yaboot/examples for example configurations.' >> $ybconfName
    echo '##' >> $ybconfName
    echo '## For a dual-boot menu, add one or more of:' >> $ybconfName
    echo '## bsd=/dev/hdaX, macos=/dev/hdaY, macosx=/dev/hdaZ' >> $ybconfName
    echo  >> $ybconfName
    echo "boot=${actualbootpart}" >> $ybconfName
    echo "device=${bootdev}" >> $ybconfName
    echo 'partition=3' >> $ybconfName
    echo "root=${actuallinuxpart}" >> $ybconfName
    echo 'timeout=50' >> $ybconfName
    echo 'install=/usr/lib/yaboot/yaboot' >> $ybconfName
    echo 'magicboot=/usr/lib/yaboot/ofboot' >> $ybconfName
    echo 'enablecdboot' >> $ybconfName
    echo  >> $ybconfName
    echo 'image=/boot/vmlinux' >> $ybconfName
    echo '        label=Linux' >> $ybconfName
    echo '        read-only' >> $ybconfName
    echo '        initrd=/boot/initrd.img' >> $ybconfName
    echo '        append="quiet splash"' >> $ybconfName
    echo  >> $ybconfName
    echo 'image=/boot/vmlinux.old' >> $ybconfName
    echo '        label=old' >> $ybconfName
    echo '        read-only' >> $ybconfName
    echo '        initrd=/boot/initrd.img.old' >> $ybconfName
    echo '        append="quiet splash"' >> $ybconfName
}

genFstab () {
# expect linux partition uuid and swap partition UUIDs as arguments;
# write a candidate /etc/fstab file using the target platform values for
# swap partition device name and uuid, and linux root partition device
# name and uuid.
    local linuxuuid swapuuid
    linuxuuid=$1
    swapuuid=$2

    echo '# /etc/fstab: static file system information.' > $fstabName
    echo '#' >> $fstabName
    echo '# <file system> <mount point>   <type>  <options>       <dump>  <pass>' >> $fstabName
    echo 'proc            /proc           proc    defaults        0       0' >> $fstabName
    echo "# $actuallinuxpart" >> $fstabName
    echo "UUID=$linuxuuid /               ext3    defaults,errors=remount-ro 0       1" >> $fstabName
    echo "# $actualswappart" >> $fstabName
    echo "UUID=$swapuuid none            swap    sw              0       0" >> $fstabName
    echo "$actualcdrom        /media/cdrom0   udf,iso9660 user,noauto     0       0" >> $fstabName
}

usage () {
# print error message and exit
    errExit 2 "usage: copyMacDisk [-t macType] srcdev targetdev"
}

getArgs () {
# parse command line options and arguments
# set values for globals: src, target, macType
    while getopts t: f; do
        case $f in
        t)  case $OPTARG in
               imac) macType=$OPTARG;;
               g3)   macType=$OPTARG;;
               g4)   macType=$OPTARG;;
               *)    errExit 1 "unrecognized target machine type $OPTARG";;
            esac;;
        *)  usage;;
        esac
    done
    shift `expr $OPTIND - 1`

    if [ $# -lt 2 ]; then
        usage
    else
        src=$(basename $1)
        target=$(basename $2)
    fi
}

verifySource () {
# expect a device name (e.g. hda) as argument;
# test for presence of partition map, and three partitions: boot, linux, swap
# fail/exit if any of these is not there
    local src
    src=$1
    # test: exactly four partitions; successful fdisk has one extra match
    n_partitions=$(( $(fdisk -l /dev/$src | grep $src | wc -l) ))
    if [ $n_partitions -ne 5 ]; then
        errExit 3 "error: $src does not contain 4 partitions"
    fi

    # test: partition 1 is partition map
    part1=$(fdisk -l /dev/$src | grep ${src}1)
    if [ -z "$part1" ]; then
        errExit 4 "error: no partition map found on $src"
    else
        if [ -z "`echo $part1 | grep -i map`" ]; then
            errExit 4 "error: no partition map found on $src"
        fi
    fi

    # test: partition 2 is boot partition
    part2=$(fdisk -l /dev/$src | grep ${src}2)
    if [ -z "$part2" ]; then
        errExit 5 "error: no boot partition found on $src"
    else
        if [ -z "`echo $part2 | grep -i bootstrap`" ]; then
            errExit 5 "error: no boot partition found on $src"
        fi
    fi

    # test: partition 3 is linux partition
    part3=$(fdisk -l /dev/$src | grep ${src}3)
    if [ -z "$part3" ]; then
        errExit 6 "error: no linux partition found on $src"
    else
        if [ -z "`echo $part3 | grep -i native`" ]; then
            errExit 6 "error: no linux partition found on $src"
        fi
    fi

    # test: partition 4 is swap partition
    part4=$(fdisk -l /dev/$src | grep ${src}4)
    if [ -z "$part4" ]; then
        errExit 7 "error: no swap partition found on $src"
    else
        if [ -z "`echo $part4 | grep -i swap`" ]; then
            errExit 7 "error: no swap partition found on $src"
        fi
    fi
}

verifyTarget () {
# expect a device name argument;
# the device is expected to be a 'clean' drive with no partition map
# fail/exit if device does not exist (hdpar failure) or has partitions.
    local target
    target=$1
    # target device has to exist
    hdparm -g /dev/$target > /dev/null 2>&1
    status=$?
    if [ $status -ne 0 ]; then
        errExit 8 "error: device $target does not seem to exist"
    fi

    # target device must have no partitions
    n_partitions=$(( $(fdisk -l /dev/$target | grep $target | wc -l) ))
    if [ $n_partitions -ne 0 ]; then
        errExit 9 "error: there appear to be existing partitions on $target"
    fi
}

createPartitions () {
# expect no arguments;
# create an fdisk script, run it, verify that the target linux partition 
# was created and create an ext3 filesystem on it.

    # run the fdisk script
    genScript $script
    fdisk /dev/$target < $script
    # create an ext3 partition on target linux partition
    ## make sure it's there
    n_partitions=$(( $(fdisk -l /dev/$target | grep $targetlinuxpart | wc -l) ))
    if [ $n_partitions -ne 1 ]; then
        errExit 10 "error: no linux partition $targetlinuxpart for fs creation"
    fi
    mkfs.ext3 $targetlinuxpart
    # rumor has it that 'mkswap' creates a new UUID
    mkswap $targetswappart
}

setupForCopy () {
# verify/create all the necessary mount points using global values
    # create mount points as necessary
    ## linux src
    if [ ! -d /mnt/$(basename ${srclinuxpart}) ]; then
        mkdir /mnt/$(basename ${srclinuxpart})
    fi
    ## linux target
    if [ ! -d /mnt/$(basename ${targetlinuxpart}) ]; then
        mkdir /mnt/$(basename ${targetlinuxpart})
    fi
    ## boot target
    if [ ! -d /mnt/$(basename ${targetbootpart}) ]; then
        mkdir /mnt/$(basename ${targetbootpart})
    fi

    # mount source and target linux partitions
#    mount -t ext3 /dev/$(basename ${srclinuxpart}) /mnt/$(basename ${srclinuxpart})
#    status=$?
#    if [ $status -ne 0 ]; then
#        errExit 11 "error: mount src linux partition failed: /dev/${srclinuxpart} to /mnt/${srclinuxpart}"
#    fi  
    mount -t ext3 -o rw /dev/$(basename ${targetlinuxpart}) /mnt/$(basename ${targetlinuxpart})
    status=$?
    if [ $status -ne 0 ]; then
        errExit 12 "error: mount target linux partition failed: /dev/${targetlinuxpart} to /mnt/${targetlinuxpart}"
    fi
}

copyPartitions () {
# expect no arguments;
# using global partition names, copy boot partition with dd, and copy 
# linux install image with rsync; verify boot partition by mounting it
# as an hfs filesystem

    # dd source boot partition to target boot partition
#    dd if=/dev/${srcbootpart} of=/dev/${targetbootpart}
    dd if=/root/bootpart.img of=/dev/$(basename ${targetbootpart})
    # verify boot partition copy
    mount -t hfs /dev/$(basename ${targetbootpart}) /mnt/$(basename ${targetbootpart})
    status=$?
    if [ $status -ne 0 ]; then
        errExit 13 "error: mount target boot partition failed: /dev/${targetbootpart} to /mnt/${targetbootpart}"
    else
        umount /mnt/$(basename ${targetbootpart})
    fi
    

    # rsync linux source root to linux target 
#    rsync -a /mnt/${src}/ /mnt/${targetlinuxpart}/
    rsync -av /root/rootdir/ /mnt/$(basename ${targetlinuxpart})/
    status=$?
    if [ $status -ne 0 ]; then
        errExit 14 "error: linux partition copy failed"
    else
        umount /mnt/$(basename ${targetlinuxpart})
    fi
}

tweakFilesForTargetMachine () {
# expect a platform selector as an argument;
# select an OF device-tree definition for the target platform boot-device,
# and capture the UUIDs of the target drive's linux and swap partitions;
# use those values to generate yaboot.conf and fstab files.
    local macType
    macType=$1
#    echo "target machine is $macType"
    
    # OF path to target boot partition.  This must be explicit, since the
    # assumption is that this host is not, in general, the target
    case $mactype in
        imac) bootDevice="/pci@f2000000/mac-io@17/ata-4@1f000/disk@0:";;
        g3)   bootDevice="/pci@80000000/pci-bridge@d/pci-ata@1/@0/disk@0:";;
        g4)   bootDevice="/pci@f2000000/pci-bridge@d/mac-io@7/ata-4@1f000/disk@0:";;
        g4q)   bootDevice="/pci@f2000000/mac-io@17/ata-4@1f000/disk@0:";;
        *)    bootDevice="hd:";;
    esac
 
    # UUID of targetlinux and targetswap partitions
    linuxuuid=$(vol_id ${targetlinuxpart} | grep -i uuid | cut -d'=' -f2)
    swapuuid=$(vol_id ${targetswappart} | grep -i uuid | cut -d'=' -f2)

    genYbConf $bootDevice
    genFstab $linuxuuid $swapuuid
}

###########################
# main                    #
###########################
# first of all, best be root to do this
if [ $(whoami) != 'root' ]; then
    errExit 1 "You must be root to run this script; try using sudo"
fi

# now get commandline options
# ignore -t for now; if it is ever used, its argument will be
# qualified as a legal specifier.  An illegal specifier is grounds
# for early exit.
while getopts t: f; do
    case $f in
    t)  case $OPTARG in
           imac) macType=$OPTARG;;
           g3)   macType=$OPTARG;;
           g4)   macType=$OPTARG;;
           *)    errExit 1 "unrecognized target machine type $OPTARG";;
        esac;;
    *)  usage;;
    esac
done
shift `expr $OPTIND - 1`

# var defs
script="/tmp/fdisk.script"
ybconfName="/tmp/yaboot.conf"
fstabName="/tmp/fstab"
bootpart=2
linuxpart=3
swappart=4
getArgs $@
srcbootpart=/dev/${src}${bootpart}
srcswappart=/dev/${src}${swappart}
targetbootpart=/dev/${target}${bootpart}
targetswappart=/dev/${target}${swappart}
srclinuxpart=/dev/${src}${linuxpart}
targetlinuxpart=/dev/${target}${linuxpart}
case $macType in
    imac) actuallinuxpart=/dev/hda3 ;
          actualswappart=/dev/hda4 ;
          actualbootpart=/dev/hda2 ;
          actualcdrom=/dev/hdb ;;
    g3)   actuallinuxpart=/dev/hdc3 ;
          actualswappart=/dev/hdc4 ;
          actualbootpart=/dev/hdc2 ;
          actualcdrom=/dev/hda ;;
    g4)   actuallinuxpart=/dev/hda3 ;
          actualswappart=/dev/hda4 ;
          actualbootpart=/dev/hda2 ;
          actualcdrom=/dec/hdc ;;
    *)    actuallinuxpart=/dev/hda3 ;
          actualswappart=/dev/hda4 ;
          actualbootpart=/dev/hda2 ;
          actualcdrom=/dev/hdc ;;
esac

verifySource ${src}
verifyTarget ${target}
createPartitions
setupForCopy
copyPartitions
if [ $macType ]; then 
    tweakFilesForTargetMachine $macType
fi
exit 1