]> git.proxmox.com Git - pve-installer.git/blobdiff - proxinstall
linewrap bootdevinfo generation
[pve-installer.git] / proxinstall
index 019ae0b2d6f4dac904cbc0f26d0a662ec7101d18..d81d71d5e40ba955f8ea64c4cdf673da431a658b 100755 (executable)
@@ -328,6 +328,8 @@ mynetworks = 127.0.0.0/8
 inet_interfaces = loopback-only
 recipient_delimiter = +
 
+compatibility_level = 2
+
 _EOD
 
 sub shellquote {
@@ -566,7 +568,7 @@ sub hd_list {
        my @disks = split /,/, $opt_testmode;
 
        for my $disk (@disks) {
-           push @$res, [-1, $disk, int((-s $disk)/512), "TESTDISK"];
+           push @$res, [-1, $disk, int((-s $disk)/512), "TESTDISK", 512];
        }
        return $res;
     }
@@ -609,7 +611,12 @@ sub hd_list {
            if (length ($model) > 30) {
                $model = substr ($model, 0, 30);
            }
-           push @$res, [$count++, $real_name, $size, $model] if $size;
+
+           my $logical_bsize = file_read_firstline("$bd/queue/logical_block_size") // '';
+           chomp $logical_bsize;
+           $logical_bsize = undef if !($logical_bsize && $logical_bsize =~ m/^\d+$/);
+
+           push @$res, [$count++, $real_name, $size, $model, $logical_bsize] if $size;
        } else {
            print STDERR "ERROR: unable to map device $dev ($bd)\n";
        }
@@ -620,7 +627,7 @@ sub hd_list {
 
 sub read_cmap {
     my $countryfn = "${proxmox_libdir}/country.dat";
-    open (TMP, "<$countryfn") || die "unable to open '$countryfn' - $!\n";
+    open (TMP, "<:encoding(utf8)", "$countryfn") || die "unable to open '$countryfn' - $!\n";
     my $line;
     my $country = {};
     my $countryhash = {};
@@ -683,14 +690,25 @@ sub hd_size {
     my ($dev) = @_;
 
     foreach my $hd (@$hds) {
-       my ($disk, $devname, $size, $model) = @$hd;
-       # size is always in 512B "sectors"! convert to KB
+       my ($disk, $devname, $size, $model, $logical_bsize) = @$hd;
+       # size is always (also for 4kn disks) in 512B "sectors"! convert to KB
        return int($size/2) if $devname eq $dev;
     }
 
     die "no such device '$dev'\n";
 }
 
+sub logical_blocksize {
+    my ($dev) = @_;
+
+    foreach my $hd (@$hds) {
+       my ($disk, $devname, $size, $model, $logical_bsize) = @$hd;
+       return $logical_bsize if $devname eq $dev;
+    }
+
+    die "no such device '$dev'\n";
+}
+
 sub get_partition_dev {
     my ($dev, $partnum) = @_;
 
@@ -972,11 +990,78 @@ sub partition_bootable_disk {
     return ($os_size, $osdev, $efibootdev);
 }
 
+sub get_pv_list_from_vgname {
+    my ($vgname) = @_;
+
+    my $res;
+
+    my $parser = sub {
+       my $line = shift;
+       $line =~ s/^\s+//;
+       $line =~ s/\s+$//;
+       return if !$line;
+       my ($pv, $vg_uuid) = split(/\s+/, $line);
+
+       if (!defined($res->{$vg_uuid}->{pvs})) {
+           $res->{$vg_uuid}->{pvs} = "$pv";
+       } else {
+           $res->{$vg_uuid}->{pvs} .= ", $pv";
+       }
+    };
+    run_command("pvs --noheadings -o pv_name,vg_uuid -S vg_name='$vgname'", $parser, undef, 1);
+
+    return $res;
+}
+
+sub ask_existing_vg_rename_or_abort {
+    my ($vgname) = @_;
+
+    # this normally only happens if one put a disk with a PVE installation in
+    # this server and that disk is not the installation target.
+    my $duplicate_vgs = get_pv_list_from_vgname($vgname);
+    return if !$duplicate_vgs;
+
+    my $message = "Detected existing '$vgname' Volume Group(s)! Do you want to:\n";
+
+    for my $vg_uuid (keys %$duplicate_vgs) {
+       my $vg = $duplicate_vgs->{$vg_uuid};
+
+       # no high randomnes properties, but this is only for the cases where
+       # we either have multiple "$vgname" vgs from multiple old PVE disks, or
+       # we have a disk with both a "$vgname" and "$vgname-old"...
+       my $short_uid = sprintf "%08X", rand(0xffffffff);
+       $vg->{new_vgname} = "$vgname-OLD-$short_uid";
+
+       $message .= "rename VG backed by PV '$vg->{pvs}' to '$vg->{new_vgname}'\n";
+    }
+    $message .= "or cancel the installation?";
+
+    my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'question', 'ok-cancel', $message);
+    my $response = $dialog->run();
+    $dialog->destroy();
+
+    if ($response eq 'ok') {
+       for my $vg_uuid (keys %$duplicate_vgs) {
+           my $vg = $duplicate_vgs->{$vg_uuid};
+           my $new_vgname = $vg->{new_vgname};
+
+           syscmd("vgrename $vg_uuid $new_vgname") == 0 ||
+               die "could not rename VG from '$vg->{pvs}' ($vg_uuid) to '$new_vgname'!\n";
+       }
+    } else {
+       set_next("_Reboot", sub { exit (0); } );
+       display_html("fail.htm");
+       die "Cancled installation by user, due to already existing volume group '$vgname'\n";
+    }
+}
+
 sub create_lvm_volumes {
     my ($lvmdev, $os_size, $swap_size) = @_;
 
     my $vgname = $setup->{product};
 
+    ask_existing_vg_rename_or_abort($vgname);
+
     my $rootdev = "/dev/$vgname/root";
     my $datadev = "/dev/$vgname/data";
     my $swapfile;
@@ -1087,24 +1172,8 @@ sub compute_swapsize {
 sub prepare_systemd_boot_esp {
     my ($espdev, $targetdir) = @_;
 
-    my $espuuid = find_dev_by_uuid($espdev);
-    my $espmp = "var/tmp/$espuuid";
-    mkdir "$targetdir/$espmp";
-
-    syscmd("mount -n $espdev -t vfat $targetdir/$espmp") == 0 ||
-       die "unable to mount ESP $espdev\n";
-
-    File::Path::make_path("$targetdir/$espmp/EFI/proxmox") ||
-       die "unable to create directory $targetdir/$espmp/EFI/proxmox\n";
-
-    syscmd("chroot $targetdir bootctl --path /$espmp install") == 0 ||
-       die "unable to install systemd-boot loader\n";
-    write_config("timeout 3\ndefault proxmox-*\n",
-       "$targetdir/$espmp/loader/loader.conf");
-
-    syscmd("umount $targetdir/$espmp") == 0 ||
-       die "unable to umount ESP $targetdir/$espmp\n";
-
+    syscmd("chroot $targetdir pve-efiboot-tool init $espdev") == 0 ||
+       die "unable to init ESP and install systemd-boot loader on '$espdev'\n";
 }
 
 sub prepare_grub_efi_boot_esp {
@@ -1113,21 +1182,29 @@ sub prepare_grub_efi_boot_esp {
     syscmd("mount -n $espdev -t vfat $targetdir/boot/efi") == 0 ||
        die "unable to mount $espdev\n";
 
-    my $rc = syscmd("chroot $targetdir /usr/sbin/grub-install --target x86_64-efi --no-floppy --bootloader-id='proxmox' $dev");
-    if ($rc != 0) {
-       if ($boot_type eq 'efi') {
-           die "unable to install the EFI boot loader on '$dev'\n";
-       } else {
-           warn "unable to install the EFI boot loader on '$dev', ignoring (not booted using UEFI)\n";
+    eval {
+       my $rc = syscmd("chroot $targetdir /usr/sbin/grub-install --target x86_64-efi --no-floppy --bootloader-id='proxmox' $dev");
+       if ($rc != 0) {
+           if ($boot_type eq 'efi') {
+               die "unable to install the EFI boot loader on '$dev'\n";
+           } else {
+               warn "unable to install the EFI boot loader on '$dev', ignoring (not booted using UEFI)\n";
+           }
        }
-    }
-    # also install fallback boot file (OVMF does not boot without)
-    mkdir("$targetdir/boot/efi/EFI/BOOT");
-    syscmd("cp $targetdir/boot/efi/EFI/proxmox/grubx64.efi $targetdir/boot/efi/EFI/BOOT/BOOTx64.EFI") == 0 ||
-       die "unable to copy efi boot loader\n";
+       # also install fallback boot file (OVMF does not boot without)
+       mkdir("$targetdir/boot/efi/EFI/BOOT");
+       syscmd("cp $targetdir/boot/efi/EFI/proxmox/grubx64.efi $targetdir/boot/efi/EFI/BOOT/BOOTx64.EFI") == 0 ||
+           die "unable to copy efi boot loader\n";
+    };
+    my $err = $@;
 
-    syscmd("umount $targetdir/boot/efi") == 0 ||
-       die "unable to umount $targetdir/boot/efi\n";
+    eval {
+       syscmd("umount $targetdir/boot/efi") == 0 ||
+           die "unable to umount $targetdir/boot/efi\n";
+    };
+    warn $@ if $@;
+
+    die "failed to prepare EFI boot using Grub on '$espdev': $err" if $err;
 }
 
 sub extract_data {
@@ -1168,6 +1245,8 @@ sub extract_data {
        die "unable to load zfs kernel module\n" if !$i;
     }
 
+    my $bootloader_err;
+
     eval {
 
 
@@ -1215,8 +1294,12 @@ sub extract_data {
                    partition_bootable_disk($devname, undef, '8300');
                $rootdev = $osdev if !defined($rootdev); # simply point to first disk
                my $by_id = find_stable_path("/dev/disk/by-id", $devname);
-               push @$bootdevinfo, { esp => $efidev, devname => $devname,
-                                     osdev => $osdev, by_id => $by_id };
+               push @$bootdevinfo, {
+                   esp => $efidev,
+                   devname => $devname,
+                   osdev => $osdev,
+                   by_id => $by_id,
+               };
                push @$btrfs_partitions, $osdev;
                $disksize = $size;
            }
@@ -1276,8 +1359,12 @@ sub extract_data {
            &$udevadm_trigger_block();
 
            my $by_id = find_stable_path ("/dev/disk/by-id", $target_hd);
-           push @$bootdevinfo, { esp => $efidev, devname => $target_hd,
-                                 osdev => $osdev, by_id => $by_id };
+           push @$bootdevinfo, {
+               esp => $efidev,
+               devname => $target_hd,
+               osdev => $osdev,
+               by_id => $by_id,
+           };
 
            my $swap_size = compute_swapsize($os_size);
            ($rootdev, $swapfile, $datadev) =
@@ -1379,7 +1466,7 @@ sub extract_data {
        syscmd("mount -n -t sysfs sysfs $targetdir/sys") == 0 ||
            die "unable to mount sysfs on $targetdir/sys\n";
        if ($boot_type eq 'efi') {
-           syscmd("mount -n -t efivarfs none $targetdir/sys/firmware/efi/efivars") == 0 ||
+           syscmd("mount -n -t efivarfs efivarfs $targetdir/sys/firmware/efi/efivars") == 0 ||
                die "unable to mount efivarfs on $targetdir/sys/firmware/efi/efivars: $!\n";
        }
        syscmd("chroot $targetdir mount --bind /mnt/hostrun /run") == 0 ||
@@ -1510,6 +1597,13 @@ sub extract_data {
        diversion_add($targetdir, "/usr/sbin/update-grub", "/bin/true");
        diversion_add($targetdir, "/usr/sbin/update-initramfs", "/bin/true");
 
+       my $machine_id = run_command("systemd-id128 new");
+       die "unable to create a new machine-id\n" if ! $machine_id;
+       write_config($machine_id, "$targetdir/etc/machine-id");
+
+       syscmd("cp /etc/hostid $targetdir/etc/") == 0 ||
+           die "unable to copy hostid\n";
+
        syscmd("touch  $targetdir/proxmox_install_mode");
 
        my $grub_install_devices_txt = '';
@@ -1573,6 +1667,8 @@ _EOD
        syscmd("chroot $targetdir /usr/sbin/postfix check");
        # cleanup mail queue
        syscmd("chroot $targetdir /usr/sbin/postsuper -d ALL");
+       # create /etc/aliases.db (/etc/aliases is shipped in the base squashfs)
+       syscmd("chroot $targetdir /usr/bin/newaliases");
 
        # enable NTP (timedatectl set-ntp true  does not work without DBUS)
        syscmd("chroot $targetdir /bin/systemctl enable systemd-timesyncd.service");
@@ -1644,29 +1740,40 @@ _EOD
            symlink ("/proc/mounts", "$targetdir/etc/mtab");
            syscmd("mount -n --bind /dev $targetdir/dev");
 
-           syscmd("chroot $targetdir /usr/sbin/update-initramfs -c -k $kapi") == 0 ||
-               die "unable to install initramfs\n";
-
-           foreach my $di (@$bootdevinfo) {
-               my $dev = $di->{devname};
-               syscmd("chroot $targetdir /usr/sbin/grub-install --target i386-pc --no-floppy --bootloader-id='proxmox' $dev") == 0 ||
-                       die "unable to install the i386-pc boot loader on '$dev'\n";
-
-               if (my $esp = $di->{esp}) {
-                   if ($use_zfs) {
-                       prepare_systemd_boot_esp($esp, $targetdir);
-                   } else {
-                       prepare_grub_efi_boot_esp($dev, $esp, $targetdir);
-                   }
+           my $bootloader_err_list = [];
+           eval {
+               syscmd("chroot $targetdir /usr/sbin/update-initramfs -c -k $kapi") == 0 ||
+                   die "unable to install initramfs\n";
+
+               foreach my $di (@$bootdevinfo) {
+                   my $dev = $di->{devname};
+                   eval {
+                       syscmd("chroot $targetdir /usr/sbin/grub-install --target i386-pc --no-floppy --bootloader-id='proxmox' $dev") == 0 ||
+                               die "unable to install the i386-pc boot loader on '$dev'\n";
+                   };
+                   push @$bootloader_err_list, $@ if $@;
+
+                   eval {
+                       if (my $esp = $di->{esp}) {
+                           if ($use_zfs) {
+                               prepare_systemd_boot_esp($esp, $targetdir);
+                           } else {
+                               prepare_grub_efi_boot_esp($dev, $esp, $targetdir);
+                           }
+                       }
+                   };
+                   push @$bootloader_err_list, $@ if $@;
                }
-           }
 
-           syscmd("chroot $targetdir /usr/sbin/update-grub") == 0 ||
-               die "unable to update boot loader config\n";
+               syscmd("chroot $targetdir /usr/sbin/update-grub") == 0 ||
+                   die "unable to update boot loader config\n";
+           };
+           push @$bootloader_err_list, $@ if $@;
 
-           if ($use_zfs && $boot_type eq 'efi') {
-               syscmd("chroot $targetdir /etc/kernel/postinst.d/zz-pve-efiboot") == 0 ||
-                   die "unable to generate systemd-boot config\n";
+           if (scalar(@$bootloader_err_list) > 0) {
+               $bootloader_err = "bootloader setup errors:\n";
+               map { $bootloader_err .= "- $_" } @$bootloader_err_list;
+               warn $bootloader_err;
            }
 
            syscmd("umount $targetdir/dev");
@@ -1761,6 +1868,10 @@ _EOD
        syscmd("zpool export $zfspoolname");
     }
 
+    if ($bootloader_err) {
+       $err = $err ? "$err\n$bootloader_err" : $bootloader_err;
+    }
+
     die $err if $err;
 }
 
@@ -1810,6 +1921,9 @@ sub display_html {
        my $title = "END USER LICENSE AGREEMENT (EULA)";
        $data =~ s/__LICENSE__/$license/;
        $data =~ s/__LICENSE_TITLE__/$title/;
+    } elsif ($filename eq 'success.htm') {
+       my $addr = $ipversion == 6 ? "[${ipaddress}]" : "$ipaddress";
+       $data =~ s/\@IPADDR\@/$addr/;
     }
 
     $htmlview->load_html($data, $url);
@@ -2671,7 +2785,7 @@ my $create_raid_disk_grid = sub {
        $disk_selector->set_active(0);
        $disk_selector->set_visible(1);
        foreach my $hd (@$hds) {
-           my ($disk, $devname, $size, $model) = @$hd;
+           my ($disk, $devname, $size, $model, $logical_bsize) = @$hd;
            $disk_selector->append_text(get_device_desc ($devname, $size, $model));
            $disk_selector->{pve_disk_id} = $i;
            $disk_selector->signal_connect (changed => sub {
@@ -3006,7 +3120,7 @@ my $get_raid_devlist = sub {
     my $devlist = [];
     for (my $i = 0; $i < @$hds; $i++) {
        if (my $hd = $config_options->{"disksel$i"}) {
-           my ($disk, $devname, $size, $model) = @$hd;
+           my ($disk, $devname, $size, $model, $logical_bsize) = @$hd;
            die "device '$devname' is used more than once\n"
                if $dev_name_hash->{$devname};
            $dev_name_hash->{$devname} = $hd;
@@ -3125,7 +3239,7 @@ sub create_hdsel_view {
     my $hbox =  Gtk3::HBox->new(0, 0);
     $vbox->pack_start($hbox, 0, 0, 10);
 
-    my ($disk, $devname, $size, $model) = @{@$hds[0]};
+    my ($disk, $devname, $size, $model, $logical_bsize) = @{@$hds[0]};
     $target_hd = $devname if !defined($target_hd);
 
     $target_hd_label = Gtk3::Label->new("Target Harddisk: ");
@@ -3134,7 +3248,7 @@ sub create_hdsel_view {
     $target_hd_combo = Gtk3::ComboBoxText->new();
 
     foreach my $hd (@$hds) {
-       ($disk, $devname, $size, $model) = @$hd;
+       ($disk, $devname, $size, $model, $logical_bsize) = @$hd;
        $target_hd_combo->append_text (get_device_desc($devname, $size, $model));
     }