#!/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); } # 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: