diff --git a/cdrom/waboot/emulabboot.sh b/cdrom/waboot/emulabboot.sh
index 289e0f79e0d76d67880c16baff0ec43f09cac027..f8999446e5e3b6b47c825f0ff5be6da2740a6b44 100755
--- a/cdrom/waboot/emulabboot.sh
+++ b/cdrom/waboot/emulabboot.sh
@@ -19,7 +19,7 @@
 #
 case "$1" in
 start)
-	if [ -f /usr/site/sbin/tbbootconfig ]; then
+	if [ -x /usr/site/sbin/tbbootconfig ]; then
 		/usr/site/sbin/tbbootconfig -c 1 $netbed_disk
 
 		case $? in
diff --git a/cdrom/waboot/rc.emulab b/cdrom/waboot/rc.emulab
index dca51b54285623ffcfd42385483b6bd70dd80a8b..bce3ddd9e359d2bb910b822ca0102430dc8d2759 100755
--- a/cdrom/waboot/rc.emulab
+++ b/cdrom/waboot/rc.emulab
@@ -28,8 +28,9 @@ EmulabCheckIPConfig()
 		case $? in
 	        0)
 		       ;;
-		-277)
+		13)
 			echo 'Installation aborted'
+			echo 'Remove the CD and reboot'
 			exit 1
 			;;
 		*)
diff --git a/cdrom/waboot/register.pl b/cdrom/waboot/register.pl
index 53dfbc1f328e80ef612cad619a9069f57ce830ec..3b7f3886bbb60c1a303f3c8979d05d0733eeaed0 100755
--- a/cdrom/waboot/register.pl
+++ b/cdrom/waboot/register.pl
@@ -19,7 +19,7 @@ use Socket;
 #
 sub usage()
 {
-    print("Usage: register.pl <bootdisk>\n");
+    print("Usage: register.pl <bootdisk> <ipaddr>\n");
     exit(-1);
 }
 my  $optlist = "";
@@ -108,10 +108,11 @@ my %weberrors =
 if (! getopts($optlist, \%options)) {
     usage();
 }
-if (@ARGV != 1) {
+if (@ARGV != 2) {
     usage();
 }
 my $rawbootdisk = $ARGV[0];
+my $IP = $ARGV[1];
 
 #
 # Untaint the arguments.
@@ -122,6 +123,12 @@ if ($rawbootdisk =~ /^([\w\/]+)$/) {
 else {
     fatal("Tainted argument $rawbootdisk!");
 }
+if ($IP =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) {
+    $IP = $1;
+}
+else {
+    fatal("Tainted argument $IP!");
+}
 
 #
 # See if we want to continue. Useful for debugging.
@@ -144,27 +151,6 @@ my $blockdevice = $rawdevice;
 #
 $fromscratch = mysystem("$tbboot -v $rawbootdisk");
 
-#
-# We need our IP.
-# 
-my $hostname = `hostname`;
-if (!defined($hostname)) {
-    fatal("No hostname!");
-}
-# Untaint and strip newline.
-if ($hostname =~ /^([-\w\.]+)$/) {
-    $hostname = $1;
-}
-else {
-    fatal("Tainted argument $hostname!\n");
-}
-
-my (undef,undef,undef,undef,@ipaddrs) = gethostbyname($hostname);
-if (!defined(@ipaddrs)) {
-    fatal("Could not map $hostname to IP address!");
-}
-my $IP = inet_ntoa($ipaddrs[0]);
-
 GetInstructions();
 
 #
@@ -313,6 +299,23 @@ for ($i = 1; $i <= 4; $i++) {
     # If told to load a local image from the CDROM, its really easy!
     # 
     if (! ($image =~ /^http:.*$/ || $image =~ /^ftp:.*$/)) {
+	#
+	# First, check the hash if provided.
+	#
+	if (defined($hash)) {
+	    print "Checking MD5 hash of the CDROM image.\n";
+	    print $PATIENCEMSG;
+
+	    my $hval = `md5 -q /$image`;
+	    chomp($hval);
+
+	    fatal("CDROM image has invalid hash!")
+		if ($hash ne $hval);
+	}
+
+	#
+	# Then load up the disk straight from the CDROM.
+	#
 	print "Loading image for slice $i from $image.\n";
 	print $PATIENCEMSG;
 
@@ -509,8 +512,8 @@ sub GetInstructions()
 	}
 	else {
 	    while (!defined($privkey)) {
-		$privkey = Prompt("Please enter your 16 character CD password",
-				  undef);
+		$privkey = Prompt("Please enter your 16 character CD password".
+				  " (no spaces)", undef);
 	    }
 	}
 
@@ -899,15 +902,7 @@ sub WriteConfigBlock()
 {
     my $cmd;
 
-    # XXX for now hack, tbbootconfig doesn't know about 'bootdisk'
-    if (1) {
-	mysystem("grep -v bootdisk $softconfig > /tmp/softcfg");
-	fatal("Could not prepare $softconfig for writing!")
-	    if ($?);
-	$cmd = "$tbboot -f -d -w /tmp/softcfg -k 1 -c 0 ";
-    } else {
-	$cmd = "$tbboot -f -d -w $softconfig -k 1 -c 0 ";
-    }
+    $cmd = "$tbboot -f -d -w $softconfig -k 1 -c 0 ";
 
     if (defined($config{privkey})) {
 	$cmd .= "-e $config{privkey} ";
diff --git a/cdrom/waboot/register.sh b/cdrom/waboot/register.sh
index 85c96e109f64fbc90a4e3905096cfbf02426eb51..2e5fba355af671522f06d52ba000dda5f8ef0f4a 100755
--- a/cdrom/waboot/register.sh
+++ b/cdrom/waboot/register.sh
@@ -17,7 +17,7 @@
 case "$1" in
 start)
 	if [ -f /usr/site/sbin/register.pl ]; then
-		/usr/site/sbin/register.pl $netbed_disk
+		/usr/site/sbin/register.pl $netbed_disk $netbed_IP
 		exit $?
 	fi
 	;;
diff --git a/cdrom/waboot/waipconfig.pl b/cdrom/waboot/waipconfig.pl
index 056bbfbb73d48a963d3bdafff7a2591f1a54fb2b..ce2703af86e275807c405850411c0713e3bdd387 100755
--- a/cdrom/waboot/waipconfig.pl
+++ b/cdrom/waboot/waipconfig.pl
@@ -13,6 +13,24 @@ use Getopt::Std;
 use Fcntl;
 use IO::Handle;
 
+#
+# Disk related parameters
+#
+
+# where to find kernel config output
+my $dmesgcmd = "/sbin/dmesg";
+my $dmesgfile = "/var/run/dmesg.boot";
+
+# preferred ordering of disks to use
+my @preferred = ("ar", "aacd", "amrd", "mlxd", "twed", "ad", "da");
+
+# ordered list of disks found and hash of sizes
+my @disklist;
+my %disksize;
+
+# min disk size we can use (in MB)
+my $MINDISKSIZE = 8000;
+
 #
 # Boot configuration for the CDROM. Determine the IP configuration, either
 # from the floopy or from the user interactively.
@@ -196,7 +214,7 @@ sub GetNewConfig()
     print "\n";
 
     if (Prompt("Continue with installation?", "No") =~ /no/i) {
-	exit(-277);
+	exit(13);
     }
 
     #
@@ -231,8 +249,8 @@ sub GetUserConfig()
     $config{'domain'}    = Prompt("Domain", $config{'domain'});
     $config{'IP'}        = Prompt("IP Address", $config{'IP'});
     $config{'netmask'}   = Prompt("Netmask", WhichNetMask());
+    $config{'gateway'}   = Prompt("Gateway IP", WhichGateway());
     $config{'nameserver'}= Prompt("Nameserver IP", $config{'nameserver'});
-    $config{'gateway'}   = Prompt("Gateway IP", $config{'gateway'});
 
     # XXX
     $rawbootdisk = $config{'bootdisk'};
@@ -326,12 +344,11 @@ sub WhichInterface()
 	}
     }
 
-    return "fxp0";
+    return undef;
 }
 
 #
-# Which network mask. Make the standard class C guess and let the caller
-# spit that out in a prompt for verification.
+# Which network mask.  Default based on the network number.
 #
 sub WhichNetMask()
 {
@@ -340,9 +357,47 @@ sub WhichNetMask()
 	return $config{'netmask'};
     }
 
+    #
+    # XXX this is a nice idea, but will likely be wrong for large
+    # institutions that subdivide class B's (e.g., us!)
+    #
+    if (0 && defined($config{'IP'})) {
+	my ($net) = split(/\./, $config{'IP'});
+	return "255.0.0.0" if $net < 128;
+	return "255.255.0.0" if $net < 192;
+    }
+
     return "255.255.255.0";
 }
 
+#
+# Which gateway IP.  Use the more or less traditional .1 for the network
+# indicated by (IP & netmask).
+#
+sub WhichGateway()
+{
+    # XXX
+    if (defined($config{'gateway'})) {
+	return $config{'gateway'};
+    }
+
+    #
+    # Grab IP and netmask, combine em, stick 1 in the low quad,
+    # make sure the result isn't the IP, and return that.
+    # Parsing tricks from the IPv4Addr package.
+    #
+    if (defined($config{'IP'}) && defined($config{'netmask'})) {
+	my $addr = unpack("N", pack("CCCC", split(/\./, $config{'IP'})));
+	my $mask = unpack("N", pack("CCCC", split(/\./, $config{'netmask'})));
+	my $gw = ($addr & $mask) | 1;
+	if ($gw != $addr) {
+	    return join(".", unpack("CCCC", pack("N", $gw)));
+	}
+    }
+
+    return undef;
+}
+
 #
 # Which raw disk. Prompt if we cannot come up with a good guess.
 # Note: raw and block devices are one in the same now.
@@ -350,41 +405,40 @@ sub WhichNetMask()
 sub WhichRawDisk()
 {
     #
-    # Search the drives until we find a valid header.
-    # Order is: IDE, SCSI, IDE RAID, SCSI RAID
+    # Find the list of configured disks
+    #
+    my @list = DiskList();
+
+    #
+    # Search the drives looking for one with a valid header.
     # 
-    foreach my $disk ("ad", "da", "ar", "aacd") {
-	foreach my $drive (0) {
-	    my $guess = "/dev/${disk}${drive}";
+    foreach my $disk (@list) {
+	my $guess = "/dev/${disk}";
 
-	    system("$tbboot -v $guess");
-	    if (! $?) {
-		#
-		# Allow for overiding the guess, with short timeout.
-		#
-		$rawbootdisk =
-		    Prompt("Which Disk Device is the boot device?",
-			   "$guess", 10);
-		goto gotone;
-	    }
+	system("$tbboot -v $guess");
+	if (! $?) {
+	    #
+	    # Allow for overiding the guess, with short timeout.
+	    #
+	    $rawbootdisk = Prompt("Which Disk Device is the boot device?",
+				  "$guess", 10);
+	    goto gotone;
 	}
     }
 
     #
-    # Okay, no candidates. Lets find the first real disk. Use dd
-    # to see if the drive is configured.
+    # None with configuration info, just use the first existing disk
+    # which is large enough and is actually accessible.
     #
-    foreach my $disk ("ad0", "da0", "ar0", "aacd0") {
+    foreach my $disk (@list) {
 	my $guess = "/dev/${disk}";
 
-	system("dd if=$guess of=/dev/null bs=512 count=32 >/dev/null 2>&1");
-	if (! $?) {
+	if (DiskSize($disk) >= $MINDISKSIZE && DiskReadable($disk)) {
 	    #
 	    # Allow for overiding the guess, with short timeout.
 	    #
-	    $rawbootdisk =
-		Prompt("Which Disk Device is the boot device?",
-		       "$guess", 10);
+	    $rawbootdisk = Prompt("Which Disk Device is the boot device?",
+				  "$guess", 10);
 	    goto gotone;
 	}
     }
@@ -394,12 +448,78 @@ sub WhichRawDisk()
     # If still not defined, then loop forever.
     # 
     while (!defined($rawbootdisk) || ! -e $rawbootdisk) {
-	$rawbootdisk = 
-	    Prompt("Which Disk Device is the boot device?", $defrawdisk);
+	$rawbootdisk = Prompt("Which Disk Device is the boot device?",
+			      $defrawdisk);
     }
     return $rawbootdisk;
 }
 
+#
+# Create a list of all disks and their sizes.
+#
+sub DiskList()
+{
+    if (-x $dmesgcmd) {
+	GetDisks($dmesgcmd);
+    }
+
+    # if we didn't grab anything there, try the /var/run file
+    if (@disklist == 0 && -r $dmesgfile) {
+	GetDisks("cat $dmesgfile");
+    }
+
+    return @disklist;
+}
+
+sub DiskSize($)
+{
+    my ($name) = @_;
+
+    if (defined($disksize{$name})) {
+	return $disksize{$name};
+    }
+    return 0;
+}
+
+sub DiskReadable($)
+{
+    my ($disk) = @_;
+    my $dev = "/dev/$disk";
+
+    if (!system("dd if=$dev of=/dev/null bs=512 count=32 >/dev/null 2>&1")) {
+	return(1);
+    }
+    return(0);
+}
+
+sub GetDisks($)
+{
+    my ($cmd) = @_;
+    my @units = (0, 1, 2, 3);
+    my @cmdout = `$cmd`;
+
+    #
+    # Arbitrary: we prefer disk type over unit number;
+    # e.g. ad1 is better than da0.
+    #
+    foreach my $disk (@preferred) {
+	foreach my $unit (@units) {
+	    my $dmesgpat = "^($disk$unit):.* (\\d+)MB.*\$";
+	    foreach my $line (@cmdout) {
+		if ($line =~ /$dmesgpat/) {
+		    my $name = $1;
+		    my $size = $2;
+		    if (!defined($disksize{$name})) {
+			push(@disklist, $name);
+		    }
+		    $disksize{$name} = $size;
+		}
+	    }
+	}
+    }
+}
+
+
 #
 # Write a config file suitable for input to the testbed boot header program.
 #