File kexec-bootloader of Package kexec-tools
#!/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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA. }}}
#
use Bootloader::Tools;
use strict;
use Getopt::Long;
use constant FALSE => 0;
use constant TRUE => 1;
my $GRUBDIR = "/boot/grub";
my $GRUBDEFAULT = "$GRUBDIR/default";
my $debug = FALSE;
my $showHelp = FALSE;
#
# Prints the given stuff (variable number of arguments) if debugging has
# been enabled. Does nothing otherwise.
sub print_debug(@) # {{{
{
if ($debug) {
print STDERR @_;
print STDERR "\n";
}
} # }}}
#
# Displays help. Does not exit.
sub show_help()
{
print STDERR "kexec-bootloader\n";
print STDERR "Loads kexec kernel from bootloader configuration.\n\n";
print STDERR "Options:\n";
print STDERR " -h | --help Shows that help message.\n";
print STDERR " -D | --debug Prints debugging information.\n";
}
#
# Returns the value stored with "grubonce". If no value has been stored
# or the /boot/grub/default file is not readable, then -1 is returned.
#
# Also emulate the behaviour when using GRUB which resets the 'magic once' flag
# when booting. Because we use kexec, we have to reset that 'magic once' flag
# ourselves.
sub get_grubonce_and_reset_magic() # {{{
{
# no /boot/grub/default file
if (! -f $GRUBDEFAULT) {
print_debug("get_grubonce_and_reset_magic(): No $GRUBDEFAULT.");
return -1;
}
# read /boot/grub/default
open(FH, $GRUBDEFAULT) or return -1;
my $value;
my $ret = sysread(FH, $value, 10);
close(FH);
# only if we have read 4 bytes it's valid
if ($ret != 10) {
print_debug("get_grubonce_and_reset_magic(): ".
"Read returned $ret instead of 4.");
return -1;
}
$value =~ s/\n//g;
my $once = int($value);
# 0x4000 is the "magic once flag"
unless ($once & 0x4000) {
print_debug("get_grubonce_and_reset_magic(): No magic 0x40000.");
return -1;
}
my $defaultno = $once & ~0x4000;
my $buf = $defaultno . "\0" . "\n" x 9;
# now reset the grubonce flag
open(FH, ">$GRUBDEFAULT") or return $defaultno;
$ret = syswrite(FH, $buf, 10);
close(FH);
return $defaultno;
} # }}}
#
# Parses command line options and sets global variables.
sub parse_options() # {{{
{
GetOptions(
"D|debug" => \$debug,
"h|help" => \$showHelp
);
} # }}}
parse_options();
if ($showHelp) {
show_help();
exit(0);
}
Bootloader::Tools::InitLibrary();
my $loader = Bootloader::Tools::GetBootloader();
my $default = -1;
if ($loader =~ m/GRUB/i) {
$default = get_grubonce_and_reset_magic();
print_debug("GRUB Default: $default");
}
my $section = undef;
# do we have a default?
if ($default >= 0) {
my @sections = Bootloader::Tools::GetSectionList();
print_debug("Number of sections: " . $#sections);
if ($#sections < 0 || $#sections < $default) {
print STDERR "WARNING: grubonce default number ($default) is invalid.\n";
print STDERR " Falling back to the default GRUB section.\n";
} else {
my $sect_name = $sections[$default];
$section = Bootloader::Tools::GetSection($sect_name);
}
}
# use the default section if we didn't get any default otherwise
if (!$section) {
$section = Bootloader::Tools::GetDefaultSection();
}
if (!$section) {
print STDERR "Unable to get default section of bootloader configuration.\n";
exit(1);
}
my $image=$section->{"image"};
my $initrd=$section->{"initrd"};
for my $file ($image, $initrd) {
# handle btfs /@ -> /
$file =~ s!^/@/!/!;
# handle /boot on separate partition
if($file !~ m!^/boot/! && ! -e $file && -e "/boot$file") {
$file="/boot$file"
}
}
if ($debug) {
print "Type : " . $section->{"type"}."\n";
print "Name : " . $section->{"name"}."\n";
print "Image : " . $image."\n";
print "Initrd : " . $initrd."\n";
print "VGA : " . $section->{"vgamode"}."\n";
print "Append : " . $section->{"append"}."\n";
print "Root : " . $section->{"root"}."\n";
}
if ($section->{"type"} ne "image") {
print STDERR "Default boot section is no image.\n";
exit(1);
}
# check if the image exists
if (! -f $image) {
print STDERR "Image '" . $image . "' does not exist.\n";
exit(1);
}
# check if the initrd exists
if ($initrd && ! -f $initrd) {
print STDERR "Initrd '" . $initrd . "' does not exist.\n";
exit(1);
}
# Do we have kexec?
if (system("which kexec &>/dev/null") != 0) {
print STDERR "kexec not available. Install kexec-tools.\n";
exit(1);
}
# build the command list
my $cmd = "kexec";
# append image
$cmd .= " -l '" . $image . "'";
# append initrd if available
if ($initrd) {
$cmd .= " --initrd='" . $initrd . "'";
}
# build append line
my $append = "";
if ($section->{"root"}) {
$append .= "root=" . $section->{"root"};
}
if ($section->{"vga"}) {
$append .= " vga=" . $section->{"vga"};
}
if ($section->{"append"}) {
$append .= " " . $section->{"append"};
}
# and tell that kexec
$cmd .= " --append='" . $append . "'";
print_debug("Kexec call: " . $cmd);
if (system($cmd) != 0) {
print STDERR "kexec($cmd) failed.";
exit(1);
}
exit(0);
# :vim set ts=4 sw=4 et fdm=markers: :collapseFolds=1: