Usability fixes

- Add the ability to automatically mount/unmount an EFI or syslinux
  partition before generating any files.

- Change execute to return an array, with the status code as the final
  array item.

- Add a fix for petitboots brainded syslinux.cfg parser. Any kernels
  ending in .0 are stripped - so v0.x.0 releases are 'broken'. Appends
  _1 to all versions to work around this behavior.

- Merges in kernel version sorting via Sort::Versions
This commit is contained in:
Zach Dykstra 2020-01-19 15:10:59 -06:00
parent 7586dfb8d4
commit 01b504f107
2 changed files with 65 additions and 14 deletions

View File

@ -8,8 +8,6 @@ our $VERSION = '0.8.0';
use Getopt::Long qw(:config no_ignore_case auto_version);
use Pod::Usage qw(pod2usage);
use File::Basename;
use Sys::Hostname;
use Config::IniFiles;
use File::Temp qw(tempfile tempdir);
use File::Copy;
use File::Path qw(make_path remove_tree);
@ -19,11 +17,20 @@ $Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Purity = 1;
use Config::IniFiles;
use Sort::Versions;
sub latestKernel;
sub createInitramfs;
sub unifiedEFI;
sub execute;
sub safeCopy;
sub cleanupMount;
BEGIN {
$SIG{INT} = \&cleanupMount;
$SIG{TERM} = \&cleanupMount;
}
my ( %runConf, %config, %components );
@ -50,6 +57,9 @@ unless ( -f $configfile ) {
exit;
}
# Versions ending in .0 will be stripped by petitboots' syslinux parser
$runConf{version} = $runConf{version} . "_1";
# Read our config into a hash
tie %config, 'Config::IniFiles', ( -file => $configfile );
@ -63,6 +73,30 @@ if ( defined $config{Global}{DracutConfDir} ) {
$runConf{confd} = $config{Global}{DracutConfDir};
}
# Ensure our bootloader partition is mounted
$runConf{umount_on_exit} = 0;
if ( ( defined $config{Global}{BootMountPoint} ) and ( length $config{Global}{BootMountPoint} ) ) {
my $mounted = 0;
my $cmd = "mount";
my @output = execute($cmd);
my $status = pop(@output);
foreach my $line (@output) {
chomp($line);
if ( $line =~ m/$config{Global}{BootMountPoint}/ ) {
$mounted = 1;
last;
}
}
unless ($mounted) {
print "Mounting $config{Global}{BootMountPoint}\n";
$cmd = "mount $config{Global}{BootMountPoint}";
execute($cmd);
$runConf{umount_on_exit} = 1;
}
}
# Create a temp directory
# It is automatically purged on program exit
my $dir = File::Temp->newdir();
@ -86,6 +120,7 @@ printf "Creating ZFS Boot Menu %s, with %s %s\n", $runConf{version}, $runConf{ke
$runConf{initramfs} = createInitramfs( $tempdir, $runConf{kernel_version} );
# Create a unified kernel/initramfs/command line EFI file
if ( defined( $config{EFI}{Copies} ) and ( $config{EFI}{Copies} gt 0 ) ) {
$runConf{unified_efi} = unifiedEFI( $tempdir, $runConf{kernel}, $runConf{initramfs} );
@ -120,6 +155,7 @@ if ( defined( $config{EFI}{Copies} ) and ( $config{EFI}{Copies} gt 0 ) ) {
}
}
# Create a separate kernel / initramfs. Used by syslinux/extlinux/grub.
if ( defined( $config{Components}{Copies} ) and ( $config{Components}{Copies} gt 0 ) ) {
if ( defined( $config{Components}{Versioned} ) and ( $config{Components}{Versioned} ) ) {
$runConf{kernel_target} =
@ -173,13 +209,12 @@ if ( defined( $config{Components}{Copies} ) and ( $config{Components}{Copies} gt
}
}
# Generate syslinux.cfg, requires components to be built
if ( defined( $config{syslinux}{CreateConfig} ) and ( $config{syslinux}{CreateConfig} eq 1 ) ) {
my $glob = sprintf( "%s/%s-*", $config{Components}{ImageDir}, $runConf{kernel_prefix} );
my @listing = sort glob($glob);
print Dumper(@listing);
# Filter EFI files and our target image
# Filter EFI files, in case they're in the same directory
my @components;
foreach my $entry (@listing) {
if ( $entry =~ /EFI$/i ) {
@ -206,6 +241,7 @@ EOF
my $entry = pop(@components);
my $directory = dirname( $entry );
# Strip the mountpoint prefix out to generate a correct path based on /
$directory =~ s/\Q$config{Global}{BootMountPoint}//;
my $kernel = basename( $entry );
@ -232,28 +268,35 @@ EOF
safeCopy( $runConf{syslinux_temp}, $config{syslinux}{Config} );
}
END {
cleanupMount;
}
# Finds the latest kernel in /boot
sub latestKernel {
my @prefixes = ( "vmlinux*", "vmlinuz*", "linux*", "kernel*" );
for my $prefix (@prefixes) {
my $glob = join( '/', ( $runConf{bootdir}, $prefix ) );
my @kernels = sort glob($glob);
my @kernels = glob($glob);
next if !@kernels;
return pop @kernels;
for (sort { versioncmp($b, $a) } @kernels ) {
return $_;
}
}
}
# Returns the path to an initramfs, or dies with an error
# Returns the path to an initramfs, or dies with an error
sub createInitramfs {
my ( $temp, $kver ) = @_;
my $output_file = join( '/', $temp, "zfsbootmenu" );
my @cmd = ( qw(dracut -q -f --confdir), $runConf{confd}, $output_file, qw(--kver), $kver, );
my ( $output, $status ) = execute(@cmd);
my @output = execute(@cmd);
my $status = pop(@output);
if ( $status eq 0 ) {
return $output_file;
} else {
print $output;
print Dumper(@output);
die "Failed to create $output_file";
}
}
@ -282,17 +325,18 @@ sub unifiedEFI {
$output_file
);
my ( $output, $status ) = execute(@cmd);
my @output = execute(@cmd);
my $status = pop(@output);
if ( $status eq 0 ) {
return $output_file;
} else {
print $output;
print Dumper(@output);
die "Failed to create $output_file";
}
}
sub execute {
( $_ = qx{@_ 2>&1}, $? >> 8 );
( @_ = qx{@_ 2>&1}, $? >> 8 );
}
sub safeCopy {
@ -304,3 +348,11 @@ sub safeCopy {
}
return 1;
}
sub cleanupMount {
if ( $runConf{umount_on_exit} ) {
print "Unmounting $config{Global}{BootMountPoint}\n";
my $cmd = "umount $config{Global}{BootMountPoint}";
execute($cmd);
}
}

View File

@ -2,7 +2,6 @@
ManageImages=0
DracutConfDir=/etc/zfsbootmenu/dracut.conf.d
BootMountPoint=/boot/efi
FatFixes=1
[Kernel]
CommandLine=ro quiet loglevel=0