From 65de520b0e041afd8dfebfdfd3666cb97e93bb45 Mon Sep 17 00:00:00 2001
From: Mike Hibler <hibler@cs.utah.edu>
Date: Tue, 6 May 2014 08:26:33 -0600
Subject: [PATCH] Add "relocatable" flag to images table to indicate that an
 image can be moved.

Hopefully, my last schema change related to images. If relocatable is not
set then an image must be loaded at the lba_low offset. If set, then the
image can be loaded at other offsets. Currently, all FBSD images are
relocatable courtesy of the relocation mechanism in imagezip (which can
fix up otherwise absolute offsets in an image). Sadly, Linux images are
not relocatable due to absolute block numbers in the grub partition
bootblock that we require. Ryan "taught" imagezip to relocate these, but
I need to find his changes.
---
 db/Image.pm.in          | 69 +++++++++++++++++++++++++++++++++++++----
 sql/database-create.sql |  1 +
 sql/database-fill.sql   |  1 +
 sql/updates/4/392       | 26 ++++++++++++++++
 utils/imageinfo.in      | 20 +++++++++---
 5 files changed, 107 insertions(+), 10 deletions(-)
 create mode 100644 sql/updates/4/392

diff --git a/db/Image.pm.in b/db/Image.pm.in
index 2def9f6332..7d3e1c2397 100644
--- a/db/Image.pm.in
+++ b/db/Image.pm.in
@@ -212,7 +212,7 @@ sub ActiveImages($)
 #
 sub ListAll($$$)
 {
-    my ($class, $format, $pid);
+    my ($class, $format, $pid) = @_;
     my @result = ();
 
     my $clause = "";
@@ -886,6 +886,36 @@ sub GetUpdate($$)
     return -1;
 }
 
+#
+# Get the disk offset at which the image will be loaded.
+# For a "whole disk" (loadpart == 0) image, it is always 0.
+# For a "partition" image, it depends on the MBR type of the image.
+#
+# Returns -1 if the offset could not be determined (e.g., unknown MBR).
+#
+sub GetDiskOffset($)
+{
+    my ($self) = @_;
+
+    # XXX these should come out of the DB or not exist at all!
+    my %mbr = (
+	"1" => [0, 63,  6281415, 12562830, 12819870],
+	"2" => [0, 63, 12305853, 24611643, 26712000]
+    );
+
+    # Must be a real reference. 
+    return -1
+	if (! ref($self));
+
+    return -1
+	if (! exists($mbr{$self->mbr_version()}));
+
+    return -1
+	if ($self->loadpart() > 4);
+
+    return $mbr{$self->mbr_version()}[$self->loadpart()];
+}
+
 #
 # Mark the update time in the record,
 #
@@ -950,24 +980,51 @@ sub SetHash($$)
     return 0;
 }
 
+#
+# Set the size.
+#
+sub SetSize($$)
+{
+    my ($self, $size) = @_;
+
+    # Must be a real reference. 
+    return -1
+	if (! ref($self));
+
+    my $imageid   = $self->imageid();
+
+    return -1
+	if (! DBQueryWarn("update images set size=$size " .
+			  "where imageid='$imageid'"));
+
+    return 0;
+}
+
 #
 # Set the sector range of an image.
+# Note that lba_size and reloc flag are left alone unless explicitly specified.
 #
-sub SetRange($$$;$)
+sub SetRange($$$;$$)
 {
-    my ($self,$start,$end,$ssize) = @_;
+    my ($self,$start,$end,$ssize,$isreloc) = @_;
 
     # Must be a real reference. 
     return -1
 	if (! ref($self));
 
     my $imageid = $self->imageid();
-    $ssize = 512
-	if (!defined($ssize));
+
+    my $clause = "";
+    if (defined($ssize)) {
+	$clause .= ",lba_size=$ssize";
+    }
+    if (defined($isreloc)) {
+	$clause .= ",relocatable=$isreloc";
+    }
 
     return -1
 	if (! DBQueryWarn("update images set ".
-			  "  lba_low=$start,lba_high=$end,lba_size=$ssize ".
+			  "  lba_low=$start,lba_high=$end$clause ".
 			  "where imageid='$imageid'"));
 
     return 0;
diff --git a/sql/database-create.sql b/sql/database-create.sql
index 33c9d4977a..34ef99a1df 100644
--- a/sql/database-create.sql
+++ b/sql/database-create.sql
@@ -1930,6 +1930,7 @@ CREATE TABLE `images` (
   `lba_low` bigint(20) unsigned NOT NULL default '0',
   `lba_high` bigint(20) unsigned NOT NULL default '0',
   `lba_size` int(10) unsigned NOT NULL default '512',
+  `relocatable` tinyint(1) NOT NULL default '0',
   `locked` datetime default NULL,
   `locker_pid` int(11) default '0',
   `metadata_url` tinytext,
diff --git a/sql/database-fill.sql b/sql/database-fill.sql
index c269475418..069bfb6165 100644
--- a/sql/database-fill.sql
+++ b/sql/database-fill.sql
@@ -1061,6 +1061,7 @@ REPLACE INTO `table_regex` VALUES ('images','size','int','redirect','default:big
 REPLACE INTO `table_regex` VALUES ('images','lba_low','int','redirect','default:bigint',0,0,NULL);
 REPLACE INTO `table_regex` VALUES ('images','lba_high','int','redirect','default:bigint',0,0,NULL);
 REPLACE INTO `table_regex` VALUES ('images','lba_size','int','redirect','default:int',0,0,NULL);
+REPLACE INTO table_regex VALUES ('images','relocatable','text','redirect','default:boolean',0,0,NULL);
 REPLACE INTO table_regex VALUES ('node_types','new_type','text','redirect','default:tinytext',0,0,NULL);
 REPLACE INTO table_regex VALUES ('node_types','node_type','text','regex','^[-\\w]+$',1,30,NULL);
 REPLACE INTO table_regex VALUES ('node_types','class','text','regex','^[\\w]+$',1,30,NULL);
diff --git a/sql/updates/4/392 b/sql/updates/4/392
new file mode 100644
index 0000000000..9a8129a415
--- /dev/null
+++ b/sql/updates/4/392
@@ -0,0 +1,26 @@
+#
+# Add the relocatable flag to indicate whether the lba_low field must
+# be respected (0) or whether the image is "position independent" (1).
+#
+use strict;
+use libdb;
+
+sub DoUpdate($$$)
+{
+    my ($dbhandle, $dbname, $version) = @_;
+
+    if (!DBSlotExists("images", "relocatable")) {
+	DBQueryFatal("ALTER TABLE images ADD ".
+		     "`relocatable` tinyint(1) NOT NULL default '0' ".
+		     "   AFTER lba_size");
+
+	DBQueryFatal("REPLACE INTO table_regex VALUES ".
+		     "('images','relocatable','text','redirect',".
+		     "'default:boolean',0,0,NULL)");
+    }
+    return 0;
+}
+
+# Local Variables:
+# mode:perl
+# End:
diff --git a/utils/imageinfo.in b/utils/imageinfo.in
index 9799bbae39..2093a60929 100644
--- a/utils/imageinfo.in
+++ b/utils/imageinfo.in
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 #
-# Copyright (c) 2012 University of Utah and the Flux Group.
+# Copyright (c) 2012-2014 University of Utah and the Flux Group.
 # 
 # {{{EMULAB-LICENSE
 # 
@@ -138,21 +138,32 @@ if (! -R $imagepath) {
     }
 }
 
-my ($isize, $imtime, $secmin, $secmax);
+my ($isize, $imtime, $secmin, $secmax, $relocatable);
 
 #
-# Use imagedump to get the sector range. It prints:
+# Use imagedump to get the sector range and whether the image is relocatable.
+# It prints:
 # ...
+#   1 relocations covering 276 bytes
 #   covered sector range: [0-12305790]
 # ...
+# Note that even if an image has no relocations, it might still be relocatable.
+# But, this is the best we can do!
 #
+$relocatable = 0;
 if ($showrange) {
     if (-x $imagedump) {
 	foreach my $line (`$imagedump $imagepath 2>&1`) {
 	    if ($line =~ /covered sector range: \[(\d+)-(\d+)\]/) {
 		$secmin = $1;
 		$secmax = $2;
-		last;
+		next;
+	    }
+	    if ($line =~ /(\d+) relocations covering/) {
+		if ($1 > 0) {
+		    $relocatable = 1;
+		}
+		next;
 	    }
 	}
     }
@@ -198,6 +209,7 @@ if ($showall) {
     printf "minsect=%lu\n", $secmin;
     printf "maxsect=%lu\n", $secmax;
     printf "secsize=512\n";
+    printf "relocatable=%d\n", $relocatable;
 }
 
 exit(0);
-- 
GitLab