package diskdrake; use common qw(:common :functional :file); use resize_fat::main; use my_gtk qw(:helpers :wrappers :ask); use partition_table qw(:types); use devices; use raid; use fsedit; use fs; my @actions4free = __("Create"); my @actions4mounted = __("Unmount"); my @actions4nonmounted = (__("Type"), __("Resize"), __("Delete"), __("Format"));#, __("Move")); my @actions4nonmountedfs = __("Mount point"); my @actions4expert = qw(Move Active Type); my @actions4expertOrStandalone = qw(Format Mount); my @actionsnot4raid = qw(Resize Move); my (%hds_widget, %part_widget); my ($width, $height, $minwidth) = (400, 50, 5); my ($w, $current_part, $action_widget, $action_text, $info_widget, $notebook_widget); my ($hds, $Raid, $raid, $in, $part_suggestions); my ($buttons1, $buttons2); $buttons1->{buttons} = [ [ 0, 0, __("Write /etc/fstab") => \&WriteFstab ], [ 0,-1, __("Toggle to expert mode") => sub { $::expert = 1 } ], [ 0, 0, __("Toggle to normal mode") => sub { $::expert = 0 } ], [ 0, 0, __("Restore from file") => \&ReadFromFile ], [ 0, 0, __("Save in file") => \&SaveInFile ], [-1, 0, __("Restore from floppy") => \&ReadFromFile ], [-1, 0, __("Save on floppy") => \&SaveInFile ], [ 1, 1, __("Done") => \&Exit ], ]; $buttons2->{buttons} = [ [ 1, 1, __("Clear all") => \&partition_table::read, 'clear_all' ], [ 0, 0, __("Format all") => \&FormatAll ], [ 1, 1, __("Auto allocate") => sub { eval { fsedit::auto_allocate([ sort { $a == current_hd() ? -1 : 0 } @$hds ], $part_suggestions) }; $@ =~ /partition table already full/ ? $in->ask_warn("", [ _("All primary partitions are used"), _("I can't add any more partition"), _("To have more partitions, please delete one to be able to create an extended partition") ]) : $@ && die ''; } ], [ 1, 1, __("Undo") => \&Undo ], [ 0, 0, __("Write partition table") => \&WritePartitions ], [-1, 0, __("Reload") => \&Reload ], ]; 1; sub update_button_box { my ($o) = @_; foreach (@{$o->{buttons}}) { my $w = $o->{$_->[2]}; $_->[0] + $::isStandalone && $_->[1] + $::expert ? $w->show : $w->hide; } } sub generate_button_box { my ($o) = @_; my $w = new Gtk::HBox(0,0); foreach (@{$o->{buttons}}) { $w->add(gtksignal_connect($o->{$_->[2]} = new Gtk::Button(translate($_->[2])), clicked => [ \&try, $_->[3], $_->[4] ])); } update_button_box($o); $w; } sub main($$$;$) { ($hds, $Raid, $in, $part_suggestions) = @_; $in->{grab} = 1; add2hash_($Raid ||= {}, { device => "md", raid => [] }); $raid = $Raid->{raid}; $w = my_gtk->new('DiskDrake'); my $rc = "/etc/gtk/diskdrake.rc"; -r $rc or $rc = dirname(__FILE__) . "/diskdrake.rc"; Gtk::Rc->parse($rc); foreach (@$hds, $Raid) { $hds_widget{$_} = gtkset_usize(new Gtk::HBox(0,0), 0, 50); create_buttons4partitions($_); } unless (is_empty_array_ref($Raid->{raid})) { raid::stopAll; $hds = [ @$hds, $Raid ]; } my @types = (__("Ext2"), __("Swap"), __("FAT"), __("Other"), __("Empty")); my %name2type = (Ext2 => 0x83, Swap => 0x82, Other => 1, FAT => 0xb); gtkadd($w->{window}, gtkpack_(new Gtk::VBox(0,7), 0, gtkpack(new Gtk::HBox(0,0), _("Filesystem types:"), map { my $w = new Gtk::Button(translate($_)); my $t = $name2type{$_}; $w->signal_connect(clicked => sub { my $t = $t; try('', sub { createOrChangeType($_[0], $_[1], $t) }, $current_part) }); $w->can_focus(0); $w->set_name($_); $w } @types), 0, $notebook_widget = create_notebook(map { $_->{device}, $hds_widget{$_} } @$hds), 1, gtkpack_(new Gtk::HBox(0,7), 0, $action_widget = gtkset_usize(new Gtk::VBox(0,0), 130, 150), 1, gtkadd(new Gtk::Frame(_("Details")), createScrolledWindow(gtkset_justify($info_widget = new Gtk::Label, 'left')), ) ), 0, generate_button_box($buttons2), 0, generate_button_box($buttons1), ), ); $hds_widget{$_}{widget_title}->signal_connect('event' => [ \&display_drive_info, $_ ]) foreach @$hds; $w->sync; create_buttons4partitions($_) foreach @$hds; $buttons1->{Done}->grab_focus; $action_text = _("You have one big fat partition (generally use by MicroSoft Dos/Windows). I suggest you first resize that partition (click on it, then click on \"Resize\")") if !$::isStandalone && fsedit::is_one_big_fat($hds); $::isStandalone and $in->ask_okcancel(_("Read carefully!"), _("Please make a backup of your data first"), 1) || return; $w->main; $hds; } sub ask_alldatawillbelost($$) { my ($part, $msg) = @_; $part->{notFormatted} && !$part->{isFormatted} and return 1; $in->ask_okcancel(_("Read carefully!"), [ _("After %s partition %s,", $msg, $part->{device}) , _("all data on this partition will be lost") ], 1); } sub hbox2 { gtkpack_(new Gtk::HBox(0,0), 0, new Gtk::Label($_[0]), 1, $_[1]) } sub current_hd { $hds->[$notebook_widget->get_current_page] } sub from_Mb($$$) { my ($mb, $min, $max) = @_; $mb == $min >> 11 and return $min; $mb == $max >> 11 and return $max; $mb << 11; } sub try($$;$) { my (undef, $f, $part) = @_; fsedit::undo_prepare($hds) unless ref $f && $f == \&Undo; eval { &$f(current_hd(), $part); }; $@ && $@ =~ /setstep/ and die; $@ and $in->ask_warn(_("Error"), $@); create_buttons4partitions($_) foreach @$hds; clear(); update_button_box($_) foreach ($buttons1, $buttons2); $part or return; foreach (fsedit::get_fstab(current_hd())) { $part->{device} eq $_->{device} || $part->{start} == $_->{start} or next; display($_); $part_widget{$_} and $part_widget{$_}->grab_focus; } } sub clear { $info_widget->set(''); $_->widget->destroy foreach $action_widget->children; } sub get_info { local $_ = shift; my $info = ''; my $hd = shift || current_hd(); my $cylinder = partition_table::cylinder_size($hd); $info .= _("Mount point: ") . "$_->{mntpoint}\n" if $_->{mntpoint}; $info .= _("Device: ") . "$_->{device}\n" if $_->{device}; $info .= _("DOS drive letter: %s (just a guess)\n", $_->{device_windobe}) if $_->{device_windobe}; $info .= _("Type: ") . type2name($_->{type}) . ($::expert ? sprintf " (0x%x)", $_->{type} : '') . "\n"; $info .= _("Start: sector %s\n", $_->{start}) if $::expert && !raid::is($_); $info .= _("Size: %s MB", $_->{size} >> 11); $info .= sprintf " (%s%%)", int 100 * $_->{size} / $hd->{totalsectors} if $hd->{totalsectors}; $info .= _(", %s sectors", $_->{size}) if $::expert; $info .= "\n"; $info .= _("Cylinder %d to cylinder %d\n", int ($_->{start} / $cylinder), int (($_->{start} + $_->{size} - 1) / $cylinder)) if $::expert && !raid::is($_); $info .= _("Formatted\n") if $_->{isFormatted}; $info .= _("Not formatted\n") if !$_->{isFormatted} && $_->{notFormatted}; $info .= _("Mounted\n") if $_->{isMounted}; $info .= _("RAID md%s\n", $_->{raid}) if defined $_->{raid}; $info .= _("Partition booted by default\n (for MS-DOS boot, not for lilo)\n") if $_->{active}; if (raid::is($_)) { $info .= _("Level %s\n", $_->{level}); $info .= _("Chunk size %s\n", $_->{'chunk-size'}); $info .= _("RAID-disks %s\n", join ", ", map {$_->{device}} @{$_->{disks}}); } $info; } sub display { clear(); $current_part = $_[0]; $info_widget->set(get_info($_[0])); display_actions($_[0]); } sub display_drive_info { my $hd = $_[1] || current_hd(); my $info = ''; clear(); undef $current_part; gtkpack($action_widget, gtktext_insert(new Gtk::Text, $action_text || _("Please click on a partition"))); $action_text = ''; return if $hd->{device} eq "md"; $info .= _("Device: ") . "$hd->{device}\n"; $info .= _("Size: %d MB\n", $hd->{totalsectors} >> 11); $info .= _("Geometry: %s cylinders, %s heads, %s sectors\n", @{$hd->{geom}}{qw(cylinders heads sectors)}) if $::expert; $info .= _("Type: ") . $hd->{info} . "\n" if $::expert; $info .= _("on bus %d id %d\n", $hd->{bus}, $hd->{id}) if $::expert; $info_widget->set($info); } sub display_actions { my ($part) = @_; my @entries; $part->{type} == 0 and push @entries, @actions4free; if ($part->{type}) { !isSwap($part) && !$part->{isMounted} && !isRAID($part) and push @entries, @actions4nonmountedfs; $part->{isMounted} and push @entries, @actions4mounted; !$part->{isMounted} && !exists $part->{raid} and push @entries, @actions4nonmounted; !$part->{isMounted} && ($part->{mntpoint} || isSwap($part)) && ($part->{isFormatted} || !$part->{notFormatted}) and push @entries, __("Mount"); !isSwap($part) && isPrimary($part, current_hd()) && !$part->{active} and push @entries, __("Active"); isRAID($part) && !exists $part->{raid} && !raid::is($part) and push @entries, __("Add to RAID"); isRAID($part) && exists $part->{raid} and push @entries, __("Remove from RAID"); raid::is($part) && !$part->{isMounted} and push @entries, __("Modify RAID"); } @entries = difference2(\@entries, \@actions4expert) unless $::expert; @entries = difference2(\@entries, \@actions4expertOrStandalone) unless $::expert || $::isStandalone; @entries = difference2(\@entries, \@actionsnot4raid) if raid::is($part); gtkpack($action_widget, gtkadd(new Gtk::Frame(_("Choose action")), createScrolledWindow(gtkpack_(new Gtk::VBox(0,0), map { 0, gtksignal_connect(new Gtk::Button(translate($_)), 'clicked' => [ \&try, $diskdrake::{$_}, $part ]) } @entries)))); } sub create_buttons4partitions($) { my $hd = shift; $width = max($width, 0.9 * second($w->{window}->window->get_size)) if $w->{window}->window; $_->widget->destroy foreach $hds_widget{$hd}->children; gtkpack_($hds_widget{$hd}, map { 0, $_ } create_buttons4partitions_($hd->{totalsectors}, sort { $a->{start} <=> $b->{start} } fsedit::get_fstab($hd))); partition_table::assign_device_numbers($hd) if ref $hd eq "HASH"; } sub create_buttons4partitions_($@) { my $totalsectors = shift; my $ratio = $totalsectors ? ($width - @_ * $minwidth) / $totalsectors : 1; my $totalwidth; my @r; my $button = sub { my ($part) = @_; my $w = $part_widget{$part} = new Gtk::Button($part->{mntpoint} || '') or die ''; $w->signal_connect(focus_in_event => sub { display($part) }); $w->signal_connect(button_press_event => sub { display($part) }); $w->signal_connect(key_press_event => sub { my ($w, $e) = @_; $e->{state} == 0 && $e->{keyval} == 0xffff and return try('', \&Delete, $part); $e->{state} & 4 or return; my $f = ${{ "a" => \&Active, "b" => \&Move, "c" => \&Create, "d" => \&Delete, "f" => \&Format, "m" => \&Mount_point, "M" => \&Mount, "n" => \&Create, "o" => \&ReadFromFile, "s" => \&SaveInFile, "q" => \&Exit, "r" => \&Resize, "R" => exists $part->{raid} ? \&RemoveFromRAID : \&Add2RAID, "t" => \&Type, "u" => \&Unmount, "w" => \&WritePartitions, "W" => \&WriteFstab, }}{chr $e->{keyval}}; $f and try('', $f, $part); }); $w->set_name("PART_" . type2name($part->{type})); $w->set_usize(my $s = $part->{size} * $ratio + $minwidth, 0); $totalwidth += $s; $w; }; my $add_empty = sub { my $o = shift; $o->{type} = 0; $o->{size} * $ratio > 1 || $o->{size} > 5 << 11 and push @r, &$button($o); }; again: my $last = 1; foreach (@_) { &$add_empty({ start => $last, size => $_->{start} - $last }); $last = $_->{start} + $_->{size}; push @r, &$button($_); } &$add_empty({ start => $last, size => $totalsectors - $last }); if ($totalwidth > $width) { $ratio /= $totalwidth / $width * 1.1; $totalwidth = 0; @r = (); goto again; } @r; } sub check_mntpoint { eval { fsedit::check_mntpoint(@_) }; local $_ = $@; if (m|/boot ending on cylinder > 1024|) { $in->ask_warn('', _("Sorry I won't accept to create /boot so far onto the drive (on a cylinder > 1024). Either you use LILO and it won't work, or you don't use LILO and you don't need /boot")); } elsif (m|/ ending on cylinder > 1024|) { $in->ask_warn('', _("The partition you've selected to add as root (/) is physically located beyond the 1024th cylinder of the hard drive, and you have no /boot partition. If you plan to use the LILO boot manager, be careful to add a /boot partition")); undef $_; } elsif ($_) { $in->ask_warn('', $_); } !$_; } sub createOrChangeType($) { my ($hd, $part, $type) = @_; $part ||= !fsedit::get_fstab($hd) && { type => 0, start => 1, size => $hd->{totalsectors} - 1 }; $part or return; if ($type == 1) { $in->ask_warn('', _("Use ``%s'' instead", $part->{type} ? _("Type") : _("Create"))); } elsif (!$type) { $in->ask_warn('', _("Use ``%s'' instead", _("Delete"))) if $part->{type}; } elsif ($part->{type}) { return if $type == $part->{type}; $part->{isMounted} || exists $part->{raid} and $in->ask_warn('', _("Use ``Unmount'' first")), return; return if !ask_alldatawillbelost($part, _("changing type of")); fsedit::change_type($hd, $part, $type); } else { $part->{type} = $type; Create($hd, $part); } } sub Exit(;$$) { eval { raid::verify($Raid) }; if ($@) { $::expert || die; $in->ask_okcancel('', [ $@, _("Continue anyway?")]) or return; } foreach (@$hds) { unless (WritePartitions($_)) { return unless $::isStandalone; $in->ask_yesorno(_("Quit without saving"), _("Quit without writing the partition table?"), 1) || return; } } Gtk->main_quit; } sub Active($$) { &partition_table::active; } sub Delete($$) { my ($hd, $part) = @_; raid::is($part) ? raid::delete($raid, $part) : &partition_table::remove; } sub Type($$) { my ($hd, $part) = @_; ask_alldatawillbelost($part, _("changing type of")) or return; my $type = type2name($part->{type}); $in->ask_from_entries_ref(_("Change partition type"), _("Which partition type do you want?"), [ _("Type") ], [ { val => \$type, list => [ partition_table::important_types($::expert) ], not_edit => !$::expert } ]) or return; fsedit::change_type($hd, $part, name2type($type)) if defined $type; } sub Mount_point($$) { my ($hd, $part) = @_; my $mntpoint = $part->{mntpoint} || do { my $part_ = { %$part }; if (fsedit::suggest_part($hd, $part_, $hds, $part_suggestions)) { fsedit::has_mntpoint('/', $hds) || $part_->{mntpoint} eq '/boot' ? $part_->{mntpoint} : '/'; } else { '' } }; $in->ask_from_entries_ref( '', _("Where do you want to mount device %s?", $part->{device}), [ _("Mount point") ], [ { val => \$mntpoint, list => [ fsedit::suggestions_mntpoint($hds), '' ] } ], complete => sub { !($part->{mntpoint} eq $mntpoint || check_mntpoint($mntpoint, $hd, $part, $hds)) } ) or return; $part->{mntpoint} = $mntpoint; } sub Mount($$) { my ($hd, $part) = @_; WritePartitions($hd) || return; fs::mount_part($part); } sub Unmount($$) { my ($hd, $part) = @_; fs::umount_part($part); } sub Format($$) { my ($hd, $part) = @_; WritePartitions($_) or return foreach raid::is($part) ? @$hds : $hd; ask_alldatawillbelost($part, _("formatting")) or return; $part->{isFormatted} = 0; my $w = $in->wait_message(_("Formatting"), _("Formatting partition %s", $part->{device})); raid::format_part($Raid, $part); } sub FormatAll() { foreach (@$hds) { WritePartitions($_) || return; } $in->ask_okcancel(_("Read carefully!"), [ _("After formatting all partitions,") , _("all data on these partitions will be lost") ], 1) or return; raid::format_part($Raid, $_) foreach fsedit::get_fstab(@$hds); } sub Move($$) { my ($hd, $part) = @_; my $hd2; if (@$hds == 1) { $hd2 = $hds->[0]; } else { my $hd2_name = $in->ask_from_list(_("Move"), _("Which disk do you want to move to?"), [ map { $_->{device} } @$hds ]) or return; ($hd2) = grep { $_->{device} eq $hd2_name } @$hds; } my $start2 = $in->ask_from_entry(_("Sector"), _("Which sector do you want to move to?")); defined $start2 or return; my $w = $in->wait_message(_("Moving"), _("Moving partition...")); fsedit::move($hd, $part, $hd2, $start2); } sub WritePartitions { my ($hd) = @_; $hd->{isDirty} or return 1; exists $hd->{raid} and return 1; $in->ask_okcancel(_("Read carefully!"), _("Partition table of drive %s is going to be written to disk!", $hd->{device}), 1) or return; partition_table::write($hd) unless $::testing; $hd->{rebootNeeded} and die _("You'll need to reboot before the modification can take place"); 1; } sub WriteFstab { fs::write_fstab([ fsedit::get_fstab(@$hds) ]); } sub Resize($$) { my ($hd, $part) = @_; my ($resize_fat, $resize_ext2); my ($min, $max) = (1, partition_table::next_start($hd, $part) - $part->{start}); if ($part->{isFormatted} || !$part->{notFormatted}) { # here we may have a non-formatted or a formatted partition # -> doing as if it was formatted isFat($part) || isExt2($part) or WritePartitions($hd) or return; if (isFat($part)) { WritePartitions($hd) or return; my $w = $in->wait_message(_("Resizing"), _("Computing fat filesystem bounds")); $resize_fat = resize_fat::main->new($part->{device}, devices::make($part->{device})); $min = max($min, $resize_fat->min_size); $max = min($max, $resize_fat->max_size); } elsif (0 && isExt2($part)) { WritePartitions($hd) or return; $resize_ext2 = devices::make($part->{device}); my ($m) = `ext2resize $resize_ext2 0 2>/dev/null`; $? ? undef $resize_ext2 : ($min = max($min, to_int($m) >> 9)); } unless ($resize_fat || $resize_ext2) { ask_alldatawillbelost($part, _("resizing")) or return; } } my $w = my_gtk->new(_("Resize"), %$in); my $adj = create_adjustment($part->{size} >> 11, $min >> 11, $max >> 11); my $spin = gtkset_usize(new Gtk::SpinButton($adj, 0, 0), 100, 0); gtkadd($w->{window}, gtkpack(new Gtk::VBox(0,20), create_packtable({ col_spacings => 10 }, [ _("Choose the new size"), $spin, _("MB"), ], [ undef, new Gtk::HScrollbar($adj) ], ), create_okcancel($w) ) ); $spin->signal_connect(activate => sub { $w->{retval} = 1; Gtk->main_quit }); $spin->grab_focus(); $w->main or return; my $size = from_Mb($spin->get_value_as_int, $min, $max); $part->{size} == $size and return; my $oldsize = $part->{size}; $hd->{isDirty} = $hd->{needKernelReread} = 1; $part->{size} = $size; partition_table::adjustEnd($hd, $part); undef $@; my $b = before_leaving { $@ and $part->{size} = $oldsize }; $w = $in->wait_message(_("Resizing"), ''); if ($resize_fat) { local *log::l = sub { $w->set(join(' ', @_)) }; $resize_fat->resize($size); } elsif ($resize_ext2) { my $s = $size << 9; local *F; open F, "ext2resize $resize_ext2 $s 2>&1 |"; $w->set($_) foreach ; close F or die "ext2resize failed"; } else { $part->{notFormatted} = 1; $part->{isFormatted} = 0; return; } $part->{isFormatted} = 1; partition_table::adjust_local_extended($hd, $part); partition_table::adjust_main_extended($hd); } sub Create($$) { my ($hd, $part) = @_; my ($start, $size, $max) = ($part->{start}, $part->{size}, $part->{start} + $part->{size}); $part->{maxsize} = $part->{size}; $part->{size} = 0; unless (fsedit::suggest_part($hd, $part, $hds, $part_suggestions)) { $part->{size} = $part->{maxsize}; $part->{type} ||= 0x83; } my $w = my_gtk->new(_("Create a new partition"), %$in); my ($type_combo, $mntpoint_combo, $primaryextended_combo); my $adj_start = create_adjustment($part->{start}, $start, $max - 1); my $adj_size = create_adjustment($part->{size} >> 11, 1, $size >> 11); my $spin_start = new Gtk::SpinButton($adj_start, 0, 0); my $spin_size = new Gtk::SpinButton($adj_size, 0, 0); ($start, $size) = ($part->{start}, $size = $part->{size}); my $update_start = sub { $adj_size->set_value($size = $spin_size->get_value_as_int); $size <<= 11; $start + $size < $max or $spin_start->set_value($start = $max - $size); }; my $update_size = sub { $adj_start->set_value($start = $spin_start->get_value_as_int); $start + $size < $max or $spin_size->set_value(($size = $max - $start) >> 11); }; my $h; gtkadd($w->{window}, gtkpack(new Gtk::VBox(0,20), create_packtable({}, [ _("Start sector: "), gtksignal_connect($spin_start, changed => $update_size) ], [ undef, new Gtk::HScrollbar($adj_start) ], [ '' ], [ _("Size in MB: "), gtksignal_connect($spin_size, changed => $update_start) ], [ undef, new Gtk::HScrollbar($adj_size) ], [ '' ], [ _("Filesystem type: "), $type_combo = new Gtk::Combo ], [ _("Mount point: "), $mntpoint_combo = new Gtk::Combo ], ($::expert ? [ _("Preference: "), $primaryextended_combo = new Gtk::Combo ] : ()), ), create_okcancel($w) ), ); $type_combo->set_popdown_strings(partition_table::important_types($::expert)); $type_combo->entry->set_text(type2name($part->{type})) if $part->{type}; $mntpoint_combo->set_popdown_strings(fsedit::suggestions_mntpoint($hds), ''); $mntpoint_combo->entry->set_text($part->{mntpoint}); if ($::expert) { $primaryextended_combo->set_popdown_strings("Extended", "Primary"); } foreach ($type_combo, $mntpoint_combo, $primaryextended_combo) { $_ or next; $_->disable_activate; $_->set_use_arrows_always(1); } $type_combo->entry->set_editable(0) unless $::expert; $type_combo->entry->signal_connect(changed => sub { $mntpoint_combo->set_sensitive(bool($type_combo->entry->get_text !~ /swap|RAID/)) }); $mntpoint_combo->entry->signal_connect(activate => sub { $w->{retval} = 1; Gtk->main_quit }); $mntpoint_combo->entry->grab_focus; $type_combo->entry->signal_emit("changed"); $w->main(sub { $part->{start} = $start; $part->{size} = from_Mb($size >> 11, 1, $max - $start); ($part->{type} = name2type($type_combo->entry->get_text)) =~ s/0x(.*)/hex($1)/e; $part->{mntpoint} = $mntpoint_combo->entry->get_text; $part->{mntpoint} = '' if isRAID($part); $part->{mntpoint} = 'swap' if isSwap($part); check_mntpoint($part->{mntpoint}, $hd, $part, $hds) or return; fsedit::add($hd, $part, $hds, { force => 1, primaryOrExtended => $::expert ? $primaryextended_combo->entry->get_text : '' } ); 1; }); } sub ReadFromFile() { my $file = $::isStandalone ? ask_file(_("Select file")) : devices::make("fd0") or return; $_->widget->destroy foreach $hds_widget{current_hd()}->children; catch_cdie { partition_table::load(current_hd(), $file) } sub { $@ =~ /Bad totalsectors/ or return; $in->ask_yesorno('', _("The backup partition table has not the same size Still continue?"), 0); }; } sub SaveInFile() { my $file = $::isStandalone ? ask_file(_("Select file")) : $in->ask_okcancel(_("Warning"), _("Insert a floppy in drive All data on this floppy will be lost"), 1) && devices::make("fd0") or return; partition_table::save(current_hd(), $file); } sub Undo() { # $_->widget->destroy foreach current_hd()->{widget}->children; # my @widgets = map { delete $_->{widget} } @$hds; fsedit::undo($hds); # mapn { $_[0]{widget} = $_[1] } $hds, \@widgets; } sub Rescuept { my $w = $in->wait_message('', _("Trying to rescue partition table")); fsedit::rescuept(current_hd()); } sub Reload { %$hds = (); %$Raid = (); $::setstep and die "setstep partitionDisks\n" } sub modifyRAID { my ($raid, $nb) = @_; my $md = "md$nb"; $in->ask_from_entries_refH('', '', [ _("device") => { val => \$md, list => [ map { "md$_" } grep { $nb == $_ || !$raid->[$_] } 0..8 ] }, _("level") => { val => \$raid->[$nb]{level}, list => [ qw(0 1 4 5 linear) ] }, _("chunk size") => \$raid->[$nb]{'chunk-size'}, ], ) or return; raid::changeNb($raid, $nb, first($md =~ /(\d+)/)); } sub ModifyRAID { modifyRAID($raid, raid::nb($_[1])) } sub Add2RAID { my ($hd, $part) = @_; local $_ = is_empty_array_ref($raid) ? "new" : $in->ask_from_list_('', _("Choose an existing RAID to add to"), [ (grep {$_} map_index { $_ && "md$::i" } @$raid), __("new") ]); if (/new/) { my $nb1 = raid::new($raid, $part); defined modifyRAID($raid, $nb1) or return raid::delete($raid, $nb1); } else { raid::add($raid, $part, $_); } raid::update(@$raid); unless (member($Raid, @$hds)) { $hds = [ @$hds, $Raid ]; raid::stopAll; my_gtk::add2notebook($notebook_widget, "raid", $hds_widget{$Raid}); $hds_widget{$Raid}{widget_title}->signal_connect('event' => [ \&display_drive_info, $Raid ]); } } sub RemoveFromRAID { raid::removeDisk($raid, $_[1]) } { no strict; *{"Mount point"} = *Mount_point; *{"Modify RAID"} = *ModifyRAID; *{"Add to RAID"} = *Add2RAID; *{"Remove from RAID"} = *RemoveFromRAID; }