summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAn-Cheng Huang <ancheng@vyatta.com>2009-11-09 18:33:33 -0800
committerAn-Cheng Huang <ancheng@vyatta.com>2009-11-09 18:33:33 -0800
commit367f7889599913817ace89ee0e2b28b1201e2bc8 (patch)
tree06e1b03c67509db63e80739d9ea2490c1da68031
parent03f9f80d8e15546af772261b01c061962d09a1c9 (diff)
downloadvyatta-op-367f7889599913817ace89ee0e2b28b1201e2bc8.tar.gz
vyatta-op-367f7889599913817ace89ee0e2b28b1201e2bc8.zip
add op command for image removal
-rwxr-xr-xscripts/vyatta-boot-image.pl198
-rw-r--r--templates/remove/installed-image/node.def2
2 files changed, 180 insertions, 20 deletions
diff --git a/scripts/vyatta-boot-image.pl b/scripts/vyatta-boot-image.pl
index 23dd7a0..7a4a85d 100755
--- a/scripts/vyatta-boot-image.pl
+++ b/scripts/vyatta-boot-image.pl
@@ -3,8 +3,12 @@
use strict;
use warnings;
use Getopt::Long;
+use File::Temp qw/ :mktemp /;
-my $UNION_GRUB_CFG = '/live/image/boot/grub/grub.cfg';
+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';
# this function parses the grub config file and returns a hash reference
# of the parsed data.
@@ -34,7 +38,7 @@ sub parseGrubCfg {
$ehash{'ver'} = $1;
} else {
# old install
- $ehash{'ver'} = 'Old non-image installation';
+ $ehash{'ver'} = $OLD_IMG_VER_STR;
}
if (/console=tty0.*console=ttyS0/) {
$ehash{'term'} = 'serial';
@@ -59,18 +63,75 @@ 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.
+sub deleteGrubEntries {
+ my ($del_ver) = @_;
+
+ my $rfd = undef;
+ return 'Cannot delete GRUB entries' if (!open($rfd, '<', $UNION_GRUB_CFG));
+ my ($wfd, $tfile) = mkstemp('/tmp/boot-image.XXXXXX');
+
+ my @entry = ();
+ my ($in_entry, $ver) = (0, 0);
+ while (<$rfd>) {
+ next if (/^$/); # ignore empty lines
+ if ($in_entry) {
+ if (/^}/) {
+ if ($ver ne $del_ver) {
+ # output entry
+ print $wfd "\n";
+ foreach my $l (@entry) {
+ print $wfd $l;
+ }
+ print $wfd "}\n";
+ }
+ $in_entry = 0;
+ $ver = 0;
+ @entry = ();
+ } else {
+ if (/^\s+linux \/boot\/([^\/ ]+)\/.* boot=live /) {
+ # kernel line
+ $ver = $1;
+ }
+ push @entry, $_;
+ }
+ } elsif (/^menuentry /) {
+ $in_entry = 1;
+ push @entry, $_;
+ } else {
+ print $wfd $_;
+ }
+ }
+ close($wfd);
+ close($rfd);
+
+ my $p = (stat($UNION_GRUB_CFG))[2];
+ return 'Failed to modify GRUB configuration'
+ if (!defined($p) || !chmod(($p & 07777), $tfile));
+ system("mv $tfile $UNION_GRUB_CFG");
+ return 'Failed to delete GRUB entries' if ($? >> 8);
+ 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.
sub getBootList {
- my ($dterm, $entries) = @_;
+ my ($dver, $dterm, $entries, $delete) = @_;
my %vhash = ();
my @list = ();
foreach (@{$entries}) {
my ($ver, $term) = ($_->{'ver'}, $_->{'term'});
+ # don't list non-image entry if deleting
+ next if (defined($delete) && $ver eq $OLD_IMG_VER_STR);
+ # 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
+
$vhash{$ver} = 1;
push @list, $_;
}
@@ -90,9 +151,10 @@ sub displayBootList {
}
}
-my ($show, $sel) = (undef, undef);
+my ($show, $del, $sel) = (undef, undef, undef);
GetOptions(
'show' => \$show,
+ 'delete' => \$del,
'select' => \$sel
);
@@ -108,37 +170,133 @@ if (!defined($def_idx) || !defined($entries)
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);
+my $bentries = getBootList($def_ver, $def_term, $entries, $del);
+if ($#{$bentries} < 0) {
+ print "No images found. Exiting...\n";
+ exit 1;
+}
-print "The system currently has the following images installed:\n\n";
+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 ($show); # show-only. done.
+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 'Select the default boot image: ';
+print "$prompt_msg";
my $resp = <STDIN>;
-if (!defined($resp) || !($resp =~ /^\d+$/) || ($resp < 1)
- || ($resp > ($#{$bentries} + 1))) {
- print "Invalid selection. Default is not changed. Exiting...\n";
+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;
-my $new_idx = ${$bentries}[$resp]->{'idx'};
-my $new_ver = ${$bentries}[$resp]->{'ver'};
-system("sed -i 's/^set default=.*\$/set default=$new_idx/' $UNION_GRUB_CFG");
-if ($? >> 8) {
- print "Failed to set the default boot image. Exiting...\n";
- exit 1;
+
+if ($sel) {
+ doSelect($resp);
+} elsif ($del) {
+ doDelete($resp);
}
-print <<EOF;
+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/' $UNION_GRUB_CFG");
+ if ($? >> 8) {
+ print "Failed to set the default boot image. Exiting...\n";
+ exit 1;
+ }
+ print <<EOF;
Default boot image has been set to "$new_ver".
You need to reboot the system to start the new default image.
EOF
-exit 0;
+ exit 0;
+}
+
+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;
+}
+
+sub doDelete {
+ my ($bdx) = @_;
+ my $del_ver = ${$bentries}[$resp]->{'ver'};
+ print "Are you sure you want to delete the\n\"$del_ver\" image? ";
+ print '(Yes/No) [No]: ';
+ my $resp = <STDIN>;
+ if (!defined($resp)) {
+ $resp = 'no';
+ }
+ chomp($resp);
+ $resp = lc($resp);
+ if ($resp ne 'yes') {
+ print "Image is NOT deleted. Exiting...\n";
+ 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/$del_ver") {
+ print "Cannot find the target image. Exiting...\n";
+ exit 1;
+ }
+
+ print "Deleting the \"$del_ver\" image...";
+ my $err = deleteGrubEntries($del_ver);
+ if (defined($err)) {
+ print "$err. Exiting...\n";
+ exit 1;
+ }
+ system("rm -rf '$UNION_BOOT/$del_ver'");
+ if ($? >> 8) {
+ print "Error deleting the image. Exiting...\n";
+ exit 1;
+ }
+
+ print "Done\n";
+ exit 0;
+}
diff --git a/templates/remove/installed-image/node.def b/templates/remove/installed-image/node.def
new file mode 100644
index 0000000..1d116e2
--- /dev/null
+++ b/templates/remove/installed-image/node.def
@@ -0,0 +1,2 @@
+help: Remove an installed image from the system
+run: sudo /opt/vyatta/bin/vyatta-boot-image.pl --delete