package fsedit; # $Id$ use diagnostics; use strict; use vars qw(%suggestions); #-###################################################################################### #- misc imports #-###################################################################################### use common; use partition_table qw(:types); use partition_table::raw; use detect_devices; use fsedit; use devices; use loopback; use log; use fs; %suggestions = ( __("simple") => [ { mntpoint => "/", size => 300 << 11, type =>0x483, ratio => 5, maxsize =>5500 << 11 }, { mntpoint => "swap", size => 64 << 11, type => 0x82, ratio => 1, maxsize => 250 << 11 }, { mntpoint => "/home", size => 300 << 11, type =>0x483, ratio => 3 }, ], __("with /usr") => [ { mntpoint => "/", size => 150 << 11, type =>0x483, ratio => 1, maxsize =>1000 << 11 }, { mntpoint => "swap", size => 64 << 11, type => 0x82, ratio => 1, maxsize => 250 << 11 }, { mntpoint => "/usr", size => 300 << 11, type =>0x483, ratio => 4, maxsize =>4000 << 11 }, { mntpoint => "/home", size => 100 << 11, type =>0x483, ratio => 3 }, ], __("server") => [ { mntpoint => "/", size => 150 << 11, type =>0x483, ratio => 1, maxsize => 250 << 11 }, { mntpoint => "swap", size => 64 << 11, type => 0x82, ratio => 2, maxsize => 400 << 11 }, { mntpoint => "/usr", size => 300 << 11, type =>0x483, ratio => 4, maxsize =>4000 << 11 }, { mntpoint => "/var", size => 150 << 11, type =>0x483, ratio => 3 }, { mntpoint => "/home", size => 150 << 11, type =>0x483, ratio => 3 }, { mntpoint => "/tmp", size => 150 << 11, type =>0x483, ratio => 2, maxsize => 500 << 11 }, ], ); foreach (values %suggestions) { if (arch() =~ /ia64/) { @$_ = ({ mntpoint => "/boot/efi", size => 50 << 11, type => 0xb, ratio => 1, maxsize => 150 << 11 }, @$_); } } my @suggestions_mntpoints = ( "/var/ftp", "/var/www", "/boot", arch() =~ /sparc/ ? "/mnt/sunos" : arch() =~ /ppc/ ? "/mnt/macos" : "/mnt/windows", #- RedHat also has /usr/local and /opt ); my @partitions_signatures = ( [ 0x8e, 0, "HM\1\0" ], [ 0x83, 0x438, "\x53\xEF" ], [ 0x183, 0x10034, "ReIsErFs" ], [ 0x183, 0x10034, "ReIsEr2Fs" ], [ 0x283, 0, 'XFSB', 0x200, 'XAGF', 0x400, 'XAGI' ], [ 0x383, 0x8000, 'JFS1' ], [ 0x82, 4086, "SWAP-SPACE" ], [ 0x82, 4086, "SWAPSPACE2" ], [ 0x7, 0x1FE, "\x55\xAA", 0x3, "NTFS" ], [ 0xc, 0x1FE, "\x55\xAA", 0x52, "FAT32" ], arch() !~ /^sparc/ ? ( [ 0x6, 0x1FE, "\x55\xAA", 0x36, "FAT" ], ) : (), ); sub typeOfPart { my $dev = devices::make($_[0]); my $t = typeFromMagic($dev, @partitions_signatures); if ($t == 0x83) { #- there is no magic to differentiate ext3 and ext2. Using libext2fs #- to check if it has a journal $t = 0x483 if c::is_ext3($dev); } $t; } #-###################################################################################### #- Functions #-###################################################################################### sub empty_all_hds { { hds => [], lvms => [], raids => [], loopbacks => [], raw_hds => [], nfss => [], smbs => [], davs => [], special => [] }; } sub recompute_loopbacks { my ($all_hds) = @_; my @fstab = get_all_fstab($all_hds); @{$all_hds->{loopbacks}} = map { isPartOfLoopback($_) ? @{$_->{loopback}} : () } @fstab; } sub raids { my ($hds) = @_; my @parts = get_fstab(@$hds); { my @l = grep { isRawRAID($_) } @parts or return []; detect_devices::raidAutoStart(@l); } fs::get_major_minor(@parts); my %devname2part = map { $_->{dev} => { %$_, device => $_->{dev} } } read_proc_partitions_raw(); my @raids; my @mdstat = cat_("/proc/mdstat"); for (my $i = 0; $i < @mdstat; $i++) { my ($nb, $level, $mdparts) = #- line format is: #- md%d : {in}?active{ (read-only)}? {linear|raid1|raid4|raid5}{ DEVNAME[%d]{(F)}?}* $mdstat[$i] =~ /^md(.).* ([^ \[\]]+) (\S+\[\d+\].*)/ or next; $level =~ s/raid//; #- { linear | raid0 | raid1 | raid5 } -> { linear | 0 | 1 | 5 } my $chunks = $mdstat[$i+1] =~ /(\S+) chunks/ ? $1 : "64k"; my @raw_mdparts = map { /([^\[]+)/ } split ' ', $mdparts; my @mdparts = map { my $mdpart = $devname2part{$_} || { device => $_ }; if (my ($part) = grep { is_same_hd($mdpart, $_) } @parts) { $part->{raid} = $nb; delete $part->{mntpoint}; $part; } else { #- forget it when not found? that way it won't break much... beurk. (); } } @raw_mdparts; my $type = typeOfPart("md$nb"); log::l("RAID: found md$nb (raid $level) chunks $chunks ", if_($type, "type $type "), "with parts ", join(", ", @raw_mdparts)); $raids[$nb] = { 'chunk-size' => $chunks, type => $type || 0x83, disks => \@mdparts, device => "md$nb", notFormatted => !$type, level => $level }; } require raid; raid::update(@raids); \@raids; } sub lvms { my ($all_hds) = @_; my @pvs = grep { isRawLVM($_) } get_all_fstab($all_hds) or return; #- otherwise vgscan won't find them devices::make($_->{device}) foreach @pvs; require lvm; my @lvms; foreach (@pvs) { my $name = lvm::get_vg($_) or next; my ($lvm) = grep { $_->{VG_name} eq $name } @lvms; if (!$lvm) { $lvm = bless { disks => [], VG_name => $name }, 'lvm'; lvm::update_size($lvm); lvm::get_lvs($lvm); push @lvms, $lvm; } $_->{lvm} = $name; push @{$lvm->{disks}}, $_; } @lvms; } sub hds { my ($flags, $ask_before_blanking) = @_; $flags ||= {}; $flags->{readonly} && ($flags->{clearall} || $flags->{clear}) and die "conflicting flags readonly and clear/clearall"; my @drives = detect_devices::hds(); my (@hds); foreach my $hd (@drives) { $hd->{file} = devices::make($hd->{device}); $hd->{prefix} ||= $hd->{device}; $hd->{readonly} = $flags->{readonly}; my $h = partition_table::raw::get_geometry($hd->{file}) or log::l("An error occurred while getting the geometry of block device $hd->{file}: $!"), next; add2hash_($hd, $h); eval { partition_table::raw::test_for_bad_drives($hd) if $::isInstall }; if (my $err = $@) { if ($err =~ /write error:/) { $hd->{readonly} = 1; } else { cdie $err if $err !~ /read error:/; next; } } if ($flags->{clearall} || member($hd->{device}, @{$flags->{clear} || []})) { partition_table::raw::zero_MBR_and_dirty($hd); } else { eval { partition_table::read($hd); compare_with_proc_partitions($hd) if $::isInstall; }; if (my $err = $@) { if ($hd->{readonly}) { use_proc_partitions($hd); } elsif ($ask_before_blanking && $ask_before_blanking->($hd->{device}, $err)) { partition_table::raw::zero_MBR($hd); } else { #- using it readonly use_proc_partitions($hd); } } member($_->{device}, @{$flags->{clear} || []}) and partition_table::remove($hd, $_) foreach partition_table::get_normal_parts($hd); } # special case for Various type $_->{type} = typeOfPart($_->{device}) || 0x100 foreach grep { $_->{type} == 0x100 } 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 || $type && $hd->isa('partition_table::gpt'); } push @hds, $hd; } #- detect raids before LVM allowing LVM on raid my $raids = raids(\@hds); my $all_hds = { %{ empty_all_hds() }, hds => \@hds, lvms => [], raids => $raids }; $all_hds->{lvms} = [ lvms($all_hds) ]; fs::get_major_minor(get_all_fstab($all_hds)); $all_hds; } sub get_hds { #- $in is optional my ($flags, $in) = @_; if ($in) { catch_cdie { hds($flags, sub { my ($dev, $err) = @_; $in->ask_yesorno(_("Error"), _("I can't read the partition table of device %s, it's too corrupted for me :( I can try to go on, erasing over bad partitions (ALL DATA will be lost!). The other solution is to not allow DrakX to modify the partition table. (the error is %s) Do you agree to loose all the partitions? ", $dev, formatError($err))); }) } sub { $in->ask_okcancel('', formatError($@)) }; } else { catch_cdie { hds($flags) } sub { 1 } } } sub read_proc_partitions_raw() { my (undef, undef, @all) = cat_("/proc/partitions"); grep { $_->{size} != 1 && # skip main extended partition $_->{size} != 0x3fffffff # skip cdroms (otherwise stops cd-audios) } map { my %l; @l{qw(major minor size dev)} = split; \%l; } @all; } sub read_proc_partitions { my ($hds) = @_; my @all = read_proc_partitions_raw(); my @parts = grep { $_->{dev} =~ /\d$/ } @all; my @disks = grep { $_->{dev} !~ /\d$/ } @all; my $devfs_like = grep { $_->{dev} =~ m|/disc$| } @disks; my %devfs2normal = map { my (undef, $major, $minor) = devices::entry($_->{device}); my ($disk) = grep { $_->{major} == $major && $_->{minor} == $minor } @disks; $disk->{dev} => $_->{device}; } @$hds; my $prev_part; foreach my $part (@parts) { my $dev; if ($devfs_like) { $dev = -e "/dev/$part->{dev}" ? $part->{dev} : sprintf("0x%x%02x", $part->{major}, $part->{minor}); $part->{rootDevice} = $devfs2normal{dirname($part->{dev}) . '/disc'}; } else { $dev = $part->{dev}; foreach my $hd (@$hds) { $part->{rootDevice} = $hd->{device} if $part->{dev} =~ /^$hd->{device}./; } } $part->{device} = $dev; $part->{size} *= 2; # from KB to sectors $part->{type} = typeOfPart($dev); $part->{start} = $prev_part ? $prev_part->{start} + $prev_part->{size} : 0; $prev_part = $part; delete $part->{dev}; # cleanup } @parts; } sub all_hds { my ($all_hds) = @_; (@{$all_hds->{hds}}, @{$all_hds->{lvms}}); } sub part2hd { my ($part, $all_hds) = @_; my ($hd) = grep { $part->{rootDevice} eq ($_->{device} || $_->{VG_name}) } all_hds($all_hds); $hd; } sub is_same_hd { my ($hd1, $hd2) = @_; if ($hd1->{major} && $hd2->{major}) { $hd1->{major} == $hd2->{major} && $hd1->{minor} == $hd2->{minoUpdated Romanian translation