#!/usr/bin/perl use lib qw(/usr/lib/libDrakX); use Getopt::Long; use common; use bootloader; $::isStandalone = 1; #- not using standalone which messes with @ARGV and usage $ENV{PATH} = "/sbin:/usr/sbin:$ENV{PATH}"; my %options = ( 'action=s' => \ (my $action), 'label=s' => \ (my $label), 'chainload=s' => \ (my $chainload), 'image=s' => \ (my $image), 'kernel-version=s' => \ (my $kernel_version), 'initrd-options=s' => \ (my $initrd_options), 'no-short-name' => \ (my $no_short_name), 'no-entry' => \ (my $no_entry), 'no-launch' => \ (my $no_launch), 'no-initrd' => \ (my $no_initrd), ); GetOptions(%options) && $action or die <<'EOF'; usage: bootloader-config --action add-kernel (--image <vmlinuz> | --kernel-version <2.6.xxx>) [--label <...>] [--no-short-name] [--initrd-options <options>] bootloader-config --action remove-kernel (--image <vmlinuz> | --kernel-version <2.6.xxx>) bootloader-config --action add-entry (--image <image> | --chainload <device>) --label <...> bootloader-config --action remove-entry (--image <image> | --chainload <device> | --label <...>) bootloader-config --action update-splash bootloader-config --action remove-splash EOF my @known_actions = qw(add-kernel remove-kernel update-splash remove-splash detectloader add-entry remove-entry); $action && member($action, @known_actions) or die "<action> must be one of " . join(' ', @known_actions) . "\n"; if ($image) { if (my $ver = bootloader::vmlinuz2version($image)) { if ($kernel_version) { $kernel_version eq $ver or die "$kernel_version and $ver do not match (hint: do not pass both --image and --kernel-version)\n"; } else { $kernel_version = $ver; } } $image = "/boot/$image" if $image !~ m!^/!; } elsif ($kernel_version) { $image = "/boot/vmlinuz-$kernel_version"; } my $all_hds = fsedit::get_hds(); fs::get_info_from_fstab($all_hds); my $bootloader = bootloader::read($all_hds) or die "Cannot find a boot loader installed\n"; $action =~ s/-/_/g; $::{$action}->(); #-############################################################################### sub remove_now_broken_boot_symlinks() { foreach (glob("/boot/vmlinuz*"), glob("/boot/initrd*")) { -l $_ && !-e $_ or next; log::l("removing now broken symlink $_"); unlink $_; } } sub remove_kernel() { unlink "/lib/modules/$kernel_version/build"; remove_now_broken_boot_symlinks(); my %proposed_labels; my @new_entries; my ($to_remove, $to_keep) = partition { if ($_->{kernel_or_dev} && $_->{kernel_or_dev} eq $image) { 1; } else { my $vmlinuz = $_->{kernel_or_dev} && bootloader::expand_vmlinuz_symlink($_->{kernel_or_dev}); if ($vmlinuz && "/boot/$vmlinuz" eq $image) { #- eg: removing kernel XXX and entry "linux" has /boot/vmlinuz -> vmlinuz-XXX #- so finding out which kernel still installed is better suited to use label "linux" if (!%proposed_labels) { %proposed_labels = bootloader::get_kernels_and_labels_before_kernel_remove($vmlinuz); } if (my $kernel_str = $proposed_labels{$_->{label}}) { push @new_entries, [ $kernel_str, $_ ]; } 1; } else { 0; } } } @{$bootloader->{entries}}; $_->{initrd} && unlink $_->{initrd} foreach @$to_remove; @{$bootloader->{entries}} = @$to_keep; foreach (@new_entries) { my ($kernel_str, $v) = @$_; bootloader::add_kernel($bootloader, $kernel_str, $v); } modify_bootloader(); } #-############################################################################### sub add_kernel() { bootloader::create_link_source(); my $kernel_str = bootloader::vmlinuz2kernel_str($image) or die "bad kernel name $image\n"; my $root_part = fs::get::root([ fs::get::fstab($all_hds) ]) or die "can not find root partition\n"; my %opts = ( root => fs::wild_device::from_part('', $root_part), initrd_options => $initrd_options, if_($label, label => $label), if_($bootloader->{default_vga}, vga => $bootloader->{default_vga}), ); #- short name bootloader::add_kernel($bootloader, $kernel_str, { %opts }, 0, $no_initrd) if !$no_short_name; #- long name $kernel_str->{use_long_name} = 1; bootloader::add_kernel($bootloader, $kernel_str, { %opts }, 1, $no_initrd); modify_bootloader(); } sub modify_bootloader() { !$no_entry or return; bootloader::action($bootloader, 'write', $all_hds); bootloader::action($bootloader, 'when_config_changed') if !$no_launch; } #-############################################################################### sub add_entry() { $label or die "you must give a label\n"; ($image xor $chainload) or die "you must give an image or a chainload\n"; my $entry = { type => $image ? 'image' : 'other', label => $label, kernel_or_dev => $image || $chainload, }; bootloader::add_entry($bootloader, $entry); modify_bootloader(); } sub remove_entry() { listlength(grep { $_ } $label, $image, $chainload) == 1 or die "you must give one of --label, --image and --chainload\n"; my $e = $label ? bootloader::get_label($label, $bootloader) : find { $_->{kernel_or_dev} && $_->{kernel_or_dev} eq ($image || $chainload) } @{$bootloader->{entries}}; if ($e) { @{$bootloader->{entries}} = grep { $_ != $e } @{$bootloader->{entries}}; } modify_bootloader(); } #-############################################################################### sub update_splash() { foreach (@{$bootloader->{entries}}) { bootloader::add_boot_splash($_->{initrd}, $_->{vga}) if $_->{initrd}; } bootloader::action($bootloader, 'when_config_changed') if !$no_launch; } sub remove_splash() { foreach (@{$bootloader->{entries}}) { bootloader::remove_boot_splash($_->{initrd}) if $_->{initrd}; } bootloader::action($bootloader, 'when_config_changed') if !$no_launch; } sub detectloader() { print uc(bootloader::main_method($bootloader->{method})), "\n" if $bootloader; }