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

tincho-guest at alioth.debian.org tincho-guest at alioth.debian.org
Sun Aug 19 04:38:03 UTC 2007


Author: tincho-guest
Date: 2007-08-19 04:38:02 +0000 (Sun, 19 Aug 2007)
New Revision: 70

Modified:
   pancutan/Makefile.PL
   pancutan/defs/Booting.yaml
   pancutan/tests/Makefile.PL
   pancutan/tests/lib/Pancutan/Test/Booting.pm
Log:
- Added alpha support, splitted a little the flow, but it still is a big messy
  chunk.


Modified: pancutan/Makefile.PL
===================================================================
--- pancutan/Makefile.PL	2007-08-19 04:32:28 UTC (rev 69)
+++ pancutan/Makefile.PL	2007-08-19 04:38:02 UTC (rev 70)
@@ -12,6 +12,7 @@
 		"IO::Select" => 0,
 		POSIX => 0,
 		YAML => 0,
-		"YAML::Syck" => 0
+		"YAML::Syck" => 0,
+		Cwd => 0
 	});
 

Modified: pancutan/defs/Booting.yaml
===================================================================
--- pancutan/defs/Booting.yaml	2007-08-19 04:32:28 UTC (rev 69)
+++ pancutan/defs/Booting.yaml	2007-08-19 04:38:02 UTC (rev 70)
@@ -2,9 +2,9 @@
 ---
 package: Pancutan::Test::Booting
 tasks:
-  read_eltorito:
+  detect_eltorito:
     type: first_cd
-    non_decoupled_sub: read_eltorito
+    non_decoupled_sub: detect_eltorito
     desc: Reads El Torito boot information
     depends: scan_files
   detect_apm_partition:
@@ -15,32 +15,53 @@
   detect_mbr_partition:
     type: first_cd
     non_decoupled_sub: detect_mbr_partition
-    desc: Searches for an Master Boot Record type partition table
+    desc: Searches for a Master Boot Record type partition table
     depends: scan_files
   detect_bsd_partition:
     type: first_cd
     non_decoupled_sub: detect_bsd_partition
-    desc: Searches for an BSD Disklabel type partition table
+    desc: Searches for a BSD Disklabel type partition table
   detect_sparc_partition:
     type: first_cd
     non_decoupled_sub: detect_sparc_partition
-    desc: Searches for an Sparc Disklabel type partition table
+    desc: Searches for a 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
+    desc: Searches for a SGI Disklabel type partition table
     depends: scan_files
-  detect_pmax_partition:
+  detect_pmax_boot:
     type: first_cd
-    non_decoupled_sub: detect_pmax_partition
-    desc: Searches for an PMAX (DECStation/MIPSel) boot block
+    non_decoupled_sub: detect_pmax_boot
+    desc: Searches for a PMAX (DECStation/MIPSel) boot block
     depends: scan_files
+  detect_alpha_boot:
+    type: first_cd
+    non_decoupled_sub: detect_alpha_boot
+    desc: Searches for a Alpha boot block
+    depends: scan_files
+  detect_boot_sequence:
+    type: first_cd
+    non_decoupled_sub: detect_boot_sequence
+    desc: Once the boot method is detected, the next steps are found out
+    depends:
+      - detect_eltorito
+      - detect_apm_partition
+      - detect_mbr_partition
+      - detect_bsd_partition
+      - detect_sparc_partition
+      - detect_sgi_partition
+      - detect_pmax_boot
+      - detect_alpha_boot
 #    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
+  unknown-boot-loader:
+    type: warn
+    desc: I don't understand this boot loader
   missing-boot-element:
     type: error
     desc: Some part of the boot process is missing

Modified: pancutan/tests/Makefile.PL
===================================================================
--- pancutan/tests/Makefile.PL	2007-08-19 04:32:28 UTC (rev 69)
+++ pancutan/tests/Makefile.PL	2007-08-19 04:38:02 UTC (rev 70)
@@ -11,5 +11,8 @@
 		"File::Spec" => 0,
 		"Compress::Zlib" => "2.0005",
 		"Compress::Bzip2" => 0,
+		"Math::BigInt" => 0,
+		"HTML::Entities" => 0,
+		"HTML::PullParser" => 0,
 	}
 );

Modified: pancutan/tests/lib/Pancutan/Test/Booting.pm
===================================================================
--- pancutan/tests/lib/Pancutan/Test/Booting.pm	2007-08-19 04:32:28 UTC (rev 69)
+++ pancutan/tests/lib/Pancutan/Test/Booting.pm	2007-08-19 04:38:02 UTC (rev 70)
@@ -6,8 +6,8 @@
 
 use Pancutan::Util;
 use Fcntl qw(:DEFAULT :seek);
-use Device::Cdio::ISO9660;
-use Device::Cdio::ISO9660::IFS;
+# For portable 64 bit operations
+use Math::BigInt;
 # Yes, this is surreal, I know - for CHRP
 use HTML::Entities;
 use HTML::PullParser;
@@ -148,22 +148,23 @@
 	0xfd => "Linux RAID"
 );
 
-sub read_eltorito {
+sub detect_eltorito {
     my ($meta, $ncd, $scratch) = @_;
     my $file = $meta->{set}[$ncd]{file};
     my @res;
-    my $iso = Device::Cdio::ISO9660::IFS->new(
-        -source => $file) or die "Error opening ISO file: $!";
-    my $boot = $iso->seek_read(17,1);
+    my $fh;
+    sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
+    my $boot = _myread($fh, 17 * 2048, 2048);
     my $stdboot = "\0CD001\1EL TORITO SPECIFICATION".("\0"x41);
     unless(substr($boot, 0, 0x47) eq $stdboot) {
-        $iso->close();
+        close($fh);
         return ();
     }
     info("Detected El Torito bootable image");
     $meta->{set}[$ncd]{boot}{eltorito} = 1;
     my $bcat_ptr = unpack("V", substr($boot, 0x47, 4));
-    my $bcat = $iso->seek_read($bcat_ptr, 1);
+    my $bcat = _myread($fh, $bcat_ptr * 2048, 2048);
+    $fh->close();
     my %platforms = (
         0 => "pc",
         1 => "ppc",
@@ -185,7 +186,6 @@
     # I don't plan on supporting more than 64 boot sections :)
     if(my $chksum = unpack("%16v*", substr($bcat, 0, 0x20)) != 0) {
         #info("Invalid boot catalog checksum: $chksum");
-        #$iso->close();
         push(@res, "invalid-eltorito",
             "Invalid boot catalog checksum: $chksum");
     }
@@ -225,7 +225,6 @@
         my $emul = ord(substr($bcat, $off + 1, 1)) & 0xf;
         my $emudesc;
         if($emul > 4) {
-            $iso->close();
             push(@res, "invalid-eltorito",
                 "Invalid boot catalog entry: media type $emul");
             $emul = "invalid";
@@ -237,36 +236,32 @@
             my @emucodes = qw(noemu 1.2disk 1.44disk 2.88disk hdd);
             $emul = $emucodes[$emul];
         }
-        my $bfile = $scratch->{lsnidx}{$lba};
-        if($bfile) {
+        my $bfile;
+        if(exists $scratch->{lsnidx}{$lba}) {
+            $bfile = $scratch->{lsnidx}{$lba};
             push @{$meta->{set}[$ncd]{boot}{images}}, {
+                method => "eltorito",
+                offset => $lba * 2048,
                 file => $bfile,
                 emul => $emul,
                 platform => $platform
             };
         } else {
             push(@res, "unknown-boot",
-                "Cannot file the file that corresponds to LSN $lba");
-            $bfile = "UNKNOWN";
+                "Cannot find the file that corresponds to LSN $lba");
         }
         info(!$bootable ? "Non-B" : "B",
             "ootable record at offset $off, $sectors sectors, ", 
-            "LBA: $lba, emulation: $emudesc, boot file: $bfile, ",
+            "LBA: $lba, emulation: $emudesc, boot file: ",
+            ($bfile || "unknown"), ", ",
             "platform: $platform, id: $idstr");
-        next unless($bootable);
-        if($emul eq "noemu") {
-            push(@{$meta->{set}[$ncd]{boot}{files}}, [ pc => $bfile ]);
-        } else {
-            push(@{$meta->{set}[$ncd]{boot}{files}}, [ pcimg => $bfile ]);
-        }
     }
-    $iso->close();
     return @res;
 }
 sub detect_apm_partition {
     my ($meta, $ncd, $scratch) = @_;
+    my $file = $meta->{set}[$ncd]{file};
     my $fh;
-    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") { # Magic
@@ -279,6 +274,7 @@
     my $nr = unpack("N", substr($buf, $bs + 4, 4)); # nr of partitions
     info("APM partition table detected: $nr partitions, block size: $bs");
     $buf = _myread($fh, 0, $bs * (1 + $nr));
+    close($fh);
     my @partitions;
     foreach(1..$nr) {
         if(substr($buf, $bs * $_, 2) ne "PM") { # Magic
@@ -327,8 +323,8 @@
         push(@res, "apm-without-hfs", "");
     }
     my @bootfiles;
-    foreach(@partitions) {
-        my($st, @files) = execute(hfsbootfiles => $file, $_->{start});
+    foreach(0..$#partitions) {
+        my($st, @files) = execute(hfsbootfiles => $file, $_ + 1);
         die "Error executing hfsbootfiles: $st\n" if($st);
         push @bootfiles, @files;
     }
@@ -338,67 +334,58 @@
         s/:/\//g;
         if($scratch->{files}{$_}) {
             info("Mac bootfile: $_");
-            push(@{$meta->{set}[$ncd]{boot}{files}}, [ mac => $_ ]);
+            push @{$meta->{set}[$ncd]{boot}{images}}, {
+                method => "mac",
+                file => $_
+            };
         } else {
             push(@res, "unknown-boot", "Cannot find bootfile $_");
         }
     }
-    close($fh);
     return @res;
 }
 sub detect_mbr_partition {
     my ($meta, $ncd, $scratch) = @_;
+    my @res;
     my $file = $meta->{set}[$ncd]{file};
     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") { # Magic
-        close($fh);
-        return ();
-    }
+    close($fh);
+    my @part = _read_mbr($buf) or return();
+    push @res, @{$part[1]};
+    @part = @{$part[0]};
     info("MBR partition detected");
-    my @res;
     foreach(0..3) {
-        my $active = ord(substr($buf, 0x1be + 16 * $_, 1));
-        my $type = ord(substr($buf, 0x1be + 16 * $_ + 4, 1));
-        next unless($type);
-        if($active != 0 and $active != 0x80) {
-            push(@res, "invalid-mbr", "Active flag has invalid value $active");
-        }
-        $active = ($active != 0);
-        my $pdesc;
-        if(!exists $mbrtypes{$type}) {
-            push(@res, "invalid-mbr", "Invalid partition type $type");
-            $pdesc = "unknown";
-        } else {
-            $pdesc = $mbrtypes{$type};
-        }
+        next unless($part[$_]{type});
+        my $start = $part[$_]{start};
+        my $desc = $part[$_]{desc};
+        my $type = $part[$_]{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) {
+        if($start % 2048) {
             push(@res, "invalid-mbr", "Partition " . ($_ + 1) .
                 " points to an out of bounds block");
         }
-        $start /= 4;
-        $size *= 512;
-        info("MBR partition: ", $_ + 1, ", type $pdesc, ",
-            "start LBA: $start, size: $size");
+        $start = int($start / 2048);
+        info("MBR partition: ", $_ + 1, ", type $desc, ",
+            "start LBA: $start, size: $part[$_]{size}");
         if($type == 0x96) { # CHRP
             if($start > 0) {
-                push(@res, "invalid-mbr", "Partition type \"$pdesc\" " .
+                push(@res, "invalid-mbr", "Partition type \"$desc\" " .
                     "should point to the beginning of the ISO image");
             } elsif(! $scratch->{files}{"ppc/bootinfo.txt"}) {
-                push(@res, "invalid-mbr", "Partition type is \"$pdesc\", " .
+                push(@res, "invalid-mbr", "Partition type is \"$desc\", " .
                     "but a CHRP boot definition cannot be found");
             } else {
-                push(@{$meta->{set}[$ncd]{boot}{files}},
-                    [ chrp => "ppc/bootinfo.txt" ]);
+                push @{$meta->{set}[$ncd]{boot}{images}}, {
+                    method => "chrp",
+                    file => "ppc/bootinfo.txt"
+                };
                 info("CHRP boot file: ppc/bootinfo.txt");
             }
             next;
         } elsif($start == 0) {
-            push(@res, "invalid-mbr", "Partition type \"$pdesc\" points to ",
+            push(@res, "invalid-mbr", "Partition type \"$desc\" 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", "Cannot file the file that " .
@@ -407,17 +394,16 @@
         }
         my $bfile = $scratch->{lsnidx}{$start};
         if($type == 0x41) { # PReP
-            push(@{$meta->{set}[$ncd]{boot}{files}},
-                [ prep => $bfile ]);
+            push @{$meta->{set}[$ncd]{boot}{images}}, {
+                method => "prep",
+                file => $bfile
+            };
             info("PReP boot file: $bfile");
         } else {
-            push(@res, "invalid-mbr", "Partition type \"$pdesc\" points to ",
+            push(@res, "invalid-mbr", "Partition type \"$desc\" points to ",
                 "$bfile, but I don't know how to handle it");
-            push(@{$meta->{set}[$ncd]{boot}{files}},
-                [ unknown => $bfile ]);
         }
     }
-    close($fh);
     return @res;
 }
 sub detect_bsd_partition {
@@ -429,12 +415,11 @@
     unless(unpack("V", substr($buf, 0, 4)) == 0x82564557) { # Magic
         $buf = _myread($fh, 512, 512);
     }
+    close($fh);
     unless(unpack("V", substr($buf, 0, 4)) == 0x82564557) { # Can be in sector 1
-        close($fh);
         return ();
     }
     info("BSD disklabel detected");
-    close($fh);
     return(@res);
 }
 sub detect_sparc_partition {
@@ -443,8 +428,8 @@
     my($fh, $buf, @res);
     sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
     $buf = _myread($fh, 0, 512);
+    close($fh);
     unless(unpack("n", substr($buf, 508, 2)) == 0xdabe) { # Magic
-        close($fh);
         return ();
     }
     info("Sparc disklabel detected");
@@ -468,33 +453,21 @@
         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
+        $start *= $cylsize;
         next unless($tag);
         $bootstarts{$start} = 1; # eliminate duplicates, we only care about
                                  # start location
     }
-    my @bootstarts = keys(%bootstarts);
-    unless(@bootstarts) {
+    unless(keys %bootstarts) {
         push(@res, "invalid-sunlabel", "Cannot find any valid partition");
     }
-    foreach(@bootstarts) {
-        # This is not very clear, just in case, we try all slices
-        my $bfile = _myread($fh, $_ * $cylsize, 15 * 512);
-        if(index($bfile, "/boot/second.b") >= 0) {
-            # geez, nothing better to look for
-            info("Detected SILO bootloader");
-            if(! $scratch->{files}{"boot/second.b"}) {
-                push(@res, "missing-boot-element",
-                    "Missing SILO second stage loader");
-            } elsif(! $scratch->{files}{"boot/silo.conf"}) {
-                push(@res, "missing-boot-element",
-                    "Missing SILO configuration file");
-            } else {
-                push(@{$meta->{set}[$ncd]{boot}{files}},
-                    [ silo => "/boot/silo.conf" ]);
-            }
-        }
+    foreach(keys %bootstarts) {
+        info("SPARC boot file at offset $_");
+        push @{$meta->{set}[$ncd]{boot}{images}}, {
+            method => "sparc",
+            offset => $_
+        };
     }
-    close($fh);
     return(@res);
 }
 sub detect_sgi_partition {
@@ -503,8 +476,8 @@
     my($fh, $buf, @res);
     sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
     $buf = _myread($fh, 0, 512);
+    close($fh);
     unless(unpack("N", substr($buf, 0, 4)) == 0x0be5a941) { # Magic
-        close($fh);
         return ();
     }
     info("SGI disklabel detected");
@@ -561,7 +534,6 @@
     }
     if(! $parts[$vhnr]) {
         push(@res, "invalid-sgilabel", "There's no volume header defined");
-        close($fh);
         return(@res);
     }
     foreach(@vhd) {
@@ -572,20 +544,22 @@
         } else {
             my $bfile = $scratch->{lsnidx}{$lsn};
             info("MIPS boot file: $bfile");
-            push(@{$meta->{set}[$ncd]{boot}{files}}, [ mips => $bfile ]);
+            push @{$meta->{set}[$ncd]{boot}{images}}, {
+                method => "mips",
+                file => $bfile
+            };
         }
     }
-    close($fh);
     return(@res);
 }
-sub detect_pmax_partition {
+sub detect_pmax_boot {
     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);
+    close($fh);
     unless(unpack("V", substr($buf, 8, 4)) == 0x0002757a) { # Magic
-        close($fh);
         return ();
     }
     info("PMAX (DECstation/MIPSel) boot block detected");
@@ -603,87 +577,251 @@
     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);
+    push @{$meta->{set}[$ncd]{boot}{images}}, {
+        method => "mipsel",
+        file => $bfile,
+        offset => $start * 2048,
+        size => $size,
+        loadaddr => $loadaddr,
+        execaddr => $execaddr
+    };
+    return(@res);
+}
+sub detect_alpha_boot {
+    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);
     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");
+    my $size = _unpack64le(substr($buf, 60 * 8, 8)) * 512;
+    my $start = _unpack64le(substr($buf, 61 * 8, 8)) / 4;
+    my $chksum = _unpack64le(substr($buf, 63 * 8, 8));
+    my $chkchk = 0;
+    $chkchk += _unpack64le(substr($buf, $_ * 8, 8)) foreach(0..62);
+    $chkchk = _trim64($chkchk);
+    # If we find a valid 64bit checksum we can guess this is an alpha boot
+    return() unless($chkchk == $chksum and $size != 0);
+    info("Alpha boot block detected");
+    if(! exists($scratch->{lsnidx}{$start})) {
+        push(@res, "unknown-boot", "Cannot file the file that " .
+            "corresponds to LSN $start, pointed from the boot block");
+        return(@res);
+    }
+    my $bfile = $scratch->{lsnidx}{$start};
+    push @{$meta->{set}[$ncd]{boot}{images}}, {
+        method => "alpha",
+        file => $bfile,
+        size => $size,
+    };
+    return(@res);
+}
+sub _trim64 {
+    return(shift() & (Math::BigInt->new(1)->blsft(64) - 1));
+}
+sub _unpack64le {
+    return(new Math::BigInt(unpack("V", substr($_[0], 4, 4)))->blsft(32) +
+        unpack("V", substr($_[0], 0, 4)));
+}
+sub detect_boot_sequence {
+    my ($meta, $ncd, $scratch) = @_;
+    my($fh, $buf, @res, @firststage, @initrd);
+    my $file = $meta->{set}[$ncd]{file};
+    sysopen($fh, $file, O_RDONLY) or die "Error opening ISO file: $!";
+    foreach(@{$meta->{set}[$ncd]{boot}{images}}) {
+        use Data::Dumper;
+        print Dumper $_;
+        if($_->{method} eq "eltorito") {
+            $buf = _myread($fh, $_->{offset}, 2048);
+            my $imgtype;
+            if(substr($buf, 0x36, 5) =~ /FAT1[26]/ or
+                substr($buf, 0x52, 5) eq "FAT32") {
+                $imgtype = "fat";
+            } elsif(my @part = _read_mbr($buf)) {
+                push @res, @{$part[1]}; # append errors
+                $imgtype = "hdd";
+            } else {
+                $imgtype = "bin";
+            }
+            my $boottype;
+            if($imgtype eq "fat" and $_->{emul} eq "noemu") {
+                # so, this should be the ia64 hack
+                $boottype = "ia64";
+            } elsif($imgtype eq "fat" and $_->{emul} =~ /disk$/) {
+                $boottype = "pcfat";
+            } elsif($imgtype eq "hdd" and $_->{emul} eq "hdd") {
+                $boottype = "pchdd";
+            } elsif($imgtype eq "bin" and $_->{emul} eq "noemu") {
+                $boottype = "pc";
+            } else {
+                warnn("ElTorito emulation (", $_->{emul},
+                    ") doesn't match image type ($imgtype)");
+                if($imgtype eq "fat") {
+                    $boottype = "pcfat";
+                } elsif($imgtype eq "hdd") {
+                    $boottype = "pchdd";
+                } elsif($imgtype eq "bin") {
+                    $boottype = "pc";
+                }
+            }
+            info("$boottype boot loader $_->{file}");
+            push(@firststage, [ $boottype => $_ ]);
+        } elsif($_->{method} eq "mac" or $_->{method} eq "chrp") {
+        } elsif($_->{method} eq "prep") {
+            push(@initrd, [ prep => $_->{file} ]);
+        } elsif($_->{method} eq "sparc") {
+        # This is not very clear, just in case, we try all slices
+            $buf = _myread($fh, $_->{offset} + 512, 15 * 512);
+            if(index($buf, "/boot/second.b") >= 0) {
+                # geez, nothing better to look for
+                if(! $scratch->{files}{"boot/second.b"}) {
+                    push(@res, "missing-boot-element",
+                        "Missing SILO second stage loader");
+                } elsif(! $scratch->{files}{"boot/silo.conf"}) {
+                    push(@res, "missing-boot-element",
+                        "Missing SILO configuration file");
+                } else {
+                    info("SILO boot loader");
+                    push(@firststage, [ silo => "/boot/silo.conf" ]);
+                }
+            } else {
+                push(@res, "unknown-boot-loader",
+                    "At block " . ($_->{offset} / 512));
+            }
+        } elsif($_->{method} eq "mips") {
+        } elsif($_->{method} eq "mipsel") {
+            my $realsize = $scratch->{files}{$_->{file}}{size};
+            my $realstart = $scratch->{files}{$_->{file}}{LSN} * 2048;
+            $buf = _myread($fh, $realstart, $realsize);
+            my @elfres =_check_mipsel_elf($buf, $_->{offset} - $realstart,
+                $realsize, $_->{loadaddr}, $_->{execaddr});
+            push(@res, @elfres);
+            if(not @elfres and index($buf, "etc/delo.conf") >= 0) {
+                if(! $scratch->{files}{"etc/delo.conf"}) {
+                    push(@res, "missing-boot-element",
+                        "Missing DELO configuration file");
+                } else {
+                    info("DELO boot loader: $_->{file}");
+                    push(@firststage, [ delo => "/etc/delo.conf" ]);
+                }
+            } elsif(not @elfres) {
+                info("Unknown boot loader: $_->{file}");
+            }
+        } elsif($_->{method} eq "alpha") {
         } 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) {
+    return @res;
+}
+sub _myread {
+    my($fh, $pos, $bytes) = @_;
+    my $buf;
+    my $read;
+    sysseek($fh, $pos, SEEK_SET) or die "Error seeking: $!";
+    $read = sysread($fh, $buf, $bytes);
+    if(not defined $read) {
+        die "Error reading ISO file: $!";
+    } elsif($read != $bytes) {
+        die "Short read on ISO file: $read";
+    }
+    return $buf;
+}
+sub _read_mbr {
+    my $buf = shift;
+    unless(substr($buf, 510, 2) eq "\x55\xaa") { # Magic
+        return ();
+    }
+    my(@part, @res);
+    foreach(0..3) {
+        my $active = ord(substr($buf, 0x1be + 16 * $_, 1));
+        my $type = ord(substr($buf, 0x1be + 16 * $_ + 4, 1));
+        # Start is in 512-byte blocks
+        my $start = unpack("V", substr($buf, 0x1be + 16 * $_ + 8, 4)) * 512;
+        my $size = unpack("V", substr($buf, 0x1be + 16 * $_ + 12, 4)) * 512;
+        if($active != 0 and $active != 0x80) {
+            push(@res, "invalid-mbr", "Active flag has invalid value $active");
+        }
+        $active = ($active != 0);
+        my $pdesc;
+        if(!exists $mbrtypes{$type}) {
+            push(@res, "invalid-mbr", "Invalid partition type $type");
+            $pdesc = $type;
+        } else {
+            $pdesc = $mbrtypes{$type};
+        }
+        $part[$_] = {
+            active => $active,
+            type => $type, 
+            desc => $pdesc, 
+            start => $start,
+            size => $size
+        };
+    }
+    return(\@part, \@res);
+}
+sub _check_mipsel_elf {
+    my($buf, $textoffset, $size, $loadaddr, $execaddr) = @_;
+    my @res;
+    my $magic = substr($buf, 0, 4);
+    if($textoffset == 0) {
         # 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 " .
+        if($magic eq "\x7fELF") {
+            return("invalid-boot-element", "The boot block points to " .
                 "the beginning of an ELF file, which cannot be executed by ",
                 "MIPSel firmware");
         }
-        return(@res);
+        return();
     }
-    # Parse ELF header -- this is neverending...
-    if(substr($buf, 0, 4) ne "\x7fELF") {
-        push(@res, "invalid-boot-element", "The boot block points inside a " .
+    # Parse ELF header
+    if($magic ne "\x7fELF") {
+        return("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");
+    my $ei_class = ord(substr($buf, 4, 1));
+    my $ei_data = ord(substr($buf, 5, 1));
+    my $ei_version = ord(substr($buf, 6, 1));
+    my $ehdr_etype = unpack("v", substr($buf, 16, 2));
+    my $ehdr_emachine = unpack("v", substr($buf, 18, 2));
+    my $ehdr_eversion = unpack("V", substr($buf, 20, 4));
+    my $phoff = unpack("V", substr($buf, 28, 4));
+    my $phnum = unpack("v", substr($buf, 44, 2));
+    if($ei_class != 1 # ELFCLASS32
+            or $ei_data != 1 # ELFDATA2LSB
+            or $ei_version != 1 # EV_CURRENT
+            or $ehdr_etype != 2 # ET_EXEC
+            or $ehdr_emachine != 8 # EM_MIPS
+            or $ehdr_eversion != 1) { # EV_CURRENT
+        return("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");
+        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");
-        }
+    my @myph = grep( {
+            $textoffset == unpack("V", substr($buf, $phoff + $_ * 32 + 4, 4))
+        } (0..($phnum - 1)));
+    if(not @myph) {
+        push(@res, "invalid-boot-element",
+            "The boot block doesn't point to any program section");
         return(@res);
     }
-    push(@res, "invalid-boot-element", "The boot block doesn't point to any " .
-        "program section");
+    my $myphoff = $myph[0] * 32 + $phoff;
+    if(unpack("V", substr($buf, $myphoff + 8, 4)) != $loadaddr) {
+        push(@res, "invalid-boot-element", "Load address mismatch");
+    }
+    unless(unpack("V", substr($buf, $myphoff + 24, 4)) & 1) {
+        push(@res, "invalid-boot-element", "ELF segment is not executable");
+    }
     return(@res);
 }
-sub _myread {
-    my($fh, $pos, $bytes) = @_;
-    my $buf;
-    my $read;
-    sysseek($fh, $pos, SEEK_SET) or die "Error seeking: $!";
-    $read = sysread($fh, $buf, $bytes);
-    if(not defined $read) {
-        die "Error reading ISO file: $!";
-    } elsif($read != $bytes) {
-        die "Short read on ISO file: $read";
-    }
-    return $buf;
-}
 1;
 
 =head1 NAME




More information about the Pancutan-commits mailing list