[Pancutan-commits] r58 - in pancutan: defs tests/lib/Pancutan/Test

tincho-guest at alioth.debian.org tincho-guest at alioth.debian.org
Mon Aug 13 22:31:22 UTC 2007


Author: tincho-guest
Date: 2007-08-13 22:31:22 +0000 (Mon, 13 Aug 2007)
New Revision: 58

Modified:
   pancutan/defs/Booting.yaml
   pancutan/tests/lib/Pancutan/Test/Booting.pm
   pancutan/tests/lib/Pancutan/Test/Files.pm
Log:
- Booting: added mips and mipsel support
- Files: added caching of size of files


Modified: pancutan/defs/Booting.yaml
===================================================================
--- pancutan/defs/Booting.yaml	2007-08-13 13:47:50 UTC (rev 57)
+++ pancutan/defs/Booting.yaml	2007-08-13 22:31:22 UTC (rev 58)
@@ -26,14 +26,30 @@
     non_decoupled_sub: detect_sparc_partition
     desc: Searches for an Sparc Disklabel type partition table
     depends: scan_files
+  detect_sgi_partition:
+    type: first_cd
+    non_decoupled_sub: detect_sgi_partition
+    desc: Searches for an SGI Disklabel type partition table
+    depends: scan_files
+  detect_pmax_partition:
+    type: first_cd
+    non_decoupled_sub: detect_pmax_partition
+    desc: Searches for an PMAX (DECStation/MIPSel) boot block
+    depends: scan_files
 #    desc: Scans the image for boot loaders (isolinux, yaboot, etc)
 errors:
+  unknown-boot:
+    type: warn
+    desc: The bootable image cannot be mapped to a file
+  missing-boot-element:
+    type: error
+    desc: Some part of the boot process is missing
+  invalid-boot-element:
+    type: error
+    desc: Some part of the boot process is invalid
   invalid-eltorito:
     type: error
     desc: El Torito specification found, but it's invalid or contains errors
-  unknown-boot:
-    type: warn
-    desc: The bootable image cannot be mapped to a file
   invalid-apm:
     type: error
     desc: APM partition table found, but it's invalid or contains errors
@@ -46,6 +62,6 @@
   invalid-sunlabel:
     type: error
     desc: Sun Disklabel partition table found, but it's invalid or contains errors
-  missing-boot-element:
+  invalid-sgilabel:
     type: error
-    desc: Some part of the boot process is missing
+    desc: SGI Disklabel partition table found, but it's invalid or contains errors

Modified: pancutan/tests/lib/Pancutan/Test/Booting.pm
===================================================================
--- pancutan/tests/lib/Pancutan/Test/Booting.pm	2007-08-13 13:47:50 UTC (rev 57)
+++ pancutan/tests/lib/Pancutan/Test/Booting.pm	2007-08-13 22:31:22 UTC (rev 58)
@@ -127,6 +127,26 @@
 	0x8e => "Linux LVM",
 	0xfd => "LInux RAID"
 );
+my %sgitypes = ( # Taken from fdisk
+	0x00 => "SGI volhdr",
+	0x01 => "SGI trkrepl",
+	0x02 => "SGI secrepl",
+	0x03 => "SGI raw",
+	0x04 => "SGI bsd",
+	0x05 => "SGI sysv",
+	0x06 => "SGI volume",
+	0x07 => "SGI efs",
+	0x08 => "SGI lvol",
+	0x09 => "SGI rlvol",
+	0x0a => "SGI xfs",
+	0x0b => "SGI xfslog",
+	0x0c => "SGI xlv",
+	0x0d => "SGI xvm",
+	0x82 => "Linux swap",
+	0x83 => "Linux native",
+	0x8e => "Linux LVM",
+	0xfd => "Linux RAID"
+);
 
 sub read_eltorito {
     my ($meta, $ncd, $scratch) = @_;
@@ -249,7 +269,7 @@
     my $file = $meta->{set}[$ncd]{file};
     sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
     my $buf = _myread($fh, 0, 1024);
-    if(substr($buf, 0, 2) ne "ER") {
+    if(substr($buf, 0, 2) ne "ER") { # Magic
         close($fh);
         return ();
     }
@@ -261,7 +281,7 @@
     $buf = _myread($fh, 0, $bs * (1 + $nr));
     my @partitions;
     foreach(1..$nr) {
-        if(substr($buf, $bs * $_, 2) ne "PM") {
+        if(substr($buf, $bs * $_, 2) ne "PM") { # Magic
             push(@res, "invalid-apm", "Invalid signature in APM partition $_: "
                 . substr($buf, $bs * $_, 2));
             next;
@@ -320,7 +340,7 @@
             info("Mac bootfile: $_");
             push(@{$meta->{set}[$ncd]{boot}{files}}, [ mac => $_ ]);
         } else {
-            push(@res, "unknown-boot", "Cannot find $_");
+            push(@res, "unknown-boot", "Cannot find bootfile $_");
         }
     }
     close($fh);
@@ -332,7 +352,7 @@
     my $fh;
     sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
     my $buf = _myread($fh, 0, 512);
-    unless(substr($buf, 510, 2) eq "\x55\xaa") {
+    unless(substr($buf, 510, 2) eq "\x55\xaa") { # Magic
         close($fh);
         return ();
     }
@@ -353,6 +373,7 @@
         } else {
             $pdesc = $mbrtypes{$type};
         }
+        # Start is in 512-byte blocks
         my $start = unpack("V", substr($buf, 0x1be + 16 * $_ + 8, 4));
         my $size = unpack("V", substr($buf, 0x1be + 16 * $_ + 12, 4));
         if($start % 4) {
@@ -380,8 +401,8 @@
             push(@res, "invalid-mbr", "Partition type \"$pdesc\" points to ",
                 "beggining of ISO image, but I don't know how to handle it");
         } elsif(not exists($scratch->{lsnidx}{$start})) {
-            push(@res, "unknown-boot", "Partition " . ($_ + 1) .
-                " points to block $start");
+            push(@res, "unknown-boot", "Cannot file the file that " .
+                "corresponds to LSN $start, pointed by partition ". ($_ + 1));
             next;
         }
         my $bfile = $scratch->{lsnidx}{$start};
@@ -405,10 +426,10 @@
     my($fh, $buf, @res);
     sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
     $buf = _myread($fh, 0, 512);
-    unless(unpack("V", substr($buf, 0, 4)) == 0x82564557) {
+    unless(unpack("V", substr($buf, 0, 4)) == 0x82564557) { # Magic
         $buf = _myread($fh, 512, 512);
     }
-    unless(unpack("V", substr($buf, 0, 4)) == 0x82564557) {
+    unless(unpack("V", substr($buf, 0, 4)) == 0x82564557) { # Can be in sector 1
         close($fh);
         return ();
     }
@@ -422,7 +443,7 @@
     my($fh, $buf, @res);
     sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
     $buf = _myread($fh, 0, 512);
-    unless(unpack("n", substr($buf, 508, 2)) == 0xdabe) {
+    unless(unpack("n", substr($buf, 508, 2)) == 0xdabe) { # Magic
         close($fh);
         return ();
     }
@@ -430,9 +451,9 @@
     my $label = unpack("Z*", substr($buf, 0, 128));
     my $volname = unpack("Z*", substr($buf, 132, 8));
     my $nr = unpack("n", substr($buf, 140, 2));
-    my $sane = unpack("N", substr($buf, 188, 4));
+    my $sane = unpack("N", substr($buf, 188, 4)); # Validation?
     my $cylsize = (unpack("n", substr($buf, 436, 2)) *
-        unpack("n", substr($buf, 438, 2)));
+        unpack("n", substr($buf, 438, 2))); # Size of cyls
     my $chksum = 0;
     $chksum ^= $_ foreach(unpack("n*", $buf));
     if($chksum) {
@@ -443,10 +464,10 @@
     }
     my %bootstarts;
     foreach(0..($nr - 1)) {
-        my $tag = unpack("n", substr($buf, 142 + $_ * 4, 2));
-        my $lag = unpack("n", substr($buf, 144 + $_ * 4, 2));
-        my $start = unpack("N", substr($buf, 444 + $_ * 8, 4));
-        my $size = unpack("N", substr($buf, 448 + $_ * 8, 4));
+        my $tag = unpack("n", substr($buf, 142 + $_ * 4, 2)); # part type
+        my $flag = unpack("n", substr($buf, 144 + $_ * 4, 2)); # RO, unmountable
+        my $start = unpack("N", substr($buf, 444 + $_ * 8, 4)); # start cyl
+        my $size = unpack("N", substr($buf, 448 + $_ * 8, 4)); # blocks
         next unless($tag);
         $bootstarts{$start} = 1; # eliminate duplicates, we only care about
                                  # start location
@@ -476,6 +497,180 @@
     close($fh);
     return(@res);
 }
+sub detect_sgi_partition {
+    my ($meta, $ncd, $scratch) = @_;
+    my $file = $meta->{set}[$ncd]{file};
+    my($fh, $buf, @res);
+    sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
+    $buf = _myread($fh, 0, 512);
+    unless(unpack("N", substr($buf, 0, 4)) == 0x0be5a941) { # Magic
+        close($fh);
+        return ();
+    }
+    info("SGI disklabel detected");
+    my $rootpt = unpack("n", substr($buf, 4, 2));
+    my $swappt = unpack("n", substr($buf, 6, 2));
+    my $bootfile = unpack("Z*", substr($buf, 8, 16));
+    my $chksum = unpack("%32N*", $buf);
+    if($chksum) {
+        push(@res, "invalid-sgilabel", "Invalid checksum: $chksum");
+    }
+    my @vhd;
+    foreach(0..14) {
+        my $vhfname = unpack("Z*", substr($buf, 72 + 16 * $_, 8));
+        my $vhfstart = unpack("N", substr($buf, 80 + 16 * $_, 4));
+        my $vhfsize = unpack("N", substr($buf, 84 + 16 * $_, 4));
+        next unless($vhfsize);
+        push @vhd, {
+            name => $vhfname,
+            start => $vhfstart,
+            size => $vhfsize
+        };
+    }
+    my @parts;
+    my $vhnr = 8;
+    foreach(0..15) {
+        my $partsize = unpack("N", substr($buf, 312 + 12 * $_, 4));
+        my $partstart = unpack("N", substr($buf, 316 + 12 * $_, 4));
+        my $parttype = unpack("N", substr($buf, 320 + 12 * $_, 4));
+        next unless($partsize);
+        $parts[$_] = {
+            type => $parttype,
+            start => $partstart,
+            size => $partsize
+        };
+        unless(exists $sgitypes{$parttype}) {
+            push(@res, "invalid-sgilabel", "Partition type $parttype unknown");
+        }
+        if($_ != 10 and $parttype == 3) {
+            push(@res, "invalid-sgilabel", "Raw partition in wrong position");
+        }
+        if($parttype == 3 and $partstart != 0) {
+            push(@res, "invalid-sgilabel", "Raw partition starts in ",
+                "sector $partstart");
+        }
+        if($_ != 8 and $parttype == 0) {
+            push(@res, "invalid-sgilabel", "Volume Header in wrong position");
+            $vhnr = $_;
+        }
+        info("SGI Partition: ", $_ + 1, ", type: $sgitypes{$parttype}, ",
+            "start: $partstart, size: $partsize");
+    }
+    if(! $parts[10]) {
+        push(@res, "invalid-sgilabel", "There's no raw partition defined");
+    }
+    if(! $parts[$vhnr]) {
+        push(@res, "invalid-sgilabel", "There's no volume header defined");
+        close($fh);
+        return(@res);
+    }
+    foreach(@vhd) {
+        my $lsn = ($parts[8]{start} + $_->{start}) / 4;
+        if(! exists($scratch->{lsnidx}{$lsn})) {
+            push(@res, "unknown-boot", "Cannot file the file that " .
+                "corresponds to LSN $lsn, named $_->{name} in the VHD");
+        } else {
+            my $bfile = $scratch->{lsnidx}{$lsn};
+            info("MIPS boot file: $bfile");
+            push(@{$meta->{set}[$ncd]{boot}{files}}, [ mips => $bfile ]);
+        }
+    }
+    close($fh);
+    return(@res);
+}
+sub detect_pmax_partition {
+    my ($meta, $ncd, $scratch) = @_;
+    my $file = $meta->{set}[$ncd]{file};
+    my($fh, $buf, @res);
+    sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
+    $buf = _myread($fh, 0, 512);
+    unless(unpack("V", substr($buf, 8, 4)) == 0x0002757a) { # Magic
+        close($fh);
+        return ();
+    }
+    info("PMAX (DECstation/MIPSel) boot block detected");
+    my $loadaddr = unpack("V", substr($buf, 16, 4));
+    my $execaddr = unpack("V", substr($buf, 20, 4));
+    my $size = unpack("V", substr($buf, 24, 4));
+    my $start = unpack("V", substr($buf, 28, 4)) / 4; # 512-byte blocks
+    my $realstart = $start;
+    if(! exists($scratch->{lsnidx}{$realstart})) {
+        # Biggest block less that start, as this should map into an elf file
+        my @firstfiles = grep({ $_ <= $start } sort({ $a <=> $b }
+                keys %{$scratch->{lsnidx}}));
+        $realstart = $firstfiles[-1];
+    }
+    if(! exists($scratch->{lsnidx}{$realstart})) {
+        push(@res, "unknown-boot", "Cannot file the file that " .
+            "corresponds to LSN $start, pointed from the boot block");
+        close($fh);
+        return(@res);
+    }
+    my $bfile = $scratch->{lsnidx}{$realstart};
+    my $realsize = $scratch->{files}{$bfile}{size};
+    $buf = _myread($fh, $realstart * 2048, $realsize);
+    close($fh);
+    if(index($buf, "etc/delo.conf") >= 0) {
+        info("DELO boot loader: $bfile");
+        if(! $scratch->{files}{"etc/delo.conf"}) {
+            push(@res, "missing-boot-element",
+                "Missing DELO configuration file");
+        } else {
+            push(@{$meta->{set}[$ncd]{boot}{files}}, [ delo => $bfile ]);
+        }
+    } else {
+        info("Unknown boot loader: $bfile");
+        push(@{$meta->{set}[$ncd]{boot}{files}}, [ mipsel => $bfile ]);
+    }
+    if($realstart == $start) {
+        # OK, so this should NOT be an ELF, but a raw binary
+        if(substr($buf, 0, 4) eq "\x7fELF") {
+            push(@res, "invalid-boot-element", "The boot block points to " .
+                "the beginning of an ELF file, which cannot be executed by ",
+                "MIPSel firmware");
+        }
+        return(@res);
+    }
+    # Parse ELF header -- this is neverending...
+    if(substr($buf, 0, 4) ne "\x7fELF") {
+        push(@res, "invalid-boot-element", "The boot block points inside a " .
+            "file I cannot understand (not ELF)");
+        return(@res);
+    }
+    unless(ord(substr($buf, 4, 1)) == 1 and # EI_CLASS == ELFCLASS32
+        ord(substr($buf, 5, 1)) == 1 and # EI_DATA == ELFDATA2LSB
+        ord(substr($buf, 6, 1)) == 1 and # EI_VERSION == EV_CURRENT
+        unpack("v", substr($buf, 16, 2)) == 2 and # ehdr.e_type == ET_EXEC
+        unpack("v", substr($buf, 18, 2)) == 8 and # ehdr.e_machine == EM_MIPS
+        unpack("V", substr($buf, 20, 4)) == 1) { # ehdr.e_version == EV_CURRENT
+        push(@res, "invalid-boot-element", "The boot file is not a MIPS " .
+            "ELF32 little endian file");
+    }
+    if(unpack("V", substr($buf, 24, 4)) != $execaddr) {
+        push(@res, "invalid-boot-element", "Exec address mismatch");
+    }
+    my $phoff = unpack("V", substr($buf, 28, 4));
+    my $phnum = unpack("v", substr($buf, 44, 2));
+    if($phnum == 0 or $phoff == 0) {
+        push(@res, "invalid-boot-element", "ELF file doesn't have program ".
+            "sections");
+        return(@res);
+    }
+    foreach(0..($phnum - 1)) {
+        my $p_offset = unpack("V", substr($buf, $phoff + $_ * 32 + 4, 4));
+        next unless(($start - $realstart) * 2048 == $p_offset);
+        if(unpack("V", substr($buf, $phoff + $_ * 32 + 8, 4)) != $loadaddr) {
+            push(@res, "invalid-boot-element", "Load address mismatch");
+        }
+        unless(unpack("V", substr($buf, $phoff + $_ * 32 + 24, 4)) & 1) {
+            push(@res, "invalid-boot-element", "ELF segment is not executable");
+        }
+        return(@res);
+    }
+    push(@res, "invalid-boot-element", "The boot block doesn't point to any " .
+        "program section");
+    return(@res);
+}
 sub _myread {
     my($fh, $pos, $bytes) = @_;
     my $buf;

Modified: pancutan/tests/lib/Pancutan/Test/Files.pm
===================================================================
--- pancutan/tests/lib/Pancutan/Test/Files.pm	2007-08-13 13:47:50 UTC (rev 57)
+++ pancutan/tests/lib/Pancutan/Test/Files.pm	2007-08-13 22:31:22 UTC (rev 58)
@@ -14,26 +14,29 @@
 sub scan_files_slave {
     my($global, $ncd, $scratch) = @_;
     my $cd = $global->{set}[$ncd];
-	my $file = $global->{set}[$ncd]{file};
-	my $iso = Device::Cdio::ISO9660::IFS->new(
-		-source => $file) or die "Error opening ISO file: $!";
+    my $file = $cd->{file};
+    my $iso = Device::Cdio::ISO9660::IFS->new(
+        -source => $file) or die "Error opening ISO file: $!";
     my $basedir = canonpath($cd->{mount});
     my @files;
     find({ wanted => sub {
                 push @files, abs2rel($_, $basedir) if(-f);
             }, no_chdir => 1}, $basedir);
-    my @lsns = map {
+    my @stats = map {
         my $s = $iso->stat($_);
         defined($s) or die "Can't stat file $_";
-        $s->{LSN} } @files;
+        ($s->{LSN}, $s->{size}) } @files;
     $iso->close();
-    return \@files, \@lsns;
+    return \@files, \@stats;
 }
 sub scan_files_master {
-    my($global, $ncd, $scratch, $files, $lsns) = @_;
+    my($global, $ncd, $scratch, $files, $stats) = @_;
     foreach(0..$#{$files}) {
-        $scratch->{files}{$files->[$_]} = { LSN => $lsns->[$_] };
-        $scratch->{lsnidx}{$lsns->[$_]} = $files->[$_];
+        $scratch->{files}{$files->[$_]} = {
+            LSN => $stats->[$_*2],
+            size => $stats->[$_*2+1],
+        };
+        $scratch->{lsnidx}{$stats->[$_*2]} = $files->[$_];
     }
     $scratch->{filelist} = [ @$files ];
     debug(scalar @$files, " files found");




More information about the Pancutan-commits mailing list