1
2
3
4
5
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
|
package Scire::Job;
use POSIX qw/WEXITSTATUS WIFEXITED waitpid/;
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $filename = shift;
my $self = {};
bless ($self, $class);
if(defined $filename) {
$self->load_jobfile($filename);
}
return $self;
}
sub load_jobfile {
my $self = shift;
my $filename = shift;
$self->{filename} = $filename;
my $jobcontents;
my $jobdata;
open JOB, "< ${filename}" or die "Can't open file ${filename}";
$jobcontents = join("", <JOB>);
close JOB;
$jobdata = eval($jobcontents);
($@) and print "ERROR: Could not parse job file ${filename}!\n";
if(defined $jobdata->{script}) {
for(keys %{$jobdata->{script}}) {
$self->{$_} = $jobdata->{script}->{$_};
}
}
for(keys %{$jobdata}) {
$self->{$_} = $jobdata->{$_} unless($_ eq "script");
}
}
sub set_stdout_file {
my ($self, $outfile) = @_;
if(defined $outfile && $outfile) {
$self->{stdout_filename} = $outfile;
}
}
sub set_stderr_file {
my ($self, $errfile) = @_;
if(defined $errfile && $errfile) {
$self->{stderr_filename} = $errfile;
}
}
sub run {
my $self = shift;
# XXX: write $self->{script_data} out to a file and mark it +x. We'll need
# to find a good location for this, since it can't be noexec. Perhaps the
# queue dir in the job directory will do, or maybe it will be configurable
my $pid = fork();
if($pid) {
# XXX: eventually, we'll move the waitpid() call to another function
# called something like is_running() and use WNOHANG instead of blocking
waitpid($pid, 0);
my $status = $?;
# my $exitcode = -1;
# if(WIFEXITED($status)) {
my $exitcode = WEXITSTATUS($status);
# }
return $exitcode;
} else {
# We redirect STDOUT and STDERR first since the new user may not have
# write access to the file locations
if(defined $self->{stdout_filename}) {
open STDOUT, '>', $self->{stdout_filename};
}
if(defined $self->{stderr_filename}) {
open STDERR, '>', $self->{stderr_filename};
}
# XXX: we might want to check capabilities here instead of UID, but I
# have no idea how to do that
if($< == 0) {
# XXX: we'll use setuid to drop privileges here
my $user = getpwnam($self->{run_as});
if(defined $user) {
setuid($user[2]);
} else {
# XXX: the specified user does not exist. we should really do
# something here
exit(-2);
}
}
# XXX: exec() to run our command. our STDOUT and STDERR have been
# redirected to the files specified, and the exit code is returned
# to the main process when we're done executing. This will be changed
# to the path of the script we've written to disk once that code is in
exec '/bin/sh', '-c', 'echo foo; echo bar >&2';
}
}
1;
|