]> git.proxmox.com Git - pve-installer.git/blobdiff - proxinstall
bump version to 8.2.6
[pve-installer.git] / proxinstall
index 6d138928573fb0ba3be4a739e8c6d61e202c456a..a6a4cfb55e4ae463ca2238f8f546c827c5c24465 100755 (executable)
@@ -180,7 +180,19 @@ sub create_main_window {
     my $abort = Gtk3::Button->new('_Abort');
     $abort->set_can_focus(0);
     $cmdbox->pack_start($abort, 0, 0, 10);
-    $abort->signal_connect(clicked => sub { app_quit(-1); });
+    $abort->signal_connect(clicked => sub {
+       my $msg = 'Abort Installation';
+       my $secondary_text = 'Are you sure you want to abort the installation?';
+       my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'question', 'yes-no', $msg);
+       $dialog->format_secondary_text($secondary_text);
+       $dialog->signal_connect(response => sub {
+           my ($dialog, $response) = @_;
+
+           $dialog->close();
+           app_quit(-1) if $response eq 'yes';
+       });
+       $dialog->present();
+    });
 
     my $vbox2 = Gtk3::Box->new('vertical', 0);
     $hbox->add($vbox2);
@@ -213,6 +225,8 @@ sub create_main_window {
     $gtk_state->{next_btn} = $next_btn;
     $gtk_state->{progress_bar} = Gtk3::ProgressBar->new();
     $gtk_state->{progress_status} = Gtk3::Label->new('');
+    $gtk_state->{abort_btn} = $abort;
+    $gtk_state->{disk_selection} = {};
 
     Proxmox::UI::init_gtk($gtk_state, $iso_env);
 
@@ -267,18 +281,14 @@ sub check_number {
 sub create_text_input {
     my ($default, $text) = @_;
 
-    my $hbox = Gtk3::Box->new('horizontal', 0);
-
     my $label = Gtk3::Label->new($text);
     $label->set_size_request(150, -1);
     $label->set_xalign(1.0);
-    $hbox->pack_start($label, 0, 0, 10);
     my $e1 = Gtk3::Entry->new();
     $e1->set_width_chars(35);
-    $hbox->pack_start($e1, 0, 0, 0);
     $e1->set_text($default);
 
-    return ($hbox, $e1);
+    return ($label, $e1);
 }
 sub create_cidr_inputs {
     my ($cidr) = @_;
@@ -290,47 +300,70 @@ sub create_cidr_inputs {
     my $label = Gtk3::Label->new('IP Address (CIDR)');
     $label->set_size_request(150, -1);
     $label->set_xalign(1.0);
-    $hbox->pack_start($label, 0, 0, 10);
 
     my $ip_el = Gtk3::Entry->new();
     $ip_el->set_width_chars(28);
-    $hbox->pack_start($ip_el, 0, 0, 0);
+    $hbox->pack_start($ip_el, 1, 1, 0);
     $ip_el->set_text($default_ip);
 
-    $label = Gtk3::Label->new('/');
-    $label->set_size_request(10, -1);
-    $hbox->pack_start($label, 0, 0, 2);
+    my $dash_label = Gtk3::Label->new('/');
+    $dash_label->set_size_request(10, -1);
+    $hbox->pack_start($dash_label, 0, 0, 2);
 
     my $cidr_el = Gtk3::Entry->new();
     $cidr_el->set_width_chars(3);
     $hbox->pack_start($cidr_el, 0, 0, 0);
     $cidr_el->set_text($default_mask);
 
-    return ($hbox, $ip_el, $cidr_el);
+    return ($label, $hbox, $ip_el, $cidr_el);
 }
 
 my $ipconf_first_view = 1;
 
+my $create_basic_grid = sub {
+    my $grid =  Gtk3::Grid->new();
+    $grid->set_visible(1);
+    $grid->set_column_spacing(10);
+    $grid->set_row_spacing(10);
+    $grid->set_hexpand(1);
+
+    $grid->set_margin_start(20);
+    $grid->set_margin_end(20);
+    $grid->set_margin_top(10);
+    $grid->set_margin_bottom(10);
+
+    return $grid;
+};
+
 sub create_ipconf_view {
 
     cleanup_view();
     Proxmox::UI::display_html('ipconf.htm');
 
-    my $vcontainer = Gtk3::Box->new('vertical', 0);
-    $gtk_state->{inbox}->pack_start($vcontainer, 1, 0, 0);
-    my $hcontainer =  Gtk3::Box->new('horizontal', 0);
-    $vcontainer->pack_start($hcontainer, 0, 0, 10);
-    my $vbox =  Gtk3::Box->new('vertical', 0);
-    $hcontainer->add($vbox);
+    my $grid = &$create_basic_grid();
+    $grid->set_row_spacing(10);
+    $grid->set_column_spacing(10);
+
+    $gtk_state->{inbox}->pack_start($grid, 0, 0, 0);
 
     my $cidr = Proxmox::Install::Config::get_cidr() // '192.168.100.2/24';
 
-    my ($cidr_box, $ipconf_entry_addr, $ipconf_entry_mask) = create_cidr_inputs($cidr);
+    my ($cidr_label, $cidr_box, $ipconf_entry_addr, $ipconf_entry_mask) = create_cidr_inputs($cidr);
 
-    my $device_cb = Gtk3::ComboBoxText->new();
+    my $device_model = Gtk3::ListStore->new('Glib::String', 'Glib::String');
+    my $device_cb = Gtk3::ComboBox->new_with_model($device_model);
     $device_cb->set_active(0);
     $device_cb->set_visible(1);
 
+    my $icon_cell = Gtk3::CellRendererText->new();
+    $device_cb->pack_start($icon_cell, 0);
+    $device_cb->add_attribute($icon_cell, 'text', 0);
+    $icon_cell->set_property('foreground', 'green');
+
+    my $cell = Gtk3::CellRendererText->new();
+    $device_cb->pack_start($cell, 0);
+    $device_cb->add_attribute($cell, 'text', 1);
+
     my $get_device_desc = sub {
        my $iface = shift;
        return "$iface->{name} - $iface->{mac} ($iface->{driver})";
@@ -360,7 +393,12 @@ sub create_ipconf_view {
     my $i = 0;
     for my $index (sort keys $ipconf->{ifaces}->%*) {
        my $iface = $ipconf->{ifaces}->{$index};
-       $device_cb->append_text($get_device_desc->($iface));
+       my $iter = $device_model->append();
+       my $symbol = "$iface->{state}" eq "UP" ? "\x{25CF}" : ' ';
+       $device_model->set($iter,
+          0 => $symbol,
+          1 => $get_device_desc->($iface),
+       );
        $device_active_map->{$i} = $index;
        $device_active_reverse_map->{$iface->{name}} = $i;
        if ($ipconf_first_view && $index == $ipconf->{default}) {
@@ -378,35 +416,39 @@ sub create_ipconf_view {
        $device_cb->set_active(0);
     }
 
-    my $devicebox = Gtk3::Box->new('horizontal', 0);
-    my $label = Gtk3::Label->new("Management Interface:");
+    my $label = Gtk3::Label->new("Management Interface");
     $label->set_size_request(150, -1);
     $label->set_xalign(1.0);
-    $devicebox->pack_start($label, 0, 0, 10);
-    $devicebox->pack_start($device_cb, 0, 0, 0);
 
-    $vbox->pack_start($devicebox, 0, 0, 2);
+    $grid->attach($label, 0, 0, 1, 1);
+    $grid->attach($device_cb, 1, 0, 1, 1);
 
     my $fqdn = Proxmox::Install::Config::get_fqdn();
-    my $hn = $fqdn // "$iso_env->{product}." . ($ipconf->{domain} // "example.invalid");
+    my $hostname = $run_env->{network}->{hostname} || $iso_env->{product};
+    my $domain = $ipconf->{domain} || "example.invalid";
+    $fqdn //= "$hostname.$domain";
 
-    my ($hostbox, $hostentry) = create_text_input($hn, 'Hostname (FQDN):');
-    $vbox->pack_start($hostbox, 0, 0, 2);
+    my ($host_label, $hostentry) = create_text_input($fqdn, 'Hostname (FQDN)');
+    $grid->attach($host_label, 0, 1, 1, 1);
+    $grid->attach($hostentry, 1, 1, 1, 1);
 
-    $vbox->pack_start($cidr_box, 0, 0, 2);
+    $grid->attach($cidr_label, 0, 2, 1, 1);
+    $grid->attach($cidr_box, 1, 2, 1, 1);
 
     my $cfg_gateway = Proxmox::Install::Config::get_gateway();
     my $gateway = $cfg_gateway // $ipconf->{gateway} || '192.168.100.1';
 
-    my ($gwbox, $ipconf_entry_gw) = create_text_input($gateway, 'Gateway:');
-    $vbox->pack_start($gwbox, 0, 0, 2);
+    my ($gw_label, $ipconf_entry_gw) = create_text_input($gateway, 'Gateway');
+    $grid->attach($gw_label, 0, 3, 1, 1);
+    $grid->attach($ipconf_entry_gw, 1, 3, 1, 1);
 
     my $cfg_dns = Proxmox::Install::Config::get_dns();
     my $dnsserver = $cfg_dns // $ipconf->{dnsserver} || $gateway;
 
-    my ($dnsbox, $ipconf_entry_dns) = create_text_input($dnsserver, 'DNS Server:');
+    my ($dns_label, $ipconf_entry_dns) = create_text_input($dnsserver, 'DNS Server');
 
-    $vbox->pack_start($dnsbox, 0, 0, 0);
+    $grid->attach($dns_label, 0, 4, 1, 1);
+    $grid->attach($ipconf_entry_dns, 1, 4, 1, 1);
 
     $gtk_state->{inbox}->show_all;
     set_next(undef, sub {
@@ -415,23 +457,16 @@ sub create_ipconf_view {
        $text =~ s/^\s+//;
        $text =~ s/\s+$//;
 
-       my $namere = "([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)";
+       my ($hostname, $domainname) = eval { Proxmox::Sys::Net::parse_fqdn($text) };
+       my $err = $@;
 
-       # Debian does not support purely numeric hostnames
-       if ($text && $text =~ /^[0-9]+(?:\.|$)/) {
-           Proxmox::UI::message("Purely numeric hostnames are not allowed.");
+       if ($err || $text =~ m/.example.invalid$/) {
+           Proxmox::UI::message($err || 'Hostname does not look like a valid fully qualified domain name');
            $hostentry->grab_focus();
            return;
-       }
-
-       if ($text && $text =~ m/^(${namere}\.)*${namere}$/ && $text !~ m/.example.invalid$/ &&
-           $text =~ m/^([^\.]+)\.(\S+)$/) {
-           Proxmox::Install::Config::set_hostname($1);
-           Proxmox::Install::Config::set_domain($2);
        } else {
-           Proxmox::UI::message("Hostname does not look like a fully qualified domain name.");
-           $hostentry->grab_focus();
-           return;
+           Proxmox::Install::Config::set_hostname($hostname);
+           Proxmox::Install::Config::set_domain($domainname);
        }
 
        # verify ip address
@@ -467,8 +502,8 @@ sub create_ipconf_view {
        $text = $ipconf_entry_dns->get_text();
        my ($dns_ip, $dns_ip_version) = parse_ip_address($text);
        if (!defined($dns_ip) || $dns_ip_version != $ipversion) {
-           my $msg = defined($gateway_ip)
-               ? "DNS and host IP version must not differ (IPv$gateway_ip_version != IPv$ipversion)."
+           my $msg = defined($dns_ip)
+               ? "DNS and host IP version must not differ (IPv$dns_ip_version != IPv$ipversion)."
                : "DNS IP is not valid.";
            Proxmox::UI::message($msg);
            $ipconf_entry_dns->grab_focus();
@@ -601,12 +636,12 @@ sub update_layout {
 
 my $lastzonecb;
 sub update_zonelist {
-    my ($box, $cc) = @_;
+    my ($grid, $cc) = @_;
 
     my $sel = Proxmox::Install::Config::get_timezone(); # initial default
     if ($lastzonecb) {
        $sel = $lastzonecb->get_active_text();
-       $box->remove($lastzonecb);
+       $grid->remove($lastzonecb);
     }
 
     my $cb = $lastzonecb = Gtk3::ComboBoxText->new();
@@ -632,7 +667,7 @@ sub update_zonelist {
     $cb->set_active($selected_index || 0);
 
     $cb->show;
-    $box->pack_start($cb, 0, 0, 0);
+    $grid->attach($cb, 1, 1, 1, 1);
 }
 
 sub create_password_view {
@@ -641,47 +676,40 @@ sub create_password_view {
 
     my $password = Proxmox::Install::Config::get_password();
 
-    my $vbox2 =  Gtk3::Box->new('vertical', 0);
-    $gtk_state->{inbox}->pack_start($vbox2, 1, 0, 0);
-    my $vbox =  Gtk3::Box->new('vertical', 0);
-    $vbox2->pack_start($vbox, 0, 0, 10);
+    my $grid = &$create_basic_grid();
+    $gtk_state->{inbox}->pack_start($grid, 0, 0, 0);
 
-    my $hbox1 = Gtk3::Box->new('horizontal', 0);
     my $label = Gtk3::Label->new("Password");
     $label->set_size_request(150, -1);
     $label->set_xalign(1.0);
-    $hbox1->pack_start($label, 0, 0, 10);
+    $grid->attach($label, 0, 0, 1, 1);
     my $pwe1 = Gtk3::Entry->new();
     $pwe1->set_visibility(0);
     $pwe1->set_text($password) if $password;
     $pwe1->set_size_request(200, -1);
-    $hbox1->pack_start($pwe1, 0, 0, 0);
+    $grid->attach($pwe1, 1, 0, 1, 1);
 
-    my $hbox2 = Gtk3::Box->new('horizontal', 0);
     $label = Gtk3::Label->new("Confirm");
     $label->set_size_request(150, -1);
     $label->set_xalign(1.0);
-    $hbox2->pack_start($label, 0, 0, 10);
+    $grid->attach($label, 0, 1, 1, 1);
     my $pwe2 = Gtk3::Entry->new();
     $pwe2->set_visibility(0);
     $pwe2->set_text($password) if $password;
     $pwe2->set_size_request(200, -1);
-    $hbox2->pack_start($pwe2, 0, 0, 0);
+    $grid->attach($pwe2, 1, 1, 1, 1);
 
-    my $hbox3 = Gtk3::Box->new('horizontal', 0);
     $label = Gtk3::Label->new("Email");
     $label->set_size_request(150, -1);
     $label->set_xalign(1.0);
-    $hbox3->pack_start($label, 0, 0, 10);
+    $label->set_margin_top(10);
+    $grid->attach($label, 0, 2, 1, 1);
+
     my $eme = Gtk3::Entry->new();
     $eme->set_size_request(200, -1);
     $eme->set_text(Proxmox::Install::Config::get_mailto());
-    $hbox3->pack_start($eme, 0, 0, 0);
-
-
-    $vbox->pack_start($hbox1, 0, 0, 5);
-    $vbox->pack_start($hbox2, 0, 0, 5);
-    $vbox->pack_start($hbox3, 0, 0, 15);
+    $eme->set_margin_top(10);
+    $grid->attach($eme, 1, 2, 1, 1);
 
     $gtk_state->{inbox}->show_all;
 
@@ -735,10 +763,8 @@ sub create_country_view {
 
     my $locales = $iso_env->{locales};
 
-    my $vbox2 =  Gtk3::Box->new('vertical', 0);
-    $gtk_state->{inbox}->pack_start($vbox2, 1, 0, 0);
-    my $vbox =  Gtk3::Box->new('vertical', 0);
-    $vbox2->pack_start($vbox, 0, 0, 10);
+    my $grid = &$create_basic_grid();
+    $gtk_state->{inbox}->pack_start($grid, 0, 0, 0);
 
     my $w = Gtk3::Entry->new();
     $w->set_size_request(200, -1);
@@ -749,18 +775,16 @@ sub create_country_view {
     $c->set_popup_set_width(1);
     $c->set_inline_completion(1);
 
-    my $hbox2 = Gtk3::Box->new('horizontal', 0);
     my $label = Gtk3::Label->new("Time zone");
     $label->set_size_request(150, -1);
     $label->set_xalign(1.0);
-    $hbox2->pack_start($label, 0, 0, 10);
-    update_zonelist ($hbox2);
+    $grid->attach($label, 0, 1, 1, 1);
+    update_zonelist ($grid);
 
-    my $hbox3 = Gtk3::Box->new('horizontal', 0);
     $label = Gtk3::Label->new("Keyboard Layout");
     $label->set_size_request(150, -1);
     $label->set_xalign(1.0);
-    $hbox3->pack_start($label, 0, 0, 10);
+    $grid->attach($label, 0, 2, 1, 1);
 
     my $kmapcb = Gtk3::ComboBoxText->new();
     $kmapcb->set_size_request (200, -1);
@@ -769,7 +793,7 @@ sub create_country_view {
     }
 
     update_layout($kmapcb);
-    $hbox3->pack_start ($kmapcb, 0, 0, 0);
+    $grid->attach($kmapcb, 1, 2, 1, 1);
 
     $kmapcb->signal_connect ('changed' => sub {
        my $sel = $kmapcb->get_active_text();
@@ -806,7 +830,7 @@ sub create_country_view {
        my $text = $entry->get_text;
 
        if (my $cc = $locales->{countryhash}->{lc($text)}) {
-           update_zonelist($hbox2, $cc);
+           update_zonelist($grid, $cc);
            my $kmap = $locales->{country}->{$cc}->{kmap} || 'en-us';
            update_layout($kmapcb, $kmap);
        }
@@ -866,17 +890,11 @@ sub create_country_view {
 
     $w->set_completion ($c);
 
-    my $hbox =  Gtk3::Box->new('horizontal', 0);
-
     $label = Gtk3::Label->new("Country");
     $label->set_xalign(1.0);
     $label->set_size_request(150, -1);
-    $hbox->pack_start($label, 0, 0, 10);
-    $hbox->pack_start($w, 0, 0, 0);
-
-    $vbox->pack_start($hbox, 0, 0, 5);
-    $vbox->pack_start($hbox2, 0, 0, 5);
-    $vbox->pack_start($hbox3, 0, 0, 5);
+    $grid->attach($label, 0, 0, 1, 1);
+    $grid->attach($w, 1, 0, 1, 1);
 
     my $country = Proxmox::Install::Config::get_country();
     if ($country && (my $entry = $locales->{country}->{$country})) {
@@ -909,36 +927,30 @@ my $target_hd_label;
 
 my $hdoption_first_setup = 1;
 
-my $create_basic_grid = sub {
-    my $grid =  Gtk3::Grid->new();
-    $grid->set_visible(1);
-    $grid->set_column_spacing(10);
-    $grid->set_row_spacing(10);
-    $grid->set_hexpand(1);
-
-    $grid->set_margin_start(10);
-    $grid->set_margin_end(20);
-    $grid->set_margin_top(5);
-    $grid->set_margin_bottom(5);
-
-    return $grid;
-};
-
+# takes an array ref of rows with [$label_text, $widget, $suffix_label] array refs as columns
+# $suffix_label is optional
 my $create_label_widget_grid = sub {
     my ($labeled_widgets) = @_;
 
     my $grid = &$create_basic_grid();
-    my $row = 0;
 
-    for (my $i = 0; $i < @$labeled_widgets; $i += 2) {
-       my $widget = @$labeled_widgets[$i+1];
-       my $label = Gtk3::Label->new(@$labeled_widgets[$i]);
+    for (my $row = 0; $row < scalar($labeled_widgets->@*); $row++) {
+       my ($label_text, $widget, $suffix_label) = $labeled_widgets->[$row]->@*;
+
+       my $label = Gtk3::Label->new($label_text);
        $label->set_visible(1);
        $label->set_xalign(1.0);
        $grid->attach($label, 0, $row, 1, 1);
+
        $widget->set_visible(1);
        $grid->attach($widget, 1, $row, 1, 1);
-       $row++;
+
+       if ($suffix_label) {
+           my $suffix_label = Gtk3::Label->new($suffix_label);
+           $suffix_label->set_visible(1);
+           $suffix_label->set_xalign(1.0);
+           $grid->attach($suffix_label, 2, $row, 1, 1);
+       }
     }
 
     return $grid;
@@ -953,8 +965,7 @@ my $get_selected_hdsize = sub {
     my $cached_disks = get_cached_disks();
     my $disk_count = scalar(@$cached_disks);
     for (my $i = 0; $i < $disk_count; $i++) {
-       next if !Proxmox::Install::Config::get_disk_selection($i);
-       my $cur_hd = $cached_disks->[$i];
+       my $cur_hd = $gtk_state->{disk_selection}->{$i} // next;
        my $disksize = int(@$cur_hd[2] / (2 * 1024 * 1024.0)); # size in GB
        $hdsize //= $disksize;
        $hdsize = $disksize if $disksize < $hdsize;
@@ -993,7 +1004,7 @@ my sub get_hdsize_spin_button {
     my $spinbutton_hdsize = Gtk3::SpinButton->new($hdsize_size_adj, 1, 1);
     $spinbutton_hdsize->set_buffer($hdsize_entry_buffer);
     $spinbutton_hdsize->set_adjustment($hdsize_size_adj);
-    $spinbutton_hdsize->set_tooltip_text("only use specified size (GB) of the harddisk (rest left unpartitioned)");
+    $spinbutton_hdsize->set_tooltip_text("only use specified size of the harddisk (rest left unpartitioned)");
     return $spinbutton_hdsize;
 };
 
@@ -1019,7 +1030,7 @@ my $create_raid_disk_grid = sub {
            my $w = shift;
            my $diskid = $w->{pve_disk_id};
            my $a = $w->get_active - 1;
-           Proxmox::Install::Config::set_disk_selection($diskid, $a >= 0);
+           $gtk_state->{disk_selection}->{$diskid} = ($a >= 0) ? $cached_disks->[$a] : undef;
            for my $btn (@$hdsize_buttons) {
                update_hdsize_adjustment($btn->get_adjustment());
            }
@@ -1029,8 +1040,7 @@ my $create_raid_disk_grid = sub {
            $disk_selector->set_active ($i+1) if $cached_disks->[$i];
        } else {
            my $hdind = 0;
-           if (Proxmox::Install::Config::get_disk_selection($i)) {
-               my $cur_hd = $cached_disks->[$i];
+           if (my $cur_hd = $gtk_state->{disk_selection}->{$i}) {
                foreach my $hd (@$cached_disks) {
                    if (@$hd[1] eq @$cur_hd[1]) {
                        $disk_selector->set_active($hdind+1);
@@ -1041,7 +1051,7 @@ my $create_raid_disk_grid = sub {
            }
        }
 
-       push @$disk_labeled_widgets, "Harddisk $i", $disk_selector;
+       push @$disk_labeled_widgets, ["Harddisk $i", $disk_selector];
     }
 
     my $clear_all_button = Gtk3::Button->new('_Deselect All');
@@ -1049,8 +1059,7 @@ my $create_raid_disk_grid = sub {
        $clear_all_button->signal_connect('clicked', sub {
            my $is_widget = 0;
            for my $disk_selector (@$disk_labeled_widgets) {
-               $disk_selector->set_active(0) if $is_widget;
-               $is_widget ^= 1;
+               $disk_selector->[1]->set_active(0);
            }
        });
        $clear_all_button->set_visible(1);
@@ -1089,8 +1098,7 @@ my $create_raid_advanced_grid = sub {
     });
     my $ashift = Proxmox::Install::Config::get_zfs_opt('ashift') // 12;
     $spinbutton_ashift->set_value($ashift);
-    push @$labeled_widgets, "ashift";
-    push @$labeled_widgets, $spinbutton_ashift;
+    push @$labeled_widgets, ['ashift', $spinbutton_ashift ];
 
     my $combo_compress = Gtk3::ComboBoxText->new();
     $combo_compress->set_tooltip_text("zfs compression algorithm for rpool dataset");
@@ -1104,12 +1112,11 @@ my $create_raid_advanced_grid = sub {
        my $w = shift;
        Proxmox::Install::Config::set_zfs_opt('compress', $w->get_active_text());
     });
-    push @$labeled_widgets, "compress";
-    push @$labeled_widgets, $combo_compress;
+    push @$labeled_widgets, ['compress', $combo_compress];
 
     my $combo_checksum = Gtk3::ComboBoxText->new();
     $combo_checksum->set_tooltip_text("zfs checksum algorithm for rpool dataset");
-    my $csum_opts = ["on", "off","fletcher2", "fletcher4", "sha256"];
+    my $csum_opts = ["on", "fletcher4", "sha256"];
     foreach my $opt (@$csum_opts) {
        $combo_checksum->append($opt, $opt);
     }
@@ -1119,8 +1126,7 @@ my $create_raid_advanced_grid = sub {
        my $w = shift;
        Proxmox::Install::Config::set_zfs_opt('checksum', $w->get_active_text());
     });
-    push @$labeled_widgets, "checksum";
-    push @$labeled_widgets, $combo_checksum;
+    push @$labeled_widgets, ['checksum', $combo_checksum];
 
     my $spinbutton_copies = Gtk3::SpinButton->new_with_range(1,3,1);
     $spinbutton_copies->set_tooltip_text("zfs copies property for rpool dataset (in addition to RAID redundancy!)");
@@ -1130,16 +1136,31 @@ my $create_raid_advanced_grid = sub {
     });
     my $copies = Proxmox::Install::Config::get_zfs_opt('copies') // 1;
     $spinbutton_copies->set_value($copies);
-    push @$labeled_widgets, "copies", $spinbutton_copies;
+    push @$labeled_widgets, ['copies', $spinbutton_copies];
+
+    if ($iso_env->{product} eq 'pve') {
+       my $total_memory = Proxmox::Install::RunEnv::get('total_memory');
+
+       my $spinbutton_arc_max = Gtk3::SpinButton->new_with_range(
+           $Proxmox::Install::RunEnv::ZFS_ARC_MIN_SIZE_MIB, $total_memory, 1);
+       $spinbutton_arc_max->set_tooltip_text('Maximum ARC size in megabytes');
+       $spinbutton_arc_max->signal_connect('value-changed' => sub {
+           my $w = shift;
+           Proxmox::Install::Config::set_zfs_opt('arc_max', $w->get_value_as_int());
+       });
+       my $arc_max = Proxmox::Install::Config::get_zfs_opt('arc_max');
+       $spinbutton_arc_max->set_value($arc_max);
+       push @$labeled_widgets, ['ARC max size', $spinbutton_arc_max, 'MiB'];
+    }
 
-    push @$labeled_widgets, "hdsize", $hdsize_btn;
+    push @$labeled_widgets, ['hdsize', $hdsize_btn, 'GB'];
     return $create_label_widget_grid->($labeled_widgets);;
 };
 
 my $create_btrfs_raid_advanced_grid = sub {
     my ($hdsize_btn) = @_;
     my $labeled_widgets = [];
-    push @$labeled_widgets, "hdsize", $hdsize_btn;
+    push @$labeled_widgets, ['hdsize', $hdsize_btn, 'GB'];
     return $create_label_widget_grid->($labeled_widgets);;
 };
 
@@ -1218,43 +1239,43 @@ sub create_hdoption_view {
     }
 
     my $spinbutton_hdsize_nonraid = get_hdsize_spin_button($hdsize);
-    push @$hdsize_labeled_widgets, "hdsize", $spinbutton_hdsize_nonraid;
+    push @$hdsize_labeled_widgets, ['hdsize', $spinbutton_hdsize_nonraid, 'GB'];
     my $spinbutton_hdsize = $spinbutton_hdsize_nonraid;
 
     my $entry_swapsize = Gtk3::Entry->new();
-    $entry_swapsize->set_tooltip_text("maximum SWAP size (GB)");
+    $entry_swapsize->set_tooltip_text("maximum SWAP size");
     $entry_swapsize->signal_connect (key_press_event => \&check_float);
     my $swapsize = Proxmox::Install::Config::get_swapsize();
     $entry_swapsize->set_text($swapsize) if defined($swapsize);
-    push @$hdsize_labeled_widgets, "swapsize", $entry_swapsize;
+    push @$hdsize_labeled_widgets, ['swapsize', $entry_swapsize, 'GB'];
 
     my $entry_maxroot = Gtk3::Entry->new();
     if ($iso_env->{product} eq 'pve') {
-       $entry_maxroot->set_tooltip_text("maximum size (GB) for LVM root volume");
+       $entry_maxroot->set_tooltip_text("maximum size for LVM root volume");
        $entry_maxroot->signal_connect (key_press_event => \&check_float);
        if (my $maxroot = Proxmox::Install::Config::get_maxroot()) {
            $entry_maxroot->set_text($maxroot);
        }
-       push @$hdsize_labeled_widgets, "maxroot", $entry_maxroot;
+       push @$hdsize_labeled_widgets, ['maxroot', $entry_maxroot, 'GB'];
     }
 
     my $entry_minfree = Gtk3::Entry->new();
-    $entry_minfree->set_tooltip_text("minimum free LVM space (GB, required for LVM snapshots)");
+    $entry_minfree->set_tooltip_text("minimum free LVM space (required for LVM snapshots)");
     $entry_minfree->signal_connect (key_press_event => \&check_float);
     if (defined(my $minfree = Proxmox::Install::Config::get_minfree())) {
        $entry_minfree->set_text($minfree);
     }
-    push @$hdsize_labeled_widgets, "minfree", $entry_minfree;
+    push @$hdsize_labeled_widgets, ['minfree', $entry_minfree, 'GB'];
 
     my $entry_maxvz;
     if ($iso_env->{product} eq 'pve') {
        $entry_maxvz = Gtk3::Entry->new();
-       $entry_maxvz->set_tooltip_text("maximum size (GB) for LVM data volume");
+       $entry_maxvz->set_tooltip_text("maximum size for LVM data volume");
        $entry_maxvz->signal_connect (key_press_event => \&check_float);
        if (defined(my $maxvz = Proxmox::Install::Config::get_maxvz())) {
            $entry_maxvz->set_text($maxvz);
        }
-       push @$hdsize_labeled_widgets, "maxvz", $entry_maxvz;
+       push @$hdsize_labeled_widgets, ['maxvz', $entry_maxvz, 'GB'];
     }
 
     my $spinbutton_hdsize_zfs = get_hdsize_spin_button($hdsize);
@@ -1303,7 +1324,7 @@ sub create_hdoption_view {
            $target_hd_label->set_text("Target: $filesys ");
            $options_stack->set_visible_child_name("raiddisk");
        } else {
-           $target_hd_label->set_text("Target Harddisk");
+           $target_hd_label->set_text("Target Harddisk");
        }
 
        if ($raid) {
@@ -1383,6 +1404,14 @@ sub create_hdoption_view {
     $dialog->destroy();
 }
 
+sub apply_raid_disk_selection {
+    Proxmox::Install::Config::set_key('disk_selection', {}); # reset
+    for my $order (sort keys $gtk_state->{disk_selection}->%*) {
+       my $disk = $gtk_state->{disk_selection}->{$order} // next;
+       Proxmox::Install::Config::set_disk_selection($order, $disk->[0]);
+    }
+}
+
 my $last_hd_selected = 0;
 sub create_hdsel_view {
 
@@ -1401,7 +1430,7 @@ sub create_hdsel_view {
        Proxmox::Install::Config::set_target_hd($devname);
     }
 
-    $target_hd_label = Gtk3::Label->new("Target Harddisk");
+    $target_hd_label = Gtk3::Label->new("Target Harddisk");
     $hbox->pack_start($target_hd_label, 0, 0, 0);
 
     $target_hd_combo = Gtk3::ComboBoxText->new();
@@ -1440,6 +1469,7 @@ sub create_hdsel_view {
     set_next(undef, sub {
        my $filesys = Proxmox::Install::Config::get_filesys();
        if ($filesys =~ m/zfs/) {
+           apply_raid_disk_selection();
            my ($devlist) = eval { Proxmox::Install::get_zfs_raid_setup() };
            if (my $err = $@) {
                Proxmox::UI::message("Warning: $err\nPlease fix ZFS setup first.");
@@ -1447,6 +1477,7 @@ sub create_hdsel_view {
            }
            $target_hds = [ map { $_->[1] } @$devlist ];
        } elsif ($filesys =~ m/btrfs/) {
+           apply_raid_disk_selection();
            my ($devlist) = eval { Proxmox::Install::get_btrfs_raid_setup() };
            if (my $err = $@) {
                Proxmox::UI::message("Warning: $err\nPlease fix BTRFS setup first.");
@@ -1522,6 +1553,10 @@ sub create_extract_view {
        return $raw_html;
     };
 
+    # It does not make sense to Abort the install at this point, whether it
+    # succeded or failed makes no difference.
+    $gtk_state->{abort_btn}->set_sensitive(0);
+
     if ($err) {
        Proxmox::UI::display_html("fail.htm");
        # suppress "empty" error as we got some case where the user choose to abort on a prompt,
@@ -1536,6 +1571,7 @@ sub create_extract_view {
                if ($autoreboot_seconds > 0) {
                    $autoreboot_seconds--;
                    Proxmox::UI::display_html("success.htm", $success_transform);
+                   return 1; # re-schedule, undef isn't enough anymore since Bookworm
                } else {
                    app_quit(0);
                }
@@ -1556,14 +1592,11 @@ sub create_intro_view {
            "See 'System Requirements' in the $iso_env->{cfg}->{fullname} documentation.");
     }
 
-    if ($iso_env->{product} eq 'pve') {
-       my $cpuinfo = eval { file_read_all('/proc/cpuinfo') };
-       if (!$cpuinfo || $cpuinfo !~ /^flags\s*:.*(vmx|svm)/m) {
-           Proxmox::UI::error(
-               "No support for hardware-accelerated KVM virtualization detected.\n\n"
-               ."Check BIOS settings for Intel VT / AMD-V / SVM."
-           );
-       }
+    if ($iso_env->{product} eq 'pve' && !$run_env->{hvm_supported}) {
+       Proxmox::UI::error(
+           "No support for hardware-accelerated KVM virtualization detected.\n\n"
+           ."Check BIOS settings for Intel VT / AMD-V / SVM."
+       );
     }
 
     Proxmox::UI::display_html('license.htm', sub {
@@ -1586,9 +1619,10 @@ sub create_intro_view {
     set_next("I a_gree", \&create_hdsel_view);
 }
 
+log_info("initializing GTK and creating main window...");
 Gtk3::init();
 
-create_main_window ();
+create_main_window();
 
 my $initial_error = 0;