install-rpm 6.06 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/perl -wT

#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#

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

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

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

#
# No configure vars.
#
my $IDENTFILE      = "/var/db/testbed.rpms";
51
52
my $rpm            = "";
my $usewget	   = 0;
53
my $copymode	   = 0;
54
55
56
57
58
59
60
61
62
my $debug	   = 0;
my $copyfile;
my $nodeid;

#
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself. 
#
use libsetup;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

# Protos
sub GetRPMFile($$$);

#
# Must be running as root to work. 
#
if ($EUID != 0) {
    die("Must be run as root! Try using sudo!\n");
}

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

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

#
# Check to make sure this RPM has not already been installed. Update
# the file now. If the rpm fails, we got big problems.
#
if (-e $IDENTFILE) {
    if (! system("egrep -q -s '^${rpm}' $IDENTFILE")) {
	print STDOUT "RPM $rpm has already been installed!\n";
	exit(1);
    }
}

#
# Must be able to see the RPM if not copying. The front end
# ensures that its in a reasonable place, but have to make sure here.
#
if (! $copymode) {
    #
    # Make sure its really there.
    #
    if (! -r $rpm) {
	fatal("$rpm does not exist or is not accessible!");
    }
}
else {
    $copyfile = `mktemp /var/tmp/rpm.XXXXXX`;

    if ($copyfile =~ /^([-\@\w\.\/]+)$/) {
	$copyfile = $1;
    }
    else {
	die("Bad data in copyfile name: $copyfile");
    }
146
    GetRPMFile($rpm, $copyfile, $usewget);
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
    #
    # Dies on any failure!
    #
}

#
# Add to index first; if fails too bad.
# 
if (system("echo \"$rpm\" >> $IDENTFILE")) {
    fatal("Could not update $IDENTFILE");
}

#
# Run the RPM. 
#
if ($copymode) {
    $rpm = $copyfile;
}
system("rpm -i $rpm");
$exit_status = $? >> 8;
if ($copymode) {
    unlink($copyfile);
}

exit($exit_status);

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

176
    if ($copymode && defined($copyfile) && -e $copyfile) {
177
178
179
180
	unlink($copyfile);
    }
    die("*** $0:\n".
	"    $msg\n");
181
182
183
184
185
186
187
}

#
# Get an RPM from the server via tmcc and stash.
#
sub GetRPMFile($$$)
{
188
    my ($rpm, $copyfile, $usewget) = @_;
189
190
191
192
    my $buf;
    my $bytelen;

    #
193
    # If copying via NFS, must watch for read errors and retry.
194
    #
195
    if (! $usewget) {
196
	open(TMCC, "< $rpm")
197
	    or fatal("Could not open rpm on server!");
198
199
200
	$bytelen = (stat($rpm))[7];

	#
201
	# Open the target file and start dumping the data in.
202
	#
203
204
	open(JFILE, "> $copyfile")
	    or fatal("Could not open local file $copyfile: $!");
205

206
207
208
209
210
	#
	# Deal with NFS read failures
	#
	my $foffset = 0;
	my $retries = 5;
211

212
213
	while ($bytelen) {
	    my $rlen = sysread(TMCC, $buf, 8192);
214

215
216
217
218
	    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.
219
220
221
222
223
224
225
		if ($retries > 0 && sysseek(TMCC, $foffset, 0)) {
		    warn("*** WARNING retrying read of $rpm ".
			 "at offset $foffset\n");
		    $retries--;
		    sleep(2);
		    next;
		}
226
227
228
229
230
231
232
		fatal("Error reading tarball $rpm: $!");
	    }
	    if ($rlen == 0) {
		last;
	    }
	    if (! syswrite(JFILE, $buf)) {
		fatal("Error writing rpm $copyfile: $!");
233
	    }
234
235
236
	    $foffset += $rlen;
	    $bytelen -= $rlen;
	    $retries = 5;
237
	}
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
	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;
	    }
261
	}
262
263
264
265
266
267
268
269
270
271
272
	#
	# 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;
273
	}
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292

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

	if ($www =~ /^[-\w]+\.(.*)$/) {
	    $www = "www.${1}";
	}
	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
293
	          ($debug ? "--server-response " : "") .
294
295
296
297
298
299
300
301
302
303
	          "'https://${www}/spewrpmtar.php3".
	          "?nodeid=${nodeid}&file=${rpm}&key=${keyhash}'";
    
	if ($debug) {
	    print STDERR "$cmd\n";
	}
	system($cmd);

	fatal("Could not retrieve $rpm from $www")
	    if ($?);
304
305
306
    }
    return 0;
}