Commit 1fdfe56f authored by Leigh B. Stoller's avatar Leigh B. Stoller
Browse files

The client side scripts to create and install a delta. The user runs

create-delta as root, and the setup scripts run install-delta. This
is going to be described in more detail in the tutorial.
parent 7aa1e29b
......@@ -23,6 +23,10 @@ install: $(INSTALL_SBINDIR)/split-image.sh
control-install:
@$(MAKE) -C imagezip install
client-install:
$(INSTALL_PROGRAM) create-delta /usr/local/bin/create-delta
$(INSTALL_PROGRAM) install-delta /usr/local/bin/install-delta
clean: subdir-clean
subdir-clean:
......
#!/usr/bin/perl -wT
use English;
use Getopt::Std;
#
# Create a delta
#
# usage: create-delta <destination filename>
#
# XXX - The destination filename must start with /proj.
# We dump per filesystem, which means a delta can be installed only
# on machines that look like the original wrt. partitions.
#
sub usage()
{
print STDOUT "Usage: create-delta <destination filename>\n";
exit(-1);
}
my $optlist = "";
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# No configure vars.
#
my $FSTAB = "/etc/fstab";
my $deltafile = "";
my $deltadir = ".";
my $indexfile = "delta.index";
my $template = "delta.dump";
my $dumpfile;
#
# Must be running as root to work.
#
if ($EUID != 0) {
die("Must be run as root! Try using sudo or su1!");
}
#
# 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 != 1) {
usage();
}
$deltafile = $ARGV[0];
#
# Untaint the arguments.
#
# Note different taint check (allow /).
if ($deltafile =~ /^([-\w.\/]+)$/) {
$deltafile = $1;
}
else {
fatal("Tainted tempfile name: $deltafile");
}
#
# Lets not overwrite an existing delta. Force user to move it.
#
if (-e $deltafile) {
fatal("$deltafile already exists. Please remove it first.");
}
#
# The delta file may only go into a /proj directory.
#
if (! ($deltafile =~ /^\/proj\//)) {
fatal("The destination file must reside in /proj");
}
#
# We need the directory the delta is going into so that we can create
# temporary files for each paritition dump.
#
if ($deltafile =~ /^(.+)\/.*$/) {
$deltadir = $1;
}
else {
fatal("Could not determine the directory component of $deltafile");
}
#
# Parse /etc/fstab to see what filesystems need to be dumped out.
# If the image was created properly, there will already be (better be)
# level 0 entries in the dumpdates file too.
#
my @fslist=();
open(TAB, "$FSTAB") or
fatal("Could not open $FSTAB: $!");
while (<TAB>) {
if ($_ =~ /^([\w\/]+)[\s]+([\w\/]+).*(\d).*\d$/) {
if ($3 != 0) {
push(@fslist, $2);
}
}
}
close(TAB);
#
# Chdir into the directory. Makes life easier.
#
chdir($deltadir) or
fatal("Could not chdir to $deltadir");
#
# Generate an index file. The first line of the index is our OSNAME, along
# with a (mostly) unique value to prevent multiple installations of the same
# delta. That would tend to mess people up, I would think. The rest of the
# index contains pairs of filesystem name and tarfile entry, so that the
# install script can find the right file in the tarball.
#
open(INDEX, ">$indexfile") or
fatal("Could not open $indexfile: $!");
#
# Form the identifier. Get some random numbers from /dev/urandom and run
# that into md5 (mostly to convert to an ascii string!).
#
my $ident;
if ($OSNAME eq "freebsd") {
$ident = `dd if=/dev/urandom bs=1b count=2 | md5`;
chop $ident;
}
elsif ($OSNAME eq "linux") {
my $res = `dd if=/dev/urandom bs=1b count=2 | md5sum`;
($ident,undef) = split(' ', $res);
}
else {
fatal("Could not generate a unique identifier!");
}
print INDEX "$OSNAME $ident\n";
my $count = 0;
foreach $fs (@fslist) {
print INDEX "$fs $template.$count\n";
$count++;
}
close(INDEX);
#
# Shove the index into the tar file, which also creates the tar file.
#
if (system("tar -cf $deltafile $indexfile")) {
fatal("Could not create initial delta file $deltafile\n");
}
#
# Now dump each filesystem to a temporary file.
#
$count = 0;
foreach $fs (@fslist) {
print "Gathering files on $fs ...\n";
$dumpfile = "$template.$count";
if (system("dump -1 -a -f - -b 64 $fs | gzip > $dumpfile")) {
fatal("Could not create dump of $fs");
}
#
# Check to make sure something happened.
#
if (-s $dumpfile <= 64) {
fatal("Dump for $fs is too small to be valid!");
}
#
# Append to the tar file.
#
if (system("tar -rf $deltafile $dumpfile")) {
fatal("Could not append dump for $fs to delta file $deltafile");
}
unlink("$dumpfile") or
fatal("Could not unlink $dumpfile");
$count++;
}
#
# Remove the temporaries.
#
unlink($indexfile);
exit 0;
sub fatal {
local($msg) = $_[0];
print STDERR "$msg\n";
exit(1);
}
#!/usr/bin/perl -wT
use English;
use Getopt::Std;
use POSIX 'setsid';
#
# Install a delta. This script is run from the setup code on client nodes.
#
# usage: install-delta <delta filename>
#
# Exit Value Matters!: 0 if delta installed.
# 1 if delta already installed
# -1 if something goes wrong.
#
# To ensure safety, the delta filename must start with /proj.
#
#
#
sub usage()
{
print STDOUT "Usage: install-delta <delta filename>\n";
exit(-1);
}
my $optlist = "";
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# No configure vars.
#
my $IDENTFILE = "/var/db/testbed.deltas";
my $deltafile = "";
my $indexfile = "delta.index";
my $dumpfile;
my %fslist = ();
my $os;
my $ident;
#
# Must be running as root to work.
#
if ($EUID != 0) {
die("Must be run as root! Try using sudo or su1!");
}
#
# 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 != 1) {
usage();
}
$deltafile = $ARGV[0];
#
# Untaint the arguments.
#
# Note different taint check (allow /).
if ($deltafile =~ /^([-\w.\/]+)$/) {
$deltafile = $1;
}
else {
fatal("Tainted tempfile name: $deltafile");
}
#
# The delta file may only come from a /proj directory.
#
if (! ($deltafile =~ /^\/proj\//)) {
fatal("The delta file must reside in /proj");
}
#
# Make sure its really there.
#
if (! -r $deltafile) {
fatal("$deltafile does not exist or is not accessible!");
}
#
# Suck out the index file from the tarball. This tells us how many
# partitions and where they belong. We use the -O option which tells
# tar to send the file to stdout so we can read it in from the pipe.
#
open(TAR, "tar Oxf $deltafile $indexfile |") or
fatal("Could not start tar to read index file");
my $first = 1;
while (<TAR>) {
my($fs, $fname);
chop;
#
# Untaint the beast.
#
if ($_ =~ /^([\w\/]+)\s*([\w.]+)$/) {
$fs = $1;
$fname = $2;
}
else {
fatal("Tainted index entry: $_");
}
#
# Get the OS and Key which are the first entry.
#
if ($first) {
$os = $fs;
$ident = $fname;
$first = 0;
next;
}
$fslist{$fs} = $fname;
}
close(TAR);
#
# Check that the OS is correct!
#
if ($os ne $OSNAME) {
fatal("This delta is not for $OSNAME. Its for $os.");
}
#
# Check to make sure this key has not already been installed. Update
# the file now. If the restore fails, we got big problems.
#
if (-e $IDENTFILE) {
if (! `egrep -q -s '^${ident}' $IDENTFILE`) {
print STDOUT "Delta $deltafile has already been installed!\n";
exit(1);
}
}
system("echo \"$ident\" >> $IDENTFILE") == 0 or
fatal("Could not update $IDENTFILE");
#
# Foreach partition, suck out the compressed dump file from the tarball,
# and run it into restore.
#
$count = 0;
foreach $fs (keys(%fslist)) {
$dumpfile = $fslist{$fs};
print "Installing files on $fs from $dumpfile\n";
chdir($fs) or
fatal("Could not chdir to $fs: $!");
#
# Big sigh. Restore opens /dev/tty to ask a silly y/n question.
# fork a child and disconnect it from /dev/tty (with setsid) so that
# restore will just blow by the question.
#
my $childpid = open(POOH, "-|");
if (! defined($childpid)) {
fatal("Could not fork child!");
}
if ($childpid) {
while (<POOH>) {
print $_;
}
close(POOH);
if ($? >> 8) {
fatal("Restore failed!");
}
}
else {
open(STDIN, "/dev/null") or
fatal("Cannot read /dev/null: $!");
open(STDERR, ">&STDOUT") or
fatal("Cannot dup stdout: $!");
$| = 1;
setsid() or
fatal("setsid failed: $!");
system("tar Oxf $deltafile $dumpfile | gunzip | restore -x -f - -y");
exit($? >> 8);
}
$count++;
}
exit(0);
sub fatal {
local($msg) = $_[0];
print STDERR "$msg\n";
exit(-1);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment