create-swapimage 5.75 KB
Newer Older
1 2 3 4
#!/usr/bin/perl -wT

#
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file 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 Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
#

use English;
use Getopt::Std;

#
# Create a swapout-time disk image.  By default, we save an incremental
# image based on the image signature.  Use -f to create a full image.
# Caller must have sudo permission!
#
# XXX for now, all the arguments are intuited (instead of using tmcc).
# XXX we should probably save the old swap image in case of failure.
#
sub usage()
{
39
    print STDOUT "Usage: create-swapimage [-fs]\n";
40 41
    exit(-1);
}
42
my  $optlist = "fs";
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

#
# Turn off line buffering on output
#
$| = 1;

# Drag in path stuff so we can find emulab stuff.
BEGIN { require "/etc/emulab/paths.pm"; import emulabpaths; }

#
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself. 
# 
use libsetup;

my $debug = 1;
my $me = "create-swapimage";

#
# No configure vars.
#
my $sudo   = "/usr/local/bin/sudo";
my $zipperdir = "/usr/local/bin";
my $zipperbin = "imagezip";
my $zipper = "$zipperdir/$zipperbin";
my $device;
my $filename;
my $fullimage = 0;
71
my $statsonly = 0;
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
my $args = "";

#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
if (@ARGV > 0) {
    usage();
}
if ($options{"f"}) {
    $fullimage = 1;
}
88 89 90
if ($options{"s"}) {
    $statsonly = 1;
}
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

my ($pid, $eid, $vname) = check_nickname();
if (!defined($eid)) {
    die("Node is not allocated!?");
}
if (!chdir("/proj/$pid/exp/$eid/swapinfo")) {
    die("Swapinfo directory for $pid/$eid does not exist!");
}
if (! -r "$vname.part" || (! $fullimage && ! -r "$vname.sig")) {
    die("Swapinfo signature/partition info for $pid/$eid does not exist!");
}

$args = "-H $vname.sig"
    if (!$fullimage);

106 107 108
$args .= " -i"
    if ($statsonly);

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
my $info = `cat $vname.part`;
if ($info !~ /DISK=(\w+) LOADPART=([0-4]) BOOTPART=([1-4])/) {
    die("Swapinfo partition info for $pid/$eid is malformed!");
}
$device = "/dev/$1";
$lpart = $2;
$bpart = $3;
$filename = "$vname-swap.ndz";

print STDERR "$me: device=$device, loadpart=$lpart, bootpart=$bpart\n"
    if ($debug);

#
# XXX For now we just use the load partition to dictate what we save.
#
# In the case where LOADPART=0, meaning a whole-disk image, we are almost
# certainly saving more than we care about.  Chances are that when swapping
# in, the user specified one of the standard OSes which is part of the whole
# disk image that is loaded on the disk by default.  In this case we will be
# saving the entire disk, even though they probably only care about the
# partition they are running from.  Technically, this is the correct thing
# to do, since they could have (re)used the other partitions and we will
# want to pick up those changes.  However, most of the time they probably
# haven't done anything to the rest of the disk and we are just waiting time
# scanning the entire disk (though the resulting image will not be any larger).
#
# So, the boot partition is passed in just in case we someday want to
# distinguish this case.  What we could (should?) do, is add an OTHERPARTS=
# field to the file to give us a list of partitions that are active.  Then
# we would always do a full-disk image but construct a list of -I options to
# ignore the inactive partitions.
#
if ($lpart != 0) {
    $args .= " -s $lpart";
}

145 146 147 148 149 150 151 152 153 154 155 156 157 158
my $ofilename = "";
if (!$statsonly) {
    #
    # Save the old swap image if it exists, both as a backup and so that the
    # imagefile size starts at zero for the benefit of monitoring processes.
    #
    my $ofilename = "$filename.OLD";
    if (-e $filename) {
	unlink($ofilename);
	if (!rename($filename, $ofilename)) {
	    warn("$me: could not back up old image, clobbering it!");
	    unlink($filename);
	    $ofilename = "";
	}
159 160
    }

161 162 163 164 165 166
    #
    # Create the new file now so it is owned by the user and not root
    #
    if (!open(FILE, "> $filename") || !close(FILE)) {
	goto failed;
    }
167 168
}

169 170 171 172 173 174 175 176 177 178
#
# XXX tmp hack: see if there is a newer version of the image zipper.
# This way we do not have to update the admin MFS everytime we want to
# try a new debugger, making it easier in the debugging phase.
#
if (-x "/proj/$pid/bin/$zipperbin") {
    $zipper = "/proj/$pid/bin/$zipperbin";
    warn("$me: using alternate zipper $zipper\n");
}

179 180 181 182
mkdir("logs")
    if (! -d "logs");
my $logfile = "logs/imagezip.$vname." . time();

183 184 185 186 187
#
# Run the command using sudo, since by definition only testbed users
# with proper trust should be able to zip up a disk. sudo will fail
# if the user is not in the proper group.
#
188
print STDERR "$me: doing '$sudo $zipper $args $device $filename >$logfile'\n"
189
    if ($debug);
190
if (system("$sudo $zipper $args $device $filename >$logfile 2>&1") == 0) {
191 192 193
    #
    # Get rid of the backup image
    #
194
    if ($ofilename ne "") {
195
	unlink($ofilename);
196
    }
197
    exit 0;
198 199
}

200 201
failed:
print STDERR "*** Failed to create image $filename!\n";
202
if ($ofilename ne "") {
203 204 205
    print STDERR "    Restoring old image\n";
    rename($ofilename, $filename) or
	warn("    Could not restore old image file!\n");
206
}
207
exit 1;