perl-Bootloader/update-bootloader

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:
#