#!/usr/local/bin/perl -w # $Id: cdbootget,v 1.2 2004/01/05 08:59:56 candy Exp candy $ use strict; use Getopt::Std; use vars qw($opt_c); use vars qw($opt_o); use vars qw($opt_v); use vars qw($opt_V); my $SECT = 2048; my $BOOT_REC = 17; sub myseek($$) { my($fd, $offset) = @_; my $pos = tell($fd); my $ret = 0; if ($offset < $pos) { $ret = seek($fd, $offset - $pos, 1); } else { $ret = seek($fd, $offset, 0); } return $ret; } sub read_boot_rec($) { my($fd) = @_; my $err = -1; my $lbuf = ""; if (myseek($fd, $SECT * $BOOT_REC)) { if (read($fd, $lbuf, $SECT) == $SECT) { $err = 0; } } if ($err == -1) { printf(STDERR "Error in read_boot_rec: $!\n"); } return $lbuf; } sub read_boot_catalog($$) { my($fd, $boot_sect) = @_; my $err = -1; my $lbuf = ""; if (myseek($fd, $SECT * $boot_sect)) { if (read($fd, $lbuf, $SECT) == $SECT) { $err = 0; } } if ($err == -1) { printf(STDERR "Error in read_boot_catalog: $!\n"); } return $lbuf; } sub get1($$) { my($s, $o) = @_; return ord(substr($s, $o, 1)); } sub get2($$) { my($s, $o) = @_; return ord(substr($s, $o, 1)) + ord(substr($s, $o + 1, 1)) * 0x100; } sub get4($$) { my($s, $o) = @_; return ord(substr($s, $o, 1)) + ord(substr($s, $o + 1, 1)) * 0x100 + ord(substr($s, $o + 2, 1)) * 0x10000 + ord(substr($s, $o + 3, 1)) * 0x1000000; } sub read_boot_code($) { my($fd) = @_; my $err = -1; my $lbuf = ""; my $boot_rec = read_boot_rec($fd); if ($boot_rec ne "") { my $boot_sect = get4($boot_rec, 0x47); $opt_v && printf(STDERR "bootsect = 0x%04x\n", $boot_sect); my $boot_catalog = read_boot_catalog($fd, $boot_sect); if ($boot_catalog ne "") { my $bootable = get1($boot_catalog, 0x20 + 0x00); my $boot_media_type = get1($boot_catalog, 0x20 + 0x01); my $sect_count = get2($boot_catalog, 0x20 + 0x06); my $load_RBA = get4($boot_catalog, 0x20 + 0x08); my $sect = $boot_media_type == 0 ? 0x200 : 0x800; my $bytes = $sect * $sect_count; $opt_v && printf(STDERR "bootable: 0x%02x\n", $bootable); $opt_v && printf(STDERR "boot_media_type: 0x%02x\n", $boot_media_type); $opt_v && printf(STDERR "sect_count: 0x%04x\n", $sect_count); $opt_v && printf(STDERR "load_RBA: 0x%08x\n", $load_RBA); $opt_v && printf(STDERR "bytes: 0x%04x\n", $bytes); if ($bootable == 0x88) { if (myseek($fd, $SECT * $load_RBA)) { if (read($fd, $lbuf, $bytes) == $bytes) { $err = 0; } } if ($err == -1) { printf(STDERR "$!\n"); } } else { printf(STDERR "not bootable CD\n"); } } } return $lbuf; } sub nain($) { my($fd) = @_; my $lbuf = read_boot_code($fd); if (!$opt_c) { if ($opt_o) { if (open(F, ">$opt_o")) { printf(F "%s", $lbuf); close(F); } else { printf(STDERR "%s: $!\n", $opt_o); } } else { printf("%s", $lbuf); } } } sub main() { my $ex = 1; getopts('co:vV'); if ($opt_V) { printf(STDERR << "END"); usage: $0 [-cvV][-o output] [iso_image_file] Read boot code of iso_image_file and write it to stdout. -c Check only. -o output Write to output instead of stdout. -v verbose -V usage END } else { if ($#ARGV >= 0) { if (open(F, $ARGV[0])) { nain(\*F); close(F); } else { printf(STDERR "%s: $!\n", $ARGV[0]); } } else { nain(\*STDIN); $ex = 0; } } return $ex; } exit(main());