install-tarfile 7.13 KB
Newer Older
1
#!/usr/bin/perl -wT
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
3
4

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
6
7
8
# All rights reserved.
#

9
10
11
12
use English;
use Getopt::Std;
use POSIX 'setsid';

13
14
15
16
# Drag in path stuff so we can find emulab stuff.
# XXX Temporary until I have the new tmcc library finished!
BEGIN { require "/etc/emulab/paths.pm"; import emulabpaths; }

17
18
#
# Install a tarfile. This script is run from the setup code on client nodes.
19
20
21
# By default the tarfile is accessed directly via NFS, if '-c' is specified
# the tar file is copied over first either via NFS (the default) or tmcc
# (-t option).
22
23
24
25
26
#
# Exit Value Matters!: 0 if installed okay
#                      1 if already installed
#                     -1 if something goes wrong.
#
27
28
# To ensure safety, the tar filename must start with /proj, except if
# running with jail option. Must be run as root.
29
30
31
#
sub usage()
{
32
33
    print STDOUT "Usage: install-tarfile [-d] [-ct] [-n nodeid] <installdir> ".
	"<filename>\n";
34
35
    exit(-1);
}
36
my $optlist  = "cdtn:";
37
38
39
40
41
42
43

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

#
44
# Untaint env.
45
46
47
48
49
50
51
52
53
54
# 
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

#
# No configure vars.
#
my $IDENTFILE      = "/var/db/testbed.tarfiles";
my $tarfile        = "";
my $decompressflag = "";
my $installdir     = "/";
55
my $usewget	   = 0;
56
my $copymode	   = 0;
57
58
59
60
61
62
63
64
65
66
my $debug	   = 0;
my $copyfile;
my $nodeid;
my $keyhash;

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

68
# Protos
69
sub GetTarFile($$$);
70

71
72
73
74
#
# Must be running as root to work. 
#
if ($EUID != 0) {
75
    die("Must be run as root! Try using sudo or su1!\n");
76
77
78
79
80
81
82
83
84
85
}

#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
86
87
88
if (defined($options{"c"})) {
    $copymode = 1;
}
89
90
91
if (defined($options{"d"})) {
    $debug = 1;
}
92
93
if (defined($options{"t"})) {
    $copymode = 1;
94
    $usewget  = 1;
95
}
96
if (defined($options{"n"})) {
97
98
99
100
101
102
    $nodeid = $options{"n"};
    if ($nodeid =~ /^([-\w]+)$/) {
	$nodeid = $1;
    }
    else {
	fatal("Tainted nodeid: $nodeid");
103
104
    }
}
105
# XXX compat
106
if (defined($options{"j"})) {
107
    $copymode = 1;
108
    $usewget  = 1;
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
if (@ARGV != 2) {
    usage();
}
$installdir = $ARGV[0];
$tarfile    = $ARGV[1];

#
# Untaint the arguments.
#
# Note different taint check (allow /).
if ($tarfile =~ /^([-\w.\/]+)$/) {
    $tarfile = $1;
}
else {
    fatal("Tainted filename: $tarfile");
}
if ($installdir =~ /^([-\w.\/]+)$/) {
    $installdir = $1;
}
else {
    fatal("Tainted directory name: $installdir");
}

#
# Make sure the installdir exists!
#
if (! -d $installdir) {
    fatal("$installdir does not exist or is not accessible!");
}

#
# Check to make sure this tarfile has not already been installed. Update
# the file now. If the tar fails, we got big problems.
#
if (-e $IDENTFILE) {
145
    if (! system("egrep -q -s '^${tarfile}' $IDENTFILE")) {
146
147
148
149
	print STDOUT "Tarfile $tarfile has already been installed!\n";
	exit(1);
    }
}
150
151

#
152
# Must be able to see the tarfile if not copying. The front end
153
# ensures that its in a reasonable place, but have to make sure here.
154
#
155
if (! $copymode) {
156
157
158
159
160
161
162
163
    #
    # Make sure its really there.
    #
    if (! -r $tarfile) {
	fatal("$tarfile does not exist or is not accessible!");
    }
}
else {
164
    $copyfile = `mktemp /var/tmp/tarball.XXXXXX`;
165

166
167
    if ($copyfile =~ /^([-\@\w\.\/]+)$/) {
	$copyfile = $1;
168
169
    }
    else {
170
	die("Bad data in copyfile name: $copyfile");
171
    }
172
    GetTarFile($tarfile, $copyfile, $usewget);
173
174
175
176
177
178
179
180
    #
    # Dies on any failure!
    #
}

#
# Add to index first; if fails too bad.
# 
181
if (system("echo \"$tarfile\" >> $IDENTFILE")) {
182
    fatal("Could not update $IDENTFILE");
183
}
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

#
# Figure what decompression flag is required, based on file extension.
#
SWITCH: for ($tarfile) {
    /^.*\.tar\.Z$/   && do {$decompressflag = "-Z"; last SWITCH; } ;
    /^.*\.tar\.gz$/  && do {$decompressflag = "-z"; last SWITCH; } ;
    /^.*\.tar\.tgz$/ && do {$decompressflag = "-y"; last SWITCH; } ;
    /^.*\.tar$/      && do {last SWITCH; } ;
}

#
# Install tar file from root?
# 
if (! chdir($installdir)) {
    fatal("Could not chdir to $installdir: $!\n");
}

#
# Run the tarfile. 
#
205
206
if ($copymode) {
    $tarfile = $copyfile;
207
}
208
209
system("tar $decompressflag -xf $tarfile");
$exit_status = $? >> 8;
210
211
212
if ($copymode) {
    unlink($copyfile);
}
213
214
215
216
217
218

exit($exit_status);

sub fatal {
    local($msg) = $_[0];

219
220
221
222
223
    if ($copymode && -e $copyfile) {
	unlink($copyfile);
    }
    die("*** $0:\n".
	"    $msg\n");
224
225
}

226
227
228
#
# Get a tarfile from the server via tmcc and stash.
#
229
sub GetTarFile($$$)
230
{
231
    my ($tarfile, $copyfile, $usewget) = @_;
232
    my $buf;
233
    my $bytelen;
234
235

    #
236
    # If copying via NFS, must watch for read errors and retry.
237
    #
238
    if (! $usewget) {
239
240
241
	open(TMCC, "< $tarfile")
	    or fatal("Could not open tarfile on server!");
	$bytelen = (stat($tarfile))[7];
242

243
	#
244
	# Open the target file and start dumping the data in.
245
	#
246
247
	open(JFILE, "> $copyfile")
	    or fatal("Could not open local file $copyfile: $!");
248

249
250
251
252
253
	#
	# Deal with NFS read failures
	#
	my $foffset = 0;
	my $retries = 5;
254

255
256
	while ($bytelen) {
	    my $rlen = sysread(TMCC, $buf, 8192);
257

258
259
260
261
	    if (! defined($rlen)) {
		#
		# If we are copying the file via NFS, retry a few times
		# on error to avoid the changing-exports-file server problem.
262
263
264
265
266
267
268
		if ($retries > 0 && sysseek(TMCC, $foffset, 0)) {
		    warn("*** WARNING retrying read of $tarfile ".
			 "at offset $foffset\n");
		    $retries--;
		    sleep(2);
		    next;
		}
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
		fatal("Error reading tarball $tarfile: $!");
	    }
	    if ($rlen == 0) {
		last;
	    }
	    if (! syswrite(JFILE, $buf)) {
		fatal("Error writing tarfile $copyfile: $!");
	    }
	    $foffset += $rlen;
	    $bytelen -= $rlen;
	    $retries = 5;
	}
	close(JFILE);
	close(TMCC);
    }
    else {
	#
	# Need the nodeid and the keyhash. We allow the nodeid to be
	# overridden on the command line, but thats just a debugging
	# feature.
	#
	if (!defined($nodeid)) {
	    #
	    # Eventually, use tmcc which will cache the result. 
	    # 
	    open(FD, "< " . TMNODEID()) or
		fatal("Could not open ". TMNODEID() . ": $!");
	    $nodeid = <FD>;
	    close(FD);
	    fatal("Could not get our nodeid!")
		if (!defined($nodeid));

	    if ($nodeid =~ /^([-\w]+)$/) {
		$nodeid = $1;
303
	    }
304
	}
305
306
307
308
309
310
311
312
313
314
315
	#
	# Eventually, use tmcc which will cache the result. 
	# 
	open(FD, "< " . TMKEYHASH()) or
	    fatal("Could not open ". TMKEYHASH() . ": $!");
	$keyhash = <FD>;
	close(FD);
	fatal("Could not get our keyhash!")
		if (!defined($keyhash));
	if ($keyhash =~ /^([\w]+)$/) {
	    $keyhash = $1;
316
	}
317
318
319
320
321
322
323
324
325
326

	#
	# Lastly, need our boss node.
	# 
	my ($www) = split(" ", `tmcc bossinfo`);
	die("Could not get bossinfo!")
	    if ($?);

	if ($www =~ /^[-\w]+\.(.*)$/) {
	    $www = "www.${1}";
327
	}
328
329
330
331
332
333
334
335
	else {
	    fatal("Tainted bossinfo $www!");
	}

	#
	# Okay, run wget with the proper arguments. 
	#
	my $cmd = "wget -q -O $copyfile ".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
336
	          ($debug ? "--server-response " : "") .
337
338
339
340
341
342
343
344
345
346
	          "'https://${www}/spewrpmtar.php3".
	          "?nodeid=${nodeid}&file=${tarfile}&key=${keyhash}'";
    
	if ($debug) {
	    print STDERR "$cmd\n";
	}
	system($cmd);

	fatal("Could not retrieve $tarfile from $www")
	    if ($?);
347
348
349
    }
    return 0;
}