home *** CD-ROM | disk | FTP | other *** search
/ Inter.Net 55-2 / Inter.Net 55-2.iso / Mandrake / mdkinst / usr / bin / perl-install / diskdrake.pm < prev    next >
Encoding:
Perl POD Document  |  2000-01-12  |  24.7 KB  |  740 lines

  1. package diskdrake;
  2.  
  3.  
  4.  
  5.  
  6.  
  7. use common qw(:common :functional :file);
  8. use resize_fat::main;
  9. use my_gtk qw(:helpers :wrappers :ask);
  10. use partition_table qw(:types);
  11. use devices;
  12. use raid;
  13. use fsedit;
  14. use fs;
  15.  
  16. my @actions4free = __("Create");
  17. my @actions4mounted = __("Unmount");
  18. my @actions4nonmounted = (__("Type"), __("Resize"), __("Delete"), __("Format"));#, __("Move"));
  19. my @actions4nonmountedfs = __("Mount point");
  20. my @actions4expert = qw(Move Active Type);
  21. my @actions4expertOrStandalone = qw(Format Mount);
  22. my @actionsnot4raid = qw(Resize Move);
  23.  
  24. my (%hds_widget, %part_widget);
  25. my ($width, $height, $minwidth) = (400, 50, 5);
  26. my ($w, $current_part, $action_widget, $action_text, $info_widget, $notebook_widget);
  27. my ($hds, $Raid, $raid, $in, $part_suggestions);
  28. my ($buttons1, $buttons2);
  29.  
  30.  
  31.  
  32. $buttons1->{buttons} = [
  33.    [ 0, 0, __("Write /etc/fstab") => \&WriteFstab ],
  34.    [ 0,-1, __("Toggle to expert mode") => sub { $::expert = 1 } ],
  35.    [ 0, 0, __("Toggle to normal mode") => sub { $::expert = 0 } ],
  36.    [ 0, 0, __("Restore from file") => \&ReadFromFile ],
  37.    [ 0, 0, __("Save in file") => \&SaveInFile ],
  38.    [-1, 0, __("Restore from floppy") => \&ReadFromFile ],
  39.    [-1, 0, __("Save on floppy") => \&SaveInFile ],
  40.    [ 1, 1, __("Done") => \&Exit ],
  41. ];
  42. $buttons2->{buttons} = [
  43.    [ 1, 1, __("Clear all") => \&partition_table::read, 'clear_all' ],
  44.    [ 0, 0, __("Format all") => \&FormatAll ],
  45.    [ 1, 1, __("Auto allocate") => sub {
  46.          eval { fsedit::auto_allocate([ sort { $a == current_hd() ? -1 : 0 } @$hds ], $part_suggestions) };
  47.          $@ =~ /partition table already full/ ?
  48.            $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") ]) :
  49.          $@ && die '';
  50.      } ],
  51.  
  52.    [ 1, 1, __("Undo") => \&Undo ],
  53.    [ 0, 0, __("Write partition table") => \&WritePartitions ],
  54.    [-1, 0, __("Reload") => \&Reload ],
  55. ];
  56.  
  57. 1;
  58.  
  59. sub update_button_box {
  60.     my ($o) = @_;
  61.     foreach (@{$o->{buttons}}) {
  62.     my $w = $o->{$_->[2]};
  63.     $_->[0] + $::isStandalone && $_->[1] + $::expert ? $w->show : $w->hide;
  64.     }
  65. }
  66. sub generate_button_box {
  67.     my ($o) = @_;
  68.     my $w = new Gtk::HBox(0,0);
  69.     foreach (@{$o->{buttons}}) {
  70.     $w->add(gtksignal_connect($o->{$_->[2]} = new Gtk::Button(translate($_->[2])),
  71.                   clicked => [ \&try, $_->[3], $_->[4] ]));
  72.     }
  73.     update_button_box($o);
  74.     $w;
  75. }
  76.  
  77. sub main($$$;$) {
  78.     ($hds, $Raid, $in, $part_suggestions) = @_;
  79.     $in->{grab} = 1;
  80.  
  81.     add2hash_($Raid ||= {}, { device => "md", raid => [] });
  82.     $raid = $Raid->{raid};
  83.  
  84.     $w = my_gtk->new('DiskDrake');
  85.     my $rc = "/etc/gtk/diskdrake.rc";
  86.     -r $rc or $rc = dirname(__FILE__) . "/diskdrake.rc";
  87.     Gtk::Rc->parse($rc);
  88.  
  89.     foreach (@$hds, $Raid) {
  90.     $hds_widget{$_} = gtkset_usize(new Gtk::HBox(0,0), 0, 50);
  91.     create_buttons4partitions($_);
  92.     }
  93.     unless (is_empty_array_ref($Raid->{raid})) {
  94.     raid::stopAll;
  95.     $hds = [ @$hds, $Raid ];
  96.     }
  97.  
  98.     my @types = (__("Ext2"), __("Swap"), __("FAT"), __("Other"), __("Empty"));
  99.     my %name2type = (Ext2 => 0x83, Swap => 0x82, Other => 1, FAT => 0xb);
  100.  
  101.     gtkadd($w->{window},
  102.        gtkpack_(new Gtk::VBox(0,7),
  103.             0, gtkpack(new Gtk::HBox(0,0), 
  104.                    _("Filesystem types:"),
  105.                    map { my $w = new Gtk::Button(translate($_));
  106.                      my $t = $name2type{$_};
  107.                      $w->signal_connect(clicked => sub { my $t = $t; try('', sub { createOrChangeType($_[0], $_[1], $t) }, $current_part) });
  108.                      $w->can_focus(0);
  109.                      $w->set_name($_); $w } @types),
  110.             0, $notebook_widget = create_notebook(map { $_->{device}, $hds_widget{$_} } @$hds),
  111.             1, gtkpack_(new Gtk::HBox(0,7),
  112.                 0, $action_widget = gtkset_usize(new Gtk::VBox(0,0), 130, 150),
  113.                 1, gtkadd(new Gtk::Frame(_("Details")),
  114.                       createScrolledWindow(gtkset_justify($info_widget = new Gtk::Label, 'left')),
  115.                      )
  116.                    ),
  117.             0, generate_button_box($buttons2),
  118.             0, generate_button_box($buttons1),
  119.            ),
  120.       );
  121.     $hds_widget{$_}{widget_title}->signal_connect('event' => [ \&display_drive_info, $_ ]) foreach @$hds;
  122.     $w->sync;
  123.     create_buttons4partitions($_) foreach @$hds;
  124.     $buttons1->{Done}->grab_focus;    
  125.  
  126.     $action_text =
  127. _("You have one big fat partition
  128. (generally use by MicroSoft Dos/Windows).
  129. I suggest you first resize that partition
  130. (click on it, then click on \"Resize\")") if !$::isStandalone && fsedit::is_one_big_fat($hds);
  131.  
  132.     $::isStandalone and $in->ask_okcancel(_("Read carefully!"), _("Please make a backup of your data first"), 1) || return;
  133.  
  134.     $w->main;
  135.  
  136.     $hds;
  137. }
  138.  
  139. sub ask_alldatawillbelost($$) {
  140.     my ($part, $msg) = @_;
  141.  
  142.     $part->{notFormatted} && !$part->{isFormatted} and return 1;
  143.  
  144.     
  145.     
  146.     $in->ask_okcancel(_("Read carefully!"), [ _("After %s partition %s,", $msg, $part->{device}) , _("all data on this partition will be lost") ], 1);
  147. }
  148.  
  149. sub hbox2 { gtkpack_(new Gtk::HBox(0,0), 0, new Gtk::Label($_[0]), 1, $_[1]) }
  150. sub current_hd { $hds->[$notebook_widget->get_current_page] }
  151. sub from_Mb($$$) {
  152.     my ($mb, $min, $max) = @_;
  153.     $mb == $min >> 11 and return $min;
  154.     $mb == $max >> 11 and return $max;
  155.     $mb << 11;
  156. }
  157.  
  158. sub try($$;$) {
  159.     my (undef, $f, $part) = @_;
  160.  
  161.     fsedit::undo_prepare($hds) unless ref $f && $f == \&Undo;
  162.  
  163.     eval { &$f(current_hd(), $part); };
  164.     $@ && $@ =~ /setstep/ and die;
  165.     $@ and $in->ask_warn(_("Error"), $@);
  166.     create_buttons4partitions($_) foreach @$hds;
  167.     clear();
  168.  
  169.     update_button_box($_) foreach ($buttons1, $buttons2);
  170.  
  171.     $part or return;
  172.     foreach (fsedit::get_fstab(current_hd())) {
  173.     $part->{device} eq $_->{device} || $part->{start} == $_->{start} or next;
  174.     display($_);
  175.     $part_widget{$_} and $part_widget{$_}->grab_focus;
  176.     }
  177. }
  178.  
  179. sub clear { 
  180.     $info_widget->set('');
  181.     $_->widget->destroy foreach $action_widget->children;
  182. }
  183. sub get_info {
  184.     local $_ = shift;
  185.     my $info = '';
  186.     my $hd = shift || current_hd();
  187.     my $cylinder = partition_table::cylinder_size($hd);
  188.  
  189.     $info .= _("Mount point: ") . "$_->{mntpoint}\n" if $_->{mntpoint};
  190.     $info .= _("Device: ") . "$_->{device}\n" if $_->{device};
  191.     $info .= _("DOS drive letter: %s (just a guess)\n", $_->{device_windobe}) if $_->{device_windobe};
  192.     $info .= _("Type: ") . type2name($_->{type}) . ($::expert ? sprintf " (0x%x)", $_->{type} : '') . "\n";
  193.     $info .= _("Start: sector %s\n", $_->{start}) if $::expert && !raid::is($_);
  194.     $info .= _("Size: %s MB", $_->{size} >> 11);
  195.     $info .= sprintf " (%s%%)", int 100 * $_->{size} / $hd->{totalsectors} if $hd->{totalsectors};
  196.     $info .= _(", %s sectors", $_->{size}) if $::expert;
  197.     $info .= "\n";
  198.     $info .= _("Cylinder %d to cylinder %d\n", int ($_->{start} / $cylinder), int (($_->{start} + $_->{size} - 1) / $cylinder)) if $::expert && !raid::is($_);
  199.     $info .= _("Formatted\n") if $_->{isFormatted};
  200.     $info .= _("Not formatted\n") if !$_->{isFormatted} && $_->{notFormatted};
  201.     $info .= _("Mounted\n") if $_->{isMounted};
  202.     $info .= _("RAID md%s\n", $_->{raid}) if defined $_->{raid};
  203.     $info .= _("Partition booted by default\n    (for MS-DOS boot, not for lilo)\n") if $_->{active};
  204.     if (raid::is($_)) {
  205.     $info .= _("Level %s\n", $_->{level});
  206.     $info .= _("Chunk size %s\n", $_->{'chunk-size'});
  207.     $info .= _("RAID-disks %s\n", join ", ", map {$_->{device}} @{$_->{disks}});
  208.     }
  209.     $info;
  210. }
  211. sub display {
  212.     clear();
  213.     $current_part = $_[0];
  214.     $info_widget->set(get_info($_[0]));
  215.     display_actions($_[0]);
  216. }
  217.  
  218. sub display_drive_info {
  219.     my $hd = $_[1] || current_hd();
  220.     my $info = '';
  221.  
  222.     clear(); 
  223.     undef $current_part;
  224.     gtkpack($action_widget, gtktext_insert(new Gtk::Text, $action_text || _("Please click on a partition")));
  225.     $action_text = '';
  226.  
  227.     return if $hd->{device} eq "md";
  228.     $info .= _("Device: ") . "$hd->{device}\n";
  229.     $info .= _("Size: %d MB\n", $hd->{totalsectors} >> 11);
  230.     $info .= _("Geometry: %s cylinders, %s heads, %s sectors\n", @{$hd->{geom}}{qw(cylinders heads sectors)}) if $::expert;
  231.     $info .= _("Type: ") . $hd->{info} . "\n" if $::expert;
  232.     $info .= _("on bus %d id %d\n", $hd->{bus}, $hd->{id}) if $::expert;
  233.     $info_widget->set($info);
  234. }
  235.  
  236. sub display_actions {
  237.     my ($part) = @_;
  238.     my @entries;
  239.  
  240.     $part->{type} == 0 and push @entries, @actions4free;
  241.     if ($part->{type}) {
  242.     !isSwap($part) && !$part->{isMounted} && !isRAID($part) and push @entries, @actions4nonmountedfs;
  243.     $part->{isMounted} and push @entries, @actions4mounted;
  244.     !$part->{isMounted} && !exists $part->{raid} and push @entries, @actions4nonmounted;
  245.     !$part->{isMounted} && ($part->{mntpoint} || isSwap($part)) && ($part->{isFormatted} || !$part->{notFormatted}) and push @entries, __("Mount");
  246.     !isSwap($part) && isPrimary($part, current_hd()) && !$part->{active} and push @entries, __("Active");
  247.     isRAID($part) && !exists $part->{raid} && !raid::is($part) and push @entries, __("Add to RAID");
  248.     isRAID($part) && exists $part->{raid} and push @entries, __("Remove from RAID");
  249.     raid::is($part) && !$part->{isMounted} and push @entries, __("Modify RAID");
  250.     }
  251.     @entries = difference2(\@entries, \@actions4expert) unless $::expert;
  252.     @entries = difference2(\@entries, \@actions4expertOrStandalone) unless $::expert || $::isStandalone;
  253.     @entries = difference2(\@entries, \@actionsnot4raid) if raid::is($part);
  254.  
  255.     gtkpack($action_widget,
  256.         gtkadd(new Gtk::Frame(_("Choose action")),
  257.            createScrolledWindow(gtkpack_(new Gtk::VBox(0,0),
  258.                   map {
  259.                   0, gtksignal_connect(new Gtk::Button(translate($_)), 
  260.                            'clicked' => [ \&try, $diskdrake::{$_}, $part ])
  261.               } @entries))));
  262. }
  263.  
  264. sub create_buttons4partitions($) {
  265.     my $hd = shift;
  266.  
  267.     $width = max($width, 0.9 * second($w->{window}->window->get_size)) if $w->{window}->window;
  268.     $_->widget->destroy foreach $hds_widget{$hd}->children;
  269.     gtkpack_($hds_widget{$hd},
  270.         map { 0, $_ }
  271.         create_buttons4partitions_($hd->{totalsectors},
  272.                        sort { $a->{start} <=> $b->{start} } fsedit::get_fstab($hd)));
  273.     partition_table::assign_device_numbers($hd) if ref $hd eq "HASH";
  274. }
  275.  
  276. sub create_buttons4partitions_($@) {
  277.     my $totalsectors = shift;
  278.     my $ratio = $totalsectors ? ($width - @_ * $minwidth) / $totalsectors : 1;
  279.     my $totalwidth;
  280.     my @r;
  281.  
  282.     my $button = sub {
  283.     my ($part) = @_;
  284.     my $w = $part_widget{$part} = new Gtk::Button($part->{mntpoint} || '') or die '';
  285.     $w->signal_connect(focus_in_event     => sub { display($part) });
  286.     $w->signal_connect(button_press_event => sub { display($part) });
  287.     $w->signal_connect(key_press_event => sub {
  288.         my ($w, $e) = @_;
  289.         $e->{state} == 0 && $e->{keyval} == 0xffff 
  290.                and return try('', \&Delete, $part);
  291.         $e->{state} & 4 or return; 
  292.         my $f = ${{
  293.         "a" => \&Active,
  294.         "b" => \&Move,
  295.         "c" => \&Create,
  296.         "d" => \&Delete,
  297.         "f" => \&Format,
  298.         "m" => \&Mount_point,
  299.         "M" => \&Mount,
  300.         "n" => \&Create,
  301.         "o" => \&ReadFromFile,
  302.         "s" => \&SaveInFile,
  303.         "q" => \&Exit,
  304.         "r" => \&Resize,
  305.         "R" => exists $part->{raid} ? \&RemoveFromRAID : \&Add2RAID,
  306.         "t" => \&Type,
  307.         "u" => \&Unmount,
  308.         "w" => \&WritePartitions,
  309.         "W" => \&WriteFstab,
  310.         }}{chr $e->{keyval}};
  311.         $f and try('', $f, $part);
  312.     });
  313.     $w->set_name("PART_" . type2name($part->{type}));
  314.     $w->set_usize(my $s = $part->{size} * $ratio + $minwidth, 0);
  315.     $totalwidth += $s;
  316.     $w;
  317.     };
  318.     my $add_empty = sub {
  319.     my $o = shift;
  320.     $o->{type} = 0;
  321.     $o->{size} * $ratio > 1 || $o->{size} > 5 << 11 and push @r, &$button($o);
  322.     };
  323.  
  324.   again:
  325.     my $last = 1;
  326.     foreach (@_) {
  327.     &$add_empty({ start => $last, size => $_->{start} - $last });
  328.     $last = $_->{start} + $_->{size};
  329.  
  330.     push @r, &$button($_);
  331.     }
  332.     &$add_empty({ start => $last, size => $totalsectors - $last });
  333.  
  334.     if ($totalwidth > $width) {
  335.     $ratio /= $totalwidth / $width * 1.1;
  336.     $totalwidth = 0;
  337.     @r = ();
  338.     goto again;
  339.     }
  340.  
  341.     @r;
  342. }
  343.  
  344. sub check_mntpoint {
  345.     eval { fsedit::check_mntpoint(@_) };
  346.     local $_ = $@;
  347.     if (m|/boot ending on cylinder > 1024|) {
  348.     $in->ask_warn('',
  349. _("Sorry I won't accept to create /boot so far onto the drive (on a cylinder > 1024).
  350. Either you use LILO and it won't work, or you don't use LILO and you don't need /boot"));
  351.     } elsif (m|/ ending on cylinder > 1024|) {
  352.     $in->ask_warn('',
  353. _("The partition you've selected to add as root (/) is physically located beyond
  354. the 1024th cylinder of the hard drive, and you have no /boot partition.
  355. If you plan to use the LILO boot manager, be careful to add a /boot partition"));
  356.     undef $_;
  357.     } elsif ($_) {
  358.     $in->ask_warn('', $_);
  359.     }
  360.     !$_;
  361. }
  362.  
  363. sub createOrChangeType($) {
  364.     my ($hd, $part, $type) = @_;
  365.  
  366.     $part ||= !fsedit::get_fstab($hd) && 
  367.               { type => 0, start => 1, size => $hd->{totalsectors} - 1 };
  368.     $part or return;
  369.     if ($type == 1) {
  370.     $in->ask_warn('', _("Use ``%s'' instead", $part->{type} ? _("Type") : _("Create")));
  371.     } elsif (!$type) {
  372.     $in->ask_warn('', _("Use ``%s'' instead", _("Delete"))) if $part->{type};
  373.     } elsif ($part->{type}) {
  374.     return if $type == $part->{type};
  375.     $part->{isMounted} || exists $part->{raid} and $in->ask_warn('', _("Use ``Unmount'' first")), return;
  376.     return if !ask_alldatawillbelost($part, _("changing type of"));
  377.     fsedit::change_type($hd, $part, $type);
  378.     } else {
  379.     $part->{type} = $type;
  380.     Create($hd, $part);
  381.     }
  382. }
  383.  
  384. sub Exit(;$$) {
  385.     eval { raid::verify($Raid) };
  386.     if ($@) {
  387.     $::expert || die;
  388.     $in->ask_okcancel('', [ $@, _("Continue anyway?")]) or return;
  389.     }
  390.     foreach (@$hds) {
  391.     unless (WritePartitions($_)) {
  392.         return unless $::isStandalone;
  393.         $in->ask_yesorno(_("Quit without saving"), _("Quit without writing the partition table?"), 1) || return;
  394.     }
  395.     }
  396.     Gtk->main_quit;
  397. }
  398.  
  399. sub Active($$) {
  400.     &partition_table::active;
  401. }
  402. sub Delete($$) {
  403.     my ($hd, $part) = @_;
  404.     raid::is($part) ? raid::delete($raid, $part) : &partition_table::remove;
  405. }
  406. sub Type($$) {
  407.     my ($hd, $part) = @_;
  408.  
  409.     ask_alldatawillbelost($part, _("changing type of")) or return;
  410.  
  411.     my $type = type2name($part->{type});
  412.     $in->ask_from_entries_ref(_("Change partition type"),
  413.                   _("Which partition type do you want?"),
  414.                   [ _("Type") ],
  415.                   [ { val => \$type, list => [ partition_table::important_types($::expert) ], not_edit => !$::expert } ]) or return;
  416.     fsedit::change_type($hd, $part, name2type($type)) if defined $type;
  417. }
  418. sub Mount_point($$) {
  419.     my ($hd, $part) = @_;
  420.  
  421.     my $mntpoint = $part->{mntpoint} || do {
  422.     my $part_ = { %$part };
  423.     if (fsedit::suggest_part($hd, $part_, $hds, $part_suggestions)) {
  424.         fsedit::has_mntpoint('/', $hds) || $part_->{mntpoint} eq '/boot' ? $part_->{mntpoint} : '/';
  425.     } else { '' }
  426.     };
  427.     $in->ask_from_entries_ref(
  428.         '',
  429. _("Where do you want to mount device %s?", $part->{device}),
  430.         [ _("Mount point") ],
  431.     [ { val => \$mntpoint, list => [ fsedit::suggestions_mntpoint($hds), '' ] } ],
  432.     complete => sub {
  433.         !($part->{mntpoint} eq $mntpoint ||
  434.           check_mntpoint($mntpoint, $hd, $part, $hds))
  435.     }
  436.     ) or return;
  437.     $part->{mntpoint} = $mntpoint;
  438. }
  439. sub Mount($$) {
  440.     my ($hd, $part) = @_;
  441.     WritePartitions($hd) || return;
  442.     fs::mount_part($part);
  443. }
  444. sub Unmount($$) {
  445.     my ($hd, $part) = @_;
  446.     fs::umount_part($part);
  447. }
  448. sub Format($$) {
  449.     my ($hd, $part) = @_;
  450.     WritePartitions($_) or return foreach raid::is($part) ? @$hds : $hd;
  451.     ask_alldatawillbelost($part, _("formatting")) or return;
  452.     $part->{isFormatted} = 0; 
  453.     my $w = $in->wait_message(_("Formatting"), _("Formatting partition %s", $part->{device}));
  454.     raid::format_part($Raid, $part);
  455. }
  456. sub FormatAll() {
  457.     foreach (@$hds) { WritePartitions($_) || return; }
  458.     $in->ask_okcancel(_("Read carefully!"), [ _("After formatting all partitions,") , _("all data on these partitions will be lost") ], 1) or return;
  459.  
  460.     raid::format_part($Raid, $_) foreach fsedit::get_fstab(@$hds);
  461. }
  462. sub Move($$) {
  463.     my ($hd, $part) = @_;
  464.     my $hd2;
  465.     if (@$hds == 1) {
  466.     $hd2 = $hds->[0];
  467.     } else {
  468.     my $hd2_name = $in->ask_from_list(_("Move"),
  469.                       _("Which disk do you want to move to?"),
  470.                       [ map { $_->{device} } @$hds ]) or return;
  471.     ($hd2) = grep { $_->{device} eq $hd2_name } @$hds;
  472.     }
  473.     my $start2 = $in->ask_from_entry(_("Sector"),
  474.                      _("Which sector do you want to move to?"));
  475.     defined $start2 or return;
  476.  
  477.     my $w = $in->wait_message(_("Moving"), _("Moving partition..."));
  478.     fsedit::move($hd, $part, $hd2, $start2);
  479. }
  480.  
  481.  
  482. sub WritePartitions {
  483.     my ($hd) = @_;
  484.     $hd->{isDirty} or return 1;
  485.     exists $hd->{raid} and return 1;
  486.  
  487.     $in->ask_okcancel(_("Read carefully!"), _("Partition table of drive %s is going to be written to disk!", $hd->{device}), 1) or return;
  488.     partition_table::write($hd) unless $::testing;
  489.     $hd->{rebootNeeded} and die _("You'll need to reboot before the modification can take place");
  490.     1;
  491. }
  492. sub WriteFstab {
  493.     fs::write_fstab([ fsedit::get_fstab(@$hds) ]);
  494. }
  495.  
  496. sub Resize($$) {
  497.     my ($hd, $part) = @_;
  498.     my ($resize_fat, $resize_ext2);
  499.     my ($min, $max) = (1, partition_table::next_start($hd, $part) - $part->{start});
  500.  
  501.     if ($part->{isFormatted} || !$part->{notFormatted}) {
  502.     # here we may have a non-formatted or a formatted partition
  503.     # -> doing as if it was formatted
  504.  
  505.     isFat($part) || isExt2($part) or WritePartitions($hd) or return;
  506.     if (isFat($part)) {
  507.         WritePartitions($hd) or return;
  508.  
  509.         
  510.         my $w = $in->wait_message(_("Resizing"), _("Computing fat filesystem bounds"));
  511.  
  512.         $resize_fat = resize_fat::main->new($part->{device}, devices::make($part->{device}));
  513.         $min = max($min, $resize_fat->min_size);
  514.         $max = min($max, $resize_fat->max_size);        
  515.     } elsif (0 && isExt2($part)) {
  516.         WritePartitions($hd) or return;
  517.         $resize_ext2 = devices::make($part->{device});
  518.         my ($m) = `ext2resize $resize_ext2 0 2>/dev/null`;
  519.         $? ?
  520.           undef $resize_ext2 :
  521.           ($min = max($min, to_int($m) >> 9));
  522.     }
  523.     unless ($resize_fat || $resize_ext2) {
  524.         ask_alldatawillbelost($part, _("resizing")) or return;
  525.     }
  526.     }
  527.     my $w = my_gtk->new(_("Resize"), %$in);
  528.     my $adj = create_adjustment($part->{size} >> 11, $min >> 11, $max >> 11);
  529.     my $spin = gtkset_usize(new Gtk::SpinButton($adj, 0, 0), 100, 0);
  530.  
  531.     gtkadd($w->{window},
  532.       gtkpack(new Gtk::VBox(0,20),
  533.          create_packtable({ col_spacings => 10 },
  534.                   [ _("Choose the new size"), $spin, _("MB"), ],
  535.                   [ undef, new Gtk::HScrollbar($adj) ],
  536.                    ),
  537.          create_okcancel($w)
  538.         )
  539.      );
  540.     $spin->signal_connect(activate => sub { $w->{retval} = 1; Gtk->main_quit });
  541.     $spin->grab_focus();
  542.     $w->main or return;
  543.  
  544.     my $size = from_Mb($spin->get_value_as_int, $min, $max);
  545.  
  546.     $part->{size} == $size and return;
  547.  
  548.     my $oldsize = $part->{size};
  549.     $hd->{isDirty} = $hd->{needKernelReread} = 1;
  550.     $part->{size} = $size;
  551.     partition_table::adjustEnd($hd, $part);
  552.  
  553.     undef $@;
  554.     my $b = before_leaving { $@ and $part->{size} = $oldsize };
  555.     $w = $in->wait_message(_("Resizing"), '');
  556.  
  557.     if ($resize_fat) {
  558.     local *log::l = sub { $w->set(join(' ', @_)) };
  559.     $resize_fat->resize($size);
  560.     } elsif ($resize_ext2) {
  561.     my $s = $size << 9;
  562.     local *F;
  563.     open F, "ext2resize $resize_ext2 $s 2>&1 |";
  564.     $w->set($_) foreach <F>;
  565.  
  566.     close F or die "ext2resize failed";
  567.     } else {
  568.     $part->{notFormatted} = 1;
  569.     $part->{isFormatted} = 0;
  570.     return;
  571.     }
  572.     $part->{isFormatted} = 1;
  573.     partition_table::adjust_local_extended($hd, $part);
  574.     partition_table::adjust_main_extended($hd);
  575. }
  576.  
  577. sub Create($$) {
  578.     my ($hd, $part) = @_;
  579.     my ($start, $size, $max) = ($part->{start}, $part->{size}, $part->{start} + $part->{size});
  580.  
  581.     $part->{maxsize} = $part->{size}; $part->{size} = 0;
  582.     unless (fsedit::suggest_part($hd, $part, $hds, $part_suggestions)) {
  583.     $part->{size} = $part->{maxsize};
  584.     $part->{type} ||= 0x83;
  585.     }    
  586.  
  587.     my $w = my_gtk->new(_("Create a new partition"), %$in);
  588.  
  589.     my ($type_combo, $mntpoint_combo, $primaryextended_combo);
  590.     my $adj_start = create_adjustment($part->{start}, $start, $max - 1);
  591.     my $adj_size  = create_adjustment($part->{size} >> 11, 1, $size >> 11);
  592.     my $spin_start = new Gtk::SpinButton($adj_start, 0, 0);
  593.     my $spin_size  = new Gtk::SpinButton($adj_size,  0, 0);
  594.  
  595.     ($start, $size) = ($part->{start}, $size = $part->{size});
  596.     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); };
  597.     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); };
  598.  
  599.     my $h;
  600.     gtkadd($w->{window},
  601.       gtkpack(new Gtk::VBox(0,20),
  602.          create_packtable({},
  603.           [ _("Start sector: "), gtksignal_connect($spin_start, changed => $update_size) ],
  604.           [ undef, new Gtk::HScrollbar($adj_start) ],
  605.           [ '' ],
  606.           [ _("Size in MB: "),   gtksignal_connect($spin_size,  changed => $update_start) ],
  607.           [ undef, new Gtk::HScrollbar($adj_size) ],
  608.           [ '' ],
  609.           [ _("Filesystem type: "), $type_combo = new Gtk::Combo ],
  610.           [ _("Mount point: "), $mntpoint_combo = new Gtk::Combo ],
  611.                   ($::expert ? [ _("Preference: "), $primaryextended_combo = new Gtk::Combo ] : ()),
  612.                  ),
  613.          create_okcancel($w)
  614.          ),
  615.     );
  616.     $type_combo->set_popdown_strings(partition_table::important_types($::expert));
  617.     $type_combo->entry->set_text(type2name($part->{type})) if $part->{type};
  618.     $mntpoint_combo->set_popdown_strings(fsedit::suggestions_mntpoint($hds), '');
  619.     $mntpoint_combo->entry->set_text($part->{mntpoint});
  620.     if ($::expert) {
  621.     $primaryextended_combo->set_popdown_strings("Extended", "Primary");
  622.     }
  623.  
  624.     foreach ($type_combo, $mntpoint_combo, $primaryextended_combo) {
  625.     $_ or next;
  626.     $_->disable_activate;
  627.     $_->set_use_arrows_always(1);
  628.     }
  629.     $type_combo->entry->set_editable(0) unless $::expert;
  630.     $type_combo->entry->signal_connect(changed => sub { $mntpoint_combo->set_sensitive(bool($type_combo->entry->get_text !~ /swap|RAID/)) });
  631.     $mntpoint_combo->entry->signal_connect(activate => sub { $w->{retval} = 1; Gtk->main_quit });
  632.     $mntpoint_combo->entry->grab_focus;
  633.  
  634.     $type_combo->entry->signal_emit("changed");
  635.  
  636.     $w->main(sub {
  637.          $part->{start} = $start;
  638.          $part->{size}  = from_Mb($size >> 11, 1, $max - $start); 
  639.          ($part->{type} = name2type($type_combo->entry->get_text)) =~ s/0x(.*)/hex($1)/e;
  640.          $part->{mntpoint} = $mntpoint_combo->entry->get_text;
  641.          $part->{mntpoint} = '' if isRAID($part);
  642.          $part->{mntpoint} = 'swap' if isSwap($part);
  643.  
  644.          check_mntpoint($part->{mntpoint}, $hd, $part, $hds) or return;
  645.          fsedit::add($hd, $part, $hds,
  646.                  { force => 1,
  647.                    primaryOrExtended => $::expert ? $primaryextended_combo->entry->get_text : '' }
  648.                 );
  649.          1;
  650.          });
  651. }
  652.  
  653. sub ReadFromFile() {
  654.     my $file = $::isStandalone ?
  655.          ask_file(_("Select file")) :
  656.                  devices::make("fd0") or return;
  657.  
  658.     $_->widget->destroy foreach $hds_widget{current_hd()}->children;
  659.  
  660.     catch_cdie { partition_table::load(current_hd(), $file) }
  661.       sub {
  662.       $@ =~ /Bad totalsectors/ or return;
  663.       $in->ask_yesorno('',
  664. _("The backup partition table has not the same size
  665. Still continue?"), 0);
  666.       };
  667. }
  668.  
  669. sub SaveInFile() {
  670.     my $file = $::isStandalone ?
  671.          ask_file(_("Select file")) :
  672.                  $in->ask_okcancel(_("Warning"),
  673. _("Insert a floppy in drive
  674. All data on this floppy will be lost"), 1) && devices::make("fd0") or return;
  675.  
  676.     partition_table::save(current_hd(), $file);
  677. }
  678.  
  679. sub Undo() {
  680. #    $_->widget->destroy foreach current_hd()->{widget}->children;
  681. #    my @widgets = map { delete $_->{widget} } @$hds;
  682.     fsedit::undo($hds);
  683. #    mapn { $_[0]{widget} = $_[1] } $hds, \@widgets;
  684. }
  685.  
  686. sub Rescuept {
  687.     my $w = $in->wait_message('', _("Trying to rescue partition table"));
  688.     fsedit::rescuept(current_hd());
  689. }
  690.  
  691. sub Reload { %$hds = (); %$Raid = (); $::setstep and die "setstep partitionDisks\n" }
  692.  
  693. sub modifyRAID {
  694.     my ($raid, $nb) = @_;
  695.     my $md = "md$nb";
  696.     $in->ask_from_entries_refH('', '',
  697.                    [
  698. _("device") => { val => \$md, list => [ map { "md$_" } grep { $nb == $_ || !$raid->[$_] } 0..8 ] },
  699. _("level") => { val => \$raid->[$nb]{level}, list => [ qw(0 1 4 5 linear) ] },
  700. _("chunk size") => \$raid->[$nb]{'chunk-size'},
  701.                    ],
  702.                   ) or return;
  703.     raid::changeNb($raid, $nb, first($md =~ /(\d+)/));
  704. }
  705.  
  706. sub ModifyRAID { modifyRAID($raid, raid::nb($_[1])) }
  707.  
  708. sub Add2RAID {
  709.     my ($hd, $part) = @_;
  710.  
  711.     local $_ = is_empty_array_ref($raid) ? "new" :
  712.       $in->ask_from_list_('', _("Choose an existing RAID to add to"),
  713.               [ (grep {$_} map_index { $_ && "md$::i" } @$raid), __("new") ]);
  714.  
  715.     if (/new/) {
  716.     my $nb1 = raid::new($raid, $part);
  717.     defined modifyRAID($raid, $nb1) or return raid::delete($raid, $nb1);
  718.     } else {
  719.     raid::add($raid, $part, $_);
  720.     }
  721.     raid::update(@$raid);
  722.  
  723.     unless (member($Raid, @$hds)) {
  724.     $hds = [ @$hds, $Raid ];
  725.     raid::stopAll;
  726.     my_gtk::add2notebook($notebook_widget, "raid", $hds_widget{$Raid});
  727.     $hds_widget{$Raid}{widget_title}->signal_connect('event' => [ \&display_drive_info, $Raid ]);
  728.     }
  729. }
  730. sub RemoveFromRAID { raid::removeDisk($raid, $_[1]) }
  731.  
  732.  
  733.     no strict; 
  734.     *{"Mount point"} = *Mount_point;
  735.     *{"Modify RAID"} = *ModifyRAID;
  736.     *{"Add to RAID"} = *Add2RAID;
  737.     *{"Remove from RAID"} = *RemoveFromRAID; 
  738. }
  739.