367 lines
8.3 KiB
Perl
367 lines
8.3 KiB
Perl
#! /usr/bin/perl
|
|
|
|
use POSIX;
|
|
use Getopt::Long;
|
|
use Pod::Usage;
|
|
use Bootloader::Tools;
|
|
use Locale::gettext;
|
|
use strict;
|
|
|
|
my %oper;
|
|
my ($opt_default, $opt_force, $opt_help, $opt_man, $opt_previous, $opt_xen)
|
|
= (0,0,0,0,0,0);
|
|
my ($opt_image, $opt_initrd, $opt_name, $opt_xen_name, $opt_failsafe, $opt_xen_kernel)
|
|
= ('','','','','',undef);
|
|
my $add_product = 0;
|
|
|
|
=head1 NAME
|
|
|
|
update-bootloader - update/change bootloader configuration using
|
|
Bootloader::Tools perl module
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
update-bootloader [operation] [options]
|
|
|
|
operation is one of --add, --remove or --refresh.
|
|
|
|
valid options are --help, --man, --image <file>, --initrd <file>,
|
|
--xen-kernel <file>, --xen, --default, --previous, --name <string>, --force.
|
|
|
|
=head1 OPERATIONS
|
|
|
|
=over 8
|
|
|
|
=item B<--add>
|
|
|
|
add an new image section.
|
|
Needs a call to --refresh to take effect.
|
|
|
|
=item B<--remove>
|
|
|
|
remove the specified image section.
|
|
Needs a call to --refresh to take effect.
|
|
|
|
=item B<--refresh>
|
|
|
|
activate the new config e.g. write boot loader to disk
|
|
|
|
|
|
=head1 PARAMETER
|
|
|
|
=item B<--help>
|
|
|
|
Print a brief help message and exits.
|
|
|
|
=item B<--man>
|
|
|
|
Prints the manual page and exits.
|
|
|
|
=item B<--image> F<file>
|
|
|
|
specify path to kernel image
|
|
|
|
=item B<--initrd> F<file>
|
|
|
|
specify path to initrd file
|
|
|
|
=item B<--xen>
|
|
|
|
specify that you what to add a xen and not a regular image section
|
|
|
|
=item B<--xen-kernel> F<file>
|
|
|
|
specify that you what to add a xen section with a specific image.
|
|
Implies --xen option.
|
|
|
|
=item B<--default>
|
|
|
|
let the new section to be added be the default section if appropriate. Only
|
|
allowed together with --add operation
|
|
|
|
=item B<--previous>
|
|
|
|
set some usuable defaults for image, initrd and name when
|
|
|
|
=item B<--name> F<string>
|
|
|
|
specify the name of the section to be added/removed
|
|
|
|
=item B<--force>
|
|
|
|
dont complain, just do the right thing
|
|
|
|
=back
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
B<update-bootloader> will let you modify your bootloader configuration using
|
|
Bootloader::Tools perl module.
|
|
|
|
=cut
|
|
|
|
# Get product name and version
|
|
# FIXME: There is still no guaranteed-to-work solution
|
|
# FIXME: as Commandline:: always prints to stderr, which is risky
|
|
# FIXME: to get garbage.
|
|
# If Commandline:: prints garbage, use /etc/SuSE-release instead
|
|
|
|
sub GetProduct {
|
|
my $namever;
|
|
|
|
# First try: Does yast work these days?
|
|
$namever = `yast2 print-product 2>&1`;
|
|
chomp $namever;
|
|
|
|
# Determine the bootloader type, because long product names may only
|
|
# be used in case of grub
|
|
my $loader = Bootloader::Tools::GetBootloader();
|
|
|
|
# Substitude whitespaces with an underscore
|
|
if ($loader ne "grub") {
|
|
$namever =~ s/\s/_/;
|
|
}
|
|
return "$namever" if $namever ne '' and $namever !~ /\n/;
|
|
|
|
# Second try: Is there a usable /etc/SuSE-release?
|
|
if (open(RELEASE, "</etc/SuSE-release") && $loader eq "grub") {
|
|
# first line is sufficient
|
|
$namever = <RELEASE>;
|
|
|
|
# delete everything starting with the first parenthesis
|
|
$namever =~ s/\s*\(.*//;
|
|
|
|
close(RELEASE);
|
|
chomp $namever;
|
|
return "$namever";
|
|
}
|
|
|
|
# the last line of defense ...
|
|
return "Linux";
|
|
}
|
|
|
|
|
|
GetOptions (\%oper,
|
|
'add|a' ,
|
|
'refresh' ,
|
|
'remove|r' ,
|
|
'default|d' => \$opt_default,
|
|
'help|h' => \$opt_help,
|
|
'force' => \$opt_force,
|
|
'image=s' => \$opt_image,
|
|
'initrd=s' => \$opt_initrd,
|
|
'man|m' => \$opt_man,
|
|
'xen' => \$opt_xen,
|
|
'xen-kernel=s' => \$opt_xen_kernel,
|
|
'name=s' => \$opt_name,
|
|
'previous|p' => \$opt_previous)
|
|
or pod2usage(2);
|
|
pod2usage(1) if $opt_help;
|
|
pod2usage(-exitstatus => 0, -verbose => 2) if $opt_man;
|
|
|
|
pod2usage("Specify exactly one operation, either 'add', 'remove' or 'refresh'")
|
|
unless scalar keys(%oper) == 1;
|
|
|
|
pod2usage("Option 'default' is only allowed for operation 'add'")
|
|
if ($opt_default and not defined $oper{add});
|
|
|
|
if ($opt_image and $opt_image !~ m;^/;) {
|
|
$opt_image = getcwd . '/' . $opt_image
|
|
}
|
|
if ($opt_initrd and $opt_initrd !~ m;^/;) {
|
|
$opt_initrd = getcwd . '/' . $opt_initrd;
|
|
}
|
|
|
|
if (defined $opt_xen_kernel) {
|
|
$opt_xen = 1;
|
|
} elsif ($opt_xen) {
|
|
$opt_xen_kernel = "/boot/xen.gz";
|
|
}
|
|
my $type = $opt_xen ? "xen" : "image";
|
|
|
|
InitLibrary();
|
|
|
|
|
|
if ($opt_previous) {
|
|
unless ($opt_image) {
|
|
$opt_image = GetDefaultImage() . ".previous";
|
|
}
|
|
unless($opt_initrd) {
|
|
$opt_initrd = GetDefaultInitrd() . ".previous";
|
|
}
|
|
}
|
|
|
|
# FIXME: these section names should be unified somehow together with multi
|
|
# language and grafical menu handling
|
|
if (defined $oper{add}) {
|
|
my $loader = Bootloader::Tools::GetBootloader();
|
|
|
|
unless ($opt_name) {
|
|
if ($opt_xen and $opt_previous) {
|
|
if ($loader eq "grub" || $loader eq "lilo") {
|
|
$opt_name = "Previous Xen";
|
|
$add_product = 1;
|
|
}
|
|
else {
|
|
$opt_name = "previous xen";
|
|
}
|
|
}
|
|
elsif ($opt_xen) {
|
|
if ($loader eq "grub" || $loader eq "lilo") {
|
|
$opt_name = "Xen";
|
|
$add_product = 1;
|
|
}
|
|
else {
|
|
$opt_name = "xen";
|
|
}
|
|
}
|
|
elsif ($opt_previous) {
|
|
if ($loader eq "grub" || $loader eq "lilo") {
|
|
$opt_name = "Previous Kernel";
|
|
$add_product = 1;
|
|
}
|
|
else {
|
|
$opt_name = "previous";
|
|
}
|
|
}
|
|
else {
|
|
$opt_name = $opt_image;
|
|
$opt_name =~ s/.*\///;
|
|
}
|
|
}
|
|
|
|
# only localize on grub and lilo
|
|
if ($loader eq "grub" || $loader eq "lilo") {
|
|
setlocale(LC_MESSAGES, Bootloader::Tools::GetSystemLanguage());
|
|
|
|
my $d = Locale::gettext->domain("bootloader");
|
|
$d->dir("/usr/share/YaST2/locale");
|
|
my $opt_trans = $d->get($opt_name);
|
|
chomp ($opt_trans);
|
|
|
|
# check whether translation only contains [a-zA-Z0-9 _]
|
|
# otherwise fall back to untranslated string
|
|
if ($opt_trans =~ /^[a-zA-Z\d _]+$/g ) {
|
|
$opt_name = $opt_trans;
|
|
}
|
|
}
|
|
|
|
# Naming scheme for default, smp and bigsmp kernels
|
|
if (($opt_name =~ /.*-default$/) ||
|
|
($opt_name =~ /.*-smp$/) ||
|
|
($opt_name =~ /.*-bigsmp$/)) {
|
|
|
|
if ($loader eq "grub") {
|
|
$opt_name =~ s/-[^-]*$//;
|
|
$opt_failsafe = "Failsafe -- " . $opt_name;
|
|
$opt_name = GetProduct() . " -- " . $opt_name;
|
|
}
|
|
else {
|
|
$opt_failsafe = "Failsafe";
|
|
$opt_name = GetProduct();
|
|
}
|
|
}
|
|
# Naming scheme for all xen kernels, thus xen and xenpae
|
|
elsif ($opt_xen) {
|
|
if ($loader eq "grub") {
|
|
$opt_name =~ s/-xen.*$//;
|
|
$opt_xen_name = "Xen -- " . GetProduct() . " - " . $opt_name;
|
|
}
|
|
else {
|
|
$opt_name = "Xen";
|
|
}
|
|
}
|
|
# Naming scheme for all other kernels
|
|
else {
|
|
if ($loader eq "grub") {
|
|
$opt_name = GetProduct() if $add_product;
|
|
}
|
|
else {
|
|
$opt_name .= " -- " . GetProduct() if $add_product;
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# execute selected operation
|
|
#
|
|
if (defined $oper{add}) {
|
|
pod2usage("Please specify name and kernel image for new section")
|
|
unless $opt_name and $opt_image;
|
|
|
|
my @params = (
|
|
type => $type,
|
|
image => $opt_image,
|
|
);
|
|
if (CountSections(@params) != 0) {
|
|
if (not $opt_force) {
|
|
pod2usage("There are already sections with image '$opt_image'");
|
|
}
|
|
} else {
|
|
# FIXME: Subject of change (depending on how the weather is)
|
|
# only add default if "appropriate"
|
|
# meaning now flavor of current default matches new one
|
|
#my $flavor = GetDefaultImage();
|
|
#$flavor =~ s/^.*-//;
|
|
#
|
|
#if ($opt_image =~ m/.*-${flavor}$/) {
|
|
# push @params, default => $opt_default;
|
|
#}
|
|
push @params, xen => $opt_xen_kernel if $type eq "xen";
|
|
push @params, initrd => $opt_initrd if $opt_initrd;
|
|
|
|
if ($opt_xen) {
|
|
# Add "xen" section
|
|
AddSection($opt_xen_name, @params);
|
|
}
|
|
else {
|
|
# Add "normal" sections
|
|
AddSection($opt_name, @params);
|
|
}
|
|
|
|
my $arch = `uname --hardware-platform`;
|
|
chomp ($arch);
|
|
|
|
# Add a "Failsafe" section
|
|
if ((($arch eq "i386") || ($arch eq "x86_64") || ($arch eq "ia64"))
|
|
&& $opt_xen != 1) {
|
|
AddSection($opt_failsafe, @params);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (defined $oper{remove}) {
|
|
my @params = (
|
|
type => $type,
|
|
image => $opt_image,
|
|
);
|
|
push @params, xen => $opt_xen_kernel if $type eq "xen";
|
|
push @params, initrd => $opt_initrd if $opt_initrd;
|
|
push @params, name => $opt_name if $opt_name;
|
|
|
|
my $num = CountSections(@params);
|
|
|
|
if ($num > 0) {
|
|
if ($num > 1 and not $opt_force) {
|
|
pod2usage("There is more than one section with image '$opt_image'");
|
|
} else {
|
|
RemoveSections(@params);
|
|
}
|
|
} elsif (not $opt_force) {
|
|
pod2usage("There is no section with image '$opt_image'");
|
|
}
|
|
}
|
|
|
|
if (defined $oper{refresh}) {
|
|
UpdateBootloader();
|
|
}
|
|
|
|
#
|
|
# Local variables:
|
|
# mode: perl
|
|
# mode: font-lock
|
|
# mode: auto-fill
|
|
# fill-column: 78
|
|
# End:
|
|
#
|