[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