diff options
author | damien <damien@mandriva.com> | 2000-11-28 16:56:52 +0000 |
---|---|---|
committer | damien <damien@mandriva.com> | 2000-11-28 16:56:52 +0000 |
commit | 0880c7ba8ce88e87fa600aeb367a8f88a3ae71e7 (patch) | |
tree | 33f7ac905998f9ad6d85090f777ee4c0d0c67032 /perl-install/fsedit.pm | |
parent | d5c526273db473a7d87a26000585900fc10dda7d (diff) | |
download | drakx-backup-do-not-use-topic/unlabeled-1.1.1.tar drakx-backup-do-not-use-topic/unlabeled-1.1.1.tar.gz drakx-backup-do-not-use-topic/unlabeled-1.1.1.tar.bz2 drakx-backup-do-not-use-topic/unlabeled-1.1.1.tar.xz drakx-backup-do-not-use-topic/unlabeled-1.1.1.zip |
branch to build the firewall install.topic/unlabeled-1.1.1
Diffstat (limited to 'perl-install/fsedit.pm')
-rw-r--r-- | perl-install/fsedit.pm | 504 |
1 files changed, 378 insertions, 126 deletions
diff --git a/perl-install/fsedit.pm b/perl-install/fsedit.pm index fb2703e8f..6e16f0810 100644 --- a/perl-install/fsedit.pm +++ b/perl-install/fsedit.pm @@ -1,31 +1,53 @@ -package fsedit; +package fsedit; # $Id$ use diagnostics; use strict; -use common qw(:common); +#-###################################################################################### +#- misc imports +#-###################################################################################### +use common qw(:common :constant :functional :file); use partition_table qw(:types); use partition_table_raw; +use detect_devices; +use Data::Dumper; +use fsedit; use devices; +use loopback; use log; +use fs; -1; - +#-##################################################################################### +#- Globals +#-##################################################################################### my @suggestions = ( - { mntpoint => "/boot", minsize => 10 << 11, size => 16 << 11, type => 0x83 }, - { mntpoint => "/", minsize => 50 << 11, size => 100 << 11, type => 0x83 }, - { mntpoint => "swap", minsize => 30 << 11, size => 60 << 11, type => 0x82 }, - { mntpoint => "/usr", minsize => 200 << 11, size => 500 << 11, type => 0x83 }, - { mntpoint => "/home", minsize => 50 << 11, size => 200 << 11, type => 0x83 }, - { mntpoint => "/var", minsize => 200 << 11, size => 250 << 11, type => 0x83 }, - { mntpoint => "/tmp", minsize => 50 << 11, size => 100 << 11, type => 0x83 }, - { mntpoint => "/mnt/iso", minsize => 700 << 11, size => 800 << 11, type => 0x83 }, + { mntpoint => "/boot", size => 16 << 11, type => 0x83, ratio => 1, maxsize => 30 << 11 }, + { mntpoint => "/", size => 50 << 11, type => 0x83, ratio => 1, maxsize => 300 << 11 }, + { mntpoint => "swap", size => 30 << 11, type => 0x82, ratio => 1, maxsize => 250 << 11 }, + { mntpoint => "/usr", size => 200 << 11, type => 0x83, ratio => 6, maxsize =>3000 << 11 }, + { mntpoint => "/home", size => 50 << 11, type => 0x83, ratio => 3 }, + { mntpoint => "/var", size => 200 << 11, type => 0x83, ratio => 1, maxsize =>1000 << 11 }, + { mntpoint => "/tmp", size => 50 << 11, type => 0x83, ratio => 3, maxsize => 500 << 11 }, ); +my @suggestions_mntpoints = ( "/root/", arch() =~ /sparc/ ? "/mnt/sunos" : "/mnt/windows" ); +my @partitions_signatures = ( + [ 0x83, 0x438, "\x53\xEF" ], + [ 0x183, 0x10034, "ReIsErFs" ], + [ 0x82, 4086, "SWAP-SPACE" ], + [ 0x7, 0x1FE, "\x55\xAA", 0x3, "NTFS" ], + [ 0xc, 0x1FE, "\x55\xAA", 0x52, "FAT32" ], +arch() !~ /^sparc/ ? ( + [ 0x6, 0x1FE, "\x55\xAA", 0x36, "FAT" ], +) : (), +); -1; +sub typeOfPart { typeFromMagic(devices::make($_[0]), @partitions_signatures) } -sub hds($$) { +#-###################################################################################### +#- Functions +#-###################################################################################### +sub hds { my ($drives, $flags) = @_; my @hds; my $rc; @@ -33,155 +55,385 @@ sub hds($$) { foreach (@$drives) { my $file = devices::make($_->{device}); - my $hd = partition_table_raw::get_geometry($file) or die "An error occurred while getting the geometry of block device $file: $!"; + my $hd = partition_table_raw::get_geometry($file) or log::l("An error occurred while getting the geometry of block device $file: $!"), next; + $hd = { (%$_, %$hd) }; $hd->{file} = $file; - $hd->{prefix} = $hd->{device} = $_->{device}; - # for RAID arrays of format c0d0p1 + $hd->{prefix} = $hd->{device}; + # for RAID arrays of format c0d0p1 $hd->{prefix} .= "p" if $hd->{prefix} =~ m,(rd|ida)/,; - eval { $rc = partition_table::read($hd, $flags->{clearall}) }; + eval { partition_table::read($hd, $flags->{clearall} || member($_->{device}, @{$flags->{clear} || []})) }; if ($@) { - $@ =~ /bad magic number/ or die; - $flags->{forcezero} && !$::testing ? partition_table_raw::zero_MBR($hd) : die; + partition_table_raw::zero_MBR($hd); + } + member($_->{device}, @{$flags->{clear} || []}) and partition_table::remove($hd, $_) + foreach partition_table::get_normal_parts($hd); + + #- special case for type overloading (eg: reiserfs is 0x183) + foreach (grep { isExt2($_) } partition_table::get_normal_parts($hd)) { + my $type = typeOfPart($_->{device}); + $_->{type} = $type if $type > 0x100; } - $rc ? push @hds, $hd : log::l("An error occurred reading the partition table for the block device $_->{device}"); + push @hds, $hd; } [ @hds ]; } -sub get_fstab(@) { - map { partition_table::get_normal_parts($_) } @_; +sub readProcPartitions { + my ($hds) = @_; + my @parts; + foreach (cat_("/proc/partitions")) { + my (undef, undef, $size, $device) = split; + next if $size eq "1"; #- extended partitions + foreach (@$hds) { + push @parts, { start => 0, size => $size * 2, device => $device, + type => typeOfPart($device), rootDevice => $_->{device} + } if $device =~ /^$_->{device}./; + } + } + @parts; +} + +#- get all normal partition including special ones as found on sparc. +sub get_fstab { + loopback::loopbacks(@_), map { partition_table::get_normal_parts($_) } @_ +} + +#- get normal partition that should be visible for working on. +sub get_visible_fstab { + grep { $_ && !partition_table::isWholedisk($_) && !partition_table::isHiddenMacPart($_) } map { partition_table::get_normal_parts($_) } @_; +} + +sub free_space { + sum map { $_->{size} } map { partition_table::get_holes($_) } @_; +} + +sub is_one_big_fat { + my ($hds) = @_; + @$hds == 1 or return; + + my @l = get_fstab(@$hds); + @l == 1 && isFat($l[0]) && free_space(@$hds) < 10 << 11; +} + + +sub computeSize { + my ($part, $best, $hds, $suggestions) = @_; + my $max = $part->{maxsize} || $part->{size}; + return min($max, $best->{size}) unless $best->{ratio}; + + my $free_space = free_space(@$hds); + my @l = my @L = grep { + if (!has_mntpoint($_->{mntpoint}, $hds) && $free_space >= $_->{size}) { + $free_space -= $_->{size}; + 1; + } else { 0 } } @$suggestions; + + my $tot_ratios = 0; + while (1) { + my $old_free_space = $free_space; + my $old_tot_ratios = $tot_ratios; + + $tot_ratios = sum(map { $_->{ratio} } @l); + last if $tot_ratios == $old_tot_ratios; + + @l = grep { + if ($_->{ratio} && $_->{maxsize} && $tot_ratios && + $_->{size} + $_->{ratio} / $tot_ratios * $old_free_space >= $_->{maxsize}) { + return min($max, $best->{maxsize}) if $best->{mntpoint} eq $_->{mntpoint}; + $free_space -= $_->{maxsize} - $_->{size}; + 0; + } else { + $_->{ratio}; + } + } @l; + } + my $size = int min($max, $best->{size} + $free_space * ($tot_ratios && $best->{ratio} / $tot_ratios)); + #- verify other entry can fill the hole + if (grep { $_->{size} < $max - $size } @L) { $size } else { $max } } -sub suggest_part($$$;$) { - my ($hd, $part, $hds, $suggestions) = @_; +sub suggest_part { + my ($part, $hds, $suggestions) = @_; $suggestions ||= \@suggestions; - foreach (@$suggestions) { $_->{minsize} ||= $_->{size} } - my $has_swap; - my @mntpoints = map { $has_swap ||= isSwap($_); $_->{mntpoint} } get_fstab(@$hds); - my %mntpoints; @mntpoints{@mntpoints} = undef; - my ($best, $second) = - grep { $part->{size} >= $_->{minsize} } - grep { !exists $mntpoints{$_->{mntpoint}} || isSwap($_) && !$has_swap } + my $has_swap = grep { isSwap($_) } get_fstab(@$hds); + + my ($best, $second) = + grep { !$_->{maxsize} || $part->{size} <= $_->{maxsize} } + grep { $_->{size} <= ($part->{maxsize} || $part->{size}) } + grep { !has_mntpoint($_->{mntpoint}, $hds) || isSwap($_) && !$has_swap } + grep { !$_->{hd} || $_->{hd} eq $part->{rootDevice} } + grep { !$part->{type} || $part->{type} == $_->{type} || isTrueFS($part) && isTrueFS($_) } @$suggestions or return; - $best = $second if - $best->{mntpoint} eq '/boot' && - $part->{start} + $best->{minsize} > 1024 * partition_table::cylinder_size($hd); # if the empty slot is beyond the 1024th cylinder, no use having /boot +#- if (arch() =~ /i.86/) { +#- $best = $second if +#- $best->{mntpoint} eq '/boot' && +#- $part->{start} + $best->{size} > 1024 * $hd->cylinder_size(); #- if the empty slot is beyond the 1024th cylinder, no use having /boot +#- } - defined $best or return; # sorry no suggestion :( + defined $best or return; #- sorry no suggestion :( $part->{mntpoint} = $best->{mntpoint}; $part->{type} = $best->{type}; - $part->{size} = min($part->{size}, $best->{size}); + $part->{size} = computeSize($part, $best, $hds, $suggestions); 1; } +sub suggestions_mntpoint { + my ($hds) = @_; + sort grep { !/swap/ && !has_mntpoint($_, $hds) } + (@suggestions_mntpoints, map { $_->{mntpoint} } @suggestions); +} -#sub partitionDrives { -# -# my $cmd = "/sbin/fdisk"; -# -x $cmd or $cmd = "/usr/bin/fdisk"; -# -# my $drives = findDrivesPresent() or die "You don't have any hard drives available! You probably forgot to configure a SCSI controller."; -# -# foreach (@$drives) { -# my $text = "/dev/" . $_->{device}; -# $text .= " - SCSI ID " . $_->{id} if $_->{device} =~ /^sd/; -# $text .= " - Model " . $_->{info}; -# $text .= " array" if $_->{device} =~ /^c.d/; -# -# # truncate at 50 columns for now -# $text = substr $text, 0, 50; -# } -# #TODO TODO -#} - - - -sub checkMountPoint($$) { -# my $type = shift; -# local $_ = shift; -# -# m|^/| or die "The mount point $_ is illegal.\nMount points must begin with a leading /"; -# m|(.)/$| and die "The mount point $_ is illegal.\nMount points may not end with a /"; -# c::isprint($_) or die "The mount point $_ is illegal.\nMount points must be made of printable characters (no accents...)"; -# -# foreach my $dev (qw(/dev /bin /sbin /etc /lib)) { -# /^$dev/ and die "The $_ directory must be on the root filesystem.", -# } -# -# if ($type eq 'linux_native') { -# $_ eq '/'; and return 1; -# foreach my $r (qw(/var /tmp /boot /root)) { -# /^$r/ and return 1; -# } -# die "The mount point $_ is illegal.\nSystem partitions must be on Linux Native partitions"; -# } -# 1; -} - -sub removeFromList($$$) { - my ($start, $end, $list) = @_; - my $err = "error in removeFromList: removing an non-free block"; - - for (my $i = 0; $i < @$list; $i += 2) { - $start < $list->[$i] and die $err; - $start > $list->[$i + 1] and next; - - if ($start == $list->[$i]) { - $end > $list->[$i + 1] and die $err; - if ($end == $list->[$i + 1]) { - # the free block is just the same size, removing it - splice(@$list, 0, 2); - } else { - # the free block now start just after this block - $list->[$i] = $end; - } - } else { - $end <= $list->[$i + 1] or die $err; - if ($end < $list->[$i + 1]) { - splice(@$list, $i + 2, 0, $end, $list->[$i + 1]); - } - $list->[$i + 1] = $start; # shorten the free block +#-sub partitionDrives { +#- +#- my $cmd = "/sbin/fdisk"; +#- -x $cmd or $cmd = "/usr/bin/fdisk"; +#- +#- my $drives = findDrivesPresent() or die "You don't have any hard drives available! You probably forgot to configure a SCSI controller."; +#- +#- foreach (@$drives) { +#- my $text = "/dev/" . $_->{device}; +#- $text .= " - SCSI ID " . $_->{id} if $_->{device} =~ /^sd/; +#- $text .= " - Model " . $_->{info}; +#- $text .= " array" if $_->{device} =~ /^c.d/; +#- +#- #- truncate at 50 columns for now +#- $text = substr $text, 0, 50; +#- } +#- #-TODO TODO +#-} + + +sub mntpoint2part { + my ($mntpoint, $fstab) = @_; + first(grep { $mntpoint eq $_->{mntpoint} } @$fstab); +} +sub has_mntpoint { + my ($mntpoint, $hds) = @_; + mntpoint2part($mntpoint, [ get_fstab(@$hds) ]); +} +sub get_root_ { + my ($fstab, $boot) = @_; + $boot && mntpoint2part("/boot", $fstab) || mntpoint2part("/", $fstab); +} +sub get_root { &get_root_ || {} } + +#- do this before modifying $part->{mntpoint} +#- $part->{mntpoint} should not be used here, use $mntpoint instead +sub check_mntpoint { + my ($mntpoint, $hd, $part, $hds, $loopbackDevice) = @_; + + ref $loopbackDevice or undef $loopbackDevice; + + $mntpoint eq '' || isSwap($part) || isRAID($part) and return; + + local $_ = $mntpoint; + m|^/| or die _("Mount points must begin with a leading /"); +#- m|(.)/$| and die "The mount point $_ is illegal.\nMount points may not end with a /"; + + has_mntpoint($mntpoint, $hds) and die _("There is already a partition with mount point %s\n", $mntpoint); + + my $fake_part = { mntpoint => $mntpoint, device => $loopbackDevice }; + $fake_part->{loopback_file} = 1 if $loopbackDevice; + my $fstab = [ get_fstab(@$hds), $fake_part ]; + my $check; $check = sub { + my ($p, @seen) = @_; + push @seen, $p->{mntpoint} || return; + @seen > 1 && $p->{mntpoint} eq $mntpoint and die _("Circular mounts %s\n", join(", ", @seen)); + if (my $part = fs::up_mount_point($p->{mntpoint}, $fstab)) { + #- '/' carrier is a special case, it will be mounted first + $check->($part, @seen) unless loopback::carryRootLoopback($p); } - return; - } + if (isLoopback($p)) { + $check->($p->{device}, @seen); + } + }; + $check->($fake_part) unless $mntpoint eq '/' && $loopbackDevice; #- '/' is a special case, no loop check + + die "raid / with no /boot" if $mntpoint eq "/" && isMDRAID($part) && !has_mntpoint("/boot", $hds); + die _("This directory should remain within the root filesystem") if member($mntpoint, qw(/bin /dev /etc /lib /sbin)); + die _("You need a true filesystem (ext2, reiserfs) for this mount point\n") if !isTrueFS($part) && member($mntpoint, qw(/ /home /tmp /usr /var)); +#- if ($part->{start} + $part->{size} > 1024 * $hd->cylinder_size() && arch() =~ /i.86/) { +#- die "/boot ending on cylinder > 1024" if $mntpoint eq "/boot"; +#- die "/ ending on cylinder > 1024" if $mntpoint eq "/" && !has_mntpoint("/boot", $hds); +#- } } +sub add($$$;$) { + my ($hd, $part, $hds, $options) = @_; + + isSwap($part) ? + ($part->{mntpoint} = 'swap') : + $options->{force} || check_mntpoint($part->{mntpoint}, $hd, $part, $hds); + + delete $part->{maxsize}; + partition_table::add($hd, $part, $options->{primaryOrExtended}); +} sub allocatePartitions($$) { my ($hds, $to_add) = @_; - my %free_sectors = map { $_->{device} => [1, $_->{totalsectors} ] } @$hds; # first sector is always occupied by the MBR - my $remove = sub { removeFromList($_->{start}, $_->{start} + $_->{size}, $free_sectors{$_->{rootDevice}}) }; - my $success = 0; - - foreach (get_fstab(@$hds)) { &$remove(); } - FSTAB: foreach (@$to_add) { - foreach my $hd (@$hds) { - my $v = $free_sectors{$hd->{device}}; - for (my $i = 0; $i < @$v; $i += 2) { - my $size = $v->[$i + 1] - $v->[$i]; - $_->{size} > $size and next; - $_->{start} = $v->[$i]; - $_->{rootDevice} = $hd->{device}; - partition_table::adjustStartAndEnd($hd, $_); - &$remove(); - partition_table::add($hd, $_); - $success++; - next FSTAB; + foreach my $hd (@$hds) { + foreach (partition_table::get_holes($hd)) { + my ($start, $size) = @$_{"start", "size"}; + my $part; + while (suggest_part($part = { start => $start, size => 0, maxsize => $size, rootDevice => $hd->{device} }, + $hds, $to_add)) { + add($hd, $part, $hds); + $size -= $part->{size} + $part->{start} - $start; + $start = $part->{start} + $part->{size}; } } - log::ld("can't allocate partition $_->{mntpoint} of size $_->{size}, not enough room"); } - $success; } sub auto_allocate($;$) { - my ($hds, $suggestions) = @_; + my ($hds, $suggestions) = @_; allocatePartitions($hds, $suggestions || \@suggestions); map { partition_table::assign_device_numbers($_) } @$hds; } + +sub undo_prepare($) { + my ($hds) = @_; + $Data::Dumper::Purity = 1; + foreach (@$hds) { + my @h = @{$_}{@partition_table::fields2save}; + push @{$_->{undo}}, Data::Dumper->Dump([\@h], ['$h']); + } +} +sub undo($) { + my ($hds) = @_; + foreach (@$hds) { + my $h; eval pop @{$_->{undo}} || next; + @{$_}{@partition_table::fields2save} = @$h; + + $_->{isDirty} = $_->{needKernelReread} = 1 if $_->{hasBeenDirty}; + } +} + +sub move { + my ($hd, $part, $hd2, $sector2) = @_; + + my $part1 = { %$part }; + my $part2 = { %$part }; + $part2->{start} = $sector2; + $part2->{size} += $hd2->cylinder_size() - 1; + partition_table::remove($hd, $part); + { + local ($part2->{notFormatted}, $part2->{isFormatted}); #- do not allow partition::add to change this + partition_table::add($hd2, $part2); + } + + return if $part2->{notFormatted} && !$part2->{isFormatted} || $::testing; + + local (*F, *G); + sysopen F, $hd->{file}, 0 or die ''; + sysopen G, $hd2->{file}, 2 or die _("Error opening %s for writing: %s", $hd2->{file}, "$!"); + + my $base = $part1->{start}; + my $base2 = $part2->{start}; + my $step = 10; + if ($hd eq $hd2) { + $base == $base2 and return; + $step = min($step, abs($base2 - $base)); + + if ($base < $base2) { + $base += $part1->{size} - $step; + $base2 += $part1->{size} - $step; + $step = -$step; + } + } + + my $f = sub { + $base < 0 and $base2 += -$base, $base = 0; + $base2 < 0 and $base += -$base2, $base2 = 0; + c::lseek_sector(fileno(F), $base, 0) or die "seeking to sector $base failed on drive $hd->{device}"; + c::lseek_sector(fileno(G), $base2, 0) or die "seeking to sector $base2 failed on drive $hd2->{device}"; + + my $buf; + sysread F, $buf, $SECTORSIZE * abs($_[0]) or die ''; + syswrite G, $buf; + }; + + for (my $i = 0; $i < $part1->{size} / abs($step); $i++, $base += $step, $base2 += $step) { + print "$base $base2\n"; + &$f($step); + } + if (my $v = ($part1->{size} % abs($step)) * sign($step)) { + $base += $v; + $base2 += $v; + &$f($v); + } +} + +sub change_type($$$) { + my ($hd, $part, $type) = @_; + $type != $part->{type} or return; + $hd->{isDirty} = 1; + $part->{mntpoint} = '' if isSwap($part) && $part->{mntpoint} eq "swap"; + $part->{type} = $type; + $part->{notFormatted} = 1; + $part->{isFormatted} = 0; +} + +sub rescuept($) { + my ($hd) = @_; + my ($ext, @hd); + + my $dev = devices::make($hd->{device}); + local *F; open F, "rescuept $dev|"; + local $_; + while (<F>) { + my ($st, $si, $id) = /start=\s*(\d+),\s*size=\s*(\d+),\s*Id=\s*(\d+)/ or next; + my $part = { start => $st, size => $si, type => hex($id) }; + if (isExtended($part)) { + $ext = $part; + } else { + push @hd, $part; + } + } + close F or die "rescuept failed"; + + partition_table_raw::zero_MBR($hd); + foreach (@hd) { + my $b = partition_table::verifyInside($_, $ext); + if ($b) { + $_->{start}--; + $_->{size}++; + } + local $_->{notFormatted}; + + partition_table::add($hd, $_, ($b ? 'Extended' : 'Primary'), 1); + } +} + +sub verifyHds { + my ($hds, $readonly, $ok) = @_; + + if (is_empty_array_ref($hds)) { #- no way + die _("An error has occurred - no valid devices were found on which to create new filesystems. Please check your hardware for the cause of this problem"); + } + + my @parts = readProcPartitions($hds); + $ok &&= @parts == listlength(get_fstab(@$hds)) unless arch() eq "ppc"; + + if ($readonly && !$ok) { + log::l("using /proc/partitions as diskdrake failed :("); + foreach my $hd (@$hds) { + partition_table_raw::zero_MBR($hd); + $hd->{primary} = { normal => [ grep { $hd->{device} eq $_->{rootDevice} } @parts ] }; + } + $ok = 1; + } + $readonly && get_fstab(@$hds) == 0 and die _("You don't have any partitions!"); + $ok; +} + +#-###################################################################################### +#- Wonderful perl :( +#-###################################################################################### +1; # |