diff options
Diffstat (limited to 'perl-install/partition_table/raw.pm')
| -rw-r--r-- | perl-install/partition_table/raw.pm | 225 | 
1 files changed, 171 insertions, 54 deletions
| diff --git a/perl-install/partition_table/raw.pm b/perl-install/partition_table/raw.pm index e01f9c1c3..453a19c6c 100644 --- a/perl-install/partition_table/raw.pm +++ b/perl-install/partition_table/raw.pm @@ -1,4 +1,4 @@ -package partition_table::raw; # $Id$ +package partition_table::raw;  use diagnostics;  use strict; @@ -6,20 +6,36 @@ use strict;  use common;  use devices;  use detect_devices; +use fs::type;  use log;  use c;  my @MBR_signatures = ( -if_(arch() =~ /ppc/, -    map { [ 'yaboot', 0, "PM", 0x200 * $_ + 0x10, "bootstrap\0" ] } 0 .. 61 -),      [ 'empty', 0, "\0\0\0\0" ],      [ 'grub', 0, "\xEBG", 0x17d, "stage1 \0" ],      [ 'grub', 0, "\xEBH", 0x17e, "stage1 \0" ],      [ 'grub', 0, "\xEBH", 0x18a, "stage1 \0" ], -    [ 'grub', 0, "\xEBH", 0x181, "GRUB \0" ], +    sub { my ($F) = @_; +	  #- standard grub has no good magic (Mageia's grub is patched to have "GRUB" at offset 6) +	  #- so scanning a range of possible places where grub can have its string +	  #- 0x176 found on Conectiva 10 +	  my ($min, $max, $magic) = (0x176, 0x181, "GRUB \0"); +	  my $tmp; +	  sysseek($F, 0, 0) && sysread($F, $tmp, $max + length($magic)) or return; +	  substr($tmp, 0, 2) eq "\xEBH" or return; +	  index($tmp, $magic, $min) >= 0 && "grub"; +      }, +    sub { my ($F) = @_; +          #- similar to grub-legacy, grub2 doesn't seem to have good magic +          #- so scanning a range of possible places where grub can have its string +          my ($min, $max, $magic) = (0x176, 0x188, "GRUB"); +          my $tmp; +          sysseek($F, 0, 0) && sysread($F, $tmp, $max + length($magic)) or return; +    	  index($tmp, $magic, $min) >= 0 && "grub2"; +      },      [ 'lilo', 0x2,  "LILO" ],      [ 'lilo', 0x6,  "LILO" ], +    [ 'lilo', 0x6 + 0x40,  "LILO" ], #- when relocated in lilo's bsect_update(), variable "space" on paragraph boundary gives 0x40      [ 'grub', 0x6,  "GRUB" ],      [ 'osbs', 0x2,  "OSBS" ], #- http://www.prz.tu-berlin.de/~wolf/os-bs.html      [ 'pqmagic', 0xef, "PQV" ], @@ -44,6 +60,7 @@ if_(arch() =~ /ppc/,  sub typeOfMBR($) { typeFromMagic(devices::make($_[0]), @MBR_signatures) }  sub typeOfMBR_($) { typeFromMagic($_[0], @MBR_signatures) } +sub use_pt_type { 0 }  sub hasExtended { 0 }  sub set_best_geometry_for_the_partition_table {} @@ -56,19 +73,13 @@ sub last_usable_sector {      my ($hd) = @_;      $hd->{totalsectors};  } +# no limit +sub max_partition_start { 1e99 } +sub max_partition_size { 1e99 } -#- default method for starting a partition, only head size or twice -#- is allowed for starting a partition after a cylinder boundarie. -sub adjustStart($$) { -    my ($hd, $part) = @_; -    my $end = $part->{start} + $part->{size}; +#- default method for starting a partition +sub adjustStart($$) {} -    $part->{start} = round_up($part->{start}, -			      $part->{start} % cylinder_size($hd) < 2 * $hd->{geom}{sectors} ? -   			      $hd->{geom}{sectors} : cylinder_size($hd)); -    $part->{size} = $end - $part->{start}; -    $part->{size} > 0 or die "adjustStart get a too small partition to handle correctly"; -}  #- adjusting end to match a cylinder boundary, two methods are used and must  #- match at the end, else something is wrong and nothing will be done on  #- partition table. @@ -91,27 +102,96 @@ sub adjustEnd($$) {  sub compute_nb_cylinders {      my ($geom, $totalsectors) = @_; -    $geom->{cylinders} = int $totalsectors / $geom->{heads} / $geom->{sectors}; +    if ($geom->{heads} && $geom->{sectors}) { +	$geom->{cylinders} = int $totalsectors / $geom->{heads} / $geom->{sectors}; +    } +} + +sub keep_non_duplicates { +    my %l; +    $l{$_->[0]}++ foreach @_; +    map { @$_ } grep { $l{$_->[0]} == 1 } @_; +} + +sub get_geometries { +    my (@hds) = @_; + +    @hds = grep { +	if ($_->{bus} =~ /dmraid/) { +	    sysopen(my $F, $_->{file}, 0); +	    my $total = c::total_sectors(fileno $F); +	    my %geom; +	    $geom{heads} = 255; +	    $geom{sectors} = 63; +	    $geom{start} = 1; +	    compute_nb_cylinders(\%geom, $total); +	    $geom{totalcylinders} = $geom{cylinders}; +	    log::l("Fake geometry on " . $_->{file} . ": heads=$geom{heads} sectors=$geom{sectors} cylinders=$geom{cylinders} start=$geom{start}"); +	    add2hash_($_, { totalsectors => $total, geom => \%geom }); +	    1; +        } elsif (my $h = get_geometry($_->{file})) { +	    add2hash_($_, $h); +	    1; +	} else { +	    log::l("An error occurred while getting the geometry of block device $_->{file}: $!"); +	    0; +	} +    } @hds; + +    my %id2hd = keep_non_duplicates(map { +	my $F = openit($_) or log::l("failed to open device $_->{device}"); +	my $tmp; +	if ($F && c::lseek_sector(fileno($F), 0, 0x1b8) && sysread($F, $tmp, 4)) { +	    [ sprintf('0x%08x', unpack('V', $tmp)), $_ ]; +	} else { +	    (); +	} +    } @hds); + + +    my %id2edd = keep_non_duplicates(map { [ scalar(chomp_(cat_("$_/mbr_signature"))), $_ ] } glob("/sys/firmware/edd/int13_dev*")); + +    log::l("id2hd: " . join(' ', map_each { "$::a=>$::b->{device}" } %id2hd)); +    log::l("id2edd: " . join(' ', map_each { "$::a=>$::b" } %id2edd)); + +    foreach my $id (keys %id2hd) { +	my $hd = $id2hd{$id}; +	$hd->{volume_id} = $id; + +	if (my $edd_dir = $id2edd{$id}) { +	    $hd->{bios_from_edd} = $1 if $edd_dir =~ /int13_dev(.*)/; + +	    require partition_table::dos; +	    my $geom = partition_table::dos::geometry_from_edd($hd, $edd_dir); +	    $hd->{geom} = $geom if $geom; +	} +    } + +    @hds;  } -sub get_geometry($) { +sub get_geometry {      my ($dev) = @_; +    sysopen(my $F, $dev, 0) or return; + +    my $total = c::total_sectors(fileno $F); +      my $g = ""; +    my %geom; +    if (ioctl($F, c::HDIO_GETGEO(), $g)) { +	@geom{qw(heads sectors cylinders start)} = unpack "CCSL", $g; +	log::l("HDIO_GETGEO on $dev succeeded: heads=$geom{heads} sectors=$geom{sectors} cylinders=$geom{cylinders} start=$geom{start}"); +	$geom{totalcylinders} = $geom{cylinders}; -    sysopen(my $F, $dev, 0) or return; -    ioctl($F, c::HDIO_GETGEO(), $g) or return; -    my %geom; @geom{qw(heads sectors cylinders start)} = unpack "CCSL", $g; -    $geom{totalcylinders} = $geom{cylinders}; - -    my $total; -    #- $geom{cylinders} is no good (only a ushort, that means less than 2^16 => at best 512MB) -    if ($total = c::total_sectors(fileno $F)) { -	compute_nb_cylinders(\%geom, $total); -    } else { -	$total = $geom{heads} * $geom{sectors} * $geom{cylinders} +	#- $geom{cylinders} is no good (only a ushort, that means less than 2^16 => at best 512MB) +	if ($total) { +	    compute_nb_cylinders(\%geom, $total); +	} else { +	    $total = $geom{heads} * $geom{sectors} * $geom{cylinders}; +	}      } -    { geom => \%geom, totalsectors => $total }; +    { totalsectors => $total, if_($geom{heads}, geom => \%geom) };  }  sub openit {  @@ -119,74 +199,111 @@ sub openit {      my $F; sysopen($F, $hd->{file}, $o_mode || 0) && $F;  } +sub can_add { +    my ($hd) = @_; +    !$_->{size} && !$_->{pt_type} || isExtended($_) and return 1 foreach @{$hd->{primary}{raw}}; +    0; +} +  sub raw_removed {      my ($_hd, $_raw) = @_;  }  sub can_raw_add {      my ($hd) = @_; -    $_->{size} || $_->{type} or return 1 foreach @{$hd->{primary}{raw}}; +    $_->{size} || $_->{pt_type} or return 1 foreach @{$hd->{primary}{raw}};      0;  }  sub raw_add {      my ($_hd, $raw, $part) = @_;      foreach (@$raw) { -	$_->{size} || $_->{type} and next; +	$_->{size} || $_->{pt_type} and next;  	$_ = $part;  	return;      }      die "raw_add: partition table already full";  } -sub zero_MBR { +sub zero_MBR { &partition_table::initialize } #- deprecated + +#- deprecated +sub zero_MBR_and_dirty {  +    my ($hd) = @_; +    fsedit::partition_table_clear_and_initialize([], $hd); +} + +#- by default, we assume the kernel doesn't automatically reread partition table: +sub need_to_tell_kernel { +    my ($_hd) = @_; +    1; +} + +sub read_primary {      my ($hd) = @_; -    #- force the standard partition type for the architecture -    my $type = arch() =~ /ia64/ ? 'gpt' : arch() eq "alpha" ? "bsd" : arch() =~ /^sparc/ ? "sun" : arch() eq "ppc" ? "mac" : "dos"; -    #- override standard mac type on PPC for IBM machines to dos -    $type = "dos" if arch() =~ /ppc/ && detect_devices::get_mac_model() =~ /^IBM/; -    require "partition_table/$type.pm"; -    bless $hd, "partition_table::$type"; -    $hd->{primary} = $hd->clear_raw; -    delete $hd->{extended}; + +    my ($pt, $info) = eval { $hd->read_one(0) }; +    $pt or return; +    my $primary = partition_table::raw::pt_info_to_primary($hd, $pt, $info); +    $primary->{is_hybrid_iso} = $hd->{current_pt_table_type} eq 'dos' && $hd->{fs_type_from_magic} eq 'iso9660'; +    $hd->{primary} = $primary; +    undef $hd->{extended}; +    partition_table::verifyPrimary($primary); +    1;  } -sub zero_MBR_and_dirty { -    my ($hd) = @_;     -    my @parts = (partition_table::get_normal_parts($hd), if_($hd->{primary}{extended}, $hd->{primary}{extended})); -    partition_table::will_tell_kernel($hd, del => $_) foreach @parts; -    zero_MBR($hd); +sub pt_info_to_primary { +    my ($hd, $pt, $info) = @_; + +    my @extended = $hd->hasExtended ? grep { isExtended($_) } @$pt : (); +    my @normal = grep { $_->{size} && !isEmpty($_) && !isExtended($_) } @$pt; +    my $nb_special_empty = int(grep { $_->{size} && isEmpty($_) } @$pt); + +    @extended > 1 and die "more than one extended partition"; + +    put_in_hash($_, partition_table::hd2minimal_part($hd)) foreach @normal, @extended; +    { raw => $pt, extended => $extended[0], normal => \@normal, info => $info, nb_special_empty => $nb_special_empty };  }  #- ugly stuff needed mainly for Western Digital IDE drives  #- try writing what we've just read, yells if it fails  #- testing on last sector of head #0 (unused in 99% cases)  #- -#- return false if the device can't be written to (especially for Smartmedia) +#- return false if the device cannot be written to (especially for Smartmedia)  sub test_for_bad_drives {      my ($hd) = @_; -    log::l("test_for_bad_drives($hd->{file})"); -    my $sector = $hd->{geom}{sectors} - 1; +    my $sector = $hd->{geom} ? $hd->{geom}{sectors} - 1 : 0; +    log::l("test_for_bad_drives($hd->{file} on sector #$sector)");      sub error { die "$_[0] error: $_[1]" } -    my $F = openit($hd, $::testing ? 0 : 2) or error(openit($hd) ? 'write' : 'read', "can't open device"); +    my $F = openit($hd, $::testing ? 0 : 2) or error(openit($hd) ? 'write' : 'read', "cannot open device");      my $seek = sub {  	c::lseek_sector(fileno($F), $sector, 0) or error('read', "seeking to sector $sector failed");      };      my $tmp; -    &$seek; sysread $F, $tmp, $SECTORSIZE or error('read', "can't even read ($!)"); +    &$seek; sysread $F, $tmp, $SECTORSIZE or error('read', "cannot even read ($!)");      return if $hd->{readonly} || $::testing; -    &$seek; syswrite $F, $tmp or error('write', "can't even write ($!)"); +    &$seek; syswrite $F, $tmp or error('write', "cannot even write ($!)");      my $tmp2; -    &$seek; sysread $F, $tmp2, $SECTORSIZE or die "test_for_bad_drives: can't even read again ($!)"; +    &$seek; sysread $F, $tmp2, $SECTORSIZE or die "test_for_bad_drives: cannot even read again ($!)";      $tmp eq $tmp2 or die -N("Something bad is happening on your drive.  +N("Something bad is happening on your hard disk drive.   A test to check the integrity of data has failed.   It means writing anything on the disk will end up with random, corrupted data.");  } +sub start_write { +    my ($_hd) = @_; +    1; +} + +sub end_write { +    my ($_hd, $_handle) = @_; +    1; +} +  1; | 
