]> git.proxmox.com Git - pve-installer.git/blobdiff - proxinstall
keep mtab symlink
[pve-installer.git] / proxinstall
index 4a1f151621dc54fdda5c7118ad31ca588f2dd17d..c3acc346cf89ba04fcf5b362efb4c25d0c6e0b5c 100755 (executable)
@@ -1,5 +1,8 @@
 #!/usr/bin/perl -w
 
+$ENV{DEBIAN_FRONTEND} = 'noninteractive';
+$ENV{LC_ALL} = 'C';
+
 use strict;
 use Getopt::Long;
 use IPC::Open3;
@@ -7,18 +10,22 @@ use IO::File;
 use IO::Dir;
 use IO::Select;
 use Cwd 'abs_path';
-use Gtk2 '-init';
-use Gtk2::Html2;
-use Gtk2::Gdk::Keysyms;
+use Gtk3 '-init';
+use Gtk3::WebKit;
 use Encode;
+use Data::Dumper;
 
-my $release = '2.0';
+my $release = '3.0';
 
 my $kapi = `uname -r`;
 chomp $kapi;
 
 my $opt_testmode;
 
+if (!$ENV{G_SLICE} ||  $ENV{G_SLICE} ne "always-malloc") {
+    die "do not use slice allocator (run with 'G_SLICE=always-malloc ./proxinstall ...')\n";
+}
+
 if (!GetOptions ('testmode=s' => \$opt_testmode)) {
     die "usage error\n";
     exit (-1);
@@ -26,12 +33,10 @@ if (!GetOptions ('testmode=s' => \$opt_testmode)) {
 
 my $logfd = IO::File->new (">/tmp/install.log");
 
-my $proxmox_dir = $opt_testmode ? "." : "/var/lib/pve-installer";
+my $proxmox_dir = $opt_testmode ? Cwd::cwd() : "/var/lib/pve-installer";
 
-$ENV{DEBIAN_FRONTEND} = 'noninteractive';
-$ENV{LC_ALL} = 'C';
 
-my ($window, $cmdbox, $inbox, $document, $htmlview);
+my ($window, $cmdbox, $inbox, $htmlview);
 my ($next, $next_fctn, $target_hd, $master_hd);
 my ($progress, $progress_status);
 my ($ipaddress, $ip_1, $ip_2, $ip_3, $ip_4);
@@ -68,19 +73,19 @@ append_dot_mydomain = no
 alias_maps = hash:/etc/aliases
 alias_database = hash:/etc/aliases
 mydestination = \$myhostname, localhost.\$mydomain, localhost
-relayhost = 
+relayhost =
 mynetworks = 127.0.0.0/8
 inet_interfaces = loopback-only
 recipient_delimiter = +
 
 _EOD
 
-sub syscmd { 
+sub syscmd {
     my ($cmd) = @_;
 
     return run_command ($cmd, undef, undef, 1);
 }
+
 sub run_command {
     my ($cmd, $func, $input, $noout) = @_;
 
@@ -111,8 +116,8 @@ sub run_command {
 
     # catch exec errors
     if ($orig_pid != $$) {
-       POSIX::_exit (1); 
-       kill ('KILL', $$); 
+       POSIX::_exit (1);
+       kill ('KILL', $$);
     }
 
     die $err if $err;
@@ -129,7 +134,7 @@ sub run_command {
     while ($select->count) {
        my @handles = $select->can_read (0.2);
 
-       Gtk2->main_iteration while Gtk2->events_pending;
+       Gtk3->main_iteration while Gtk3->events_pending;
 
        next if !scalar (@handles); # timeout
 
@@ -168,7 +173,7 @@ sub run_command {
 
     my $ec = ($? >> 8);
 
-    if ($ec) {  
+    if ($ec) {
        die "command '$cmd' failed with exit code $ec";
     }
 
@@ -179,7 +184,7 @@ sub detect_country {
 
     print "trying to detect country...\n";
     open (TMP, "traceroute -N 1 -q 1 -n www.debian.org|");
-    
+
     my $country;
 
     my $previous_alarm = alarm (10);
@@ -224,7 +229,7 @@ sub get_memtotal {
     while (my $line = <MEMINFO>) {
        if ($line =~ m/^MemTotal:\s+(\d+)\s*kB/i) {
            $res = int ($1 / 1024);
-       } 
+       }
     }
 
     close (MEMINFO);
@@ -291,7 +296,7 @@ sub hd_list {
 
        my $dev = `cat '$bd/dev'`;
        chomp $dev;
-       
+
        next if !$dev;
 
        my $info = `udevadm info --path $bd --query all`;
@@ -303,7 +308,7 @@ sub hd_list {
 
        my ($name) = $info =~ m/^N: (\S+)$/m;
 
-       if ($name) { 
+       if ($name) {
            my $real_name = "/dev/$name";
 
            my $size = `cat '$bd/size'`;
@@ -326,7 +331,7 @@ sub hd_list {
 }
 
 sub read_cmap {
-    my $countryfn = $opt_testmode ? "/usr/share/pve-manager/country.dat" : 
+    my $countryfn = $opt_testmode ? "/usr/share/pve-manager/country.dat" :
        "/proxmox/country.dat";
     open (TMP, "<$countryfn") || die "unable to open '$countryfn' - $!\n";
     my $line;
@@ -400,7 +405,7 @@ sub hd_size {
 
 # find the master boot disk - return the first found scsi/ide disk
 sub find_master {
-    my ($target_hd) = @_; 
+    my ($target_hd) = @_;
 
     foreach my $hd (sort { ${$a}[1] cmp ${$b}[1] } @$hds) {
        my ($disk, $devname) = @$hd;
@@ -474,7 +479,7 @@ sub update_progress {
     $progress->set_text (sprintf ("%d%%", int ($res*100)));
     $progress_status->set_text ($text) if defined ($text);
 
-    Gtk2->main_iteration while Gtk2->events_pending;
+    Gtk3->main_iteration while Gtk3->events_pending;
 }
 
 sub create_filesystem {
@@ -500,7 +505,7 @@ sub create_filesystem {
            update_progress (0.95, $rs, $re);
        } elsif ($line =~ m/Writing superblocks and filesystem.*done/) {
            update_progress (1, $rs, $re);
-       } 
+       }
     });
 }
 
@@ -509,8 +514,8 @@ sub debconfig_set {
 
     my $cfgfile = "/tmp/debconf.txt";
     write_config ($dcdata, "$targetdir/$cfgfile");
-    syscmd ("chroot $targetdir debconf-set-selections $cfgfile"); 
-    unlink "$targetdir/$cfgfile";    
+    syscmd ("chroot $targetdir debconf-set-selections $cfgfile");
+    unlink "$targetdir/$cfgfile";
 }
 
 sub diversion_add {
@@ -521,7 +526,7 @@ sub diversion_add {
            die "unable to exec dpkg-divert\n";
 
     syscmd ("ln -sf ${new_cmd} $targetdir/$cmd") == 0 ||
-       die "unable to link diversion to ${new_cmd}\n";  
+       die "unable to link diversion to ${new_cmd}\n";
 }
 
 sub diversion_remove {
@@ -529,7 +534,7 @@ sub diversion_remove {
 
     syscmd ("mv $targetdir/${cmd}.distrib $targetdir/${cmd};") == 0 ||
        die "unable to remove $cmd diversion\n";
-           
+
     syscmd ("chroot $targetdir dpkg-divert --remove $cmd") == 0 ||
        die "unable to remove $cmd diversion\n";
 }
@@ -560,6 +565,16 @@ sub extract_data {
                $ptype = 'gpt';
            }
 
+           if ($cmdline =~ m/hdsize=(\d+)[\s\n]/i) {
+               # max hdsize passed on cmdline (GB)
+               my $maxhdsize=$1*1024*1024;
+
+               # use $maxhdsize if specified size is lower than hdsize
+               if ($maxhdsize < $hdsize) {
+                   $hdsize = $maxhdsize;
+               }
+           }
+
            my $bootsize_mb = 512;
            my $bootsize = $bootsize_mb * 1024;
            my $hdsize_mb = $hdsize/1024;
@@ -625,7 +640,21 @@ sub extract_data {
            }
 
            my $rootsize = (($hdgb > ($maxroot*4)) ? $maxroot : $hdgb/4)*1024*1024;
-           my $rest = int($hdsize) - $bootsize - $swapsize - $space - $rootsize; # in KB
+           my $rest = int($hdsize) - $bootsize - $swapsize - $rootsize; # in KB
+
+           my $minfree;
+            if ($cmdline =~ m/minfree=(\d+)[\s\n]/i) {
+               $minfree = (($1*1024*1024) >= $rest ) ? $space : $1*1024*1024 ;
+            } else {
+               $minfree = $space;
+            }
+
+           $rest = $rest - $minfree;
+
+            if ($cmdline =~ m/maxvz=(\d+)[\s\n]/i) {
+               $rest = (($1*1024*1024) <= $rest) ? $1*1024*1024 : $rest;
+           }
+
            syscmd ("/sbin/lvcreate -L${swapsize}K -nswap pve") == 0 ||
                die "unable to create swap volume";
 
@@ -691,7 +720,7 @@ sub extract_data {
 
        my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size) = stat ($tgzfile);
        $ino || die "unable to open file '$tgzfile' - $!\n";
-       
+
        my $files;
        if ($opt_testmode) {
            $files = `cat /pve/$release/install/pve-base.cnt`;
@@ -725,9 +754,9 @@ sub extract_data {
 
        # configure hosts
 
-       my $hosts = 
+       my $hosts =
            "127.0.0.1 localhost.localdomain localhost\n" .
-           "$ipaddress $hostname.$domain $hostname pvelocalhost\n\n" . 
+           "$ipaddress $hostname.$domain $hostname pvelocalhost\n\n" .
            "# The following lines are desirable for IPv6 capable hosts\n\n" .
            "::1     ip6-localhost ip6-loopback\n" .
            "fe00::0 ip6-localnet\n" .
@@ -736,15 +765,15 @@ sub extract_data {
            "ff02::2 ip6-allrouters\n" .
            "ff02::3 ip6-allhosts\n";
 
-       write_config ($hosts, "$targetdir/etc/hosts"); 
+       write_config ($hosts, "$targetdir/etc/hosts");
 
-       write_config ("$hostname\n", "$targetdir/etc/hostname"); 
+       write_config ("$hostname\n", "$targetdir/etc/hostname");
 
        syscmd ("/bin/hostname $hostname") if !$opt_testmode;
 
        # configure interfaces
 
-       my $ifaces = 
+       my $ifaces =
            "auto lo\niface lo inet loopback\n\n" .
            "auto vmbr0\niface vmbr0 inet static\n" .
            "\taddress $ipaddress\n" .
@@ -769,7 +798,7 @@ sub extract_data {
 
        # configure fstab
 
-       my $fstab = 
+       my $fstab =
            "# <file system> <mount point> <type> <options> <dump> <pass>\n" .
            "$rootdev / $filesys errors=remount-ro 0 1\n";
 
@@ -783,12 +812,12 @@ sub extract_data {
 
        write_config ($fstab, "$targetdir/etc/fstab");
        write_config ("", "$targetdir/etc/mtab");
-       
+
        syscmd ("cp ${proxmox_dir}/policy-disable-rc.d " .
-               "$targetdir/usr/sbin/policy-rc.d") == 0 || 
+               "$targetdir/usr/sbin/policy-rc.d") == 0 ||
                die "unable to copy policy-rc.d\n";
        syscmd ("cp ${proxmox_dir}/fake-start-stop-daemon " .
-               "$targetdir/sbin/") == 0 || 
+               "$targetdir/sbin/") == 0 ||
                die "unable to copy start-stop-daemon\n";
 
        diversion_add ($targetdir, "/sbin/start-stop-daemon", "/sbin/fake-start-stop-daemon");
@@ -820,7 +849,7 @@ _EOD
            syscmd ("cp $path $targetdir/tmp/$deb") == 0 ||
                die "installation of package $deb failed\n";
            syscmd ("chroot $targetdir dpkg --force-depends --no-triggers --unpack /tmp/$deb") == 0 ||
-               die "installation of package $deb failed\n";    
+               die "installation of package $deb failed\n";
            update_progress ((++$count)/$pkg_count, 0.5, 0.75);
        }
 
@@ -835,8 +864,8 @@ _EOD
                                 "configuring $1");
            }
        });
-           
-       debconfig_set ($targetdir, <<_EOD); 
+
+       debconfig_set ($targetdir, <<_EOD);
 postfix postfix/main_mailer_type select No configuration
 _EOD
 
@@ -854,7 +883,7 @@ _EOD
        # disable bacula-fd
        syscmd ("touch '$targetdir/etc/bacula/do_not_run'");
 
-       # set timezone  
+       # set timezone
        unlink ("$targetdir/etc/localtime");
        symlink ("/usr/share/zoneinfo/$timezone", "$targetdir/etc/localtime");
        write_config ("$timezone\n", "$targetdir/etc/timezone");
@@ -870,7 +899,7 @@ _EOD
        # set apt mirror
        if (my $mirror = $cmap->{country}->{$country}->{mirror}) {
            my $fn = "$targetdir/etc/apt/sources.list";
-           syscmd ("sed -i 's/ftp\\.debian\\.org/$mirror/' '$fn'"); 
+           syscmd ("sed -i 's/ftp\\.debian\\.org/$mirror/' '$fn'");
        }
 
        # create extended_states for apt (avoid cron job warning if that
@@ -910,20 +939,17 @@ _EOD
        }
 
 
-       # cleanup 
+       # cleanup
 
-       # hack: remove dead.letter from sshd installation 
+       # hack: remove dead.letter from sshd installation
        syscmd ("rm -rf $targetdir/dead.letter");
 
-       unlink ("$targetdir/etc/mtab");
-       syscmd ("touch $targetdir/etc/mtab");
-
        unlink "$targetdir/usr/sbin/policy-rc.d";
 
        diversion_remove ($targetdir, "/sbin/start-stop-daemon");
 
        # set root password
-       my $octets = encode("utf-8", $password);        
+       my $octets = encode("utf-8", $password);
        run_command ("chroot $targetdir /usr/sbin/chpasswd", undef,
                     "root:$octets\n");
 
@@ -934,13 +960,13 @@ _EOD
 
        # write vnc keymap to datacenter.cfg
        my $vnckmap = $cmap->{kmap}->{$keymap}->{kvm} || 'en-us';
-       write_config ("keyboard: $vnckmap\n", 
+       write_config ("keyboard: $vnckmap\n",
                      "$tmpdir/datacenter.cfg");
 
        # save admin email
-       write_config ("user:root\@pam:1:0:::${mailto}::\n", 
+       write_config ("user:root\@pam:1:0:::${mailto}::\n",
                      "$tmpdir/user.cfg");
-       
+
        run_command("chroot $targetdir /usr/bin/create_pmxcfs_db /tmp/pve /var/lib/pve-cluster/config.db");
 
        syscmd ("rm -rf $tmpdir");
@@ -969,14 +995,24 @@ _EOD
 sub display_html {
     my ($filename) = @_;
 
+    my $url = "file://${proxmox_dir}/html/$filename";
+    $htmlview->load_uri($url);
+}
+
+sub display_html_old {
+    my ($filename) = @_;
+
     $htmlview->set_document(undef);
+
+    my $document;
+
     $document->clear;
     $htmlview->set_document($document);
 
     $document->open_stream ("text/html");
 
     my $fn = "${proxmox_dir}/html/$filename";
-    open (HTML, $fn) || 
+    open (HTML, $fn) ||
        die "unable to open file '$fn' - $!\n";
     while (<HTML>) { $document->write_stream ($_); }
     close (HTML);
@@ -990,13 +1026,13 @@ sub set_next {
     $next_fctn = $fctn;
     $text = "_Next" if !$text;
     $next->set_label ($text);
-    
+
     $next->grab_focus ();
 }
 
 sub url_requested {
     my ($doc, $url, $stream) = @_;
-       
+
     $stream->set_cancel_func (sub {}); # hack: avoid warning
 
     my $path = "${proxmox_dir}/html/$url";
@@ -1006,8 +1042,8 @@ sub url_requested {
            die "unable to open file '$path' - $! ";
        my $buf;
        while (my $i = read (HTMLTMP, $buf, 4096)) {
-           $stream->write ($buf);                      
-           Gtk2->main_iteration while Gtk2->events_pending;
+           $stream->write ($buf);
+           Gtk3->main_iteration while Gtk3->events_pending;
        }
        close (HTMLTMP);
     }
@@ -1017,63 +1053,55 @@ sub url_requested {
 
 sub create_main_window {
 
-    $window = Gtk2::Window->new ();
+    $window = Gtk3::Window->new ();
     $window->set_default_size (1024, 768);
     $window->set_decorated (0) if !$opt_testmode;
 
-    my $vbox = Gtk2::VBox->new (0, 0);
+    my $vbox = Gtk3::VBox->new (0, 0);
 
-    my $image = Gtk2::Image->new_from_file  ("${proxmox_dir}/proxlogo.xpm");
+    my $image = Gtk3::Image->new_from_file  ("${proxmox_dir}/proxlogo.xpm");
     $vbox->pack_start ($image, 0, 0, 0);
 
-    my $hbox = Gtk2::HBox->new (0, 0);
+    my $hbox = Gtk3::HBox->new (0, 0);
     $vbox->pack_start ($hbox, 1, 1, 0);
 
   my $f1 = Gtk2::Frame->new ();
   $f1->set_shadow_type ('in');
   $hbox->pack_start ($f1, 1, 1, 0);
#  my $f1 = Gtk3::Frame->new ('test');
#  $f1->set_shadow_type ('none');
#  $hbox->pack_start ($f1, 1, 1, 0);
 
-    my $sep1 = Gtk2::HSeparator->new;
+    my $sep1 = Gtk3::HSeparator->new;
     $vbox->pack_start ($sep1, 0, 0, 0);
 
-    $cmdbox = Gtk2::HBox->new ();
+    $cmdbox = Gtk3::HBox->new ();
     $vbox->pack_start ($cmdbox, 0, 0, 10);
 
-    $next = Gtk2::Button->new ('_Next');
+    $next = Gtk3::Button->new ('_Next');
     $next->signal_connect (clicked => sub { &$next_fctn (); });
     $cmdbox->pack_end ($next, 0, 0, 10);
-    my $abort = Gtk2::Button->new ('_Abort');
-    $abort->can_focus (0);
+    my $abort = Gtk3::Button->new ('_Abort');
+    $abort->set_can_focus (0);
     $cmdbox->pack_start ($abort, 0, 0, 10);
     $abort->signal_connect (clicked => sub { exit (-1); });
 
-    my $vbox2 = Gtk2::VBox->new (0, 0);
-    $f1->add ($vbox2);
-
-    $htmlview = new Gtk2::Html2::View;
-    # hack: create a separate style - else Gtk2::Html2 modifies
-    # main window style
-    my $rcs1 = Gtk2::RcStyle->new;
-    $htmlview->modify_style ($rcs1);
-
-    $document = new Gtk2::Html2::Document;
-    $document->signal_connect (request_url => \&url_requested);
-
-    $document->clear;
-    $htmlview->set_document ($document);
+    my $vbox2 = Gtk3::VBox->new (0, 0);
+    $hbox->add ($vbox2);
 
-    my $hbox2 = Gtk2::HBox->new (0, 0);
-    $hbox2->pack_start ($htmlview, 1, 1, 0);
+    $htmlview = Gtk3::WebKit::WebView->new();
+    my $scrolls = Gtk3::ScrolledWindow->new();
+    $scrolls->add($htmlview);
+   
+    my $hbox2 = Gtk3::HBox->new (0, 0);
+    $hbox2->pack_start ($scrolls, 1, 1, 0);
 
     $vbox2->pack_start ($hbox2, 1, 1, 0);
 
-    my $vbox3 = Gtk2::VBox->new (0, 0);
+    my $vbox3 = Gtk3::VBox->new (0, 0);
     $vbox2->pack_start ($vbox3, 0, 0, 0);
 
-    my $sep2 = Gtk2::HSeparator->new;
+    my $sep2 = Gtk3::HSeparator->new;
     $vbox3->pack_start ($sep2, 0, 0, 0);
 
-    $inbox = Gtk2::HBox->new (0, 0);
+    $inbox = Gtk3::HBox->new (0, 0);
     $vbox3->pack_start ($inbox, 0, 0, 0);
 
     $window->add ($vbox);
@@ -1084,7 +1112,7 @@ sub create_main_window {
 
 sub cleanup_view {
     my $list = $inbox->get_children;
-    foreach my $c ($list) {
+    foreach my $c (@$list) {
        next if !defined ($c);
        $inbox->remove ($c);
     }
@@ -1093,21 +1121,22 @@ sub cleanup_view {
 sub check_num {
     my ($entry, $event) = @_;
 
-    my $val = $event->keyval;
+
+    my $val = $event->get_keyval;
 
     if ($val == ord '.') {
-       $entry->parent->child_focus ('right');
+       $entry->get_parent->child_focus ('right');
        return 1;
     }
 
-    if ($val == $Gtk2::Gdk::Keysyms{ISO_Left_Tab} || 
-       $val == $Gtk2::Gdk::Keysyms{Shift_L} || 
-       $val == $Gtk2::Gdk::Keysyms{Tab} ||
-       $val == $Gtk2::Gdk::Keysyms{BackSpace} ||
-       $val == $Gtk2::Gdk::Keysyms{Delete} ||
+    if ($val == Gtk3::Gdk::KEY_ISO_Left_Tab ||
+       $val == Gtk3::Gdk::KEY_Shift_L ||
+       $val == Gtk3::Gdk::KEY_Tab ||
+       $val == Gtk3::Gdk::KEY_BackSpace ||
+       $val == Gtk3::Gdk::KEY_Delete ||
        ($val >= ord '0' && $val <= ord '9') ||
-       ($val >= $Gtk2::Gdk::Keysyms{KP_0} && 
-        $val <= $Gtk2::Gdk::Keysyms{KP_9})) {
+       ($val >= Gtk3::Gdk::KEY_KP_0 &&
+        $val <= Gtk3::Gdk::KEY_KP_9)) {
        return undef;
     }
 
@@ -1129,13 +1158,13 @@ sub check_range {
 sub creat_text_input {
     my ($default, $text) = @_;
 
-    my $hbox = Gtk2::HBox->new (0, 0);
+    my $hbox = Gtk3::HBox->new (0, 0);
 
-    my $label = Gtk2::Label->new ($text);
+    my $label = Gtk3::Label->new ($text);
     $label->set_size_request (150, -1);
     $label->set_alignment (1, 0.5);
     $hbox->pack_start ($label, 0, 0, 10);
-    my $e1 = Gtk2::Entry->new ();
+    my $e1 = Gtk3::Entry->new ();
     $e1->set_width_chars (30);
     $hbox->pack_start ($e1, 0, 0, 0);
     $e1->set_text ($default);
@@ -1149,14 +1178,15 @@ sub creat_ip_input {
     my (@ips) = split /\./, $init;
     my (@defs) = split /\./, $default;
 
-    my $hbox = Gtk2::HBox->new (0, 0);
+    my $hbox = Gtk3::HBox->new (0, 0);
 
-    my $label = Gtk2::Label->new ($text);
+    my $label = Gtk3::Label->new ($text);
     $label->set_size_request (150, -1);
     $label->set_alignment (1, 0.5);
     $hbox->pack_start ($label, 0, 0, 10);
-    
-    my $e1 = Gtk2::Entry->new_with_max_length  (3);
+
+    my $e1 = Gtk3::Entry->new();
+    $e1->set_max_length(3);
     $e1->{default} = $defs[0];
     $hbox->pack_start ($e1, 0, 0, 0);
     $e1->set_width_chars (3);
@@ -1164,10 +1194,11 @@ sub creat_ip_input {
     $e1->signal_connect (key_press_event => \&check_num);
     $e1->signal_connect (focus_out_event => \&check_range);
 
-    my $l1 = Gtk2::Label->new (".");
+    my $l1 = Gtk3::Label->new (".");
     $hbox->pack_start ($l1, 0, 0, 2);
 
-    my $e2 = Gtk2::Entry->new_with_max_length  (3);
+    my $e2 = Gtk3::Entry->new();
+    $e2->set_max_length(3);
     $e2->{default} = $defs[1];
     $hbox->pack_start ($e2, 0, 0, 0);
     $e2->set_width_chars (3);
@@ -1175,10 +1206,11 @@ sub creat_ip_input {
     $e2->signal_connect (key_press_event => \&check_num);
     $e2->signal_connect (focus_out_event => \&check_range);
 
-    my $l2 = Gtk2::Label->new (".");
+    my $l2 = Gtk3::Label->new (".");
     $hbox->pack_start ($l2, 0, 0, 2);
 
-    my $e3 = Gtk2::Entry->new_with_max_length  (3);
+    my $e3 = Gtk3::Entry->new();
+    $e3->set_max_length(3);
     $e3->{default} = $defs[2];
     $hbox->pack_start ($e3, 0, 0, 0);
     $e3->set_width_chars (3);
@@ -1186,10 +1218,11 @@ sub creat_ip_input {
     $e3->signal_connect (key_press_event => \&check_num);
     $e3->signal_connect (focus_out_event => \&check_range);
 
-    my $l3 = Gtk2::Label->new (".");
+    my $l3 = Gtk3::Label->new (".");
     $hbox->pack_start ($l3, 0, 0, 2);
 
-    my $e4 = Gtk2::Entry->new_with_max_length  (3);
+    my $e4 = Gtk3::Entry->new();
+    $e4->set_max_length(3);
     $e4->{default} = $defs[3];
     $hbox->pack_start ($e4, 0, 0, 0);
     $e4->set_width_chars (3);
@@ -1224,7 +1257,7 @@ sub get_ip_config {
 sub display_message {
     my ($msg) = @_;
 
-    my $dialog = Gtk2::MessageDialog->new ($window, 'modal', 
+    my $dialog = Gtk3::MessageDialog->new ($window, 'modal',
                                           'info', 'ok', $msg);
     $dialog->run();
     $dialog->destroy();
@@ -1233,7 +1266,7 @@ sub display_message {
 sub display_error {
     my ($msg) = @_;
 
-    my $dialog = Gtk2::MessageDialog->new ($window, 'modal', 
+    my $dialog = Gtk3::MessageDialog->new ($window, 'modal',
                                           'error', 'ok', $msg);
     $dialog->run();
     $dialog->destroy();
@@ -1244,55 +1277,55 @@ sub create_ipconf_view {
     cleanup_view ();
     display_html ("ipconf.htm");
 
-    my $vbox =  Gtk2::VBox->new (0, 0);
+    my $vbox =  Gtk3::VBox->new (0, 0);
     $inbox->pack_start ($vbox, 1, 0, 0);
-    my $hbox =  Gtk2::HBox->new (0, 0);
-    $vbox->pack_start ($hbox, 0, 0, 30);
-    my $vbox2 =  Gtk2::VBox->new (0, 0);
+    my $hbox =  Gtk3::HBox->new (0, 0);
+    $vbox->pack_start ($hbox, 0, 0, 10);
+    my $vbox2 =  Gtk3::VBox->new (0, 0);
     $hbox->add ($vbox2);
 
     my $addr = $ipconf->{addr} || '192.168.100.2';
     my $mask = $ipconf->{mask} || '255.255.255.0';
-    my ($hostbox, $hostentry) = 
+
+    my ($hostbox, $hostentry) =
        creat_text_input ('proxmox.domain.tld', 'Hostname (FQDN):');
     $vbox2->pack_start ($hostbox, 0, 0, 2);
 
     my $ipbox;
-    ($ipbox, $ip_1, $ip_2, $ip_3, $ip_4) = 
+    ($ipbox, $ip_1, $ip_2, $ip_3, $ip_4) =
        creat_ip_input ($addr, '0.0.0.0', 'IP Address:');
     $vbox2->pack_start ($ipbox, 0, 0, 2);
 
     my $maskbox;
-    ($maskbox, $mask_1, $mask_2, $mask_3, $mask_4) = 
+    ($maskbox, $mask_1, $mask_2, $mask_3, $mask_4) =
        creat_ip_input ($mask, '255.255.255.0', 'Netmask:');
     $vbox2->pack_start ($maskbox, 0, 0, 2);
 
     $gateway = $ipconf->{gateway} || '192.168.100.1';
 
     my $gwbox;
-    ($gwbox, $gw_1, $gw_2, $gw_3, $gw_4) = 
+    ($gwbox, $gw_1, $gw_2, $gw_3, $gw_4) =
        creat_ip_input ($gateway, '0.0.0.0', 'Gateway:');
 
-    $vbox2->pack_start ($gwbox, 0, 0, 15);
+    $vbox2->pack_start ($gwbox, 0, 0, 2);
 
     $dnsserver = $ipconf->{dnsserver} || $gateway;
 
     my $dnsbox;
-    ($dnsbox, $dns_1, $dns_2, $dns_3, $dns_4) = 
+    ($dnsbox, $dns_1, $dns_2, $dns_3, $dns_4) =
        creat_ip_input ($dnsserver, '0.0.0.0', 'DNS Server:');
 
     $vbox2->pack_start ($dnsbox, 0, 0, 0);
 
     $inbox->show_all;
-    set_next (undef, sub { 
+    set_next (undef, sub {
        my $text = $hostentry->get_text();
-       
+
        $text =~ s/^\s+//;
        $text =~ s/\s+$//;
 
        my $namere = "([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)";
+
        if ($text && $text =~ m/^(${namere}\.)*${namere}$/ && $text !~ m/.domain.tld$/ &&
            $text =~ m/^([^\.]+)\.(\S+)$/) {
            $hostname = $1;
@@ -1356,7 +1389,7 @@ sub update_zonelist {
        $sel = $timezone; # used once to select default
     }
 
-    my $cb = $lastzonecb = Gtk2::ComboBox->new_text (); 
+    my $cb = $lastzonecb = Gtk3::ComboBoxText->new_with_entry();
     $cb->set_size_request (200, -1);
 
     $cb->signal_connect ('changed' => sub {
@@ -1387,37 +1420,37 @@ sub create_password_view {
 
     cleanup_view ();
 
-    my $vbox2 =  Gtk2::VBox->new (0, 0);
+    my $vbox2 =  Gtk3::VBox->new (0, 0);
     $inbox->pack_start ($vbox2, 1, 0, 0);
-    my $vbox =  Gtk2::VBox->new (0, 0);
-    $vbox2->pack_start ($vbox, 0, 0, 30);
+    my $vbox =  Gtk3::VBox->new (0, 0);
+    $vbox2->pack_start ($vbox, 0, 0, 10);
 
-    my $hbox1 = Gtk2::HBox->new (0, 0);
-    my $label = Gtk2::Label->new ("Password");
+    my $hbox1 = Gtk3::HBox->new (0, 0);
+    my $label = Gtk3::Label->new ("Password");
     $label->set_size_request (150, -1);
     $label->set_alignment (1, 0.5);
     $hbox1->pack_start ($label, 0, 0, 10);
-    my $pwe1 = Gtk2::Entry->new ();  
+    my $pwe1 = Gtk3::Entry->new ();
     $pwe1->set_visibility (0);
     $pwe1->set_size_request (200, -1);
     $hbox1->pack_start ($pwe1, 0, 0, 0);
 
-    my $hbox2 = Gtk2::HBox->new (0, 0);
-    $label = Gtk2::Label->new ("Confirm");
+    my $hbox2 = Gtk3::HBox->new (0, 0);
+    $label = Gtk3::Label->new ("Confirm");
     $label->set_size_request (150, -1);
     $label->set_alignment (1, 0.5);
     $hbox2->pack_start ($label, 0, 0, 10);
-    my $pwe2 = Gtk2::Entry->new ();  
+    my $pwe2 = Gtk3::Entry->new ();
     $pwe2->set_visibility (0);
     $pwe2->set_size_request (200, -1);
     $hbox2->pack_start ($pwe2, 0, 0, 0);
 
-    my $hbox3 = Gtk2::HBox->new (0, 0);
-    $label = Gtk2::Label->new ("E-Mail");
+    my $hbox3 = Gtk3::HBox->new (0, 0);
+    $label = Gtk3::Label->new ("E-Mail");
     $label->set_size_request (150, -1);
     $label->set_alignment (1, 0.5);
     $hbox3->pack_start ($label, 0, 0, 10);
-    my $eme = Gtk2::Entry->new ();  
+    my $eme = Gtk3::Entry->new ();
     $eme->set_size_request (200, -1);
     $hbox3->pack_start ($eme, 0, 0, 0);
 
@@ -1473,33 +1506,34 @@ sub create_country_view {
     my $countryhash = $cmap->{countryhash};
     my $ctr = $cmap->{country};
 
-    my $vbox2 =  Gtk2::VBox->new (0, 0);
+    my $vbox2 =  Gtk3::VBox->new (0, 0);
     $inbox->pack_start ($vbox2, 1, 0, 0);
-    my $vbox =  Gtk2::VBox->new (0, 0);
-    $vbox2->pack_start ($vbox, 0, 0, 30);
+    my $vbox =  Gtk3::VBox->new (0, 0);
+    $vbox2->pack_start ($vbox, 0, 0, 10);
 
-    my $w = Gtk2::Entry->new ();  
+    my $w = Gtk3::Entry->new ();
     $w->set_size_request (200, -1);
 
-    my $c = Gtk2::EntryCompletion->new ();  
+    my $c = Gtk3::EntryCompletion->new ();
     $c->set_text_column (0);
     $c->set_minimum_key_length(0);
     $c->set_popup_set_width (1);
+    $c->set_inline_completion (1);
 
-    my $hbox2 = Gtk2::HBox->new (0, 0);
-    my $label = Gtk2::Label->new ("Time zone");
+    my $hbox2 = Gtk3::HBox->new (0, 0);
+    my $label = Gtk3::Label->new ("Time zone");
     $label->set_size_request (150, -1);
     $label->set_alignment (1, 0.5);
     $hbox2->pack_start ($label, 0, 0, 10);
     update_zonelist ($hbox2);
 
-    my $hbox3 = Gtk2::HBox->new (0, 0);
-    $label = Gtk2::Label->new ("Keyboard Layout");
+    my $hbox3 = Gtk3::HBox->new (0, 0);
+    $label = Gtk3::Label->new ("Keyboard Layout");
     $label->set_size_request (150, -1);
     $label->set_alignment (1, 0.5);
     $hbox3->pack_start ($label, 0, 0, 10);
 
-    my $kmapcb = Gtk2::ComboBox->new_text (); 
+    my $kmapcb = Gtk3::ComboBoxText->new_with_entry ();
     $kmapcb->set_size_request (200, -1);
     foreach my $layout (sort keys %{$cmap->{kmaphash}}) {
        $kmapcb->append_text ($layout);
@@ -1533,46 +1567,60 @@ sub create_country_view {
        my ($entry, $event) = @_;
        my $text = $entry->get_text;
 
-       my $val = $event->keyval;
-       if ($val == $Gtk2::Gdk::Keysyms{Tab}) {
+       my $val = $event->get_keyval;
+
+       if ($val == Gtk3::Gdk::KEY_Tab) {
            my $cc = $countryhash->{lc($text)};
-           return undef if $cc;
+           
            my $found = 0;
            my $compl;
-           foreach my $cc (keys %$ctr) {
-               my $ct = $ctr->{$cc}->{name};
-               if ($ct =~ m/^\Q$text\E.*$/i) {
-                   $found++;
-                   $compl = $ct;
+
+           if ($cc) {
+               $found = 1;
+               $compl = $ctr->{$cc}->{name};
+           } else {
+               foreach my $cc (keys %$ctr) {
+                   my $ct = $ctr->{$cc}->{name};
+                   if ($ct =~ m/^\Q$text\E.*$/i) {
+                       $found++;
+                       $compl = $ct;
+                   }
+                   last if $found > 1;
                }
-               last if $found > 1;
            }
+
            if ($found == 1) {
-               $entry->set_text ($compl);
+               $entry->set_text($compl);
+               $c->complete();
                return undef;
            } else {
-               Gtk2::Gdk->beep();
+               #Gtk3::Gdk::beep();
+               print chr(7); # beep ?
            }
 
-           $w->insert_text('', -1); # popup selection
+           $c->complete();
+
+           my $buf = $w->get_buffer();
+           $buf->insert_text(-1, '', -1); # popup selection
+
            return 1;
        }
 
        return undef;
     });
-
-    my $ls = Gtk2::ListStore->new('Glib::String');
+    my $ls = Gtk3::ListStore->new('Glib::String');
     foreach my $cc (sort {$ctr->{$a}->{name} cmp $ctr->{$b}->{name} } keys %$ctr) {
        my $iter = $ls->append();
        $ls->set ($iter, 0, $ctr->{$cc}->{name});
     }
     $c->set_model ($ls);
 
-    $w->set_completion ($c);    
+    $w->set_completion ($c);
 
-    my $hbox =  Gtk2::HBox->new (0, 0);
+    my $hbox =  Gtk3::HBox->new (0, 0);
 
-    $label = Gtk2::Label->new ("Country");
+    $label = Gtk3::Label->new ("Country");
     $label->set_alignment (1, 0.5);
     $label->set_size_request (150, -1);
     $hbox->pack_start ($label, 0, 0, 10);
@@ -1610,11 +1658,11 @@ sub create_hdsel_view {
 
     cleanup_view ();
 
-    my $vbox =  Gtk2::VBox->new (0, 0);
+    my $vbox =  Gtk3::VBox->new (0, 0);
     $inbox->pack_start ($vbox, 1, 0, 0);
-    my $hbox =  Gtk2::HBox->new (0, 0);
-    $vbox->pack_start ($hbox, 0, 0, 30);
-       
+    my $hbox =  Gtk3::HBox->new (0, 0);
+    $vbox->pack_start ($hbox, 0, 0, 10);
+
     my ($disk, $devname, $size, $model) = @{@$hds[0]};
     $target_hd = $devname;
     $master_hd = find_master ($target_hd);
@@ -1622,21 +1670,23 @@ sub create_hdsel_view {
 
     if (scalar (@$hds) == 1) {
        my $devdesc = get_device_desc ($devname, $size, $model);
-       $label = Gtk2::Label->new ("Target Harddisk: $devdesc");
+       $label = Gtk3::Label->new ("Target Harddisk: $devdesc");
        $hbox->pack_start ($label, 0, 0, 0);
     } else {
-       $label = Gtk2::Label->new ("Target Harddisks: ");
+       $label = Gtk3::Label->new ("Target Harddisks: ");
        $hbox->pack_start ($label, 0, 0, 0);
 
-       my $combo = Gtk2::ComboBox->new_text ();
+       my $combo = Gtk3::ComboBoxText->new_with_entry();
+       my $e = $combo->get_child();
+       $e->set_width_chars(40);
 
        foreach my $hd (@$hds) {
            ($disk, $devname, $size, $model) = @$hd;
-           $combo->append_text (get_device_desc ($devname, $size, $model)); 
+           $combo->append_text (get_device_desc ($devname, $size, $model));
        }
 
-       $combo->set_active (0); 
-       $combo->signal_connect (changed => sub { 
+       $combo->set_active (0);
+       $combo->signal_connect (changed => sub {
            $a = shift->get_active;
            my ($disk, $devname) = @{@$hds[$a]};
            $target_hd = $devname;
@@ -1654,16 +1704,16 @@ sub create_hdsel_view {
 
 sub create_extract_view {
 
-    $ipaddress = $ip_1->get_text . "." . $ip_2->get_text . "." . 
+    $ipaddress = $ip_1->get_text . "." . $ip_2->get_text . "." .
        $ip_3->get_text . "." . $ip_4->get_text;
-    
-    $netmask = $mask_1->get_text . "." . $mask_2->get_text . "." . 
+
+    $netmask = $mask_1->get_text . "." . $mask_2->get_text . "." .
        $mask_3->get_text . "." . $mask_4->get_text;
 
-    $gateway = $gw_1->get_text . "." . $gw_2->get_text . "." . 
+    $gateway = $gw_1->get_text . "." . $gw_2->get_text . "." .
        $gw_3->get_text . "." . $gw_4->get_text;
 
-    $dnsserver = $dns_1->get_text . "." . $dns_2->get_text . "." . 
+    $dnsserver = $dns_1->get_text . "." . $dns_2->get_text . "." .
        $dns_3->get_text . "." . $dns_4->get_text;
 
     # print "TEST $ipaddress $netmask $gateway $dnsserver\n";
@@ -1672,19 +1722,20 @@ sub create_extract_view {
     display_html ("extract1-license.htm");
     $next->set_sensitive (0);
 
-    my $vbox =  Gtk2::VBox->new (0, 0);
+    my $vbox =  Gtk3::VBox->new (0, 0);
     $inbox->pack_start ($vbox, 1, 0, 0);
-    my $hbox =  Gtk2::HBox->new (0, 0);
-    $vbox->pack_start ($hbox, 0, 0, 30);
+    my $hbox =  Gtk3::HBox->new (0, 0);
+    $vbox->pack_start ($hbox, 0, 0, 10);
 
-    my $vbox2 =  Gtk2::VBox->new (0, 0);
+    my $vbox2 =  Gtk3::VBox->new (0, 0);
     $hbox->pack_start ($vbox2, 0, 0, 0);
 
-    $progress_status = Gtk2::Label->new ();
+    $progress_status = Gtk3::Label->new ('');
     $vbox2->pack_start ($progress_status, 1, 1, 0);
-    
-    $progress = Gtk2::ProgressBar->new;
-    $progress->set_size_request (400, -1);
+
+    $progress = Gtk3::ProgressBar->new;
+    $progress->set_show_text(1);
+    $progress->set_size_request (600, -1);
 
     $vbox2->pack_start ($progress, 0, 0, 0);
 
@@ -1701,15 +1752,13 @@ sub create_extract_view {
 
     set_next ("_Reboot", sub { exit (0); } );
 
-    display_html ($err ? "fail.htm" : "success.htm");
-
-    display_error ($err) if $err;
-}
-
-sub mupdate_progress {
-    my $per = shift;
-    print "GOT1: $per\n";
-
+    if ($err) {
+       display_html ("fail.htm");
+       display_error ($err);
+    } else {
+       cleanup_view ();
+       display_html ("success.htm");
+    }
 }
 
 sub create_intro_view {
@@ -1745,6 +1794,6 @@ if (!defined ($hds) || (scalar (@$hds) <= 0)) {
     create_intro_view ();
 }
 
-Gtk2->main;
+Gtk3->main;
 
 exit 0;