]>
Commit | Line | Data |
---|---|---|
6981164e | 1 | #!/usr/bin/perl |
89a12446 DM |
2 | |
3 | use strict; | |
6981164e DM |
4 | use warnings; |
5 | ||
89a12446 | 6 | use Getopt::Long; |
89a12446 | 7 | use IO::File; |
dfc02f3c | 8 | use Glib; |
0387544f | 9 | use Gtk3; |
ed0e6aea | 10 | use Gtk3::WebKit2; |
0e631479 | 11 | use POSIX ":sys_wait_h"; |
2630cca4 | 12 | use JSON; |
89a12446 | 13 | |
84dc3d6f | 14 | use Proxmox::Log; |
8d479e26 TL |
15 | Proxmox::Log::init("/tmp/install.log"); |
16 | ||
ea3b7cae TL |
17 | { # NOTE: order is important here |
18 | my $test_image; | |
19 | GetOptions( | |
20 | 'test-image|t=s' => \$test_image | |
21 | ) or die "usage error\n"; | |
22 | ||
23 | Proxmox::Install::ISOEnv::set_test_image($test_image) if $test_image; | |
24 | } | |
25 | ||
26 | ||
8d479e26 | 27 | use Proxmox::Install::ISOEnv; |
b91f9cad | 28 | use Proxmox::Install::RunEnv; |
ea3b7cae TL |
29 | |
30 | # init singletons | |
31 | my $iso_env = Proxmox::Install::ISOEnv::get(); | |
32 | my $run_env = Proxmox::Install::RunEnv::get(); | |
33 | ||
a677c773 | 34 | use Proxmox::Install; |
390889ab | 35 | use Proxmox::Install::Config; |
09480a9a TL |
36 | use Proxmox::Install::StorageConfig; |
37 | ||
059e9650 TL |
38 | use Proxmox::Sys::Block qw(get_cached_disks); |
39 | use Proxmox::Sys::Command qw(syscmd); | |
40 | use Proxmox::Sys::File qw(file_read_all file_write_all); | |
625e8f60 | 41 | use Proxmox::Sys::Net qw(parse_ip_address parse_ip_mask); |
5f031868 | 42 | use Proxmox::UI; |
b9075af2 | 43 | |
7becc472 DM |
44 | if (!$ENV{G_SLICE} || $ENV{G_SLICE} ne "always-malloc") { |
45 | die "do not use slice allocator (run with 'G_SLICE=always-malloc ./proxinstall ...')\n"; | |
46 | } | |
47 | ||
201a5120 OB |
48 | my $step_number = 0; # Init number for global function list |
49 | ||
50 | my @steps = ( | |
51 | { | |
52 | step => 'intro', | |
53 | html => 'license.htm', | |
54 | next_button => 'I a_gree', | |
55 | function => \&create_intro_view, | |
56 | }, | |
57 | { | |
58 | step => 'intro', | |
59 | html => 'page1.htm', | |
60 | function => \&create_hdsel_view, | |
61 | }, | |
62 | { | |
63 | step => 'country', | |
64 | html => 'country.htm', | |
65 | function => \&create_country_view, | |
66 | }, | |
67 | { | |
68 | step => 'password', | |
69 | html => 'passwd.htm', | |
70 | function => \&create_password_view, | |
71 | }, | |
72 | { | |
73 | step => 'ipconf', | |
201a5120 OB |
74 | html => 'ipconf.htm', |
75 | function => \&create_ipconf_view, | |
76 | }, | |
2e33c3f0 OB |
77 | { |
78 | step => 'ack', | |
79 | html => 'ack.htm', | |
80 | next_button => '_Install', | |
81 | function => \&create_ack_view, | |
82 | }, | |
201a5120 OB |
83 | { |
84 | step => 'extract', | |
85 | next_button => '_Reboot', | |
86 | function => \&create_extract_view, | |
87 | }, | |
88 | ); | |
89 | ||
90 | # GUI global variables | |
2266526b TL |
91 | my $gtk_state = {}; |
92 | ||
5bcefda0 | 93 | my $target_hds; # only for the summary view |
dfc02f3c | 94 | my $autoreboot_seconds = 5; |
89a12446 | 95 | |
fd09e893 MS |
96 | sub app_quit { |
97 | my ($exit_code) = @_; | |
98 | ||
99 | Gtk3->main_quit() if Gtk3->main_level() > 0; | |
100 | ||
101 | # reap left over zombie processes | |
102 | while ((my $child = waitpid(-1, POSIX::WNOHANG)) > 0) { | |
5b43e82d | 103 | print STDERR "reaped child $child\n"; |
fd09e893 MS |
104 | } |
105 | exit($exit_code); | |
106 | } | |
107 | ||
201a5120 | 108 | sub prev_function { |
201a5120 OB |
109 | my ($text, $fctn) = @_; |
110 | ||
111 | $fctn = $step_number if !$fctn; | |
112 | $text = "_Previous" if !$text; | |
2266526b | 113 | $gtk_state->{prev_btn}->set_label($text); |
201a5120 OB |
114 | |
115 | $step_number--; | |
116 | $steps[$step_number]->{function}(); | |
117 | ||
2266526b | 118 | $gtk_state->{prev_btn}->grab_focus(); |
201a5120 OB |
119 | } |
120 | ||
89a12446 DM |
121 | sub set_next { |
122 | my ($text, $fctn) = @_; | |
123 | ||
2266526b | 124 | $gtk_state->{next_btn_callback} = $fctn; |
201a5120 OB |
125 | my $step = $steps[$step_number]; |
126 | $text //= $steps[$step_number]->{next_button} // '_Next'; | |
2266526b | 127 | $gtk_state->{next_btn}->set_label($text); |
968fa90b | 128 | |
2266526b | 129 | $gtk_state->{next_btn}->grab_focus(); |
89a12446 | 130 | } |
89a12446 DM |
131 | |
132 | sub create_main_window { | |
133 | ||
2266526b | 134 | my $window = Gtk3::Window->new(); |
71590b6a | 135 | $window->set_default_size(1024, 768); |
f9bc57c4 | 136 | $window->signal_connect(map => sub { $window->set_resizable(0); }); |
09362211 TL |
137 | $window->fullscreen() if !is_test_mode(); |
138 | $window->set_decorated(0) if !is_test_mode(); | |
ddc887bc | 139 | $window->signal_connect(destroy => sub { Gtk3->main_quit(); }); |
89a12446 | 140 | |
d6efed19 | 141 | my $vbox = Gtk3::Box->new('vertical', 0); |
89a12446 | 142 | |
84f90cbb | 143 | my $logofn = "$iso_env->{product}-banner.png"; |
a677c773 | 144 | my $proxmox_libdir = $iso_env->{locations}->{lib}; |
782b4acd | 145 | my $image = Gtk3::Image->new_from_file("${proxmox_libdir}/$logofn"); |
7cf64825 TL |
146 | |
147 | my $provider = Gtk3::CssProvider->new(); | |
148 | my $theming = "* {\nbackground: #171717;\n}"; | |
149 | $provider->load_from_data ([map ord, split //, $theming]); | |
150 | my $context = $image->get_style_context(); | |
151 | $context->add_provider($provider, 600); | |
152 | ||
71590b6a | 153 | $vbox->pack_start($image, 0, 0, 0); |
89a12446 | 154 | |
d6efed19 | 155 | my $hbox = Gtk3::Box->new('horizontal', 0); |
71590b6a | 156 | $vbox->pack_start($hbox, 1, 1, 0); |
89a12446 | 157 | |
7becc472 DM |
158 | # my $f1 = Gtk3::Frame->new ('test'); |
159 | # $f1->set_shadow_type ('none'); | |
160 | # $hbox->pack_start ($f1, 1, 1, 0); | |
89a12446 | 161 | |
bbf51225 | 162 | my $sep1 = Gtk3::Separator->new('horizontal'); |
71590b6a | 163 | $vbox->pack_start($sep1, 0, 0, 0); |
89a12446 | 164 | |
2266526b | 165 | my $cmdbox = Gtk3::Box->new('horizontal', 0); |
71590b6a | 166 | $vbox->pack_start($cmdbox, 0, 0, 10); |
89a12446 | 167 | |
2266526b | 168 | my $next_btn = Gtk3::Button->new('_Next'); |
a677c773 TL |
169 | $next_btn->signal_connect(clicked => sub { |
170 | Proxmox::Install::reset_last_display_change(); | |
171 | $gtk_state->{next_btn_callback}->(); | |
172 | }); | |
2266526b | 173 | $cmdbox->pack_end($next_btn, 0, 0, 10); |
201a5120 | 174 | |
2266526b | 175 | my $prev_btn = Gtk3::Button->new('_Previous'); |
a677c773 TL |
176 | $prev_btn->signal_connect(clicked => sub { |
177 | Proxmox::Install::reset_last_display_change(); | |
178 | prev_function(); | |
179 | }); | |
71590b6a | 180 | $cmdbox->pack_end($prev_btn, 0, 0, 10); |
201a5120 OB |
181 | |
182 | ||
71590b6a OB |
183 | my $abort = Gtk3::Button->new('_Abort'); |
184 | $abort->set_can_focus(0); | |
185 | $cmdbox->pack_start($abort, 0, 0, 10); | |
fd09e893 | 186 | $abort->signal_connect(clicked => sub { app_quit(-1); }); |
89a12446 | 187 | |
d6efed19 | 188 | my $vbox2 = Gtk3::Box->new('vertical', 0); |
71590b6a | 189 | $hbox->add($vbox2); |
89a12446 | 190 | |
2266526b TL |
191 | my $html_view = Gtk3::WebKit2::WebView->new(); |
192 | $html_view->set_hexpand(1); | |
7becc472 | 193 | my $scrolls = Gtk3::ScrolledWindow->new(); |
2266526b | 194 | $scrolls->add($html_view); |
1464c7c9 | 195 | |
d6efed19 | 196 | my $hbox2 = Gtk3::Box->new('horizontal', 0); |
71590b6a | 197 | $hbox2->pack_start($scrolls, 1, 1, 0); |
89a12446 | 198 | |
71590b6a | 199 | $vbox2->pack_start($hbox2, 1, 1, 0); |
89a12446 | 200 | |
d6efed19 | 201 | my $vbox3 = Gtk3::Box->new('vertical', 0); |
71590b6a | 202 | $vbox2->pack_start($vbox3, 0, 0, 0); |
89a12446 | 203 | |
bbf51225 | 204 | my $sep2 = Gtk3::Separator->new('horizontal'); |
71590b6a | 205 | $vbox3->pack_start($sep2, 0, 0, 0); |
89a12446 | 206 | |
2266526b | 207 | my $inbox = Gtk3::Box->new('horizontal', 0); |
71590b6a | 208 | $vbox3->pack_start($inbox, 0, 0, 0); |
89a12446 | 209 | |
71590b6a | 210 | $window->add($vbox); |
89a12446 | 211 | |
2266526b TL |
212 | $gtk_state->{window} = $window; |
213 | $gtk_state->{html_view} = $html_view; | |
214 | $gtk_state->{inbox} = $inbox; | |
215 | $gtk_state->{prev_btn} = $prev_btn; | |
216 | $gtk_state->{next_btn} = $next_btn; | |
217 | $gtk_state->{progress_bar} = Gtk3::ProgressBar->new(); | |
218 | $gtk_state->{progress_status} = Gtk3::Label->new(''); | |
219 | ||
84f90cbb | 220 | Proxmox::UI::init_gtk($gtk_state, $iso_env); |
5f031868 | 221 | |
89a12446 | 222 | $window->show_all; |
f9bc57c4 | 223 | $window->present(); |
89a12446 DM |
224 | } |
225 | ||
1464c7c9 | 226 | sub cleanup_view { |
2266526b | 227 | $gtk_state->{inbox}->foreach(sub { |
d2120e51 | 228 | my $child = shift; |
2266526b | 229 | $gtk_state->{inbox}->remove ($child); |
d2120e51 | 230 | }); |
89a12446 DM |
231 | } |
232 | ||
aed81ff0 DM |
233 | # fixme: newer GTK3 has special properties to handle numbers with Entry |
234 | # only allow floating point numbers with Gtk3::Entry | |
e73c5fcf | 235 | |
aed81ff0 DM |
236 | sub check_float { |
237 | my ($entry, $event) = @_; | |
238 | ||
e73c5fcf FG |
239 | return check_number($entry, $event, 1); |
240 | } | |
241 | ||
242 | sub check_int { | |
243 | my ($entry, $event) = @_; | |
244 | ||
245 | return check_number($entry, $event, 0); | |
246 | } | |
247 | ||
248 | sub check_number { | |
249 | my ($entry, $event, $float) = @_; | |
aed81ff0 DM |
250 | |
251 | my $val = $event->get_keyval; | |
252 | ||
e73c5fcf | 253 | if (($float && $val == ord '.') || |
aed81ff0 DM |
254 | $val == Gtk3::Gdk::KEY_ISO_Left_Tab || |
255 | $val == Gtk3::Gdk::KEY_Shift_L || | |
256 | $val == Gtk3::Gdk::KEY_Tab || | |
257 | $val == Gtk3::Gdk::KEY_Left || | |
258 | $val == Gtk3::Gdk::KEY_Right || | |
259 | $val == Gtk3::Gdk::KEY_BackSpace || | |
260 | $val == Gtk3::Gdk::KEY_Delete || | |
261 | ($val >= ord '0' && $val <= ord '9') || | |
262 | ($val >= Gtk3::Gdk::KEY_KP_0 && | |
263 | $val <= Gtk3::Gdk::KEY_KP_9)) { | |
264 | return undef; | |
265 | } | |
266 | ||
267 | return 1; | |
268 | } | |
269 | ||
d2120e51 | 270 | sub create_text_input { |
89a12446 DM |
271 | my ($default, $text) = @_; |
272 | ||
cc120d79 | 273 | my $hbox = Gtk3::Box->new('horizontal', 0); |
89a12446 | 274 | |
71590b6a OB |
275 | my $label = Gtk3::Label->new($text); |
276 | $label->set_size_request(150, -1); | |
9f91507b | 277 | $label->set_xalign(1.0); |
71590b6a OB |
278 | $hbox->pack_start($label, 0, 0, 10); |
279 | my $e1 = Gtk3::Entry->new(); | |
cc120d79 | 280 | $e1->set_width_chars(35); |
71590b6a OB |
281 | $hbox->pack_start($e1, 0, 0, 0); |
282 | $e1->set_text($default); | |
89a12446 DM |
283 | |
284 | return ($hbox, $e1); | |
285 | } | |
cc120d79 | 286 | sub create_cidr_inputs { |
7f3941d1 TL |
287 | my ($cidr) = @_; |
288 | ||
289 | my ($default_ip, $default_mask) = split('/', $cidr); | |
cc120d79 TL |
290 | |
291 | my $hbox = Gtk3::Box->new('horizontal', 0); | |
292 | ||
293 | my $label = Gtk3::Label->new('IP Address (CIDR)'); | |
294 | $label->set_size_request(150, -1); | |
9f91507b | 295 | $label->set_xalign(1.0); |
cc120d79 TL |
296 | $hbox->pack_start($label, 0, 0, 10); |
297 | ||
298 | my $ip_el = Gtk3::Entry->new(); | |
299 | $ip_el->set_width_chars(28); | |
300 | $hbox->pack_start($ip_el, 0, 0, 0); | |
301 | $ip_el->set_text($default_ip); | |
302 | ||
303 | $label = Gtk3::Label->new('/'); | |
304 | $label->set_size_request(10, -1); | |
cc120d79 TL |
305 | $hbox->pack_start($label, 0, 0, 2); |
306 | ||
307 | my $cidr_el = Gtk3::Entry->new(); | |
308 | $cidr_el->set_width_chars(3); | |
309 | $hbox->pack_start($cidr_el, 0, 0, 0); | |
310 | $cidr_el->set_text($default_mask); | |
311 | ||
312 | return ($hbox, $ip_el, $cidr_el); | |
313 | } | |
89a12446 | 314 | |
fe44bd92 FG |
315 | my $ipconf_first_view = 1; |
316 | ||
89a12446 DM |
317 | sub create_ipconf_view { |
318 | ||
201a5120 | 319 | cleanup_view(); |
efc7a8be | 320 | Proxmox::UI::display_html('ipconf.htm'); |
89a12446 | 321 | |
cc120d79 | 322 | my $vcontainer = Gtk3::Box->new('vertical', 0); |
2266526b | 323 | $gtk_state->{inbox}->pack_start($vcontainer, 1, 0, 0); |
cc120d79 TL |
324 | my $hcontainer = Gtk3::Box->new('horizontal', 0); |
325 | $vcontainer->pack_start($hcontainer, 0, 0, 10); | |
326 | my $vbox = Gtk3::Box->new('vertical', 0); | |
327 | $hcontainer->add($vbox); | |
89a12446 | 328 | |
7f3941d1 TL |
329 | my $cidr = Proxmox::Install::Config::get_cidr() // '192.168.100.2/24'; |
330 | ||
331 | my ($cidr_box, $ipconf_entry_addr, $ipconf_entry_mask) = create_cidr_inputs($cidr); | |
fe44bd92 FG |
332 | |
333 | my $device_cb = Gtk3::ComboBoxText->new(); | |
334 | $device_cb->set_active(0); | |
335 | $device_cb->set_visible(1); | |
336 | ||
337 | my $get_device_desc = sub { | |
338 | my $iface = shift; | |
339 | return "$iface->{name} - $iface->{mac} ($iface->{driver})"; | |
340 | }; | |
341 | ||
fe06d7e9 TL |
342 | my $ipconf = $run_env->{ipconf}; |
343 | ||
344 | my ($device_active_map, $device_active_reverse_map) = ({}, {}); | |
5b6ba737 FG |
345 | |
346 | my $device_change_handler = sub { | |
347 | my $current = shift; | |
d6524c52 TL |
348 | |
349 | my $new = $device_active_map->{$current->get_active()}; | |
8a7e31ce TL |
350 | my $selected = Proxmox::Install::Config::get_mngmt_nic_id(); |
351 | return if defined($selected) && $new eq $selected; | |
d6524c52 | 352 | |
8a7e31ce TL |
353 | Proxmox::Install::Config::set_mngmt_nic_id($new); |
354 | my $iface = $ipconf->{ifaces}->{$new}; | |
355 | Proxmox::Install::Config::set_mngmt_nic($iface->{name}); | |
5b6ba737 FG |
356 | $ipconf_entry_addr->set_text($iface->{inet}->{addr} || $iface->{inet6}->{addr}) |
357 | if $iface->{inet}->{addr} || $iface->{inet6}->{addr}; | |
cc120d79 TL |
358 | $ipconf_entry_mask->set_text($iface->{inet}->{prefix} || $iface->{inet6}->{prefix}) |
359 | if $iface->{inet}->{prefix} || $iface->{inet6}->{prefix}; | |
5b6ba737 FG |
360 | }; |
361 | ||
fe44bd92 | 362 | my $i = 0; |
fe06d7e9 TL |
363 | for my $index (sort keys $ipconf->{ifaces}->%*) { |
364 | my $iface = $ipconf->{ifaces}->{$index}; | |
365 | $device_cb->append_text($get_device_desc->($iface)); | |
ebc4f76f | 366 | $device_active_map->{$i} = $index; |
fe06d7e9 | 367 | $device_active_reverse_map->{$iface->{name}} = $i; |
fe44bd92 FG |
368 | if ($ipconf_first_view && $index == $ipconf->{default}) { |
369 | $device_cb->set_active($i); | |
5b6ba737 | 370 | &$device_change_handler($device_cb); |
fe44bd92 FG |
371 | $ipconf_first_view = 0; |
372 | } | |
71590b6a | 373 | $device_cb->signal_connect('changed' => $device_change_handler); |
fe44bd92 FG |
374 | $i++; |
375 | } | |
376 | ||
8a7e31ce | 377 | if (my $nic = Proxmox::Install::Config::get_mngmt_nic()) { |
ebc4f76f TL |
378 | $device_cb->set_active($device_active_reverse_map->{$nic} // 0); |
379 | } else { | |
380 | $device_cb->set_active(0); | |
381 | } | |
5b6ba737 | 382 | |
d6efed19 | 383 | my $devicebox = Gtk3::Box->new('horizontal', 0); |
71590b6a OB |
384 | my $label = Gtk3::Label->new("Management Interface:"); |
385 | $label->set_size_request(150, -1); | |
9f91507b | 386 | $label->set_xalign(1.0); |
71590b6a OB |
387 | $devicebox->pack_start($label, 0, 0, 10); |
388 | $devicebox->pack_start($device_cb, 0, 0, 0); | |
fe44bd92 | 389 | |
cc120d79 | 390 | $vbox->pack_start($devicebox, 0, 0, 2); |
968fa90b | 391 | |
e02f38dc TL |
392 | my $fqdn = Proxmox::Install::Config::get_fqdn(); |
393 | my $hn = $fqdn // "$iso_env->{product}." . ($ipconf->{domain} // "example.invalid"); | |
1464c7c9 | 394 | |
cc120d79 TL |
395 | my ($hostbox, $hostentry) = create_text_input($hn, 'Hostname (FQDN):'); |
396 | $vbox->pack_start($hostbox, 0, 0, 2); | |
89a12446 | 397 | |
cc120d79 | 398 | $vbox->pack_start($cidr_box, 0, 0, 2); |
89a12446 | 399 | |
7f3941d1 TL |
400 | my $cfg_gateway = Proxmox::Install::Config::get_gateway(); |
401 | my $gateway = $cfg_gateway // $ipconf->{gateway} || '192.168.100.1'; | |
89a12446 | 402 | |
7f3941d1 | 403 | my ($gwbox, $ipconf_entry_gw) = create_text_input($gateway, 'Gateway:'); |
cc120d79 | 404 | $vbox->pack_start($gwbox, 0, 0, 2); |
89a12446 | 405 | |
7f3941d1 TL |
406 | my $cfg_dns = Proxmox::Install::Config::get_dns(); |
407 | my $dnsserver = $cfg_dns // $ipconf->{dnsserver} || $gateway; | |
89a12446 | 408 | |
7f3941d1 | 409 | my ($dnsbox, $ipconf_entry_dns) = create_text_input($dnsserver, 'DNS Server:'); |
89a12446 | 410 | |
cc120d79 | 411 | $vbox->pack_start($dnsbox, 0, 0, 0); |
89a12446 | 412 | |
2266526b | 413 | $gtk_state->{inbox}->show_all; |
71590b6a | 414 | set_next(undef, sub { |
d2120e51 | 415 | # verify hostname |
89a12446 | 416 | my $text = $hostentry->get_text(); |
89a12446 DM |
417 | $text =~ s/^\s+//; |
418 | $text =~ s/\s+$//; | |
419 | ||
ac3757a9 | 420 | my $namere = "([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)"; |
968fa90b | 421 | |
24973868 WB |
422 | # Debian does not support purely numeric hostnames |
423 | if ($text && $text =~ /^[0-9]+(?:\.|$)/) { | |
72bea995 | 424 | Proxmox::UI::message("Purely numeric hostnames are not allowed."); |
24973868 WB |
425 | $hostentry->grab_focus(); |
426 | return; | |
427 | } | |
428 | ||
a39bc1f2 | 429 | if ($text && $text =~ m/^(${namere}\.)*${namere}$/ && $text !~ m/.example.invalid$/ && |
89a12446 | 430 | $text =~ m/^([^\.]+)\.(\S+)$/) { |
e02f38dc TL |
431 | Proxmox::Install::Config::set_hostname($1); |
432 | Proxmox::Install::Config::set_domain($2); | |
d2120e51 | 433 | } else { |
72bea995 | 434 | Proxmox::UI::message("Hostname does not look like a fully qualified domain name."); |
d2120e51 | 435 | $hostentry->grab_focus(); |
89a12446 DM |
436 | return; |
437 | } | |
d2120e51 DM |
438 | |
439 | # verify ip address | |
d2120e51 | 440 | $text = $ipconf_entry_addr->get_text(); |
7f3941d1 | 441 | my ($ipaddress, $ipversion) = parse_ip_address($text); |
625e8f60 | 442 | if (!defined($ipaddress)) { |
72bea995 | 443 | Proxmox::UI::message("IP address is not valid."); |
d2120e51 DM |
444 | $ipconf_entry_addr->grab_focus(); |
445 | return; | |
446 | } | |
447 | ||
448 | $text = $ipconf_entry_mask->get_text(); | |
7f3941d1 | 449 | my $netmask = parse_ip_mask($text, $ipversion); |
625e8f60 | 450 | if (!defined($netmask)) { |
72bea995 | 451 | Proxmox::UI::message("Netmask is not valid."); |
d2120e51 DM |
452 | $ipconf_entry_mask->grab_focus(); |
453 | return; | |
454 | } | |
7f3941d1 | 455 | Proxmox::Install::Config::set_cidr("$ipaddress/$netmask"); |
d2120e51 DM |
456 | |
457 | $text = $ipconf_entry_gw->get_text(); | |
625e8f60 TL |
458 | my ($gateway_ip, $gateway_ip_version) = parse_ip_address($text); |
459 | if (!defined($gateway_ip) || $gateway_ip_version != $ipversion) { | |
460 | my $msg = defined($gateway_ip) | |
461 | ? "Gateway and host IP version must not differ (IPv$gateway_ip_version != IPv$ipversion)." | |
462 | : "Gateway is not valid."; | |
72bea995 | 463 | Proxmox::UI::message($msg); |
d2120e51 DM |
464 | $ipconf_entry_gw->grab_focus(); |
465 | return; | |
466 | } | |
7f3941d1 | 467 | Proxmox::Install::Config::set_gateway($gateway_ip); |
1464c7c9 | 468 | |
d2120e51 | 469 | $text = $ipconf_entry_dns->get_text(); |
625e8f60 TL |
470 | my ($dns_ip, $dns_ip_version) = parse_ip_address($text); |
471 | if (!defined($dns_ip) || $dns_ip_version != $ipversion) { | |
472 | my $msg = defined($gateway_ip) | |
473 | ? "DNS and host IP version must not differ (IPv$gateway_ip_version != IPv$ipversion)." | |
474 | : "DNS IP is not valid."; | |
72bea995 | 475 | Proxmox::UI::message($msg); |
d2120e51 DM |
476 | $ipconf_entry_dns->grab_focus(); |
477 | return; | |
478 | } | |
7f3941d1 | 479 | Proxmox::Install::Config::set_dns($dns_ip); |
1464c7c9 | 480 | |
7f3941d1 | 481 | #print STDERR "TEST $ipaddress/$netmask $gateway_ip $dns_ip\n"; |
1464c7c9 | 482 | |
201a5120 | 483 | $step_number++; |
2e33c3f0 | 484 | create_ack_view(); |
89a12446 DM |
485 | }); |
486 | ||
487 | $hostentry->grab_focus(); | |
488 | } | |
489 | ||
2e33c3f0 OB |
490 | sub create_ack_view { |
491 | ||
492 | cleanup_view(); | |
493 | ||
d6efed19 | 494 | my $vbox = Gtk3::Box->new('vertical', 0); |
2266526b | 495 | $gtk_state->{inbox}->pack_start($vbox, 1, 0, 0); |
dfc02f3c TL |
496 | |
497 | my $reboot_checkbox = Gtk3::CheckButton->new('Automatically reboot after successful installation'); | |
498 | $reboot_checkbox->set_active(1); | |
499 | $reboot_checkbox->signal_connect ("toggled" => sub { | |
500 | my $cb = shift; | |
0a3ac982 | 501 | Proxmox::Install::Config::set_autoreboot(!!$cb->get_active()); |
dfc02f3c TL |
502 | }); |
503 | $vbox->pack_start($reboot_checkbox, 0, 0, 2); | |
504 | ||
a677c773 | 505 | my $proxmox_libdir = $iso_env->{locations}->{lib}; |
029fde30 | 506 | my $ack_template = "${proxmox_libdir}/html/ack_template.htm"; |
84f90cbb | 507 | my $ack_html = "${proxmox_libdir}/html/$iso_env->{product}/$steps[$step_number]->{html}"; |
a28c08e9 | 508 | my $html_data = file_read_all($ack_template); |
2e33c3f0 | 509 | |
74041d68 TL |
510 | my $country = Proxmox::Install::Config::get_country(); |
511 | ||
2e33c3f0 | 512 | my %config_values = ( |
5bcefda0 | 513 | __target_hd__ => join(' | ', $target_hds->@*), |
cd1a45ad | 514 | __target_fs__ => Proxmox::Install::Config::get_filesys(), |
84f90cbb | 515 | __country__ => $iso_env->{locales}->{country}->{$country}->{name}, |
2959225b | 516 | __timezone__ => Proxmox::Install::Config::get_timezone(), |
b3bcf70e | 517 | __keymap__ => Proxmox::Install::Config::get_keymap(), |
8924c145 | 518 | __mailto__ => Proxmox::Install::Config::get_mailto(), |
8a7e31ce | 519 | __interface__ => Proxmox::Install::Config::get_mngmt_nic(), |
e02f38dc | 520 | __hostname__ => Proxmox::Install::Config::get_hostname(), |
7f3941d1 TL |
521 | __cidr__ => Proxmox::Install::Config::get_cidr(), |
522 | __gateway__ => Proxmox::Install::Config::get_gateway(), | |
523 | __dnsserver__ => Proxmox::Install::Config::get_dns(), | |
2e33c3f0 OB |
524 | ); |
525 | ||
029fde30 | 526 | while (my ($k, $v) = each %config_values) { |
2e33c3f0 OB |
527 | $html_data =~ s/$k/$v/g; |
528 | } | |
529 | ||
2630cca4 TL |
530 | eval { |
531 | my $config = Proxmox::Install::Config::get(); | |
532 | file_write_all( | |
533 | "$iso_env->{locations}->{run}/config-ack.json", | |
534 | to_json($config, { utf8 => 1, canonical => 1 }) ."\n", | |
535 | ); | |
536 | }; | |
537 | warn "failed to write config-for-ack - $@" if $@; | |
538 | ||
a28c08e9 | 539 | file_write_all($ack_html, $html_data); |
2e33c3f0 | 540 | |
efc7a8be | 541 | Proxmox::UI::display_html('ack.htm'); |
2e33c3f0 | 542 | |
2266526b | 543 | $gtk_state->{inbox}->show_all; |
dfc02f3c | 544 | |
2e33c3f0 OB |
545 | set_next(undef, sub { |
546 | $step_number++; | |
547 | create_extract_view(); | |
548 | }); | |
549 | } | |
550 | ||
89a12446 DM |
551 | sub get_device_desc { |
552 | my ($devname, $size, $model) = @_; | |
553 | ||
d2120e51 | 554 | if ($size && ($size > 0)) { |
b04864ec | 555 | $size = int($size/2048); # size in MiB, from 512B "sectors" |
89a12446 | 556 | |
d2120e51 | 557 | my $text = "$devname ("; |
89a12446 | 558 | if ($size >= 1024) { |
b04864ec | 559 | $size = $size/1024; # size in GiB |
ceabb291 | 560 | if ($size >= 1024) { |
b04864ec SI |
561 | $size = $size/1024; # size in TiB |
562 | $text .= sprintf("%.2f", $size) . "TiB"; | |
ceabb291 | 563 | } else { |
b04864ec | 564 | $text .= sprintf("%.2f", $size) . "GiB"; |
ceabb291 | 565 | } |
89a12446 | 566 | } else { |
ceabb291 | 567 | $text .= "${size}MiB"; |
89a12446 DM |
568 | } |
569 | ||
d2120e51 DM |
570 | $text .= ", $model" if $model; |
571 | $text .= ")"; | |
b04864ec | 572 | return $text; |
d2120e51 | 573 | |
89a12446 DM |
574 | } else { |
575 | return $devname; | |
576 | } | |
577 | } | |
578 | ||
d92ada4e SI |
579 | my $last_layout; |
580 | my $country_layout; | |
89a12446 DM |
581 | sub update_layout { |
582 | my ($cb, $kmap) = @_; | |
583 | ||
584 | my $ind; | |
585 | my $def; | |
586 | my $i = 0; | |
84f90cbb | 587 | my $kmaphash = $iso_env->{locales}->{kmaphash}; |
89a12446 DM |
588 | foreach my $layout (sort keys %$kmaphash) { |
589 | $def = $i if $kmaphash->{$layout} eq 'en-us'; | |
590 | $ind = $i if $kmap && $kmaphash->{$layout} eq $kmap; | |
591 | $i++; | |
592 | } | |
593 | ||
d92ada4e SI |
594 | my $val = $ind || $def || 0; |
595 | ||
596 | if (!defined($kmap)) { | |
597 | $last_layout //= $val; | |
598 | } elsif (!defined($country_layout) || $country_layout != $val) { | |
599 | $last_layout = $country_layout = $val; | |
600 | } | |
601 | $cb->set_active($last_layout); | |
89a12446 DM |
602 | } |
603 | ||
604 | my $lastzonecb; | |
605 | sub update_zonelist { | |
606 | my ($box, $cc) = @_; | |
607 | ||
2959225b | 608 | my $sel = Proxmox::Install::Config::get_timezone(); # initial default |
89a12446 DM |
609 | if ($lastzonecb) { |
610 | $sel = $lastzonecb->get_active_text(); | |
2c757f5e | 611 | $box->remove($lastzonecb); |
89a12446 DM |
612 | } |
613 | ||
bcbfab6b | 614 | my $cb = $lastzonecb = Gtk3::ComboBoxText->new(); |
71590b6a | 615 | $cb->set_size_request(200, -1); |
71590b6a | 616 | $cb->signal_connect('changed' => sub { |
2959225b TL |
617 | my $timezone = $cb->get_active_text(); |
618 | Proxmox::Install::Config::set_timezone($timezone); | |
89a12446 DM |
619 | }); |
620 | ||
84f90cbb | 621 | my ($cczones, $zones) = $iso_env->{locales}->@{'cczones', 'zones'}; |
2c757f5e TL |
622 | my @available_zones = $cc && defined($cczones->{$cc}) ? keys %{$cczones->{$cc}} : keys %$zones; |
623 | ||
624 | my ($i, $selected_index) = (0, undef); | |
625 | for my $zone (sort @available_zones) { | |
626 | $selected_index = $i if $sel && $zone eq $sel; | |
71590b6a | 627 | $cb->append_text($zone); |
89a12446 DM |
628 | $i++; |
629 | } | |
630 | ||
6bbe42ef TL |
631 | # Append UTC here, so it is always the last item and never the default for any country. |
632 | $cb->append_text('UTC'); | |
c5be8337 | 633 | |
2c757f5e | 634 | $cb->set_active($selected_index || 0); |
89a12446 DM |
635 | |
636 | $cb->show; | |
71590b6a | 637 | $box->pack_start($cb, 0, 0, 0); |
89a12446 DM |
638 | } |
639 | ||
640 | sub create_password_view { | |
641 | ||
71590b6a | 642 | cleanup_view(); |
89a12446 | 643 | |
a024147b TL |
644 | my $password = Proxmox::Install::Config::get_password(); |
645 | ||
d6efed19 | 646 | my $vbox2 = Gtk3::Box->new('vertical', 0); |
2266526b | 647 | $gtk_state->{inbox}->pack_start($vbox2, 1, 0, 0); |
d6efed19 | 648 | my $vbox = Gtk3::Box->new('vertical', 0); |
71590b6a OB |
649 | $vbox2->pack_start($vbox, 0, 0, 10); |
650 | ||
d6efed19 | 651 | my $hbox1 = Gtk3::Box->new('horizontal', 0); |
71590b6a OB |
652 | my $label = Gtk3::Label->new("Password"); |
653 | $label->set_size_request(150, -1); | |
9f91507b | 654 | $label->set_xalign(1.0); |
71590b6a OB |
655 | $hbox1->pack_start($label, 0, 0, 10); |
656 | my $pwe1 = Gtk3::Entry->new(); | |
657 | $pwe1->set_visibility(0); | |
201a5120 | 658 | $pwe1->set_text($password) if $password; |
71590b6a OB |
659 | $pwe1->set_size_request(200, -1); |
660 | $hbox1->pack_start($pwe1, 0, 0, 0); | |
661 | ||
d6efed19 | 662 | my $hbox2 = Gtk3::Box->new('horizontal', 0); |
71590b6a OB |
663 | $label = Gtk3::Label->new("Confirm"); |
664 | $label->set_size_request(150, -1); | |
9f91507b | 665 | $label->set_xalign(1.0); |
71590b6a OB |
666 | $hbox2->pack_start($label, 0, 0, 10); |
667 | my $pwe2 = Gtk3::Entry->new(); | |
668 | $pwe2->set_visibility(0); | |
201a5120 | 669 | $pwe2->set_text($password) if $password; |
71590b6a OB |
670 | $pwe2->set_size_request(200, -1); |
671 | $hbox2->pack_start($pwe2, 0, 0, 0); | |
672 | ||
d6efed19 | 673 | my $hbox3 = Gtk3::Box->new('horizontal', 0); |
b11c55ff | 674 | $label = Gtk3::Label->new("Email"); |
71590b6a | 675 | $label->set_size_request(150, -1); |
9f91507b | 676 | $label->set_xalign(1.0); |
71590b6a OB |
677 | $hbox3->pack_start($label, 0, 0, 10); |
678 | my $eme = Gtk3::Entry->new(); | |
679 | $eme->set_size_request(200, -1); | |
8924c145 | 680 | $eme->set_text(Proxmox::Install::Config::get_mailto()); |
71590b6a | 681 | $hbox3->pack_start($eme, 0, 0, 0); |
89a12446 DM |
682 | |
683 | ||
71590b6a OB |
684 | $vbox->pack_start($hbox1, 0, 0, 5); |
685 | $vbox->pack_start($hbox2, 0, 0, 5); | |
686 | $vbox->pack_start($hbox3, 0, 0, 15); | |
89a12446 | 687 | |
2266526b | 688 | $gtk_state->{inbox}->show_all; |
89a12446 | 689 | |
efc7a8be | 690 | Proxmox::UI::display_html('passwd.htm'); |
89a12446 DM |
691 | |
692 | set_next (undef, sub { | |
693 | ||
694 | my $t1 = $pwe1->get_text; | |
695 | my $t2 = $pwe2->get_text; | |
696 | ||
697 | if (length ($t1) < 5) { | |
72bea995 | 698 | Proxmox::UI::message("Password is too short."); |
89a12446 DM |
699 | $pwe1->grab_focus(); |
700 | return; | |
701 | } | |
702 | ||
703 | if ($t1 ne $t2) { | |
72bea995 | 704 | Proxmox::UI::message("Password does not match."); |
89a12446 DM |
705 | $pwe1->grab_focus(); |
706 | return; | |
707 | } | |
708 | ||
709 | my $t3 = $eme->get_text; | |
c82fffd8 | 710 | if ($t3 !~ m/^[\w\+\-\~]+(\.[\w\+\-\~]+)*@[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*$/) { |
8924c145 | 711 | Proxmox::UI::message("Email does not look like a valid address (user\@domain.tld)"); |
89a12446 DM |
712 | $eme->grab_focus(); |
713 | return; | |
a39bc1f2 | 714 | } |
89a12446 | 715 | |
a39bc1f2 | 716 | if ($t3 eq 'mail@example.invalid') { |
72bea995 | 717 | Proxmox::UI::message("Please enter a valid Email address"); |
a39bc1f2 FG |
718 | $eme->grab_focus(); |
719 | return; | |
89a12446 DM |
720 | } |
721 | ||
a024147b | 722 | Proxmox::Install::Config::set_password($t1); |
8924c145 | 723 | Proxmox::Install::Config::set_mailto($t3); |
89a12446 | 724 | |
201a5120 | 725 | $step_number++; |
89a12446 DM |
726 | create_ipconf_view(); |
727 | }); | |
728 | ||
729 | $pwe1->grab_focus(); | |
730 | ||
731 | } | |
732 | ||
d92ada4e | 733 | my $installer_kmap; |
89a12446 DM |
734 | sub create_country_view { |
735 | ||
71590b6a | 736 | cleanup_view(); |
89a12446 | 737 | |
84f90cbb | 738 | my $locales = $iso_env->{locales}; |
89a12446 | 739 | |
d6efed19 | 740 | my $vbox2 = Gtk3::Box->new('vertical', 0); |
2266526b | 741 | $gtk_state->{inbox}->pack_start($vbox2, 1, 0, 0); |
d6efed19 | 742 | my $vbox = Gtk3::Box->new('vertical', 0); |
71590b6a | 743 | $vbox2->pack_start($vbox, 0, 0, 10); |
89a12446 | 744 | |
71590b6a OB |
745 | my $w = Gtk3::Entry->new(); |
746 | $w->set_size_request(200, -1); | |
89a12446 | 747 | |
71590b6a OB |
748 | my $c = Gtk3::EntryCompletion->new(); |
749 | $c->set_text_column(0); | |
89a12446 | 750 | $c->set_minimum_key_length(0); |
71590b6a OB |
751 | $c->set_popup_set_width(1); |
752 | $c->set_inline_completion(1); | |
753 | ||
d6efed19 | 754 | my $hbox2 = Gtk3::Box->new('horizontal', 0); |
71590b6a OB |
755 | my $label = Gtk3::Label->new("Time zone"); |
756 | $label->set_size_request(150, -1); | |
9f91507b | 757 | $label->set_xalign(1.0); |
71590b6a | 758 | $hbox2->pack_start($label, 0, 0, 10); |
89a12446 DM |
759 | update_zonelist ($hbox2); |
760 | ||
d6efed19 | 761 | my $hbox3 = Gtk3::Box->new('horizontal', 0); |
71590b6a OB |
762 | $label = Gtk3::Label->new("Keyboard Layout"); |
763 | $label->set_size_request(150, -1); | |
9f91507b | 764 | $label->set_xalign(1.0); |
71590b6a | 765 | $hbox3->pack_start($label, 0, 0, 10); |
89a12446 | 766 | |
bcbfab6b | 767 | my $kmapcb = Gtk3::ComboBoxText->new(); |
89a12446 | 768 | $kmapcb->set_size_request (200, -1); |
2c757f5e TL |
769 | for my $layout (sort keys %{$locales->{kmaphash}}) { |
770 | $kmapcb->append_text($layout); | |
89a12446 DM |
771 | } |
772 | ||
71590b6a | 773 | update_layout($kmapcb); |
89a12446 DM |
774 | $hbox3->pack_start ($kmapcb, 0, 0, 0); |
775 | ||
776 | $kmapcb->signal_connect ('changed' => sub { | |
777 | my $sel = $kmapcb->get_active_text(); | |
d92ada4e | 778 | $last_layout = $kmapcb->get_active(); |
2c757f5e TL |
779 | if (my $kmap = $locales->{kmaphash}->{$sel}) { |
780 | my $xkmap = $locales->{kmap}->{$kmap}->{x11}; | |
781 | my $xvar = $locales->{kmap}->{$kmap}->{x11var}; | |
07ec6825 | 782 | |
b3bcf70e | 783 | Proxmox::Install::Config::set_keymap($kmap); |
d92ada4e | 784 | |
b3bcf70e TL |
785 | return if (defined($installer_kmap) && $installer_kmap eq $kmap); |
786 | $installer_kmap = $kmap; | |
d92ada4e | 787 | |
09362211 | 788 | if (!is_test_mode()) { |
059e9650 | 789 | syscmd("setxkbmap $xkmap $xvar"); |
2663e171 SI |
790 | |
791 | my $kbd_config = qq{ | |
792 | XKBLAYOUT="$xkmap" | |
793 | XKBVARIANT="$xvar" | |
794 | BACKSPACE="guess" | |
795 | }; | |
796 | $kbd_config =~ s/^\s+//gm; | |
797 | ||
d9ba239d | 798 | Proxmox::Sys::Command::run_in_background(sub { |
a28c08e9 | 799 | file_write_all('/etc/default/keyboard', $kbd_config); |
2663e171 SI |
800 | system("setupcon"); |
801 | }); | |
07ec6825 | 802 | } |
89a12446 DM |
803 | } |
804 | }); | |
805 | ||
806 | $w->signal_connect ('changed' => sub { | |
807 | my ($entry, $event) = @_; | |
808 | my $text = $entry->get_text; | |
809 | ||
2c757f5e | 810 | if (my $cc = $locales->{countryhash}->{lc($text)}) { |
71590b6a | 811 | update_zonelist($hbox2, $cc); |
2c757f5e | 812 | my $kmap = $locales->{country}->{$cc}->{kmap} || 'en-us'; |
71590b6a | 813 | update_layout($kmapcb, $kmap); |
89a12446 DM |
814 | } |
815 | }); | |
816 | ||
817 | $w->signal_connect (key_press_event => sub { | |
818 | my ($entry, $event) = @_; | |
819 | my $text = $entry->get_text; | |
820 | ||
7becc472 DM |
821 | my $val = $event->get_keyval; |
822 | ||
823 | if ($val == Gtk3::Gdk::KEY_Tab) { | |
2c757f5e | 824 | my $cc = $locales->{countryhash}->{lc($text)}; |
1464c7c9 | 825 | |
89a12446 DM |
826 | my $found = 0; |
827 | my $compl; | |
7becc472 | 828 | |
4443aa27 DM |
829 | if ($cc) { |
830 | $found = 1; | |
2c757f5e | 831 | $compl = $locales->{country}->{$cc}->{name}; |
4443aa27 | 832 | } else { |
2c757f5e TL |
833 | for my $country (values $locales->{country}->%*) { |
834 | if ($country->{name} =~ m/^\Q$text\E.*$/i) { | |
4443aa27 | 835 | $found++; |
2c757f5e | 836 | $compl = $country->{name}; |
4443aa27 DM |
837 | } |
838 | last if $found > 1; | |
89a12446 | 839 | } |
89a12446 | 840 | } |
4443aa27 | 841 | |
89a12446 | 842 | if ($found == 1) { |
7becc472 | 843 | $entry->set_text($compl); |
3df718ea | 844 | $c->complete(); |
89a12446 DM |
845 | return undef; |
846 | } else { | |
5b43e82d | 847 | # beep ? |
89a12446 DM |
848 | } |
849 | ||
3df718ea DM |
850 | $c->complete(); |
851 | ||
7becc472 DM |
852 | my $buf = $w->get_buffer(); |
853 | $buf->insert_text(-1, '', -1); # popup selection | |
854 | ||
89a12446 DM |
855 | return 1; |
856 | } | |
857 | ||
858 | return undef; | |
859 | }); | |
1464c7c9 | 860 | |
2c757f5e TL |
861 | my $country_store = Gtk3::ListStore->new('Glib::String'); |
862 | my $countries = $locales->{country}; | |
863 | for my $cc (sort { $countries->{$a}->{name} cmp $countries->{$b}->{name} } keys %$countries) { | |
864 | my $iter = $country_store->append(); | |
865 | $country_store->set($iter, 0, $countries->{$cc}->{name}); | |
89a12446 | 866 | } |
2c757f5e | 867 | $c->set_model($country_store); |
89a12446 | 868 | |
968fa90b | 869 | $w->set_completion ($c); |
89a12446 | 870 | |
d6efed19 | 871 | my $hbox = Gtk3::Box->new('horizontal', 0); |
89a12446 | 872 | |
71590b6a | 873 | $label = Gtk3::Label->new("Country"); |
9f91507b | 874 | $label->set_xalign(1.0); |
71590b6a OB |
875 | $label->set_size_request(150, -1); |
876 | $hbox->pack_start($label, 0, 0, 10); | |
877 | $hbox->pack_start($w, 0, 0, 0); | |
89a12446 | 878 | |
71590b6a OB |
879 | $vbox->pack_start($hbox, 0, 0, 5); |
880 | $vbox->pack_start($hbox2, 0, 0, 5); | |
881 | $vbox->pack_start($hbox3, 0, 0, 5); | |
89a12446 | 882 | |
74041d68 | 883 | my $country = Proxmox::Install::Config::get_country(); |
2c757f5e TL |
884 | if ($country && (my $entry = $locales->{country}->{$country})) { |
885 | $w->set_text($entry->{name}); | |
89a12446 DM |
886 | } |
887 | ||
2266526b | 888 | $gtk_state->{inbox}->show_all; |
89a12446 | 889 | |
efc7a8be | 890 | Proxmox::UI::display_html('country.htm'); |
89a12446 DM |
891 | set_next (undef, sub { |
892 | ||
893 | my $text = $w->get_text; | |
894 | ||
2c757f5e | 895 | if (my $cc = $locales->{countryhash}->{lc($text)}) { |
74041d68 | 896 | Proxmox::Install::Config::set_country($cc); |
201a5120 | 897 | $step_number++; |
89a12446 DM |
898 | create_password_view(); |
899 | return; | |
900 | } else { | |
72bea995 | 901 | Proxmox::UI::message("Please select a country first."); |
89a12446 DM |
902 | $w->grab_focus(); |
903 | } | |
904 | }); | |
905 | ||
906 | $w->grab_focus(); | |
907 | } | |
908 | ||
c6ed3b24 DM |
909 | my $target_hd_combo; |
910 | my $target_hd_label; | |
911 | ||
bd3a2e26 | 912 | my $hdoption_first_setup = 1; |
c6ed3b24 | 913 | |
c7779156 FG |
914 | my $create_basic_grid = sub { |
915 | my $grid = Gtk3::Grid->new(); | |
916 | $grid->set_visible(1); | |
917 | $grid->set_column_spacing(10); | |
918 | $grid->set_row_spacing(10); | |
919 | $grid->set_hexpand(1); | |
920 | ||
6d8b8564 TL |
921 | $grid->set_margin_start(10); |
922 | $grid->set_margin_end(20); | |
c7779156 FG |
923 | $grid->set_margin_top(5); |
924 | $grid->set_margin_bottom(5); | |
925 | ||
926 | return $grid; | |
927 | }; | |
928 | ||
929 | my $create_label_widget_grid = sub { | |
930 | my ($labeled_widgets) = @_; | |
931 | ||
932 | my $grid = &$create_basic_grid(); | |
933 | my $row = 0; | |
934 | ||
935 | for (my $i = 0; $i < @$labeled_widgets; $i += 2) { | |
936 | my $widget = @$labeled_widgets[$i+1]; | |
937 | my $label = Gtk3::Label->new(@$labeled_widgets[$i]); | |
938 | $label->set_visible(1); | |
9f91507b | 939 | $label->set_xalign(1.0); |
c7779156 FG |
940 | $grid->attach($label, 0, $row, 1, 1); |
941 | $widget->set_visible(1); | |
942 | $grid->attach($widget, 1, $row, 1, 1); | |
943 | $row++; | |
944 | } | |
945 | ||
946 | return $grid; | |
947 | }; | |
948 | ||
329a65a5 | 949 | # only relevant for raid with its multipl diskX to diskY mappings. |
ebf1e983 | 950 | my $get_selected_hdsize = sub { |
c07739f4 | 951 | my $hdsize = shift; |
329a65a5 TL |
952 | return $hdsize if defined($hdsize); |
953 | ||
954 | # compute the smallest disk size of the actually selected disks | |
40fbf8e6 TL |
955 | my $cached_disks = get_cached_disks(); |
956 | my $disk_count = scalar(@$cached_disks); | |
957 | for (my $i = 0; $i < $disk_count; $i++) { | |
5bcefda0 TL |
958 | next if !Proxmox::Install::Config::get_disk_selection($i); |
959 | my $cur_hd = $cached_disks->[$i]; | |
329a65a5 TL |
960 | my $disksize = int(@$cur_hd[2] / (2 * 1024 * 1024.0)); # size in GB |
961 | $hdsize //= $disksize; | |
962 | $hdsize = $disksize if $disksize < $hdsize; | |
c07739f4 | 963 | } |
3bcf46e2 | 964 | |
a8a14c4d | 965 | if (my $cfg_hdsize = Proxmox::Install::Config::get_hdsize()) { |
3bcf46e2 TL |
966 | # had the dialog open previously and set an even lower size than the disk selection allows |
967 | $hdsize = $cfg_hdsize if $cfg_hdsize < $hdsize; | |
968 | } | |
ebf1e983 TL |
969 | return $hdsize // 0; # fall back to zero, e.g., if none is selected hdsize cannot be any size |
970 | }; | |
971 | ||
972 | my sub update_hdsize_adjustment { | |
973 | my ($adjustment, $hdsize) = @_; | |
974 | ||
975 | $hdsize = $get_selected_hdsize->($hdsize); | |
976 | # expect that lower = 0 and step increments = 1 still are valid | |
977 | $adjustment->set_upper($hdsize + 1); | |
978 | $adjustment->set_value($hdsize); | |
979 | } | |
c07739f4 | 980 | |
ebf1e983 TL |
981 | my sub create_hdsize_adjustment { |
982 | my ($hdsize) = @_; | |
983 | $hdsize = $get_selected_hdsize->($hdsize); | |
a8a14c4d | 984 | my $cfg_hdsize = Proxmox::Install::Config::get_hdsize(); |
ebf1e983 | 985 | # params are: initial value, lower, upper, step increment, page increment, page size |
a8a14c4d | 986 | return Gtk3::Adjustment->new($cfg_hdsize || $hdsize, 0, $hdsize+1, 1, 1, 1); |
ebf1e983 | 987 | } |
c07739f4 | 988 | |
e2b003a6 | 989 | my sub get_hdsize_spin_button { |
c07739f4 SI |
990 | my $hdsize = shift; |
991 | ||
992 | my $hdsize_entry_buffer = Gtk3::EntryBuffer->new(undef, 1); | |
ebf1e983 | 993 | my $hdsize_size_adj = create_hdsize_adjustment($hdsize); |
c07739f4 SI |
994 | |
995 | my $spinbutton_hdsize = Gtk3::SpinButton->new($hdsize_size_adj, 1, 1); | |
996 | $spinbutton_hdsize->set_buffer($hdsize_entry_buffer); | |
997 | $spinbutton_hdsize->set_adjustment($hdsize_size_adj); | |
998 | $spinbutton_hdsize->set_tooltip_text("only use specified size (GB) of the harddisk (rest left unpartitioned)"); | |
999 | return $spinbutton_hdsize; | |
1000 | }; | |
1001 | ||
c7779156 | 1002 | my $create_raid_disk_grid = sub { |
679c813c | 1003 | my ($hdsize_buttons) = @_; |
c2ca8ba8 | 1004 | |
40fbf8e6 TL |
1005 | my $cached_disks = get_cached_disks(); |
1006 | my $disk_count = scalar(@$cached_disks); | |
c7779156 | 1007 | my $disk_labeled_widgets = []; |
40fbf8e6 | 1008 | for (my $i = 0; $i < $disk_count; $i++) { |
c7779156 FG |
1009 | my $disk_selector = Gtk3::ComboBoxText->new(); |
1010 | $disk_selector->append_text("-- do not use --"); | |
1011 | $disk_selector->set_active(0); | |
1012 | $disk_selector->set_visible(1); | |
c2ca8ba8 | 1013 | |
40fbf8e6 | 1014 | for my $hd (@$cached_disks) { |
17fd908e | 1015 | my ($disk, $devname, $size, $model, $logical_bsize) = @$hd; |
40fbf8e6 | 1016 | $disk_selector->append_text(get_device_desc($devname, $size, $model)); |
c7779156 FG |
1017 | } |
1018 | ||
8d1ca71a TL |
1019 | $disk_selector->{pve_disk_id} = $i; |
1020 | $disk_selector->signal_connect(changed => sub { | |
1021 | my $w = shift; | |
1022 | my $diskid = $w->{pve_disk_id}; | |
1023 | my $a = $w->get_active - 1; | |
5bcefda0 | 1024 | Proxmox::Install::Config::set_disk_selection($diskid, $a >= 0); |
8d1ca71a | 1025 | for my $btn (@$hdsize_buttons) { |
ebf1e983 | 1026 | update_hdsize_adjustment($btn->get_adjustment()); |
8d1ca71a TL |
1027 | } |
1028 | }); | |
1029 | ||
bd3a2e26 | 1030 | if ($hdoption_first_setup) { |
40fbf8e6 | 1031 | $disk_selector->set_active ($i+1) if $cached_disks->[$i]; |
c7779156 FG |
1032 | } else { |
1033 | my $hdind = 0; | |
5bcefda0 TL |
1034 | if (Proxmox::Install::Config::get_disk_selection($i)) { |
1035 | my $cur_hd = $cached_disks->[$i]; | |
40fbf8e6 | 1036 | foreach my $hd (@$cached_disks) { |
c7779156 FG |
1037 | if (@$hd[1] eq @$cur_hd[1]) { |
1038 | $disk_selector->set_active($hdind+1); | |
1039 | last; | |
1040 | } | |
1041 | $hdind++; | |
1042 | } | |
1043 | } | |
1044 | } | |
1045 | ||
1046 | push @$disk_labeled_widgets, "Harddisk $i", $disk_selector; | |
1047 | } | |
1048 | ||
3235f39b | 1049 | my $clear_all_button = Gtk3::Button->new('_Deselect All'); |
40fbf8e6 | 1050 | if ($disk_count > 3) { |
3235f39b TL |
1051 | $clear_all_button->signal_connect('clicked', sub { |
1052 | my $is_widget = 0; | |
1053 | for my $disk_selector (@$disk_labeled_widgets) { | |
1054 | $disk_selector->set_active(0) if $is_widget; | |
1055 | $is_widget ^= 1; | |
1056 | } | |
1057 | }); | |
1058 | $clear_all_button->set_visible(1); | |
1059 | } | |
1060 | ||
c7779156 FG |
1061 | my $scrolled_window = Gtk3::ScrolledWindow->new(); |
1062 | $scrolled_window->set_hexpand(1); | |
40fbf8e6 | 1063 | $scrolled_window->set_propagate_natural_height(1) if $disk_count > 4; |
3235f39b TL |
1064 | |
1065 | my $diskgrid = $create_label_widget_grid->($disk_labeled_widgets); | |
1066 | ||
1067 | $scrolled_window->add($diskgrid); | |
c7779156 | 1068 | $scrolled_window->set_policy('never', 'automatic'); |
3235f39b | 1069 | $scrolled_window->set_visible(1); |
0bc39c50 | 1070 | $scrolled_window->set_min_content_height(190); |
3235f39b TL |
1071 | |
1072 | my $vbox = Gtk3::Box->new('vertical', 0); | |
1073 | $vbox->pack_start($scrolled_window, 1, 1, 10); | |
1074 | ||
1075 | my $hbox = Gtk3::Box->new('horizontal', 0); | |
1076 | $hbox->pack_end($clear_all_button, 0, 0, 20); | |
1077 | $hbox->set_visible(1); | |
1078 | $vbox->pack_end($hbox, 0, 0, 0); | |
c7779156 | 1079 | |
3235f39b | 1080 | return $vbox; |
c7779156 FG |
1081 | }; |
1082 | ||
1083 | my $create_raid_advanced_grid = sub { | |
c07739f4 | 1084 | my ($hdsize_btn) = @_; |
c7779156 | 1085 | my $labeled_widgets = []; |
2cdba397 | 1086 | my $spinbutton_ashift = Gtk3::SpinButton->new_with_range(9, 13, 1); |
6c99667a FG |
1087 | $spinbutton_ashift->set_tooltip_text("zpool ashift property (pool sector size, default 2^12)"); |
1088 | $spinbutton_ashift->signal_connect ("value-changed" => sub { | |
1089 | my $w = shift; | |
6edd095a | 1090 | Proxmox::Install::Config::set_zfs_opt('ashift', $w->get_value_as_int()); |
c7779156 | 1091 | }); |
6edd095a TL |
1092 | my $ashift = Proxmox::Install::Config::get_zfs_opt('ashift') // 12; |
1093 | $spinbutton_ashift->set_value($ashift); | |
c7779156 | 1094 | push @$labeled_widgets, "ashift"; |
6c99667a | 1095 | push @$labeled_widgets, $spinbutton_ashift; |
c7779156 FG |
1096 | |
1097 | my $combo_compress = Gtk3::ComboBoxText->new(); | |
1098 | $combo_compress->set_tooltip_text("zfs compression algorithm for rpool dataset"); | |
59cea7a7 | 1099 | my $comp_opts = ["on","off","lzjb","lz4", "zle", "gzip", "zstd"]; |
c7779156 FG |
1100 | foreach my $opt (@$comp_opts) { |
1101 | $combo_compress->append($opt, $opt); | |
1102 | } | |
6edd095a TL |
1103 | my $compress = Proxmox::Install::Config::get_zfs_opt('compress') // 'on'; |
1104 | $combo_compress->set_active_id($compress); | |
c7779156 FG |
1105 | $combo_compress->signal_connect (changed => sub { |
1106 | my $w = shift; | |
6edd095a | 1107 | Proxmox::Install::Config::set_zfs_opt('compress', $w->get_active_text()); |
c7779156 FG |
1108 | }); |
1109 | push @$labeled_widgets, "compress"; | |
1110 | push @$labeled_widgets, $combo_compress; | |
1111 | ||
1112 | my $combo_checksum = Gtk3::ComboBoxText->new(); | |
1113 | $combo_checksum->set_tooltip_text("zfs checksum algorithm for rpool dataset"); | |
1114 | my $csum_opts = ["on", "off","fletcher2", "fletcher4", "sha256"]; | |
1115 | foreach my $opt (@$csum_opts) { | |
1116 | $combo_checksum->append($opt, $opt); | |
1117 | } | |
6edd095a TL |
1118 | my $checksum = Proxmox::Install::Config::get_zfs_opt('checksum') // 'on'; |
1119 | $combo_checksum->set_active_id($checksum); | |
c7779156 FG |
1120 | $combo_checksum->signal_connect (changed => sub { |
1121 | my $w = shift; | |
6edd095a | 1122 | Proxmox::Install::Config::set_zfs_opt('checksum', $w->get_active_text()); |
c7779156 FG |
1123 | }); |
1124 | push @$labeled_widgets, "checksum"; | |
1125 | push @$labeled_widgets, $combo_checksum; | |
1126 | ||
1127 | my $spinbutton_copies = Gtk3::SpinButton->new_with_range(1,3,1); | |
1128 | $spinbutton_copies->set_tooltip_text("zfs copies property for rpool dataset (in addition to RAID redundancy!)"); | |
1129 | $spinbutton_copies->signal_connect ("value-changed" => sub { | |
1130 | my $w = shift; | |
6edd095a | 1131 | Proxmox::Install::Config::set_zfs_opt('copies', $w->get_value_as_int()); |
c7779156 | 1132 | }); |
6edd095a TL |
1133 | my $copies = Proxmox::Install::Config::get_zfs_opt('copies') // 1; |
1134 | $spinbutton_copies->set_value($copies); | |
c7779156 FG |
1135 | push @$labeled_widgets, "copies", $spinbutton_copies; |
1136 | ||
c07739f4 | 1137 | push @$labeled_widgets, "hdsize", $hdsize_btn; |
2cdba397 | 1138 | return $create_label_widget_grid->($labeled_widgets);; |
c7779156 FG |
1139 | }; |
1140 | ||
679c813c SI |
1141 | my $create_btrfs_raid_advanced_grid = sub { |
1142 | my ($hdsize_btn) = @_; | |
1143 | my $labeled_widgets = []; | |
1144 | push @$labeled_widgets, "hdsize", $hdsize_btn; | |
1145 | return $create_label_widget_grid->($labeled_widgets);; | |
1146 | }; | |
1147 | ||
aed81ff0 | 1148 | sub create_hdoption_view { |
aed81ff0 DM |
1149 | my $dialog = Gtk3::Dialog->new(); |
1150 | ||
1151 | $dialog->set_title("Harddisk options"); | |
1152 | ||
1153 | $dialog->add_button("_OK", 1); | |
1154 | ||
1155 | my $contarea = $dialog->get_content_area(); | |
1156 | ||
1157 | my $hbox2 = Gtk3::Box->new('horizontal', 0); | |
6d8b8564 | 1158 | $contarea->pack_start($hbox2, 1, 1, 5); |
aed81ff0 DM |
1159 | |
1160 | my $grid = Gtk3::Grid->new(); | |
1161 | $grid->set_column_spacing(10); | |
1162 | $grid->set_row_spacing(10); | |
1464c7c9 | 1163 | |
6d8b8564 | 1164 | $hbox2->pack_start($grid, 1, 0, 5); |
c6ed3b24 DM |
1165 | |
1166 | my $row = 0; | |
1167 | ||
aed81ff0 | 1168 | # Filesystem type |
71590b6a | 1169 | my $label0 = Gtk3::Label->new("Filesystem"); |
9f91507b | 1170 | $label0->set_xalign(1.0); |
c6ed3b24 | 1171 | $grid->attach($label0, 0, $row, 1, 1); |
1464c7c9 | 1172 | |
bcbfab6b | 1173 | my $fstypecb = Gtk3::ComboBoxText->new(); |
2cdba397 TL |
1174 | my $fstype = [ |
1175 | 'ext4', | |
1176 | 'xfs', | |
1177 | 'zfs (RAID0)', | |
1178 | 'zfs (RAID1)', | |
1179 | 'zfs (RAID10)', | |
1180 | 'zfs (RAIDZ-1)', | |
1181 | 'zfs (RAIDZ-2)', | |
1182 | 'zfs (RAIDZ-3)', | |
1183 | ]; | |
6f52fc3d | 1184 | push @$fstype, 'btrfs (RAID0)', 'btrfs (RAID1)', 'btrfs (RAID10)' |
84f90cbb | 1185 | if $iso_env->{cfg}->{enable_btrfs}; |
aed81ff0 | 1186 | |
cd1a45ad | 1187 | my $filesys = Proxmox::Install::Config::get_filesys(); |
c6ed3b24 DM |
1188 | my $tcount = 0; |
1189 | foreach my $tmp (@$fstype) { | |
1190 | $fstypecb->append_text($tmp); | |
cd1a45ad | 1191 | $fstypecb->set_active ($tcount) if $filesys eq $tmp; |
c6ed3b24 DM |
1192 | $tcount++; |
1193 | } | |
1194 | ||
1195 | $grid->attach($fstypecb, 1, $row, 1, 1); | |
1196 | ||
1197 | $hbox2->show_all(); | |
1198 | ||
1199 | $row++; | |
1200 | ||
bbf51225 | 1201 | my $sep = Gtk3::Separator->new('horizontal'); |
c7779156 FG |
1202 | $sep->set_visible(1); |
1203 | $grid->attach($sep, 0, $row, 2, 1); | |
1204 | $row++; | |
aed81ff0 | 1205 | |
af35966c | 1206 | my $hw_raid_note = Gtk3::Label->new(""); # text will be set below, before making it visible |
f0a0d90b TL |
1207 | $hw_raid_note->set_line_wrap(1); |
1208 | $hw_raid_note->set_max_width_chars(30); | |
f0a0d90b TL |
1209 | $hw_raid_note->set_visible(0); |
1210 | $grid->attach($hw_raid_note, 0, $row++, 2, 1); | |
1211 | ||
c7779156 | 1212 | my $hdsize_labeled_widgets = []; |
aed81ff0 | 1213 | |
5bcefda0 TL |
1214 | my $target_hd = Proxmox::Install::Config::get_target_hd(); |
1215 | my $hdsize = 0; # size compute | |
aed81ff0 | 1216 | if ( -b $target_hd) { |
c2d5b241 | 1217 | $hdsize = int(Proxmox::Sys::Block::hd_size($target_hd) / (1024 * 1024.0)); # size in GB |
c6ed3b24 | 1218 | } elsif ($target_hd) { |
c2ca8ba8 | 1219 | $hdsize = int((-s $target_hd) / (1024 * 1024 * 1024.0)); |
aed81ff0 DM |
1220 | } |
1221 | ||
e2b003a6 | 1222 | my $spinbutton_hdsize_nonraid = get_hdsize_spin_button($hdsize); |
c07739f4 SI |
1223 | push @$hdsize_labeled_widgets, "hdsize", $spinbutton_hdsize_nonraid; |
1224 | my $spinbutton_hdsize = $spinbutton_hdsize_nonraid; | |
aed81ff0 DM |
1225 | |
1226 | my $entry_swapsize = Gtk3::Entry->new(); | |
1227 | $entry_swapsize->set_tooltip_text("maximum SWAP size (GB)"); | |
1228 | $entry_swapsize->signal_connect (key_press_event => \&check_float); | |
ef41b049 TL |
1229 | my $swapsize = Proxmox::Install::Config::get_swapsize(); |
1230 | $entry_swapsize->set_text($swapsize) if defined($swapsize); | |
c7779156 | 1231 | push @$hdsize_labeled_widgets, "swapsize", $entry_swapsize; |
aed81ff0 DM |
1232 | |
1233 | my $entry_maxroot = Gtk3::Entry->new(); | |
84f90cbb | 1234 | if ($iso_env->{product} eq 'pve') { |
0adc7ca0 DM |
1235 | $entry_maxroot->set_tooltip_text("maximum size (GB) for LVM root volume"); |
1236 | $entry_maxroot->signal_connect (key_press_event => \&check_float); | |
b4ab3f19 TL |
1237 | if (my $maxroot = Proxmox::Install::Config::get_maxroot()) { |
1238 | $entry_maxroot->set_text($maxroot); | |
1239 | } | |
0adc7ca0 DM |
1240 | push @$hdsize_labeled_widgets, "maxroot", $entry_maxroot; |
1241 | } | |
aed81ff0 DM |
1242 | |
1243 | my $entry_minfree = Gtk3::Entry->new(); | |
034f75e4 | 1244 | $entry_minfree->set_tooltip_text("minimum free LVM space (GB, required for LVM snapshots)"); |
aed81ff0 | 1245 | $entry_minfree->signal_connect (key_press_event => \&check_float); |
35e7bf16 TL |
1246 | if (defined(my $minfree = Proxmox::Install::Config::get_minfree())) { |
1247 | $entry_minfree->set_text($minfree); | |
1248 | } | |
c7779156 | 1249 | push @$hdsize_labeled_widgets, "minfree", $entry_minfree; |
aed81ff0 | 1250 | |
b6e875ca | 1251 | my $entry_maxvz; |
84f90cbb | 1252 | if ($iso_env->{product} eq 'pve') { |
b6e875ca DM |
1253 | $entry_maxvz = Gtk3::Entry->new(); |
1254 | $entry_maxvz->set_tooltip_text("maximum size (GB) for LVM data volume"); | |
1255 | $entry_maxvz->signal_connect (key_press_event => \&check_float); | |
140f2e85 TL |
1256 | if (defined(my $maxvz = Proxmox::Install::Config::get_maxvz())) { |
1257 | $entry_maxvz->set_text($maxvz); | |
1258 | } | |
b6e875ca DM |
1259 | push @$hdsize_labeled_widgets, "maxvz", $entry_maxvz; |
1260 | } | |
c7779156 | 1261 | |
e2b003a6 TL |
1262 | my $spinbutton_hdsize_zfs = get_hdsize_spin_button($hdsize); |
1263 | my $spinbutton_hdsize_btrfs = get_hdsize_spin_button($hdsize); | |
679c813c | 1264 | my $hdsize_buttons = [ $spinbutton_hdsize_zfs, $spinbutton_hdsize_btrfs ]; |
c7779156 FG |
1265 | my $options_stack = Gtk3::Stack->new(); |
1266 | $options_stack->set_visible(1); | |
1267 | $options_stack->set_hexpand(1); | |
1268 | $options_stack->set_vexpand(1); | |
679c813c | 1269 | $options_stack->add_titled(&$create_raid_disk_grid($hdsize_buttons), "raiddisk", "Disk Setup"); |
c7779156 | 1270 | $options_stack->add_titled(&$create_label_widget_grid($hdsize_labeled_widgets), "hdsize", "Size Options"); |
c07739f4 | 1271 | $options_stack->add_titled(&$create_raid_advanced_grid($spinbutton_hdsize_zfs), "raidzfsadvanced", "Advanced Options"); |
679c813c | 1272 | $options_stack->add_titled(&$create_btrfs_raid_advanced_grid($spinbutton_hdsize_btrfs), "raidbtrfsadvanced", "Advanced Options"); |
c7779156 FG |
1273 | $options_stack->set_visible_child_name("raiddisk"); |
1274 | my $options_stack_switcher = Gtk3::StackSwitcher->new(); | |
1275 | $options_stack_switcher->set_halign('center'); | |
1276 | $options_stack_switcher->set_stack($options_stack); | |
1277 | $grid->attach($options_stack_switcher, 0, $row, 2, 1); | |
1278 | $row++; | |
1279 | $grid->attach($options_stack, 0, $row, 2, 1); | |
c6ed3b24 | 1280 | $row++; |
aed81ff0 | 1281 | |
bd3a2e26 | 1282 | $hdoption_first_setup = 0; |
c7779156 FG |
1283 | |
1284 | my $switch_view = sub { | |
cd1a45ad TL |
1285 | my $filesys = Proxmox::Install::Config::get_filesys(); |
1286 | my $raid = $filesys =~ m/zfs|btrfs/; | |
1287 | my $is_zfs = $filesys =~ m/zfs/; | |
c6ed3b24 | 1288 | |
c7779156 FG |
1289 | $target_hd_combo->set_visible(!$raid); |
1290 | $options_stack->get_child_by_name("hdsize")->set_visible(!$raid); | |
1291 | $options_stack->get_child_by_name("raiddisk")->set_visible($raid); | |
af35966c TL |
1292 | |
1293 | if ($raid) { | |
1294 | my $msg = "<b>Note</b>: " . ($is_zfs | |
1295 | ? "ZFS is not compatible with hardware RAID controllers, for details see the documentation." | |
84f90cbb | 1296 | : "BTRFS integration in $iso_env->{cfg}->{fullname} is a technology preview!" |
af35966c TL |
1297 | ); |
1298 | $hw_raid_note->set_markup($msg); | |
1299 | } | |
f0a0d90b | 1300 | $hw_raid_note->set_visible($raid); |
679c813c | 1301 | $options_stack_switcher->set_visible($raid); |
af35966c | 1302 | $options_stack->get_child_by_name("raidzfsadvanced")->set_visible($is_zfs); |
679c813c | 1303 | $options_stack->get_child_by_name("raidbtrfsadvanced")->set_visible(!$is_zfs); |
c7779156 | 1304 | if ($raid) { |
cd1a45ad | 1305 | $target_hd_label->set_text("Target: $filesys "); |
c7779156 | 1306 | $options_stack->set_visible_child_name("raiddisk"); |
c6ed3b24 | 1307 | } else { |
c6ed3b24 DM |
1308 | $target_hd_label->set_text("Target Harddisk: "); |
1309 | } | |
c07739f4 SI |
1310 | |
1311 | if ($raid) { | |
679c813c | 1312 | $spinbutton_hdsize = $is_zfs ? $spinbutton_hdsize_zfs : $spinbutton_hdsize_btrfs; |
c07739f4 SI |
1313 | } else { |
1314 | $spinbutton_hdsize = $spinbutton_hdsize_nonraid; | |
1315 | } | |
1316 | ||
c7779156 FG |
1317 | my (undef, $pref_width) = $dialog->get_preferred_width(); |
1318 | my (undef, $pref_height) = $dialog->get_preferred_height(); | |
650a9aab | 1319 | $pref_height = 750 if $pref_height > 750; |
c7779156 | 1320 | $dialog->resize($pref_width, $pref_height); |
f7b853d1 DM |
1321 | }; |
1322 | ||
c7779156 | 1323 | &$switch_view(); |
f7b853d1 DM |
1324 | |
1325 | $fstypecb->signal_connect (changed => sub { | |
cd1a45ad TL |
1326 | my $new_filesys = $fstypecb->get_active_text(); |
1327 | Proxmox::Install::Config::set_filesys($new_filesys); | |
c7779156 | 1328 | &$switch_view(); |
f7b853d1 DM |
1329 | }); |
1330 | ||
bbf51225 | 1331 | my $sep2 = Gtk3::Separator->new('horizontal'); |
95844cc6 TL |
1332 | $sep2->set_visible(1); |
1333 | $contarea->pack_end($sep2, 1, 1, 10); | |
1334 | ||
c6ed3b24 | 1335 | $dialog->show(); |
aed81ff0 DM |
1336 | |
1337 | $dialog->run(); | |
1338 | ||
1339 | my $get_float = sub { | |
1340 | my ($entry) = @_; | |
1341 | ||
1342 | my $text = $entry->get_text(); | |
1343 | return undef if !defined($text); | |
1344 | ||
1345 | $text =~ s/^\s+//; | |
1346 | $text =~ s/\s+$//; | |
1347 | ||
1348 | return undef if $text !~ m/^\d+(\.\d+)?$/; | |
1349 | ||
1350 | return $text; | |
1351 | }; | |
1352 | ||
1353 | my $tmp; | |
1354 | ||
1355 | if (($tmp = &$get_float($spinbutton_hdsize)) && ($tmp != $hdsize)) { | |
a8a14c4d | 1356 | Proxmox::Install::Config::set_hdsize($tmp); |
aed81ff0 | 1357 | } else { |
a8a14c4d | 1358 | Proxmox::Install::Config::set_hdsize(undef); |
aed81ff0 DM |
1359 | } |
1360 | ||
1361 | if (defined($tmp = &$get_float($entry_swapsize))) { | |
ef41b049 | 1362 | Proxmox::Install::Config::set_swapsize($tmp); |
aed81ff0 | 1363 | } else { |
ef41b049 | 1364 | Proxmox::Install::Config::set_swapsize(undef); |
aed81ff0 DM |
1365 | } |
1366 | ||
1367 | if (defined($tmp = &$get_float($entry_maxroot))) { | |
b4ab3f19 | 1368 | Proxmox::Install::Config::set_maxroot($tmp); |
aed81ff0 | 1369 | } else { |
b4ab3f19 | 1370 | Proxmox::Install::Config::set_maxroot(undef); |
aed81ff0 DM |
1371 | } |
1372 | ||
1373 | if (defined($tmp = &$get_float($entry_minfree))) { | |
35e7bf16 | 1374 | Proxmox::Install::Config::set_minfree($tmp); |
aed81ff0 | 1375 | } else { |
35e7bf16 | 1376 | Proxmox::Install::Config::set_minfree(undef); |
aed81ff0 DM |
1377 | } |
1378 | ||
b6e875ca | 1379 | if ($entry_maxvz && defined($tmp = &$get_float($entry_maxvz))) { |
140f2e85 | 1380 | Proxmox::Install::Config::set_maxvz($tmp); |
aed81ff0 | 1381 | } else { |
140f2e85 | 1382 | Proxmox::Install::Config::set_maxvz(undef); |
aed81ff0 DM |
1383 | } |
1384 | ||
1385 | $dialog->destroy(); | |
1386 | } | |
1387 | ||
121ebc59 | 1388 | my $get_raid_devlist = sub { |
c6ed3b24 DM |
1389 | |
1390 | my $dev_name_hash = {}; | |
1391 | ||
40fbf8e6 | 1392 | my $cached_disks = get_cached_disks(); |
c6ed3b24 | 1393 | my $devlist = []; |
40fbf8e6 | 1394 | for (my $i = 0; $i < @$cached_disks; $i++) { |
5bcefda0 TL |
1395 | next if !Proxmox::Install::Config::get_disk_selection($i); |
1396 | ||
1397 | my $hd = $cached_disks->[$i]; | |
1398 | my ($disk, $devname, $size, $model, $logical_bsize) = @$hd; | |
1399 | die "device '$devname' is used more than once\n" if $dev_name_hash->{$devname}; | |
1400 | $dev_name_hash->{$devname} = $hd; | |
1401 | push @$devlist, $hd; | |
c6ed3b24 DM |
1402 | } |
1403 | ||
121ebc59 DM |
1404 | return $devlist; |
1405 | }; | |
1406 | ||
14aacec8 FG |
1407 | sub zfs_mirror_size_check { |
1408 | my ($expected, $actual) = @_; | |
1409 | ||
1410 | die "mirrored disks must have same size\n" | |
1411 | if abs($expected - $actual) > $expected / 10; | |
1412 | } | |
1413 | ||
5ea943cf SI |
1414 | sub legacy_bios_4k_check { |
1415 | my ($lbs) = @_; | |
1416 | die "Booting from 4kn drive in legacy BIOS mode is not supported.\n" | |
71583761 | 1417 | if $run_env->{boot_type} ne 'efi' && $lbs == 4096; |
5ea943cf SI |
1418 | } |
1419 | ||
121ebc59 | 1420 | sub get_zfs_raid_setup { |
cd1a45ad | 1421 | my $filesys = Proxmox::Install::Config::get_filesys(); |
121ebc59 DM |
1422 | |
1423 | my $devlist = &$get_raid_devlist(); | |
1424 | ||
224bb7b0 | 1425 | my $diskcount = scalar(@$devlist); |
0cfa502c | 1426 | die "$filesys needs at least one device\n" if $diskcount < 1; |
c6ed3b24 DM |
1427 | |
1428 | my $cmd= ''; | |
1429 | if ($filesys eq 'zfs (RAID0)') { | |
c6ed3b24 | 1430 | foreach my $hd (@$devlist) { |
5ea943cf | 1431 | legacy_bios_4k_check(@$hd[4]); |
c6ed3b24 DM |
1432 | $cmd .= " @$hd[1]"; |
1433 | } | |
1434 | } elsif ($filesys eq 'zfs (RAID1)') { | |
0cfa502c | 1435 | die "zfs (RAID1) needs at least 2 device\n" if $diskcount < 2; |
c6ed3b24 | 1436 | $cmd .= ' mirror '; |
269c66a6 | 1437 | my $hd = @$devlist[0]; |
14aacec8 | 1438 | my $expected_size = @$hd[2]; # all disks need approximately same size |
eaeccd9f | 1439 | foreach my $hd (@$devlist) { |
14aacec8 | 1440 | zfs_mirror_size_check($expected_size, @$hd[2]); |
5ea943cf | 1441 | legacy_bios_4k_check(@$hd[4]); |
c6ed3b24 | 1442 | $cmd .= " @$hd[1]"; |
c6ed3b24 DM |
1443 | } |
1444 | } elsif ($filesys eq 'zfs (RAID10)') { | |
0cfa502c | 1445 | die "zfs (RAID10) needs at least 4 device\n" if $diskcount < 4; |
b8f4f0f9 | 1446 | die "zfs (RAID10) needs an even number of devices\n" if $diskcount & 1; |
1464c7c9 | 1447 | |
224bb7b0 | 1448 | for (my $i = 0; $i < $diskcount; $i+=2) { |
c6ed3b24 DM |
1449 | my $hd1 = @$devlist[$i]; |
1450 | my $hd2 = @$devlist[$i+1]; | |
14aacec8 | 1451 | zfs_mirror_size_check(@$hd1[2], @$hd2[2]); # pairs need approximately same size |
5ea943cf SI |
1452 | legacy_bios_4k_check(@$hd1[4]); |
1453 | legacy_bios_4k_check(@$hd2[4]); | |
c6ed3b24 DM |
1454 | $cmd .= ' mirror ' . @$hd1[1] . ' ' . @$hd2[1]; |
1455 | } | |
1456 | ||
1457 | } elsif ($filesys =~ m/^zfs \(RAIDZ-([123])\)$/) { | |
1458 | my $level = $1; | |
1459 | my $mindisks = 2 + $level; | |
0cfa502c | 1460 | die "zfs (RAIDZ-$level) needs at least $mindisks devices\n" if scalar(@$devlist) < $mindisks; |
269c66a6 | 1461 | my $hd = @$devlist[0]; |
14aacec8 | 1462 | my $expected_size = @$hd[2]; # all disks need approximately same size |
097ecf8f | 1463 | $cmd .= " raidz$level"; |
eaeccd9f | 1464 | foreach my $hd (@$devlist) { |
14aacec8 | 1465 | zfs_mirror_size_check($expected_size, @$hd[2]); |
5ea943cf | 1466 | legacy_bios_4k_check(@$hd[4]); |
c6ed3b24 | 1467 | $cmd .= " @$hd[1]"; |
c6ed3b24 DM |
1468 | } |
1469 | } else { | |
1470 | die "unknown zfs mode '$filesys'\n"; | |
1471 | } | |
1472 | ||
82695821 | 1473 | return ($devlist, $cmd); |
c6ed3b24 DM |
1474 | } |
1475 | ||
121ebc59 | 1476 | sub get_btrfs_raid_setup { |
cd1a45ad | 1477 | my $filesys = Proxmox::Install::Config::get_filesys(); |
121ebc59 DM |
1478 | |
1479 | my $devlist = &$get_raid_devlist(); | |
1480 | ||
1481 | my $diskcount = scalar(@$devlist); | |
0cfa502c | 1482 | die "$filesys needs at least one device\n" if $diskcount < 1; |
121ebc59 DM |
1483 | |
1484 | my $mode; | |
1485 | ||
1486 | if ($diskcount == 1) { | |
1487 | $mode = 'single'; | |
1488 | } else { | |
1489 | if ($filesys eq 'btrfs (RAID0)') { | |
1490 | $mode = 'raid0'; | |
1491 | } elsif ($filesys eq 'btrfs (RAID1)') { | |
0cfa502c | 1492 | die "btrfs (RAID1) needs at least 2 device\n" if $diskcount < 2; |
121ebc59 DM |
1493 | $mode = 'raid1'; |
1494 | } elsif ($filesys eq 'btrfs (RAID10)') { | |
0cfa502c | 1495 | die "btrfs (RAID10) needs at least 4 device\n" if $diskcount < 4; |
121ebc59 DM |
1496 | $mode = 'raid10'; |
1497 | } else { | |
9d69f3d3 | 1498 | die "unknown btrfs mode '$filesys'\n"; |
121ebc59 DM |
1499 | } |
1500 | } | |
1501 | ||
1502 | return ($devlist, $mode); | |
1503 | } | |
1504 | ||
218a4b6b | 1505 | my $last_hd_selected = 0; |
89a12446 DM |
1506 | sub create_hdsel_view { |
1507 | ||
2266526b | 1508 | $gtk_state->{prev_btn}->set_sensitive(1); # enable previous button at this point |
201a5120 | 1509 | |
71590b6a | 1510 | cleanup_view(); |
89a12446 | 1511 | |
d6efed19 | 1512 | my $vbox = Gtk3::Box->new('vertical', 0); |
2266526b | 1513 | $gtk_state->{inbox}->pack_start($vbox, 1, 0, 0); |
d6efed19 | 1514 | my $hbox = Gtk3::Box->new('horizontal', 0); |
71590b6a | 1515 | $vbox->pack_start($hbox, 0, 0, 10); |
968fa90b | 1516 | |
40fbf8e6 TL |
1517 | my $cached_disks = get_cached_disks(); |
1518 | my ($disk, $devname, $size, $model, $logical_bsize) = $cached_disks->[0]->@*; | |
5bcefda0 TL |
1519 | if (!defined(Proxmox::Install::Config::get_target_hd())) { |
1520 | Proxmox::Install::Config::set_target_hd($devname); | |
1521 | } | |
89a12446 | 1522 | |
71590b6a OB |
1523 | $target_hd_label = Gtk3::Label->new("Target Harddisk: "); |
1524 | $hbox->pack_start($target_hd_label, 0, 0, 0); | |
89a12446 | 1525 | |
bcbfab6b | 1526 | $target_hd_combo = Gtk3::ComboBoxText->new(); |
89a12446 | 1527 | |
40fbf8e6 | 1528 | foreach my $hd ($cached_disks->@*) { |
17fd908e | 1529 | ($disk, $devname, $size, $model, $logical_bsize) = @$hd; |
c2ca8ba8 | 1530 | $target_hd_combo->append_text(get_device_desc($devname, $size, $model)); |
1aa5bd02 | 1531 | } |
89a12446 | 1532 | |
cd1a45ad | 1533 | my $raid = Proxmox::Install::Config::get_filesys() =~ m/zfs|btrfs/; |
90af1603 | 1534 | if ($raid) { |
cd1a45ad TL |
1535 | my $filesys = Proxmox::Install::Config::get_filesys(); |
1536 | $target_hd_label->set_text("Target: $filesys "); | |
90af1603 OB |
1537 | $target_hd_combo->set_visible(0); |
1538 | $target_hd_combo->set_no_show_all(1); | |
1539 | } | |
218a4b6b | 1540 | $target_hd_combo->set_active($last_hd_selected); |
71590b6a | 1541 | $target_hd_combo->signal_connect(changed => sub { |
1aa5bd02 | 1542 | $a = shift->get_active; |
40fbf8e6 | 1543 | my ($disk, $devname) = @{@$cached_disks[$a]}; |
3b959bef | 1544 | $last_hd_selected = $a; |
5bcefda0 | 1545 | Proxmox::Install::Config::set_target_hd($devname); |
1aa5bd02 | 1546 | }); |
1464c7c9 | 1547 | |
71590b6a | 1548 | $hbox->pack_start($target_hd_combo, 0, 0, 10); |
aed81ff0 | 1549 | |
71590b6a | 1550 | my $options = Gtk3::Button->new('_Options'); |
aed81ff0 DM |
1551 | $options->signal_connect (clicked => \&create_hdoption_view); |
1552 | $hbox->pack_start ($options, 0, 0, 0); | |
1553 | ||
89a12446 | 1554 | |
2266526b | 1555 | $gtk_state->{inbox}->show_all; |
89a12446 | 1556 | |
efc7a8be | 1557 | Proxmox::UI::display_html('page1.htm'); |
c6ed3b24 | 1558 | |
71590b6a | 1559 | set_next(undef, sub { |
cd1a45ad TL |
1560 | my $filesys = Proxmox::Install::Config::get_filesys(); |
1561 | if ($filesys =~ m/zfs/) { | |
a7d40341 | 1562 | my ($devlist) = eval { get_zfs_raid_setup() }; |
c6ed3b24 | 1563 | if (my $err = $@) { |
72bea995 | 1564 | Proxmox::UI::message("Warning: $err\nPlease fix ZFS setup first."); |
303dfb2c | 1565 | return; |
c6ed3b24 | 1566 | } |
5bcefda0 | 1567 | $target_hds = [ map { $_->[1] } @$devlist ]; |
cd1a45ad | 1568 | } elsif ($filesys =~ m/btrfs/) { |
a7d40341 | 1569 | my ($devlist) = eval { get_btrfs_raid_setup() }; |
121ebc59 | 1570 | if (my $err = $@) { |
72bea995 | 1571 | Proxmox::UI::message("Warning: $err\nPlease fix BTRFS setup first."); |
303dfb2c | 1572 | return; |
121ebc59 | 1573 | } |
5bcefda0 | 1574 | $target_hds = [ map { $_->[1] } @$devlist ]; |
c6ed3b24 | 1575 | } else { |
5bcefda0 | 1576 | my $target_hd = Proxmox::Install::Config::get_target_hd(); |
5cfca6d7 | 1577 | eval { |
40fbf8e6 | 1578 | my $target_block_size = Proxmox::Sys::Block::logical_blocksize($target_hd); |
5cfca6d7 TL |
1579 | legacy_bios_4k_check($target_block_size); |
1580 | }; | |
5ea943cf | 1581 | if (my $err = $@) { |
72bea995 | 1582 | Proxmox::UI::message("Warning: $err\n"); |
5ea943cf SI |
1583 | return; |
1584 | } | |
5bcefda0 | 1585 | $target_hds = [ $target_hd ]; |
c6ed3b24 | 1586 | } |
303dfb2c TL |
1587 | |
1588 | $step_number++; | |
1589 | create_country_view(); | |
c6ed3b24 | 1590 | }); |
89a12446 DM |
1591 | } |
1592 | ||
1593 | sub create_extract_view { | |
71590b6a | 1594 | cleanup_view(); |
89a12446 | 1595 | |
efc7a8be | 1596 | Proxmox::Install::display_info(); |
550958aa | 1597 | |
2266526b TL |
1598 | $gtk_state->{next_btn}->set_sensitive(0); |
1599 | $gtk_state->{prev_btn}->set_sensitive(0); | |
1600 | $gtk_state->{prev_btn}->hide(); | |
89a12446 | 1601 | |
d6efed19 | 1602 | my $vbox = Gtk3::Box->new('vertical', 0); |
2266526b | 1603 | $gtk_state->{inbox}->pack_start ($vbox, 1, 0, 0); |
d6efed19 | 1604 | my $hbox = Gtk3::Box->new('horizontal', 0); |
53986d77 | 1605 | $vbox->pack_start ($hbox, 0, 0, 10); |
89a12446 | 1606 | |
d6efed19 | 1607 | my $vbox2 = Gtk3::Box->new('vertical', 0); |
89a12446 DM |
1608 | $hbox->pack_start ($vbox2, 0, 0, 0); |
1609 | ||
2266526b | 1610 | $vbox2->pack_start($gtk_state->{progress_status}, 1, 1, 0); |
968fa90b | 1611 | |
2266526b TL |
1612 | $gtk_state->{progress_bar}->set_show_text(1); |
1613 | $gtk_state->{progress_bar}->set_size_request (600, -1); | |
89a12446 | 1614 | |
2266526b | 1615 | $vbox2->pack_start($gtk_state->{progress_bar}, 0, 0, 0); |
89a12446 | 1616 | |
2266526b | 1617 | $gtk_state->{inbox}->show_all(); |
89a12446 | 1618 | |
a677c773 | 1619 | eval { Proxmox::Install::extract_data() }; |
89a12446 DM |
1620 | my $err = $@; |
1621 | ||
2266526b | 1622 | $gtk_state->{next_btn}->set_sensitive(1); |
89a12446 | 1623 | |
fd09e893 | 1624 | set_next("_Reboot", sub { app_quit(0); } ); |
89a12446 | 1625 | |
0a3ac982 | 1626 | my $autoreboot = Proxmox::Install::Config::get_autoreboot(); |
0903eb5c | 1627 | my $success_transform = sub { |
84f90cbb | 1628 | my ($raw_html, $iso_env) = @_; |
0903eb5c | 1629 | |
7f3941d1 TL |
1630 | my $ip_addr = Proxmox::Install::Config::get_ip_addr(); |
1631 | my $ip_version = Proxmox::Install::Config::get_ip_version(); | |
1632 | ||
1633 | my $addr = $ip_version == 6 ? "[${ip_addr}]" : "$ip_addr"; | |
0903eb5c | 1634 | $raw_html =~ s/__IPADDR__/$addr/g; |
84f90cbb | 1635 | $raw_html =~ s/__PORT__/$iso_env->{cfg}->{port}/g; |
0903eb5c | 1636 | |
0a3ac982 | 1637 | my $autoreboot_msg = $autoreboot ? "Automatic reboot scheduled in $autoreboot_seconds seconds." : ''; |
0903eb5c TL |
1638 | $raw_html =~ s/__AUTOREBOOT_MSG__/$autoreboot_msg/; |
1639 | ||
1640 | return $raw_html; | |
1641 | }; | |
1642 | ||
296cf41f | 1643 | if ($err) { |
693c5d4b TL |
1644 | Proxmox::UI::display_html("fail.htm"); |
1645 | # suppress "empty" error as we got some case where the user choose to abort on a prompt, | |
1646 | # there it doesn't make sense to show them an error again, they "caused" it after all. | |
1647 | Proxmox::UI::error($err) if $err ne "\n"; | |
296cf41f | 1648 | } else { |
201a5120 | 1649 | cleanup_view(); |
efc7a8be | 1650 | Proxmox::UI::display_html("success.htm", $success_transform); |
dfc02f3c | 1651 | |
0a3ac982 | 1652 | if ($autoreboot) { |
dfc02f3c TL |
1653 | Glib::Timeout->add(1000, sub { |
1654 | if ($autoreboot_seconds > 0) { | |
1655 | $autoreboot_seconds--; | |
efc7a8be | 1656 | Proxmox::UI::display_html("success.htm", $success_transform); |
dfc02f3c | 1657 | } else { |
fd09e893 | 1658 | app_quit(0); |
dfc02f3c TL |
1659 | } |
1660 | }); | |
1661 | } | |
296cf41f | 1662 | } |
89a12446 DM |
1663 | } |
1664 | ||
89a12446 DM |
1665 | sub create_intro_view { |
1666 | ||
2266526b | 1667 | $gtk_state->{prev_btn}->set_sensitive(0); |
201a5120 OB |
1668 | |
1669 | cleanup_view(); | |
89a12446 | 1670 | |
b91f9cad | 1671 | if (int($run_env->{total_memory}) < 1024) { |
72bea995 | 1672 | Proxmox::UI::error("Less than 1 GiB of usable memory detected, installation will probably fail.\n\n". |
84f90cbb | 1673 | "See 'System Requirements' in the $iso_env->{cfg}->{fullname} documentation."); |
2b85ee1b OB |
1674 | } |
1675 | ||
84f90cbb | 1676 | if ($iso_env->{product} eq 'pve') { |
a28c08e9 | 1677 | my $cpuinfo = eval { file_read_all('/proc/cpuinfo') }; |
468900c7 | 1678 | if (!$cpuinfo || $cpuinfo !~ /^flags\s*:.*(vmx|svm)/m) { |
72bea995 | 1679 | Proxmox::UI::error( |
468900c7 TL |
1680 | "No support for hardware-accelerated KVM virtualization detected.\n\n" |
1681 | ."Check BIOS settings for Intel VT / AMD-V / SVM." | |
1682 | ); | |
1683 | } | |
bdeca872 | 1684 | } |
7fff0d85 | 1685 | |
efc7a8be | 1686 | Proxmox::UI::display_html('license.htm', sub { |
84f90cbb | 1687 | my ($raw_html, $iso_env) = @_; |
0903eb5c | 1688 | |
a677c773 | 1689 | my $proxmox_cddir = $iso_env->{locations}->{iso}; |
0903eb5c TL |
1690 | my $license = eval { decode('utf8', file_read_all("${proxmox_cddir}/EULA")) }; |
1691 | if (my $err = $@) { | |
1692 | die $err if !is_test_mode(); | |
1693 | $license = "TESTMODE: Ignore non existent EULA...\n"; | |
1694 | } | |
1695 | my $title = "END USER LICENSE AGREEMENT (EULA)"; | |
1696 | $raw_html =~ s/__LICENSE__/$license/; | |
1697 | $raw_html =~ s/__LICENSE_TITLE__/$title/; | |
1698 | ||
1699 | return $raw_html; | |
1700 | }); | |
89a12446 | 1701 | |
201a5120 | 1702 | $step_number++; |
71590b6a | 1703 | set_next("I a_gree", \&create_hdsel_view); |
89a12446 DM |
1704 | } |
1705 | ||
0387544f TL |
1706 | Gtk3::init(); |
1707 | ||
89a12446 DM |
1708 | create_main_window (); |
1709 | ||
ff2ce71c FG |
1710 | my $initial_error = 0; |
1711 | ||
40fbf8e6 TL |
1712 | { |
1713 | my $cached_disks = get_cached_disks(); | |
1714 | if (!defined($cached_disks) || (scalar (@$cached_disks) <= 0)) { | |
5b43e82d | 1715 | print STDERR "no harddisks found\n"; |
40fbf8e6 | 1716 | $initial_error = 1; |
efc7a8be | 1717 | Proxmox::UI::display_html("nohds.htm"); |
fd09e893 | 1718 | set_next("Reboot", sub { app_quit(0); } ); |
40fbf8e6 TL |
1719 | } else { |
1720 | foreach my $hd (@$cached_disks) { | |
1721 | my ($disk, $devname) = @$hd; | |
1722 | next if $devname =~ m|^/dev/md\d+$|; | |
5b43e82d | 1723 | print STDERR "found Disk$disk N:$devname\n"; |
40fbf8e6 | 1724 | } |
89a12446 | 1725 | } |
89a12446 DM |
1726 | } |
1727 | ||
fe06d7e9 | 1728 | if (!$initial_error && (scalar keys $run_env->{ipconf}->{ifaces}->%* == 0)) { |
5b43e82d | 1729 | print STDERR "no network interfaces found\n"; |
72836708 | 1730 | $initial_error = 1; |
efc7a8be | 1731 | Proxmox::UI::display_html("nonics.htm"); |
fd09e893 | 1732 | set_next("Reboot", sub { app_quit(0); } ); |
72836708 FG |
1733 | } |
1734 | ||
ff2ce71c FG |
1735 | create_intro_view () if !$initial_error; |
1736 | ||
7becc472 | 1737 | Gtk3->main; |
89a12446 | 1738 | |
fd09e893 | 1739 | app_quit(0); |