#!/usr/bin/perl -w use strict; # V. 2.00 # Will create a customized Boot Sector for a partition, ready # to boot io.sys / msdos.sys . Take drive geometry information # from fdisk and from a bootsector extracted after # mkfs.vfat -F 32 /dev/hda1 # dd if=/dev/hda1 of=linux.fat.bs count=3 bs=512 my $Verbose = 1; # Check/Get the arguments, and assign defaults. # if(defined($ARGV[0]) && $ARGV[0] =~/\?/) { print "Syntax:\n"; print " ex: $0 Dev=hda LNX_BS=linux.fat.bs WIN_BS=win98.bs OUT_BS=test.bs \\\n"; print " Nb_Sect=63 Size_Cyl=15120 Size_Sect=512 Nb_Heads=240 Nb_Blocks_hda1=9797760\\\n"; print " Change_Only_Heads=0\n"; print " ex: $0 Dev=hda LNX_BS=linux.fat.bs WIN_BS=win98.bs OUT_BS=test.bs \\\n"; print " Nb_Sect=63 Size_Cyl=16065 Size_Sect=512 Nb_Heads=255 Nb_Blocks_hda1=9775552\\\n"; print " Change_Only_Heads=0\n"; print " ex: $0 Dev=hda LNX_BS=linux.fat.bs WIN_BS=win98.bs OUT_BS=test.bs \\\n"; print " Nb_Sect=63 Size_Cyl=0 Size_Sect=512 Nb_Heads=255 Nb_Blocks_hda1=9766071\\\n"; print " Change_Only_Heads=0\n\n"; print " New: Direct_NTFS=1 => will try to convert BS from fat32 to ntfs\n\n"; exit; } my %ARG = (); { my @Accept = ('Dev', 'LNX_BS', 'WIN_BS', 'OUT_BS', 'Nb_Sect', 'Size_Cyl', 'Size_Sect', 'Nb_Heads', 'Nb_Blocks_hda1', 'Change_Only_Heads', 'Direct_NTFS'); foreach(@Accept) { $ARG{$_} = ''; } foreach(@ARGV) { my(@F) = split(/\=/, $_); foreach(@Accept) { if(lc($_) eq lc($F[0])) { $ARG{$_} = join("=", @F[1..$#F]); $ARG{$_} =~s/^\s*//; $ARG{$_} =~s/\s*$//; last; } } } } $ARG{LNX_BS} = "linux.fat.bs" unless($ARG{LNX_BS}); $ARG{WIN_BS} = "win98.bs" unless($ARG{WIN_BS}); $ARG{OUT_BS} = "test.bs" unless($ARG{OUT_BS}); foreach('Nb_Sect', 'Size_Cyl', 'Size_Sect', 'Nb_Heads', 'Nb_Blocks_hda1', 'Direct_NTFS') { $ARG{$_} = 0 unless($ARG{$_}); } # Find the right device # my $Dev = $ARG{Dev}; unless($Dev) { foreach my $d ('hda', 'hdb', 'sda', 'sdb', 'sra', 'srb') { my $out = `echo |fdisk /dev/$d 2>&1`; $out =~s/^\s*//; $out =~s/\s*$//; if($out !~/^unable to open/i && $out !~/you will not be able to write/i) { $Dev = $d; last; } } unless($Dev) { print "\nCould not find a disk drive.\n"; exit; } } if($Verbose) { print "$$> Dev: [$Dev]\n"; } # Disk geometry retrieving # my $Size_hda1 = 0; { my $out = `echo -e "p\nq"|fdisk /dev/$Dev 2>/dev/null`; if($Verbose) { print "$$> Output fdisk: [$out]\n"; } my @L = split(/\n/, $out); foreach(@L) { if(m/sect.{1,2}rs/i && ! $ARG{Nb_Sect}) { $ARG{Nb_Sect} = $_; $ARG{Nb_Sect} =~s/\n//g; $ARG{Nb_Sect} =~s/^.*( \d+ sect.{1,2}rs).*$/$1/i; $ARG{Nb_Sect} =~s/\D//g; } if(m/sect.{1,2}rs/i && ! $ARG{Nb_Heads}) { $ARG{Nb_Heads} = $_; $ARG{Nb_Heads} =~s/\n//g; $ARG{Nb_Heads} =~s/^\D*//g; $ARG{Nb_Heads} =~s/(\d+) heads.*$/$1/i; $ARG{Nb_Heads} =~s/(\d+) t.{0,2}tes.*$/$1/i; $ARG{Nb_Heads} =~s/\D//g; } if(m/unit.{0,2}s.*cylind..s/i && ! $ARG{Size_Cyl}) { $ARG{Size_Cyl} = $_; $ARG{Size_Cyl} =~s/\n//g; $ARG{Size_Cyl} =~s/^.*(cylind..s .. \d+ ).*$/$1/i; $ARG{Size_Cyl} =~s/\D//g; } if(m/unit.{0,2}s.*cylind..s/i && ! $ARG{Size_Sect}) { $ARG{Size_Sect} = $_; $ARG{Size_Sect} =~s/\n//g; $ARG{Size_Sect} =~s/^.*(\* \d+ ).*$/$1/i; $ARG{Size_Sect} =~s/\D//g; } my $tmp = $Dev."1"; if(m/^\/dev\/$Dev/i && ! $ARG{Nb_Blocks_hda1}) { $ARG{Nb_Blocks_hda1} = $_; $ARG{Nb_Blocks_hda1} =~s/\n//g; $ARG{Nb_Blocks_hda1} =~s/\t/ /g; while($ARG{Nb_Blocks_hda1} =~/ /) { $ARG{Nb_Blocks_hda1} =~s/ / /g; } $ARG{Nb_Blocks_hda1} = (split(/ /, $ARG{Nb_Blocks_hda1}))[4]; $ARG{Nb_Blocks_hda1} =~s/\+//g; } } $Size_hda1 = $ARG{Nb_Blocks_hda1} / $ARG{Size_Sect} * 1024; if($Verbose) { print "$$> Nb of sectors by cylinder: [$ARG{Nb_Sect}]\n"; print "$$> Nb of heads: [$ARG{Nb_Heads}]\n"; print "$$> Size of cylinders: [$ARG{Size_Cyl}]\n"; print "$$> Size of each sector: [$ARG{Size_Sect}]\n"; print "$$> Nb of blocks of hda1: [$ARG{Nb_Blocks_hda1}]\n"; print "$$> Size of hda1: [$Size_hda1]\n"; } } # Beware of the number of heads! # http://howtos.linux.com/howtos/Large-Disk-HOWTO-4.shtml # http://www.pcguide.com/ref/hdd/bios/sizeGB394-c.html # # Ha! we are not alone in the world experiencing trouble # with 2.6.x kernels and disk geometry! # http://www.ces.clemson.edu/linux/fc2.shtml # # Well, if 16, could be either 240 either 255, but most # often 255. Should boot the current OS before smashing it, # then read the correct value, then install our linux/dows. # Say, if 16 then it's 255. # if($ARG{Nb_Heads} == 16 || $ARG{Nb_Heads} == 15 || $ARG{Nb_Heads} == 172 || $ARG{Nb_Heads} == 207) { $ARG{Nb_Heads} = 255; if($Verbose) { print "$$> Nb of heads (Corrected): [$ARG{Nb_Heads}]\n"; } } # One info is lacking: the number of sectors per fat => double word 24h # It's hard to retrieve; let's get it from mkfs.vfat's partition creation. # my(@Nb_Sect_per_FAT) = (); { my $byteCount = 0; open(LNX, "< $ARG{LNX_BS}"); binmode(LNX); while(read(LNX, $b, 1)) { if($byteCount >= 36 && $byteCount <= 39) { push(@Nb_Sect_per_FAT, $b); } ++$byteCount; } close(LNX); } # Creating the bootsector # if($Verbose) { print "\n$$> Writing the BootSector\n"; } my $byteCount = 0; if($ARG{Change_Only_Heads}) { open(IN, "< $ARG{LNX_BS}"); binmode(IN); open(OUT, "> $ARG{OUT_BS}"); binmode(OUT); while(read(IN, $b, 1)) { # 1Ah => nb of heads # if($byteCount == 26) { my $tmp = sprintf("%x", $ARG{Nb_Heads}); while(length($tmp) < 4) { $tmp = "0$tmp"; } if($Verbose) { print "$$> Nb_Heads: will write [$tmp]\n"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 2, 2)))), 0, 1)); } elsif($byteCount == 27) { my $tmp = sprintf("%x", $ARG{Nb_Heads}); while(length($tmp) < 4) { $tmp = "0$tmp"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 0, 2)))), 0, 1)); } else { print(OUT $b); } $byteCount++; } close(IN); close(OUT); } else { open(IN, "< $ARG{WIN_BS}"); binmode(IN); open(OUT, "> $ARG{OUT_BS}"); binmode(OUT); while(read(IN, $b, 1)) { # 0Dh => 08 instead of 10 ?? # #if($byteCount == 13) { # print(OUT substr(pack("i", 8), 0, 1)); #} # 18h => nb of sectors by track # if($byteCount == 24) { my $tmp = sprintf("%x", $ARG{Nb_Sect}); while(length($tmp) < 4) { $tmp = "0$tmp"; } if($Verbose) { print "$$> Nb_Sect: will write [$tmp]\n"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 2, 2)))), 0, 1)); } elsif($byteCount == 25) { my $tmp = sprintf("%x", $ARG{Nb_Sect}); while(length($tmp) < 4) { $tmp = "0$tmp"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 0, 2)))), 0, 1)); } # 1Ah => nb of heads # if($byteCount == 26) { my $tmp = sprintf("%x", $ARG{Nb_Heads}); while(length($tmp) < 4) { $tmp = "0$tmp"; } if($Verbose) { print "$$> Nb_Heads: will write [$tmp]\n"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 2, 2)))), 0, 1)); } elsif($byteCount == 27) { my $tmp = sprintf("%x", $ARG{Nb_Heads}); while(length($tmp) < 4) { $tmp = "0$tmp"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 0, 2)))), 0, 1)); } # 20h => Nb of blocks of boot sector's partition (hda1) # elsif($byteCount == 32) { my $tmp = sprintf("%x", $Size_hda1); while(length($tmp) < 8) { $tmp = "0$tmp"; } if($Verbose) { print "$$> Size_hda1: will write [$tmp]\n"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 6, 2)))), 0, 1)); } elsif($byteCount == 33) { my $tmp = sprintf("%x", $Size_hda1); while(length($tmp) < 8) { $tmp = "0$tmp"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 4, 2)))), 0, 1)); } elsif($byteCount == 34) { my $tmp = sprintf("%x", $Size_hda1); while(length($tmp) < 8) { $tmp = "0$tmp"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 2, 2)))), 0, 1)); } elsif($byteCount == 35) { my $tmp = sprintf("%x", $Size_hda1); while(length($tmp) < 8) { $tmp = "0$tmp"; } print(OUT substr(pack("i", sprintf("%d", hex(substr($tmp, 0, 2)))), 0, 1)); } # 26h => Nb of sectors per FAT # elsif($byteCount >= 36 && $byteCount <= 39) { if($Verbose) { print "$$> Nb_Sect_per_FAT[".($byteCount - 36)."]\n"; } print(OUT $Nb_Sect_per_FAT[$byteCount - 36]); } else { print(OUT $b); } $byteCount++; } close(IN); close(OUT); } if($Verbose) { print "$$> Wrote [$byteCount] bytes. End.\n"; } if($ARG{Direct_NTFS}) { if(-e "./bsnt.1" && -e "./bsnt.2" && -e "./bsnt.3") { my @cmd = ( "dd if=$ARG{OUT_BS} of=/tmp/new count=90 bs=1", "cat bsnt.1 >>/tmp/new", "dd if=$ARG{OUT_BS} of=/tmp/aaa count=488 skip=512 bs=1", "cat /tmp/aaa >>/tmp/new", "cat bsnt.2 >>/tmp/new", "dd if=$ARG{OUT_BS} of=/tmp/aaa count=5138 skip=1006 bs=1", "cat /tmp/aaa >>/tmp/new", "cat bsnt.3 >>/tmp/new", "dd if=$ARG{OUT_BS} of=/tmp/aaa count=1536 skip=6656 bs=1", "cat /tmp/aaa >>/tmp/new", "rm -f /tmp/aaa", "cat /tmp/new >$ARG{OUT_BS}", "rm -f /tmp/new" ); foreach(@cmd) { if($Verbose) { print "$$> [$_]\n"; } system($_); } } else { if($Verbose) { print "$$> bsnt.* files lacking. Wont direct ntfs.\n"; } } }