source: trunk/eval/utilities.php @ 1184

Revision 1046, 6.2 KB checked in by bogdan2412, 3 years ago (diff)

Merge changes from eval

Fixes virtual contest task hideing issues and eval hanging on jobs with no rounds.

  • Property svn:eol-style set to native
Line 
1<?php
2
3// Sleeps for a number of miliseconds.
4function milisleep($ms) {
5    usleep($ms * 1000);
6}
7
8// Delete and remake a directory.
9// Return success value.
10function clean_dir($dir)
11{
12    system("rm -rf " . $dir, $res);
13    if (mkdir($dir, 0777, true) === false) {
14        log_warn("Failed re-creating directory $dir");
15        return false;
16    }
17    if (chmod($dir, 0777) == false) {
18        log_warn("Failed chmod 0777 directory $dir");
19        return false;
20    }
21    return true;
22}
23
24// Compile a certain file.
25// Returns success value, and a friendly error message in $compiler_message.
26//
27// Can currently handle C, C++, FreePascal, and Python.
28function compile_file($input_file_name, $output_file_name, &$compiler_message)
29{
30    $compiler_message = false;
31    $compiler_lines = array(
32            // Make sure -lm stays after source file & target output
33            'c' => 'gcc -Wall -O2 -static %file_name% -o %exe_name% -lm',
34            'cpp' => 'g++ -Wall -O2 -static %file_name% -o %exe_name% -lm',
35            'pas' => 'fpc -O2 -Xs %file_name%',
36            'fpc' => 'fpc -O2 -Xs %file_name%',
37            'py' => IA_JUDGE_PY_COMPILER.' %file_name% %exe_name%',
38    );
39    if (!preg_match("/^(.*)\.(c|cpp|pas|fpc|py)$/i", $input_file_name, $matches)) {
40        $compiler_message = "Nu am putut sa determin compilatorul ".
41                "pentru '$input_file_name'.";
42        return false;
43    }
44    $exe_name = $matches[1];
45    $extension = $matches[2];
46    if (!isset($compiler_lines[$extension])) {
47        $compiler_message = "Nu stiu cum sa compilez fisiere '$extension'";
48        return false;
49    }
50
51    $cmdline = $compiler_lines[$extension];
52    $cmdline = preg_replace('/%file_name%/', $input_file_name, $cmdline);
53    $cmdline = preg_replace('/%exe_name%/', $exe_name, $cmdline);
54
55    // Running compiler
56    $compiler_message = shell_exec("$cmdline 2>&1 | head -n 50");
57
58    // This is the BEST way to fail on compilation errors.
59    if (!is_executable($exe_name)) {
60        return false;
61    }
62
63    // Rename to $output_file_name.
64    if ($exe_name != $output_file_name) {
65        if (!@rename($exe_name, $output_file_name)) {
66            log_error("Failed renaming $exe_name to $output_file_name");
67            return false;
68        }
69    }
70
71    // Hooray!
72    return true;
73}
74
75// Parses jrun output.
76// Returns an array with result, time, memory and message.
77//
78// Result is 'OK', 'FAIL' or 'ERROR'
79// If result is ERROR time and memory are not available
80// Returns false on error.
81function jrun_parse_message($message)
82{
83    if (!preg_match("/^(ERROR|FAIL|OK):\ (.*)$/", $message, $matches)) {
84        log_warn("Invalid jrun output: $message");
85        return false;
86    }
87
88    $res = array();
89    $res['result'] = $matches[1];
90    $res['message'] = $matches[2];
91    if ($matches[1] == 'OK' || $matches[1] == 'FAIL') {
92        if (!preg_match("/^time\ ([0-9]+)ms\ memory\ ([0-9]+)kb:\ (.*)$/",
93                    $res['message'], $matches)) {
94            return false;
95        } else {
96            $res['time'] = (int)$matches[1];
97            $res['memory'] = (int)$matches[2];
98            $res['message'] = $matches[3];
99        }
100    }
101
102    // Trim . .\n and other stupid shit like that.
103    $res['message'] = preg_replace("/\s*\.?\n?^/i", "", $res['message']);
104    return $res;
105}
106
107// Returns a jrun message array for an error.
108// Sort of a hack.
109function jrun_make_error($message)
110{
111    return array('result' => "ERROR", 'message' => $message);
112}
113
114// Run a program in a special jail environment.
115// It calls an external jailer and parses output.
116//
117// $time and $memory contain the time and memory limits (or false).
118// if $capture_std is true the it will ask jrun to capture user program
119// stdin/stdout.
120//
121// The return value is an array:
122//      result: OK:    program ran perfectly
123//              FAIL:  program failed for various reasons.
124//              ERROR: internal error (user program not to blame).
125//      message: an explanatory string.
126//      time, memory: Amount of time and memory the program used.
127//      stdin, stderr: Contents of user program standard i/o.
128//               Only if $capture_std is true.
129//
130// All timings are in miliseconds and memory is in kilobytes
131//
132// If result is ERROR time, memory, stdin and stdout are never set.
133function jail_run($program, $jaildir, $time, $memory, $capture_std = false)
134{
135    log_assert(is_whole_number($time));
136    log_assert(is_whole_number($memory));
137    $cmdline = IA_ROOT_DIR . 'jrun/jrun';
138    $cmdline .= " --prog=./" . $program;
139    $cmdline .= " --dir=" . $jaildir;
140    $cmdline .= " --chroot";
141    //$cmdline .= " --verbose";
142    $cmdline .= " --block-syscalls-file=" . IA_ROOT_DIR . 'jrun/bad_syscalls';
143    if (defined('IA_JUDGE_JRUN_NICE') && IA_JUDGE_JRUN_NICE != 0) {
144        $cmdline .= " --nice=" . IA_JUDGE_JRUN_NICE;
145    }
146    if (defined('IA_JUDGE_JRUN_UID')) {
147        $cmdline .= " --uid=" . IA_JUDGE_JRUN_UID;
148    }
149    if (defined('IA_JUDGE_JRUN_GID')) {
150        $cmdline .= " --gid=" . IA_JUDGE_JRUN_GID;
151    }
152    if ($capture_std) {
153        $cmdline .= " --redirect-stdout=jailed_stdout";
154        $cmdline .= " --redirect-stderr=jailed_stderr";
155    }
156    if (isset($time)) {
157        $cmdline .= " --time-limit=" . $time;
158    }
159    if (isset($memory)) {
160        $cmdline .= " --memory-limit=" . $memory;
161    }
162    //$cmdline .= " --verbose";
163
164    log_print("Running $cmdline");
165    $message = shell_exec($cmdline);
166
167    $result = jrun_parse_message($message);
168    if ($result == false) {
169        return jrun_make_error('Failed executing jail');
170    }
171
172    if ($capture_std) {
173        $result['stdout'] = @file_get_contents($jaildir.'jailed_stdout');
174        if ($result['stdout'] === false) {
175            return jrun_make_error('Failed reading captured stdout');
176        }
177        $result['stderr'] = @file_get_contents($jaildir.'jailed_stderr');
178        if ($result['stderr'] === false) {
179            return jrun_make_error('Failed reading captured stderr');
180        }
181    }
182
183    if ($result['result'] == 'OK') {
184        if ($result['time'] > $time || $result['memory'] > $memory) {
185            log_print_r($result);
186            log_print("time $time memory $memory limits");
187            log_error("JRun says ok, but limits broken");
188        }
189    }
190
191    return $result;
192}
193
194?>
Note: See TracBrowser for help on using the repository browser.