diff options
author | An-Cheng Huang <ancheng@vyatta.com> | 2009-11-09 18:33:33 -0800 |
---|---|---|
committer | An-Cheng Huang <ancheng@vyatta.com> | 2009-11-09 18:33:33 -0800 |
commit | 367f7889599913817ace89ee0e2b28b1201e2bc8 (patch) | |
tree | 06e1b03c67509db63e80739d9ea2490c1da68031 | |
parent | 03f9f80d8e15546af772261b01c061962d09a1c9 (diff) | |
download | vyatta-op-367f7889599913817ace89ee0e2b28b1201e2bc8.tar.gz vyatta-op-367f7889599913817ace89ee0e2b28b1201e2bc8.zip |
add op command for image removal
-rwxr-xr-x | scripts/vyatta-boot-image.pl | 198 | ||||
-rw-r--r-- | templates/remove/installed-image/node.def | 2 |
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 |