summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/vyatta-boot-image.pl370
1 files changed, 247 insertions, 123 deletions
diff --git a/scripts/vyatta-boot-image.pl b/scripts/vyatta-boot-image.pl
index 8b8a19a..304f35c 100755
--- a/scripts/vyatta-boot-image.pl
+++ b/scripts/vyatta-boot-image.pl
@@ -1,20 +1,54 @@
#!/usr/bin/perl
+# **** License ****
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# 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.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: An-Cheng Huang, Bob Gilligan
+# Date: January, 2010
+# Description: Script to manage system images. Provides the ability to
+# display status of images, select the default image to boot, and
+# to delete images.
+#
+# **** End License ****
+
use strict;
use warnings;
use Getopt::Long;
use File::Temp qw/ :mktemp /;
+#
+# Constants
+#
my $UNION_BOOT = '/live/image/boot';
my $UNION_GRUB_CFG = "$UNION_BOOT/grub/grub.cfg";
my $VER_FILE = '/opt/vyatta/etc/version';
my $OLD_IMG_VER_STR = 'Old-non-image-installation';
my $OLD_GRUB_CFG = '/boot/grub/grub.cfg';
my $DISK_BOOT = '/boot';
-my $grub_cfg;
-# this function parses the grub config file and returns a hash reference
-# of the parsed data.
+#
+# Globals
+#
+my $grub_cfg; # Pathname of grub config file we will use.
+
+# This function parses the grub config file and returns a hash array
+# of the parsed data. There is one element of the array for each grub
+# config file entry. Each element is a hash that contains: The "index" of
+# entry in the grub config file, the "version" string of the entry, the
+# "terminal type" of the entry -- "kvm" or "serisl", and a flag indicating
+# whether the entry is a "lost password reset" boot menu item.
+#
sub parseGrubCfg {
my $fd = undef;
return undef if (!open($fd, '<', $grub_cfg));
@@ -66,8 +100,10 @@ sub parseGrubCfg {
return \%ghash;
}
-# this function deletes the entries for the specified version from the grub
-# config file. returns undef if successful. otherwise returns error message.
+# This function deletes the entries for the specified version from the grub
+# config file. returns undef if successful. Otherwise it returns an
+# error message.
+#
sub deleteGrubEntries {
my ($del_ver) = @_;
@@ -121,18 +157,17 @@ sub deleteGrubEntries {
return undef;
}
-# this function takes the default terminal type and a list of all entries
-# and returns the "boot list", i.e., the list for user to select which one
-# to boot.
+# This function takes the default terminal type and a list of all grub
+# config file entries as generated by parseGrubConfig() and returns
+# the "boot list". This list contains one entry for each image
+# version.
+#
sub getBootList {
- my ($dver, $dterm, $entries, $delete) = @_;
+ my ($dterm, $entries) = @_;
my %vhash = ();
my @list = ();
foreach (@{$entries}) {
my ($ver, $term) = ($_->{'ver'}, $_->{'term'});
- # don't list default entry if deleting
- next if (defined($delete) && $ver eq $dver);
-
next if ($_->{'reset'}); # skip password reset entry
next if ($term ne $dterm); # not the default terminal
next if (defined($vhash{$ver})); # version already in list
@@ -143,105 +178,39 @@ sub getBootList {
return \@list;
}
+# Prints the boot list generated by getBootList().
+#
sub displayBootList {
my ($didx, $entries) = @_;
+ my $running_ver = curVer();
for my $i (0 .. $#{$entries}) {
my $di = $i + 1;
- my $ver = ${$entries}[$i]->{'ver'};
+ my $ver = $ {$entries}[$i]->{'ver'};
my $m = '';
- if ($didx == ${$entries}[$i]->{'idx'}) {
+ if ($didx == $ {$entries}[$i]->{'idx'}) {
$m = ' (default boot)';
}
+
+ if ($ver eq $running_ver) {
+ $m .= ' (running version)';
+ }
+
printf " %2d: %s%s\n", $di, $ver, $m;
}
}
-my ($show, $del, $sel) = (undef, undef, undef);
-GetOptions(
- 'show' => \$show,
- 'delete' => \$del,
- 'select' => \$sel
-);
-
-
-if (-e $UNION_GRUB_CFG) {
- $grub_cfg = $UNION_GRUB_CFG;
-} elsif (-e $OLD_GRUB_CFG) {
- $grub_cfg = $OLD_GRUB_CFG;
-} else {
- print "Can not open Grub config file\n";
- exit 1;
-}
-
-
-my $gref = parseGrubCfg();
-if (!defined($gref)) {
- print "Cannot find GRUB configuration file. Exiting...\n";
- exit 1;
-}
-my $def_idx = $gref->{'default'};
-my $entries = $gref->{'entries'};
-if (!defined($def_idx) || !defined($entries)
- || !defined(${$entries}[$def_idx])) {
- print "Error parsing GRUB configuration file. Exiting...\n";
- exit 1;
-}
-my $def_ver = ${$entries}[$def_idx]->{'ver'};
-my $def_term = ${$entries}[$def_idx]->{'term'};
-
-my $bentries = getBootList($def_ver, $def_term, $entries, $del);
-if ($#{$bentries} < 0) {
- print "No images found. Exiting...\n";
- exit 1;
-}
-
-my $msg = 'The system currently has the following image(s) installed:';
-if (defined($del)) {
- # doing delete
- $msg = 'The following image(s) can be deleted:';
-}
-print "$msg\n\n";
-displayBootList($def_idx, $bentries);
-print "\n";
-
-exit 0 if (defined($show) || (!defined($sel) && !defined($del))); # show-only
-
-# for doing select
-my $prompt_msg = 'Select the default boot image: ';
-my $error_msg = 'Invalid selection. Default is not changed.';
-if ($del) {
- # doing delete
- $prompt_msg = 'Select the image to delete: ';
- $error_msg = 'Invalid selection. Nothing is deleted.';
-}
-
-print "$prompt_msg";
-my $resp = <STDIN>;
-if (defined($resp)) {
- chomp($resp);
- if (!($resp =~ /^\d+$/) || ($resp < 1) || ($resp > ($#{$bentries} + 1))) {
- $resp = undef;
+# Sets the grub config file default pointer to the boot list entry
+# number passed in.
+#
+sub doSelect {
+ my ($resp, $def_ver, $bentries) = @_;
+ my $new_idx = $ {$bentries}[$resp]->{'idx'};
+ my $new_ver = $ {$bentries}[$resp]->{'ver'};
+ if ($new_ver eq $def_ver) {
+ print "The default boot image has not been changed.\n";
+ exit 0;
}
-}
-if (!defined($resp)) {
- print "$error_msg Exiting...\n";
- exit 1;
-}
-print "\n";
-
-$resp -= 1;
-if ($sel) {
- doSelect($resp);
-} elsif ($del) {
- doDelete($resp);
-}
-exit 0;
-
-sub doSelect {
- my ($bdx) = @_;
- my $new_idx = ${$bentries}[$resp]->{'idx'};
- my $new_ver = ${$bentries}[$resp]->{'ver'};
system("sed -i 's/^set default=.*\$/set default=$new_idx/' $grub_cfg");
if ($? >> 8) {
print "Failed to set the default boot image. Exiting...\n";
@@ -255,18 +224,71 @@ EOF
exit 0;
}
+# Set the grub default pointer to the entry whose name is passed in
+#
+sub select_by_name {
+ my ($new_def_ver, $def_term) = @_;
+ my $def_index;
+
+ # Re-scan the the grub config file to get the current indexes
+ # of each entry.
+ my $gref = parseGrubCfg();
+ if (!defined($gref)) {
+ print "Cannot parse GRUB configuration file. Exiting...\n";
+ exit 1;
+ }
+
+ # Find the entry that matches the new default version
+ my $entries = $gref->{'entries'};
+ my $entry;
+ foreach $entry (@{$entries}) {
+ # Skip entries that are not using the same term type as before
+ next if ($entry->{'term'} ne $def_term);
+ # Skip the password reset entries
+ next if ($entry->{'reset'});
+ if ($entry->{'ver'} eq $new_def_ver) {
+ $def_index = $entry->{'idx'};
+ last;
+ }
+ }
+
+ if (!defined($def_index)) {
+ print "Can't find entry for $new_def_ver in grub config file.\n";
+ exit 1;
+ }
+
+ # Set default pointer in grub config file to point to the new
+ # default version.
+ system("sed -i 's/^set default=.*\$/set default=$def_index/' $grub_cfg");
+ if ($? >> 8) {
+ print "Failed to set the default boot image. Exiting...\n";
+ exit 1;
+ }
+}
+
+# Returns the version string of the currently running system.
+#
sub curVer {
- my ($fd, $ver) = (undef, undef);
- open($fd, '<', $VER_FILE) or return undef;
- while (<$fd>) {
- next if (!(/^Version\s+:\s+(\S+)$/));
- $ver = $1;
- last;
- }
- close($fd);
- return $ver;
+ my ($fd, $ver) = (undef, undef);
+
+ my $image_boot = `grep -e '^unionfs / unionfs.*squashfs=ro' /proc/mounts`;
+ if ($image_boot ne "") {
+ open($fd, '<', $VER_FILE) or return undef;
+ while (<$fd>) {
+ next if (!(/^Version\s+:\s+(\S+)$/));
+ $ver = $1;
+ last;
+ }
+ close($fd);
+ } else {
+ $ver = $OLD_IMG_VER_STR;
+ }
+ return $ver;
}
+# Deletes all of the files belonging to the disk-based non-image
+# installation.
+#
sub del_non_image_files {
my $logfile="/var/log/vyatta/disk-image-del-";
$logfile .= `date +%F-%T`;
@@ -290,14 +312,30 @@ sub del_non_image_files {
}
+# Takes the boot list entry number selected by the user and deletes
+# the corresponding image. Deletes all of the grub config file entries
+# associated with that image and deletes the files associated
+# with that entry.
+#
sub doDelete {
- my ($bdx) = @_;
- my $del_ver = ${$bentries}[$resp]->{'ver'};
+ my ($resp, $orig_def_ver, $def_ter, $bentries) = @_;
+ my $del_ver = $ {$bentries}[$resp]->{'ver'};
my $boot_dir;
+ my $cver = curVer();
+ if (!defined($cver)) {
+ print "Cannot verify current version. Exiting...\n";
+ exit 1;
+ }
+ if ($cver eq $del_ver) {
+ print "Cannot delete current running image. Reboot into a different\n";
+ print "image to delete this image. Exiting...\n";
+ exit 1;
+ }
+
print "Are you sure you want to delete the\n\"$del_ver\" image? ";
print '(Yes/No) [No]: ';
- my $resp = <STDIN>;
+ $resp = <STDIN>;
if (!defined($resp)) {
$resp = 'no';
}
@@ -308,19 +346,6 @@ sub doDelete {
exit 1;
}
- my $cver = curVer();
- if (!defined($cver)) {
- print "Cannot verify current version. Exiting...\n";
- exit 1;
- }
- if ($cver eq $del_ver) {
- print <<EOF;
-Cannot delete current running image. Reboot into a different version
-before deleting. Exiting...
-EOF
- exit 1;
- }
-
if (-d $UNION_BOOT) {
$boot_dir = $UNION_BOOT;
} elsif (-d $DISK_BOOT) {
@@ -350,6 +375,105 @@ EOF
}
print "Done\n";
+
+ # Need to reset the grub default pointer becuase entry before default
+ # may have been deleted, or the default entry itself may have
+ # been deleted.
+ if ($del_ver eq $orig_def_ver) {
+ select_by_name($cver, $def_ter);
+ print "The default image has been changed to the currently running image:\n";
+ print "$cver\n";
+ } else {
+ select_by_name($orig_def_ver, $def_ter);
+ }
+
exit 0;
}
+#
+# Main section
+#
+
+my ($show, $del, $sel) = (undef, undef, undef);
+
+GetOptions(
+ 'show' => \$show,
+ 'delete' => \$del,
+ 'select' => \$sel
+);
+
+if (-e $UNION_GRUB_CFG) {
+ $grub_cfg = $UNION_GRUB_CFG;
+} elsif (-e $OLD_GRUB_CFG) {
+ $grub_cfg = $OLD_GRUB_CFG;
+} else {
+ print "Can not open Grub config file\n";
+ exit 1;
+}
+
+my $gref = parseGrubCfg();
+if (!defined($gref)) {
+ print "Cannot find GRUB configuration file. Exiting...\n";
+ exit 1;
+}
+
+my $def_idx = $gref->{'default'};
+my $entries = $gref->{'entries'};
+if (!defined($def_idx) || !defined($entries)
+ || !defined(${$entries}[$def_idx])) {
+ print "Error parsing GRUB configuration file. Exiting...\n";
+ exit 1;
+}
+my $def_ver = ${$entries}[$def_idx]->{'ver'};
+my $def_term = ${$entries}[$def_idx]->{'term'};
+
+my $bentries = getBootList($def_term, $entries);
+if ($#{$bentries} < 0) {
+ print "No images found. Exiting...\n";
+ exit 1;
+}
+
+my $msg = 'The system currently has the following image(s) installed:';
+if (defined($del)) {
+ # doing delete
+ $msg = 'The following image(s) can be deleted:';
+}
+print "$msg\n\n";
+displayBootList($def_idx, $bentries);
+print "\n";
+
+exit 0 if (defined($show) || (!defined($sel) && !defined($del))); # show-only
+
+# for doing select
+my $prompt_msg = 'Select the default boot image: ';
+my $error_msg = 'Invalid selection. Default is not changed.';
+if ($del) {
+ # doing delete
+ $prompt_msg = 'Select the image to delete: ';
+ $error_msg = 'Invalid selection. Nothing is deleted.';
+}
+
+print "$prompt_msg";
+my $resp = <STDIN>;
+if (defined($resp)) {
+ chomp($resp);
+ if (!($resp =~ /^\d+$/) || ($resp < 1) || ($resp > ($#{$bentries} + 1))) {
+ $resp = undef;
+ }
+}
+if (!defined($resp)) {
+ print "$error_msg Exiting...\n";
+ exit 1;
+}
+print "\n";
+
+$resp -= 1;
+
+if ($sel) {
+ doSelect($resp, $def_ver, $bentries);
+} elsif ($del) {
+ doDelete($resp, $def_ver, $def_term, $bentries);
+}
+
+exit 0;
+