Dualboot-Installations fails for boot to Windows 10 after running fai

Sven Schumacher schumacher at tfd.uni-hannover.de
Tue Oct 5 19:41:27 CEST 2021


Hello Markus,

thanks for your hint regarding the PARTUUIDs.

I modified setup-storage (see attached file, Thomas, might by of 
interest) so it takes a look for preserved or resized partitions, and 
saves the PARTUUID before recreating the partition-table and setting 
them back afterwards using the mechanisms setup-storage already has.

But that doesn't help. Windows still gets a bluescreen (Errorcode 
0xc000000e) on reboot after fai-install and tries to do the "automatic 
repair" before that (before saving the PARTUUIDs the "automatic repair" 
wans't started.

the output before running setup-storage of sgdisk was (partition 4 & 5 
are created by fai, so shouldn't keep their part unique guid):

partuuids before setup-storage
         Disk info of partition 1:
Partition GUID code: C12A7328-F81F-11D2-BA4B-00A0C93EC93B (EFI system 
partition)
Partition unique GUID: FE08D6AE-2648-11EC-9CA9-806E6F6E6963
First sector: 2048 (at 1024.0 KiB)
Last sector: 204800 (at 100.0 MiB)
Partition size: 202753 sectors (99.0 MiB)
Attribute flags: 0000000000000000
Partition name: 'primary'
         Disk info of partition 2:
Partition GUID code: E3C9E316-0B5C-4DB8-817D-F92DF00215AE (Microsoft 
reserved)
Partition unique GUID: FE08D6AF-2648-11EC-9CA9-806E6F6E6963
First sector: 206848 (at 101.0 MiB)
Last sector: 468991 (at 229.0 MiB)
Partition size: 262144 sectors (128.0 MiB)
Attribute flags: 0000000000000000
Partition name: 'primary'
         Disk info of partition 3:
Partition GUID code: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 (Microsoft 
basic data)
Partition unique GUID: 95BAE942-B396-47EE-B5C3-A00BC349D877
First sector: 468992 (at 229.0 MiB)
Last sector: 840382463 (at 400.7 GiB)
Partition size: 839913472 sectors (400.5 GiB)
Attribute flags: 0000000000000000
Partition name: 'primary'
         Disk info of partition 6:
Partition GUID code: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 (Microsoft 
basic data)
Partition unique GUID: 1287D7DE-E2D8-43EC-9358-2E5AF80B56DA
First sector: 978794496 (at 466.7 GiB)
Last sector: 1000215182 (at 476.9 GiB)
Partition size: 21420687 sectors (10.2 GiB)
Attribute flags: 0000000000000000
Partition name: 'primary'


and afterwards:

partuuids after setup-storage
         Disk info of partition 1:
Partition GUID code: C12A7328-F81F-11D2-BA4B-00A0C93EC93B (EFI system 
partition)
Partition unique GUID: FE08D6AE-2648-11EC-9CA9-806E6F6E6963
First sector: 2048 (at 1024.0 KiB)
Last sector: 204800 (at 100.0 MiB)
Partition size: 202753 sectors (99.0 MiB)
Attribute flags: 0000000000000000
Partition name: 'primary'
         Disk info of partition 2:
Partition GUID code: E3C9E316-0B5C-4DB8-817D-F92DF00215AE (Microsoft 
reserved)
Partition unique GUID: FE08D6AF-2648-11EC-9CA9-806E6F6E6963
First sector: 206848 (at 101.0 MiB)
Last sector: 468991 (at 229.0 MiB)
Partition size: 262144 sectors (128.0 MiB)
Attribute flags: 0000000000000000
Partition name: 'primary'
         Disk info of partition 3:
Partition GUID code: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 (Microsoft 
basic data)
Partition unique GUID: 95BAE942-B396-47EE-B5C3-A00BC349D877
First sector: 468992 (at 229.0 MiB)
Last sector: 840382463 (at 400.7 GiB)
Partition size: 839913472 sectors (400.5 GiB)
Attribute flags: 0000000000000000
Partition name: 'primary'
         Disk info of partition 6:
Partition GUID code: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 (Microsoft 
basic data)
Partition unique GUID: 1287D7DE-E2D8-43EC-9358-2E5AF80B56DA
First sector: 978794496 (at 466.7 GiB)
Last sector: 1000215182 (at 476.9 GiB)
Partition size: 21420687 sectors (10.2 GiB)
Attribute flags: 0000000000000000
Partition name: 'primary'

So here doesn't it seem to matter...

Any more hints?

Thanks in advance

Sven


Am 04.10.21 um 20:29 schrieb Markus Köberl:
> On Monday, 4 October 2021 12:34:35 CEST Sven Schumacher wrote:
>
>> What does setup-storage do (or the used programs behind that tool), that
>> the windows-bootloader can't find the C: partition after using fai?
> setup-storage recreates the partition table. therefore the partition table and
> all partitions get different ids.
> at least with MS-DOS partition table this was the case for the partition id,
> with GPT partition table I never searched what exactly is necessary.
>
> I am using a mountdisks hook to restore the ids using sgdisk.
>
>> Thanks for any input... If I didn't find the solution I have to boot 140
>> PCs with Windows-USB-Stick to type the bcdedit lines mentioned above...
> I do have a windows 10 image which I restore on all my laboratory hosts.
> after the restore I mount the C: partition and edit the registry using chntpw
> to replace the hostname.
>
> If you are interested I can give you my scripts (which are very particular to
> my system) but they might help you finding a solution.
>
>
> regards
> Markus Köberl


-- 
Sven Schumacher                       Tel: (0511)762-2753
Leibniz Universitaet Hannover
Fakultät für Maschinenbau, Head of Systemadministration
An der Universität 1 - 30823 Garbsen

Institut für Turbomaschinen und Fluid-Dynamik       - TFD
Institut für Kraftwerkstechnik und Wärmeübertragung - IKW
Institut für Technische Verbrennung                 - ITV

-------------- next part --------------
#!/usr/bin/perl -w

#*********************************************************************
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# A copy of the GNU General Public License is available as
# `/usr/share/common-licences/GPL' in the Debian GNU/Linux distribution
# or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html. You
# can also obtain it by writing to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#*********************************************************************

use strict;

# treat all warnings about uninitialised values as errors
use warnings FATAL => qw(uninitialized);

################################################################################
#
# @file setup-storage
#
# @brief The main function of setup-storage - the tool to configure the
# partitioning from within FAI.
#
# This is an implementation from scratch to properly support LVM and RAID. The
# input format is documented in @ref parser.pm
#
# Some (developer) documentation may be found on
# https://wiki.fai-project.org/index.php/Setup-storage
#
# Some coding conventions:
# - no whitespace after ( and before )
# - keyword<whitespace>(...)
# - do not start a new line for {
# - } goes on a line on its own
# - one blank line after sub ...
#
# $Id$
#
# @author Christian Kern, Michael Tautschnig
# @date Sun Jul 23 16:09:36 CEST 2006
#
################################################################################

package FAI;

my $version = "2.3";
$|=1;

# command line parameter handling
use Getopt::Std;
$main::VERSION = $version;
$Getopt::Std::STANDARD_HELP_VERSION = 1;
our ($opt_X, $opt_f, $opt_h, $opt_d, $opt_s, $opt_D, $opt_L,$opt_y); # the variables for getopt
(&getopts('Xf:hdsD:L:y') && !$opt_h) || die <<EOF;
setup-storage version $version

USAGE: [-X]                     no test, your harddisks will be formated
                                default: only test, no real formating
       [-f<config-filename>]    default: parse classes
       [-d]                     enable debug output (equivalent to debug=1)
       [-s]                     perform syntax check only and exit
       [-D<disks>]              override disklist variable by space-separated <disks>
       [-L<logdir>]             use <logdir> instead of LOGDIR variable
       [-h]                     print this help message
       [-y]                     print disk variables as YAML file into disk_var.yml
EOF

# include all subparts, which are part of the FAI perl package
use lib "/usr/share/fai/setup-storage/";
use Init;
use Volumes;
use Parser;
use Sizes;
use Commands;
use Fstab;
use Exec;

sub prtdebug {

  # for debugging purposes to print the hash structures
  use Data::Dumper;

  print "Current disk layout in \%current_config\n";
  print Dumper \%FAI::current_config;

  print "Current LVM layout in \%current_lvm_config\n";
  print Dumper \%FAI::current_lvm_config;

  print "Current RAID layout in \%current_raid_config\n";
  print Dumper \%FAI::current_raid_config;

  print "Current device tree in \%current_dev_children\n";
  print Dumper \%FAI::current_dev_children;
}

# enable debug mode, if requested using -d
$opt_d and $FAI::debug = 1;

# Really write any changes to disk
$opt_X and $FAI::no_dry_run = 1;
warn "setup-storage is running in test-only mode\n" unless ($FAI::no_dry_run);

# syntactic checks only
$opt_s and $FAI::check_only = 1;

# Find out whether $LOGDIR is usable or default to /tmp/fai
$opt_L and $FAI::DATADIR = $opt_L;
if (! -d $FAI::DATADIR) {
  !defined($opt_L) and defined ($ENV{LOGDIR}) and die
    "Environment variable LOGDIR is set, but $FAI::DATADIR is not a directory\n";
  mkdir $FAI::DATADIR or die
    "Failed to create directory $FAI::DATADIR\n";
  warn "Created data directory $FAI::DATADIR\n";
}

# $disklist may be provided by the environment
my $disklist = $ENV{disklist};
$opt_D and $disklist = $opt_D;
if (! defined($disklist)) {
  &FAI::in_path("/usr/lib/fai/fai-disk-info") or die "/usr/lib/fai/fai-disk-info not found\n";
  $disklist = `/usr/lib/fai/fai-disk-info | sort`;
}

@FAI::disks = split( /[\n ]/, $disklist);
if ($FAI::debug) {
  print "disklist: ";
  print "$_\n" foreach(@FAI::disks);
}
warn "No disks defined in \$disklist\n" unless (@FAI::disks);

# the config source file
my $config_file = undef;
# use the config file, if given
open($config_file, $opt_f) or die "Failed to open config file $opt_f\n" if ($opt_f);
unless ($opt_f) {
  defined ($ENV{classes}) or
    die "Environment variable classes is not set and -f was not given\n";
  # see which class file to use
  foreach my $classfile (reverse split(/\s+/, $ENV{classes})) {
    next unless (-r "$ENV{FAI}/disk_config/$classfile");
    open($config_file, "$ENV{FAI}/disk_config/$classfile")
      or die "Failed to open $ENV{FAI}/disk_config/$classfile\n";
    $opt_f = "$ENV{FAI}/disk_config/$classfile";
    last;
  }
}

# if we could not find any matching class file, bail out
defined ($config_file) or die "No matching disk_config found\n";

# start the parsing - thereby $FAI::configs is filled
warn "Starting setup-storage $version\n";
print "Using config file: $opt_f\n";
&FAI::run_parser($config_file);

# make sure there are no empty disk_config stanzas
&FAI::check_config;

if ($FAI::check_only) {
  print "Syntax ok\n";
  exit 0;
}

# first find the proper way to tell udev to settle
$FAI::udev_settle = "udevadm settle --timeout=10" if (&FAI::in_path("udevadm"));
$FAI::udev_settle = "udevsettle --timeout=10" if (&FAI::in_path("udevsettle"));
defined($FAI::udev_settle) or die "Failed to find determine a proper way to tell udev to settle; is udev installed?";

# start all RAID arrays in case some of the aren't running yet
&FAI::in_path("mdadm-startall") and `mdadm-startall`;
`$FAI::udev_settle`;

# read the sizes and partition tables of all disks listed in $FAI::disks
&FAI::get_current_disks;

# see whether there are any existing LVMs
$FAI::uses_lvm and &FAI::in_path("pvdisplay") and &FAI::get_current_lvm;

# see whether there are any existing RAID devices
$FAI::uses_raid and &FAI::in_path("mdadm") and &FAI::get_current_raid;

# mark devices as preserve, where not all already done so and check that only
# defined devices are marked preserve
&FAI::propagate_and_check_preserve;

################################################################################
# 
# @brief get partuuid for specified partition
#
# Added by Sven Schumacher, 2021-10-04
################################################################################
sub find_partuuid {
	my ($device_name,$missing) = @_;
	my $partuuid=`/usr/sbin/blkid -s PARTUUID -o value $device_name`;
	chomp($partuuid);
	return $partuuid;
}


################################################################################
#
# @brief build commands for restoring old partuuids for preserved partitions
#
# Added by Sven Schumacher, 2021-10-04
# ##############################################################################
sub build_partuuids_commands() {
  my $setpartuuid_tool="/usr/sbin/sgdisk";
  foreach my $disk (keys(%FAI::configs)) {
	  if ($disk=~m/PHY_(.*)/) {
		  my $device_name=$1;
		  if (defined $FAI::configs{$disk}->{'partitions'}) {
			  my %part=%{$FAI::configs{$disk}->{'partitions'}};
			  foreach my $part_no (keys(%part)) {
				if (defined($part{$part_no}->{OLDPARTUUID})) {
					my $prereqs = "exist_$device_name$part_no";
					my $desired_partuuid=$part{$part_no}->{OLDPARTUUID};
					my $setpartuuid_tool_options="--partition-guid=".$part_no.":".$desired_partuuid;
					my $provides = "has_restoredpartuuid_$device_name$part_no";
					&FAI::push_command( "$setpartuuid_tool $setpartuuid_tool_options $device_name", $prereqs, $provides);
				}
			  }
		  }
			
	  }
  }
}

###### Sven Schumacher, 2021-10-04
# Added for retaining partuuid
#
######
sub retain_partuuids {
  use Data::Dumper;
  $FAI::debug and print Dumper \%FAI::configs;
  # loop through %FAI::configs looking for preserved partitions
  foreach my $disk (keys(%FAI::configs)) {
	  if ($disk=~m/PHY_(.*)/) {
		  my $device_name=$1;
		  if (defined $FAI::configs{$disk}->{'partitions'}) {
			  my %part=%{$FAI::configs{$disk}->{'partitions'}};
			  foreach my $part_no (keys(%part)) {
				if ($part{$part_no}->{size}->{preserve}==1 || $part{$part_no}->{size}->{resize}==1) {
					$part{$part_no}->{OLDPARTUUID}=&FAI::find_partuuid($device_name.$part_no);
				}
			  }
		  }
			
	  }
  }
  $FAI::debug and print Dumper \%FAI::configs;
}

# debugging only: print the current configuration
if ($FAI::debug) {
  use Data::Dumper;
  prtdebug;
}

# compute the new LVM and partition sizes; do the partition sizes first to have
# them available for the the volume group size estimation
&FAI::compute_partition_sizes;
&FAI::compute_lv_sizes;

# print the current contents of $FAI::configs
$FAI::debug and print "Desired disk layout in %FAI::configs\n";
$FAI::debug and print Dumper \%FAI::configs;
$FAI::debug and print "Desired device tree in %FAI::dev_children\n";
$FAI::debug and print Dumper \%FAI::dev_children;

# generate the command script
&FAI::get_parted_version;
&FAI::retain_partuuids;           #### Sven Schumacher, 2021-10-04
&FAI::build_disk_commands;
$FAI::uses_raid and &FAI::build_raid_commands;
&FAI::build_btrfs_commands;
$FAI::uses_lvm and &FAI::build_lvm_commands;
&FAI::build_cryptsetup_commands;
&FAI::build_partuuids_commands;   #### Sven Schumacher, 2021-10-04
&FAI::order_commands;

# run all commands
# debugging only: print the command script
if ($FAI::debug) {
  foreach (&numsort(keys %FAI::commands)) {
    defined($FAI::commands{$_}{cmd}) or &FAI::internal_error("Missing command entry for $_");
    print "$_:" . $FAI::commands{$_}{cmd} . "\n";
    defined($FAI::commands{$_}{pre}) and print "\tpre: " . $FAI::commands{$_}{pre} . "\n";
    defined($FAI::commands{$_}{post}) and print "\tpost: " . $FAI::commands{$_}{post} . "\n";
  }
}

# run the commands (if $FAI::no_dry_run is set)
foreach (&numsort(keys %FAI::commands)) {
  `$FAI::udev_settle`;
  next if ($FAI::commands{$_}{cmd} eq "true");
  &FAI::execute_command($FAI::commands{$_}{cmd});
}

# generate the proposed fstab contents
# wait for udev to set up all devices
`$FAI::udev_settle`;
my @fstab = &FAI::generate_fstab(\%FAI::configs);

# print fstab
$FAI::debug and print "$_\n" foreach (@fstab);

# write the proposed contents of fstab to $FAI::DATADIR/fstab
if ($FAI::no_dry_run) {
  open(FSTAB, ">$FAI::DATADIR/fstab")
    or die "Failed to open $FAI::DATADIR/fstab for writing\n";
  print FSTAB "$_\n" foreach (@fstab);
  close FSTAB;
}

# write variables to $FAI::DATADIR/disk_var.sh
# debugging
$FAI::debug and print "$_=\${$_:-$FAI::disk_var{$_}}\n"
  foreach (keys %FAI::disk_var);

if ($FAI::no_dry_run) {
  # List all bootable devices. Can be used by later tasks to install a
  # boot loader. Using Variable PHYSICAL_BOOT_DEVICES.
  my @boot_devices;
  foreach (keys %FAI::configs) {
    $_ =~ /PHY_(.+)/;
    if ( $1 && defined $FAI::configs{$_}{'bootable'}
      &&  $FAI::configs{$_}{'bootable'} > 0 )  {
      push @boot_devices, $1;
    }
  }
  @boot_devices = sort @boot_devices;

  open(DISK_VAR, ">$FAI::DATADIR/disk_var.sh")
    or die "Unable to write to file $FAI::DATADIR/disk_var.sh\n";
  print DISK_VAR "$_=\${$_:-$FAI::disk_var{$_}}\n" foreach (keys %FAI::disk_var);
  print DISK_VAR "PHYSICAL_BOOT_DEVICES=\"", join(" ", @boot_devices), "\"\n";
  close DISK_VAR;

  if ($opt_y) {
    open(DISK_YML, ">$FAI::DATADIR/disk_var.yml")
      or die "Unable to write to file $FAI::DATADIR/disk_var.yml\n";

    print DISK_YML "---\n# disk_var.sh as YAML\n";
    foreach (keys %FAI::disk_var) {
      $FAI::disk_var{$_} =~ s/"//g;
      if ( $FAI::disk_var{$_} =~ m/\s/ ) {
	# print an array
	print DISK_YML "$_:\n";
	my $a = join("\n  - ", split(/ /,$FAI::disk_var{$_}));
	print DISK_YML "  - $a\n";
      } else {
	print DISK_YML "$_: $FAI::disk_var{$_}\n";
      }
    }
    print DISK_YML "PHYSICAL_BOOT_DEVICES:\n";
    my $a = join("\n  - ", @boot_devices);
    print DISK_YML "  - $a\n";
    close DISK_YML;
  }
}

# print crypttab
$FAI::debug and print "$_\n" foreach (@FAI::crypttab);

# write the proposed contents of fstab to $FAI::DATADIR/fstab
if ($FAI::no_dry_run && scalar(@FAI::crypttab)) {
  open(CRYPTTAB, ">$FAI::DATADIR/crypttab")
    or die "Failed to open $FAI::DATADIR/crypttab for writing\n";
  print CRYPTTAB "$_\n" foreach (@FAI::crypttab);
  close CRYPTTAB;
}


# at the end print the whole config again
if ($FAI::debug) {
  print "==========================================\n";
  print "=  Variables at the end of setup-storage =\n";
  print "==========================================\n";
  prtdebug;
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 5391 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://lists.uni-koeln.de/pipermail/linux-fai/attachments/20211005/5b24aa9e/attachment.p7s>


More information about the linux-fai mailing list