eventsys.proxy.in 4.41 KB
Newer Older
1
2
3
4
#!/usr/bin/perl -w

#
# EMULAB-COPYRIGHT
5
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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
# All rights reserved.
#

use English;
use Getopt::Std;
use Errno;
use POSIX ":sys_wait_h";
    
#
# A wrapper for controlling the event scheduler from boss. 
#
# The first argument option is the user to run this script as, since we
# get invoked by a root ssh from boss. 
#
#
sub usage()
{
    print "Usage: eventsys.proxy -u user -g gid -e pid/eid -k keyfile ".
	"-l logfile start|stop|replay\n";
    exit(-1);
}
my $optlist = "u:e:k:dl:g:";
my $debug   = 0;
my $user;
my $pid;
my $eid;
my $gid;
my $keyfile;
my $logfile;
my $action;

#
# Configure variables
#
my $TB       = "@prefix@";
my $TBOPS    = "@TBOPSEMAIL@";
my $sched    = "$TB/sbin/event-sched";
my $PIDDIR   = "/var/run/emulab/evsched";
my $PIDFILE;

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

#
# Untaint the path
# 
$ENV{'PATH'} = "/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

#
# Only real root, cause the script has to read/write a pid file that
# cannot be accessed by the user.
#
if ($UID != 0) {
    die("*** $0:\n".
	"    Must be root to run this script!\n");
}

#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libtestbed;

#
# 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();
}
if (! defined($options{"u"}) ||
    ! defined($options{"e"}) ||
    ! defined($options{"g"}) ||
    ! defined($options{"l"}) ||
    ! defined($options{"k"})) {
    usage();
}    
	    
if (defined($options{"d"})) {
    $debug = 1;
}

$logfile    = $options{"l"};
$keyfile    = $options{"k"};
$user       = $options{"u"};
$gid        = $options{"g"};
$action     = $ARGV[0];

if ($options{"e"} =~ /^([-\w]*)\/([-\w]*)$/) {
    $pid = $1;
    $eid = $2;
}
else {
    usage();
}
$PIDFILE = "$PIDDIR/${pid}_${eid}.pid";

#
# Deal with stop and replay.
#
if ($action eq "stop" || $action eq "replay") {
    if (-e $PIDFILE) {    
	my $epid = `cat $PIDFILE`;
	# untaint
	if ($epid =~ /^(\d*)$/) {
	    $epid = $1;
	}
	else {
	    die("*** $0:\n".
		"    Bad data in pid: $epid!\n");
	}
	unlink($PIDFILE);

126
127
128
	if (! kill('TERM', $epid)) {
	    die("*** $0:\n".
		"Failed to stop event system for $pid/$eid! - $! $epid\n");
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
	}
    }
    
    if ($action eq "stop") {
	exit(0);
    }
    # replay continues below, but give exiting scheduler a chance to react!
    sleep(1);
}

#
# Make sure the pid directory exists.
#
if (! -d $PIDDIR) {
    if (system("mkdir -p -m 775 $PIDDIR")) {
	die("*** $0:\n".
	    "    Could not mkdir $PIDDIR\n");
    }
}

#
# Okay, now flip to user before running the event scheduler. Must put the
# user into both the project group and the experiment subgroup.
#
my (undef,undef,$unix_uid) = getpwnam($user) or
    die("*** $0:\n".
	"    No such user $user\n");

my (undef,undef,$unix_ggid) = getgrnam($gid) or
    die("*** $0:\n".
	"    No such group $gid\n");

my (undef,undef,$unix_pgid) = getgrnam($pid) or
    die("*** $0:\n".
	"    No such group $pid\n");

165
my $LOGDIR = `dirname $logfile`;
Timothy Stack's avatar
Timothy Stack committed
166
$LOGDIR =~ s/\s+$//;
167
168
169
170
171
172
173
if (! -d $LOGDIR) {
    if (system("mkdir -p -m 775 $LOGDIR")) {
	die("*** $0:\n".
	    "    Could not mkdir $LOGDIR\n");
    }
}

174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#
# Create a chile whose output is directed into the logfile. Parents waits
# a moment and then exits.
#
if (-e $logfile) {
    system("mv -f $logfile ${logfile}.old");
}

if (my $childpid = TBBackGround($logfile)) {
    #
    # Delay a moment, and they look for an exit status. This is intended
    # to catch startup problems.
    #
    sleep(1);
    my $foo = waitpid($childpid, &WNOHANG);
    if ($foo) {
	my $status = $?;
	unlink($PIDFILE);

	system("cat $logfile")
	    if (-s $logfile);
	
	die("*** $0:\n".
	    "    Failed to start event system for $pid/$eid: $foo $status!\n");
    }
    exit(0);
}

#
# Write out a pid file just prior to doing the exec. The user is not granted
# access to this pid file.
#
if (system("echo '$PID' > $PIDFILE")) {
    die("*** $0:\n".
	"    Could not create $PIDFILE!");
}

# Flip to user and never go back!
$GID            = $unix_ggid;
$EGID           = "$unix_ggid $unix_ggid $unix_pgid";
$EUID = $UID    = $unix_uid;
$ENV{'USER'}    = $user;
$ENV{'LOGNAME'} = $user;

# And run it.
exec("$sched " . ($debug ? "-d" : "") . " -s localhost -k $keyfile $pid $eid");
die("*** $0:\n".
    "    Could not exec $sched!");