mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-10 19:46:24 +00:00
fix(grub2): keep the whole kernel command line past a grub2 separator
grub2 reads its configuration as a script, so an unquoted command separator ends the linux command and everything after it is lost. The Ubuntu installer seed is written as ds=nocloud-net;s=<url>, so the node booted without the seed URL and without the arguments that followed it, including BOOTIF. The installer then found no autoinstall configuration and waited for someone to answer its questions. A separator that is neither escaped nor inside a quoted span is now escaped where it stands, which grub2 removes before it hands the line to the kernel. A value the caller escaped or quoted keeps exactly the form the caller gave it. Signed-off-by: Vinícius Ferrão <2031761+viniciusferrao@users.noreply.github.com>
This commit is contained in:
@@ -85,6 +85,29 @@ sub getstate {
|
||||
}
|
||||
}
|
||||
|
||||
# grub2 reads its configuration as a script, so an unquoted word carrying one of the
|
||||
# characters below ends the linux command and the rest of the kernel command line is lost.
|
||||
# The Ubuntu installer seed (ds=nocloud-net;s=<url>) is the usual casualty.
|
||||
my $GRUB2_TERMINATOR = qr/[;{}|&<>()]/;
|
||||
|
||||
sub quote_kcmdline {
|
||||
my $kcmdline = shift;
|
||||
|
||||
return $kcmdline unless (defined $kcmdline and $kcmdline =~ $GRUB2_TERMINATOR);
|
||||
|
||||
# Escaped in place rather than quoted as a whole: a value the caller quoted keeps the
|
||||
# quoting it was given, which grub2 removes before the kernel sees the value.
|
||||
my $escaped = '';
|
||||
while (length $kcmdline) {
|
||||
if ($kcmdline =~ s/^('[^']*'|"[^"]*")//) { $escaped .= $1; next; }
|
||||
if ($kcmdline =~ s/^(\\.)//) { $escaped .= $1; next; }
|
||||
$kcmdline =~ s/^(.)//s;
|
||||
my $char = $1;
|
||||
$escaped .= ($char =~ $GRUB2_TERMINATOR) ? "\\$char" : $char;
|
||||
}
|
||||
return $escaped;
|
||||
}
|
||||
|
||||
sub setstate {
|
||||
|
||||
=pod
|
||||
@@ -260,7 +283,8 @@ sub setstate {
|
||||
}
|
||||
|
||||
if ($kern and $kern->{kcmdline}) {
|
||||
print $pcfg " linux$efi $protocolrootdir/$kern->{kernel} $kern->{kcmdline} BOOTIF=\$net_default_mac\n";
|
||||
my $kcmdline = quote_kcmdline($kern->{kcmdline});
|
||||
print $pcfg " linux$efi $protocolrootdir/$kern->{kernel} $kcmdline BOOTIF=\$net_default_mac\n";
|
||||
} else {
|
||||
print $pcfg " linux$efi $protocolrootdir/$kern->{kernel} BOOTIF=\$net_default_mac\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user