-#!/usr/bin/perl -w
+#!/usr/bin/perl
use v5.14;
use strict;
+use warnings;
-use BSD::Resource qw/setrlimit RLIMIT_AS RLIMIT_FSIZE/;
-use sigtrap qw/XFSZ/;
-
-##################################################
+use constant +{
+ # Accepted
+ AC => 0,
-my ($mlimit, $olimit, @args) = @ARGV;
+ # Internal server error
+ ERR => -1,
-setrlimit RLIMIT_AS, $mlimit, $mlimit or die $! if $mlimit;
-setrlimit RLIMIT_FSIZE, $olimit, $olimit or die $! if $olimit;
+ # All other errors
+ WA => 1,
+ NZX => 2,
+ TLE => 3,
+ OLE => 4,
+ DIED => 5,
+ REJ => 10,
+};
-%ENV = (ONLINE_JUDGE => 1, PATH => $ENV{PATH}, HOME => $ENV{HOME});
-exec @args;
+use BSD::Resource qw/setrlimit RLIMIT_AS RLIMIT_FSIZE/;
+use IPC::Signal qw/sig_name sig_num/;
+use sigtrap qw/XFSZ/;
+use Getopt::Long;
+use POSIX qw//;
+use Time::HiRes qw/alarm/;
+
+my (@fds, $timeout, $mlimit, $olimit);
+GetOptions(
+ "fd=s" => \@fds,
+ "timeout=f" => \$timeout,
+ "mlimit=i" => \$mlimit,
+ "olimit=i" => \$olimit,
+);
+
+my $ret = fork // die 'Cannot fork';
+if ($ret) {
+ my $tle;
+ local $SIG{ALRM} = sub { kill KILL => $ret; $tle = 1};
+ alarm ($timeout || 5);
+ waitpid $ret, 0;
+ alarm 0;
+ my $sig = $? & 127;
+ my $signame = sig_name $sig;
+ exit !say TLE, "\nTime Limit Exceeded" if $tle;
+ exit !say OLE, "\nOutput Limit Exceeded" if $sig && $signame eq 'XFSZ';
+ exit !say DIED, "\nCrash (SIG$signame)" if $sig && $signame ne 'PIPE';
+ exit !say NZX, "\nNon-zero exit status: " . ($? >> 8) if $? >> 8;
+ exit !say AC, "\nAll OK";
+} else {
+ $^F = 50;
+ POSIX::close $_ for 0 .. $^F;
+ for my $fdstring (@fds) {
+ my ($fd, $file) = split ' ', $fdstring, 2;
+ open my $fh, $file or die $!;
+ my $oldfd = fileno $fh;
+ if ($oldfd != $fd) {
+ POSIX::dup2 $oldfd, $fd or die $!;
+ POSIX::close $oldfd or die $!;
+ }
+ }
+ %ENV = (ONLINE_JUDGE => 1, PATH => $ENV{PATH}, HOME => $ENV{HOME});
+ setrlimit RLIMIT_AS, $mlimit, $mlimit or die $! if $mlimit;
+ setrlimit RLIMIT_FSIZE, $olimit, $olimit or die $! if $olimit;
+ exec @ARGV;
+}
+
+1;
__END__
=encoding utf-8
use POSIX qw//;
use File::Basename qw/fileparse/;
-use File::Slurp qw/write_file/;
+use File::Slurp qw/read_file write_file/;
use Gruntmaster::Daemon::Constants qw/TLE OLE DIED NZX/;
use Time::HiRes qw/alarm/;
use List::MoreUtils qw/natatime/;
use Log::Log4perl qw/get_logger/;
use IPC::Signal qw/sig_name sig_num/;
+use Try::Tiny;
our $VERSION = "5999.000_004";
our @EXPORT_OK = qw/prepare_files/;
##################################################
+sub execlist {
+ my (@args) = @_;
+ my $ret = fork // die 'Cannot fork';
+ if ($ret) {
+ waitpid $ret, 0;
+ die "gruntmaster-exec died\n" if -z 'exec-result';
+ my ($excode, $exmsg) = read_file 'exec-result';
+ unlink 'exec-result';
+ chomp ($excode, $exmsg);
+ die [$excode, $exmsg] if $excode > 0;
+ } else {
+ open STDOUT, '>exec-result';
+ exec 'gruntmaster-exec', @args;
+ }
+}
+
sub command_and_args{
my ($format, $basename) = @_;
java => $basename when 'JAVA';
perl => $basename when 'PERL';
python => $basename when 'PYTHON';
- default { die "Don't know how to execute format $format" }
+ default { die "Don't know how to execute format $format\n" }
}
}
my ($name, %args) = @_;
get_logger->trace("Running $name...");
my $basename = fileparse $name, qr/\.[^.]*/;
- my $ret = fork // die 'Cannot fork';
- if ($ret) {
- my $tle;
- local $SIG{ALRM} = sub { kill KILL => $ret; $tle = 1};
- alarm $args{timeout} if exists $args{timeout};
- waitpid $ret, 0;
- alarm 0;
- my $sig = $? & 127;
- my $signame = sig_name $sig;
- die [TLE, "Time Limit Exceeded"] if $tle;
- die [OLE, 'Output Limit Exceeded'] if $sig && $signame eq 'XFSZ';
- die [DIED, "Crash (SIG$signame)"] if $sig && $signame ne 'PIPE';
- die [NZX, "Non-zero exit status: " . ($? >> 8)] if $? >> 8;
- } else {
- my @fds = exists $args{fds} ? @{$args{fds}} : ();
- $^F = 50;
- POSIX::close $_ for 0 .. $^F;
- my $it = natatime 2, @fds;
- while (my ($fd, $file) = $it->()) {
- open my $fh, $file or die $!;
- my $oldfd = fileno $fh;
- if ($oldfd != $fd) {
- POSIX::dup2 $oldfd, $fd or die $!;
- POSIX::close $oldfd or die $!;
- }
- }
- exec 'gruntmaster-exec', $args{mlimit} // 0, $args{olimit} // 0, command_and_args($format, $basename), exists $args{args} ? @{$args{args}} : ();
- exit 42
+ my @args;
+ push @args, '--timeout', $args{timeout} if $args{timeout};
+ push @args, '--mlimit', $args{mlimit} if $args{mlimit};
+ push @args, '--olimit', $args{olimit} if $args{olimit};
+ my @fds = exists $args{fds} ? @{$args{fds}} : ();
+ my $it = natatime 2, @fds;
+ while (my ($fd, $file) = $it->()) {
+ push @args, "--fd=$fd $file";
}
+ execlist @args, command_and_args($format, $basename);
}
}
my ($name, $format) = @_;
get_logger->trace("Preparing file $name...");
- $Gruntmaster::Daemon::errors .= `gruntmaster-compile $format $name 2>&1`;
- $Gruntmaster::Daemon::errors .= "\n";
- die 'Compile error' if $?
+ try {
+ execlist '--fd=1 >>errors', '--fd=2 >>errors', 'gruntmaster-compile', $format, $name;
+ } catch {
+ die "Compile error\n"
+ } finally {
+ $Gruntmaster::Daemon::errors .= read_file 'errors';
+ $Gruntmaster::Daemon::errors .= "\n";
+ unlink 'errors';
+ };
}
sub prepare_files{
+++ /dev/null
-/usr/(local/)?bin/gruntmasterd gen_context(system_u:object_r:gruntmasterd_exec_t, s0)
-/usr/(local/)?bin/gruntmaster-compile gen_context(system_u:object_r:gruntmaster_compile_exec_t, s0)
-/usr/(local/)?bin/gruntmaster-exec gen_context(system_u:object_r:gruntmaster_job_exec_t, s0)
-/usr/(local/)?bin/gruntmaster-paged gen_context(system_u:object_r:gruntmaster_paged_exec_t, s0)
-/etc/gruntmasterd(/.*)? gen_context(system_u:object_r:gruntmasterd_etc_t, s0)
-/var/lib/gruntmasterd(/.*)? gen_context(system_u:object_r:gruntmasterd_var_lib_t, s0)
-/var/log/gruntmasterd gen_context(system_u:object_r:gruntmasterd_log_t, s0)
+++ /dev/null
-policy_module(gruntmasterd, 1.0)
-
-define(`read_file_perms', `{ getattr ioctl read lock open }')
-define(`read_dir_perms', `{ getattr ioctl read lock open search}')
-define(`everything_file_perms', `{ getattr ioctl read lock open unlink setattr append write create rename link }')
-define(`everything_dir_perms', `{ getattr ioctl read lock open search unlink setattr write create rename link rmdir remove_name reparent add_name }')
-define(`domain_read_files', `allow $1 $2 : dir read_dir_perms; allow $1 $2 : file read_file_perms; allow $1 $2 : lnk_file read_file_perms;')
-define(`domain_everything_files', `allow $1 $2 : dir everything_dir_perms; allow $1 $2 : file everything_file_perms; allow $1 $2 : lnk_file everything_file_perms;')
-define(`gruntmaster_read', `domain_read_files(gruntmasterd_t, $1)')
-define(`gruntmaster_everything', `domain_everything_files(gruntmasterd_t, $1)')
-
-require{
- type bin_t;
- type http_port_t;
- type httpd_sys_content_rw_t;
- type httpd_sys_content_t;
- type httpd_t;
- type httpd_tmp_t;
- type net_conf_t;
- type port_t;
- type proc_t;
- type urandom_device_t;
-}
-
-# Types
-type gruntmasterd_t;
-type gruntmasterd_etc_t;
-type gruntmasterd_exec_t;
-type gruntmasterd_log_t;
-type gruntmasterd_tmp_t;
-type gruntmasterd_var_lib_t;
-type gruntmaster_job_t;
-type gruntmaster_job_exec_t;
-type gruntmaster_compile_t;
-type gruntmaster_compile_exec_t;
-type gruntmaster_paged_t;
-type gruntmaster_paged_exec_t;
-
-domain_type(gruntmaster_job_t)
-domain_entry_file(gruntmaster_job_t, gruntmaster_job_exec_t)
-role system_r types gruntmaster_job_t;
-
-domain_type(gruntmaster_compile_t)
-domain_entry_file(gruntmaster_compile_t, gruntmaster_compile_exec_t)
-role system_r types gruntmaster_compile_t;
-type_transition gruntmaster_compile_t gruntmasterd_tmp_t : file gruntmaster_job_exec_t;
-
-init_daemon_domain(gruntmaster_paged_t, gruntmaster_paged_exec_t)
-type_transition gruntmaster_paged_t httpd_sys_content_t : { file dir } httpd_sys_content_rw_t;
-
-init_daemon_domain(gruntmasterd_t, gruntmasterd_exec_t)
-logging_log_file(gruntmasterd_log_t)
-logging_log_filetrans(gruntmasterd_t, gruntmasterd_log_t, file)
-logging_search_logs(gruntmasterd_t)
-type_transition gruntmasterd_t gruntmaster_compile_exec_t : process gruntmaster_compile_t;
-type_transition gruntmasterd_t gruntmaster_job_exec_t : process gruntmaster_job_t;
-type_transition gruntmasterd_t tmp_t : dir gruntmasterd_tmp_t;
-files_type(gruntmasterd_tmp_t)
-files_type(gruntmasterd_etc_t)
-files_type(gruntmasterd_var_lib_t)
-
-# Daemon permissions
-allow gruntmasterd_t { gruntmaster_compile_t gruntmaster_job_t } : process { sigkill siginh rlimitinh transition };
-allow gruntmasterd_t bin_t : file { execute execute_no_trans };
-allow gruntmasterd_t self : process fork;
-allow gruntmasterd_t self:fifo_file everything_file_perms;
-allow gruntmasterd_t urandom_device_t:chr_file read_file_perms;
-allow gruntmasterd_t { gruntmaster_compile_exec_t gruntmaster_job_exec_t } : file execute;
-allow gruntmasterd_t port_t:tcp_socket name_connect;
-allow gruntmasterd_t http_port_t:tcp_socket name_connect;
-allow gruntmasterd_t net_conf_t:file { read getattr open };
-allow gruntmasterd_t self:udp_socket { write read create connect getattr };
-allow gruntmasterd_t self:tcp_socket { read write create ioctl connect };
-dontaudit gruntmasterd_t { gruntmaster_compile_t gruntmaster_job_t } : process noatsecure;
-
-allow gruntmasterd_t tmp_t : dir { getattr write search add_name };
-
-gruntmaster_read(bin_t)
-gruntmaster_read(gruntmaster_compile_exec_t)
-gruntmaster_read(gruntmasterd_etc_t)
-gruntmaster_read(gruntmasterd_var_lib_t)
-gruntmaster_read(gruntmaster_job_exec_t)
-gruntmaster_read(httpd_sys_content_t)
-gruntmaster_read(lib_t)
-gruntmaster_read(proc_t)
-gruntmaster_read(usr_t)
-
-gruntmaster_everything(gruntmasterd_log_t)
-gruntmaster_everything(gruntmasterd_tmp_t)
-
-files_read_etc_files(gruntmasterd_t)
-files_search_etc(gruntmasterd_t)
-libs_use_ld_so(gruntmasterd_t)
-libs_use_shared_libs(gruntmasterd_t)
-miscfiles_read_localization(gruntmasterd_t)
-
-# Executor and job permissions
-domain_read_files(gruntmaster_job_t, bin_t)
-domain_read_files(gruntmaster_job_t, usr_t)
-allow gruntmaster_job_t gruntmaster_job_exec_t : file { execute execute_no_trans };
-allow gruntmaster_job_t gruntmasterd_t:fd use;
-allow gruntmaster_job_t gruntmasterd_t:process sigchld;
-allow gruntmaster_job_t gruntmasterd_tmp_t : dir read_dir_perms;
-allow gruntmaster_job_t gruntmasterd_tmp_t : file { getattr ioctl read write };
-allow gruntmaster_job_t init_t:fd use;
-allow gruntmaster_job_t self:process setrlimit;
-allow gruntmaster_job_t urandom_device_t:chr_file read_file_perms;
-
-libs_use_ld_so(gruntmaster_job_t)
-libs_use_shared_libs(gruntmaster_job_t)
-miscfiles_read_localization(gruntmaster_job_t)
-
-# Compile permissions
-domain_everything_files(gruntmaster_compile_t, gruntmaster_job_exec_t)
-domain_everything_files(gruntmaster_compile_t, tmp_t)
-domain_read_files(gruntmaster_compile_t, bin_t)
-domain_read_files(gruntmaster_compile_t, lib_t)
-domain_read_files(gruntmaster_compile_t, proc_t)
-domain_read_files(gruntmaster_compile_t, proc_t)
-domain_read_files(gruntmaster_compile_t, usr_t)
-domain_read_files(gruntmaster_compile_t, gruntmasterd_tmp_t)
-allow gruntmaster_compile_t gruntmasterd_t : fifo_file { read write ioctl };
-allow gruntmaster_compile_t gruntmasterd_t:fd use;
-allow gruntmaster_compile_t gruntmasterd_t:process sigchld;
-allow gruntmaster_compile_t gruntmasterd_tmp_t:dir { write add_name };
-allow gruntmaster_compile_t self : fifo_file { read write ioctl };
-allow gruntmaster_compile_t self:process signal;
-allow gruntmaster_compile_t urandom_device_t:chr_file read_file_perms;
-allow gruntmaster_compile_t { bin_t lib_t } : file { execute execute_no_trans };
-
-libs_use_ld_so(gruntmaster_compile_t)
-libs_use_shared_libs(gruntmaster_compile_t)
-miscfiles_read_localization(gruntmaster_compile_t)
-
-# Page generator permissions
-domain_everything_files(gruntmaster_paged_t, httpd_sys_content_rw_t)
-domain_read_files(gruntmaster_paged_t, usr_t)
-domain_read_files(gruntmaster_paged_t, bin_t)
-allow gruntmaster_paged_t urandom_device_t:chr_file read_file_perms;
-allow gruntmaster_paged_t port_t:tcp_socket name_connect;
-allow gruntmaster_paged_t self:tcp_socket { read write create ioctl connect };
-
-libs_use_ld_so(gruntmaster_paged_t)
-libs_use_shared_libs(gruntmaster_paged_t)
-miscfiles_read_localization(gruntmaster_paged_t)