Skip to content

Instantly share code, notes, and snippets.

@nickygerritsen
Created March 18, 2023 19:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nickygerritsen/ca9af7aa2f4a046b37ca2c471847a0ce to your computer and use it in GitHub Desktop.
Save nickygerritsen/ca9af7aa2f4a046b37ca2c471847a0ce to your computer and use it in GitHub Desktop.
Diff on judgedaemon with PHP CS Fixer
<?php
$finder = PhpCsFixer\Finder::create()
->in([
__DIR__ . '/judge',
]);
$config = new PhpCsFixer\Config();
return $config
->setRules([
'@Symfony' => true,
'yoda_style' => false,
'concat_space' => false,
'single_quote' => false,
'no_alias_language_construct_call' => false,
'increment_style' => ['style' => 'post'],
'cast_spaces' => ['space' => 'none'],
])
->setFinder($finder);
diff --git a/judge/judgedaemon.main.php b/judge/judgedaemon.main.php
index 35db3c238..fb04d09ca 100644
--- a/judge/judgedaemon.main.php
+++ b/judge/judgedaemon.main.php
@@ -1,4 +1,6 @@
-<?php declare(strict_types=1);
+<?php
+
+declare(strict_types=1);
/**
* Request a yet unjudged submission from the domserver, judge it, and pass
* the results back to the domserver.
@@ -10,13 +12,13 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
die("Commandline use only");
}
-require(ETCDIR . '/judgehost-config.php');
-require(LIBDIR . '/lib.misc.php');
+require ETCDIR . '/judgehost-config.php';
+require LIBDIR . '/lib.misc.php';
$endpoints = [];
$domjudge_config = [];
-function judging_directory(string $workdirpath, array $judgeTask) : string
+function judging_directory(string $workdirpath, array $judgeTask): string
{
if (filter_var($judgeTask['submitid'], FILTER_VALIDATE_INT) === false ||
filter_var($judgeTask['jobid'], FILTER_VALIDATE_INT) === false) {
@@ -39,7 +41,7 @@ function read_credentials(): void
}
$lineno = 0;
foreach ($credentials as $credential) {
- ++$lineno;
+ $lineno++;
$credential = trim($credential);
if ($credential === '' || $credential[0] === '#') {
continue;
@@ -76,6 +78,7 @@ function setup_curl_handle(string $restuser, string $restpass)
curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl_handle, CURLOPT_USERPWD, $restuser . ":" . $restpass);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
+
return $curl_handle;
}
@@ -83,7 +86,7 @@ function close_curl_handles(): void
{
global $endpoints;
foreach ($endpoints as $id => $endpoint) {
- if (! empty($endpoint['ch'])) {
+ if (!empty($endpoint['ch'])) {
curl_close($endpoint['ch']);
unset($endpoints[$id]['ch']);
}
@@ -108,8 +111,8 @@ function request(string $url, string $verb = 'GET', $data = '', bool $failonerro
global $endpoints, $endpointID, $lastrequest;
// Don't flood the log with requests for new judgings every few seconds.
- if (strpos($url, 'judgehosts/fetch-work') === 0 && $verb==='POST') {
- if ($lastrequest!==$url) {
+ if (strpos($url, 'judgehosts/fetch-work') === 0 && $verb === 'POST') {
+ if ($lastrequest !== $url) {
logmsg(LOG_DEBUG, "API request $verb $url");
$lastrequest = $url;
}
@@ -177,7 +180,7 @@ function request(string $url, string $verb = 'GET', $data = '', bool $failonerro
if ($trial == BACKOFF_STEPS) {
$errstr = $errstr . " Retry limit reached.";
} else {
- $retry_in_sec = $delay_in_sec + BACKOFF_JITTER_SEC*rand()/getrandmax();
+ $retry_in_sec = $delay_in_sec + BACKOFF_JITTER_SEC * rand() / getrandmax();
$warnstr = $errstr . " This request will be retried after about " .
$retry_in_sec . "sec... (" . $trial . "/" . BACKOFF_STEPS . ")";
warning($warnstr);
@@ -191,6 +194,7 @@ function request(string $url, string $verb = 'GET', $data = '', bool $failonerro
} else {
warning($errstr);
$endpoints[$endpointID]['errorred'] = true;
+
return null;
}
}
@@ -225,6 +229,7 @@ function djconfig_get_value(string $name)
if (empty($domjudge_config)) {
error("DOMjudge config not initialised before call to djconfig_get_value()");
}
+
return $domjudge_config[$name];
}
@@ -235,19 +240,20 @@ function djconfig_get_value(string $name)
* $sizelimit can be set to the following values:
* - TRUE: use the 'output_storage_limit' configuration setting
* - positive integer: limit to this many bytes
- * - FALSE or -1: no size limit imposed
+ * - FALSE or -1: no size limit imposed.
*/
-function rest_encode_file(string $file, $sizelimit = true) : string
+function rest_encode_file(string $file, $sizelimit = true): string
{
- if ($sizelimit===true) {
- $maxsize = (int) djconfig_get_value('output_storage_limit');
- } elseif ($sizelimit===false || $sizelimit==-1) {
+ if ($sizelimit === true) {
+ $maxsize = (int)djconfig_get_value('output_storage_limit');
+ } elseif ($sizelimit === false || $sizelimit == -1) {
$maxsize = -1;
- } elseif (is_int($sizelimit) && $sizelimit>0) {
+ } elseif (is_int($sizelimit) && $sizelimit > 0) {
$maxsize = $sizelimit;
} else {
error("Invalid argument sizelimit = '$sizelimit' specified.");
}
+
return base64_encode(dj_file_get_contents($file, $maxsize));
}
@@ -270,10 +276,11 @@ function usage(): void
exit;
}
-function read_judgehostlog(int $n = 20) : string
+function read_judgehostlog(int $n = 20): string
{
ob_start();
passthru("tail -n $n " . dj_escapeshellarg(LOGFILE));
+
return trim(ob_get_clean());
}
@@ -286,7 +293,7 @@ function fetch_executable(
string $hash,
int $judgeTaskId,
bool $combined_run_compare = false
-) : array {
+): array {
list($execrunpath, $error, $buildlogpath) = fetch_executable_internal($workdirpath, $type, $execid, $hash, $combined_run_compare);
if (isset($error)) {
$extra_log = null;
@@ -305,6 +312,7 @@ function fetch_executable(
$extra_log
);
}
+
return [$execrunpath, $error];
}
@@ -319,23 +327,23 @@ function fetch_executable_internal(
string $execid,
string $hash,
bool $combined_run_compare = false
-) : array {
- $execdir = join('/', [
+): array {
+ $execdir = join('/', [
$workdirpath,
'executable',
$type,
$execid,
- $hash
+ $hash,
]);
- $execdeploypath = $execdir . '/.deployed';
- $execbuilddir = $execdir . '/build';
- $execbuildpath = $execbuilddir . '/build';
- $execrunpath = $execbuilddir . '/run';
+ $execdeploypath = $execdir . '/.deployed';
+ $execbuilddir = $execdir . '/build';
+ $execbuildpath = $execbuilddir . '/build';
+ $execrunpath = $execbuilddir . '/run';
$execrunjurypath = $execbuilddir . '/runjury';
if (!is_dir($execdir) || !file_exists($execdeploypath)) {
system('rm -rf ' . dj_escapeshellarg($execdir) . ' ' . dj_escapeshellarg($execbuilddir));
system('mkdir -p ' . dj_escapeshellarg($execbuilddir), $retval);
- if ($retval!==0) {
+ if ($retval !== 0) {
error("Could not create directory '$execbuilddir'");
}
@@ -360,11 +368,11 @@ function fetch_executable_internal(
];
}
unset($files);
- uasort($filesArray, fn(array $a, array $b) => strcmp($a['filename'], $b['filename']));
+ uasort($filesArray, fn (array $a, array $b) => strcmp($a['filename'], $b['filename']));
$computedHash = md5(
join(
array_map(
- fn($file) => $file['hash'] . $file['filename'] . $file['is_executable'],
+ fn ($file) => $file['hash'] . $file['filename'] . $file['is_executable'],
$filesArray
)
)
@@ -442,7 +450,7 @@ function fetch_executable_internal(
if ($do_compile) {
logmsg(LOG_DEBUG, "Building executable in $execdir, under 'build/'");
system(LIBJUDGEDIR . '/build_executable.sh ' . dj_escapeshellarg($execdir), $retval);
- if ($retval!==0) {
+ if ($retval !== 0) {
return [null, "Failed to build executable in $execdir.", "$execdir/build.log"];
}
chmod($execrunpath, 0755);
@@ -451,11 +459,11 @@ function fetch_executable_internal(
return [null, "Invalid build file, must produce an executable file 'run'.", null];
}
if ($combined_run_compare) {
- # For combined run and compare (i.e. for interactive problems), we
- # need to wrap the jury provided 'run' script with 'runpipe' to
- # handle the bidirectional communication. First 'run' is renamed to
- # 'runjury', and then replaced by the script below, which runs the
- # team submission and runjury programs and connects their pipes.
+ // For combined run and compare (i.e. for interactive problems), we
+ // need to wrap the jury provided 'run' script with 'runpipe' to
+ // handle the bidirectional communication. First 'run' is renamed to
+ // 'runjury', and then replaced by the script below, which runs the
+ // team submission and runjury programs and connects their pipes.
$runscript = file_get_contents(LIBJUDGEDIR . '/run-interactive.sh');
if (rename($execrunpath, $execrunjurypath) === false) {
error("Could not move file 'run' to 'runjury' in $execbuilddir");
@@ -479,7 +487,7 @@ function fetch_executable_internal(
$options = getopt("dv:n:hVe:j:t:", ["diskspace-error"]);
// FIXME: getopt doesn't return FALSE on parse failure as documented!
-if ($options===false) {
+if ($options === false) {
echo "Error: parsing options failed.\n";
usage();
}
@@ -497,12 +505,12 @@ if (isset($options['h'])) {
usage();
}
-if (posix_getuid()==0 || posix_geteuid()==0) {
+if (posix_getuid() == 0 || posix_geteuid() == 0) {
echo "This program should not be run as root.\n";
exit(1);
}
-$myhost = trim(`hostname | cut -d . -f 1`);
+$myhost = trim(shell_exec("hostname | cut -d . -f 1"));
if (isset($options['daemonid'])) {
if (preg_match('/^\d+$/', $options['daemonid'])) {
$myhost = $myhost . "-" . $options['daemonid'];
@@ -513,7 +521,7 @@ if (isset($options['daemonid'])) {
}
define('LOGFILE', LOGDIR.'/judge.'.$myhost.'.log');
-require(LIBDIR . '/lib.error.php');
+require LIBDIR . '/lib.error.php';
$verbose = LOG_INFO;
if (isset($options['verbose'])) {
@@ -584,7 +592,7 @@ if (!empty($options['e'])) {
$endpointID = $options['e'];
$endpoint = $endpoints[$endpointID];
$endpoints[$endpointID]['ch'] = setup_curl_handle($endpoint['user'], $endpoint['pass']);
- $new_judging_run = (array) dj_json_decode(base64_decode(file_get_contents($options['j'])));
+ $new_judging_run = (array)dj_json_decode(base64_decode(file_get_contents($options['j'])));
$judgeTaskId = $options['t'];
for ($i = 0; $i < 5; $i++) {
@@ -600,7 +608,7 @@ if (!empty($options['e'])) {
break;
}
logmsg(LOG_WARNING, "Failed to report $judgeTaskId in attempt #" . ($i + 1) . ".");
- $sleep_ms = 100 + random_int(200, ($i+1)*1000);
+ $sleep_ms = 100 + random_int(200, ($i + 1) * 1000);
dj_sleep(0.001 * $sleep_ms);
}
unlink($options['j']);
@@ -614,7 +622,7 @@ umask(0022);
// Check basic prerequisites for chroot at judgehost startup
logmsg(LOG_INFO, "🔏 Executing chroot script: '".CHROOT_SCRIPT." check'");
system(LIBJUDGEDIR.'/'.CHROOT_SCRIPT.' check', $retval);
-if ($retval!==0) {
+if ($retval !== 0) {
error("chroot validation check exited with exitcode $retval");
}
@@ -645,9 +653,9 @@ while (true) {
}
}
// Sleep only if everything is "waiting" and only if we're looking at the first endpoint again
- if ($dosleep && $currentEndpoint==0) {
+ if ($dosleep && $currentEndpoint == 0) {
dj_sleep($waittime);
- $waittime = min($waittime*2, MAXIMAL_WAITTIME_SEC);
+ $waittime = min($waittime * 2, MAXIMAL_WAITTIME_SEC);
}
// Increment our currentEndpoint pointer
@@ -669,21 +677,20 @@ while (true) {
continue;
}
-
if ($endpoints[$endpointID]['waiting'] === false) {
// Check for available disk space
$free_space = disk_free_space(JUDGEDIR);
- $allowed_free_space = djconfig_get_value('diskspace_error'); // in kB
- if ($free_space < 1024*$allowed_free_space) {
+ $allowed_free_space = djconfig_get_value('diskspace_error'); // in kB
+ if ($free_space < 1024 * $allowed_free_space) {
$after = disk_free_space(JUDGEDIR);
if (!isset($options['diskspace-error'])) {
$candidateDirs = [];
foreach (scandir($workdirpath) as $subdir) {
- if (is_numeric($subdir) && is_dir(($workdirpath . "/" . $subdir))) {
+ if (is_numeric($subdir) && is_dir($workdirpath . "/" . $subdir)) {
$candidateDirs[] = $workdirpath . "/" . $subdir;
}
}
- uasort($candidateDirs, fn($a, $b) => filemtime($a) <=> filemtime($b));
+ uasort($candidateDirs, fn ($a, $b) => filemtime($a) <=> filemtime($b));
$after = $before = disk_free_space(JUDGEDIR);
logmsg(LOG_INFO,
"🗑 Low on diskspace, cleaning up (" . count($candidateDirs) . " potential candidates).");
@@ -704,8 +711,8 @@ while (true) {
sprintf("%01.2fMB.", ($after - $before) / (1024 * 1024))
);
}
- if ($after < 1024*$allowed_free_space) {
- $free_abs = sprintf("%01.2fGB", $after / (1024*1024*1024));
+ if ($after < 1024 * $allowed_free_space) {
+ $free_abs = sprintf("%01.2fGB", $after / (1024 * 1024 * 1024));
logmsg(LOG_ERR, "Low on disk space: $free_abs free, clean up or " .
"change 'diskspace error' value in config before resolving this error.");
@@ -724,7 +731,7 @@ while (true) {
// nothing returned -> no open submissions for us
if (empty($row)) {
- if (! $endpoints[$endpointID]["waiting"]) {
+ if (!$endpoints[$endpointID]["waiting"]) {
$endpoints[$endpointID]["waiting"] = true;
if ($lastWorkdir !== null) {
cleanup_judging($lastWorkdir);
@@ -868,7 +875,6 @@ while (true) {
$lastWorkdir = null;
}
-
system('mkdir -p ' . dj_escapeshellarg("$workdir/compile"), $retval);
if ($retval !== 0) {
error("Could not create '$workdir/compile'");
@@ -884,7 +890,7 @@ while (true) {
// create chroot environment
logmsg(LOG_INFO, " 🔒 Executing chroot script: '".CHROOT_SCRIPT." start'");
system(LIBJUDGEDIR.'/'.CHROOT_SCRIPT.' start', $retval);
- if ($retval!==0) {
+ if ($retval !== 0) {
logmsg(LOG_ERR, "chroot script exited with exitcode $retval");
disable('judgehost', 'hostname', $myhost, "chroot script exited with exitcode $retval on $myhost");
continue;
@@ -936,6 +942,7 @@ function registerJudgehost(string $myhost): void
$now = time();
if ($now - $endpoint['last_attempt'] < 30) {
$endpoint['waiting'] = true;
+
return;
}
$endpoint['last_attempt'] = $now;
@@ -977,9 +984,9 @@ function disable(
?string $extra_log = null
): void {
global $myhost;
- $disabled = dj_json_encode(array(
+ $disabled = dj_json_encode([
'kind' => $kind,
- $idcolumn => $id));
+ $idcolumn => $id]);
$judgehostlog = read_judgehostlog();
if (isset($extra_log)) {
$judgehostlog .= "\n\n"
@@ -1018,7 +1025,7 @@ function read_metadata(string $filename): ?array
return $res;
}
-function cleanup_judging(string $workdir) : void
+function cleanup_judging(string $workdir): void
{
global $myhost;
// revoke readablity for domjudge-run user to this workdir
@@ -1027,7 +1034,7 @@ function cleanup_judging(string $workdir) : void
// destroy chroot environment
logmsg(LOG_INFO, " 🔓 Executing chroot script: '".CHROOT_SCRIPT." stop'");
system(LIBJUDGEDIR.'/'.CHROOT_SCRIPT.' stop', $retval);
- if ($retval!==0) {
+ if ($retval !== 0) {
logmsg(LOG_ERR, "chroot script exited with exitcode $retval");
disable('judgehost', 'hostname', $myhost, "chroot script exited with exitcode $retval on $myhost");
// Just continue here: even though we might continue a current
@@ -1038,7 +1045,7 @@ function cleanup_judging(string $workdir) : void
// Evict all contents of the workdir from the kernel fs cache
system(LIBJUDGEDIR . '/evict ' . dj_escapeshellarg($workdir), $retval);
- if ($retval!==0) {
+ if ($retval !== 0) {
warning("evict script exited with exitcode $retval");
}
}
@@ -1105,10 +1112,11 @@ function compile(
// Revoke readablity for domjudge-run user to this workdir.
chmod($workdir, 0700);
logmsg(LOG_NOTICE, "Judging s$judgeTask[submitid], task $judgeTask[judgetaskid]: compile error");
+
return false;
}
- if (count($files)==0) {
+ if (count($files) == 0) {
error("No submission files could be downloaded.");
}
@@ -1131,7 +1139,7 @@ function compile(
], $files)));
logmsg(LOG_DEBUG, "Compile command: ".$compile_cmd);
system($compile_cmd, $retval);
- if ($retval!==0) {
+ if ($retval !== 0) {
warning("compile script exited with exitcode $retval");
}
@@ -1168,7 +1176,7 @@ function compile(
}
// What does the exitcode mean?
- if (! isset($EXITCODES[$retval])) {
+ if (!isset($EXITCODES[$retval])) {
alert('error');
$description = "Unknown exitcode from compile.sh for s$judgeTask[submitid]: $retval";
logmsg(LOG_ERR, $description);
@@ -1178,7 +1186,7 @@ function compile(
}
logmsg(LOG_INFO, " 💻 Compilation: ($files[0]) '".$EXITCODES[$retval]."'");
- $compile_success = ($EXITCODES[$retval]==='correct');
+ $compile_success = ($EXITCODES[$retval] === 'correct');
// Pop the compilation result back into the judging table.
$args = 'compile_success=' . $compile_success .
@@ -1192,7 +1200,7 @@ function compile(
request($url, 'PUT', $args);
// compile error: our job here is done
- if (! $compile_success) {
+ if (!$compile_success) {
return false;
}
@@ -1206,7 +1214,7 @@ function judge(array $judgeTask): bool
global $EXITCODES, $myhost, $options, $workdirpath, $exitsignalled, $gracefulexitsignalled, $endpointID;
$compile_config = dj_json_decode($judgeTask['compile_config']);
- $run_config = dj_json_decode($judgeTask['run_config']);
+ $run_config = dj_json_decode($judgeTask['run_config']);
$compare_config = dj_json_decode($judgeTask['compare_config']);
// Set configuration variables for called programs
@@ -1225,7 +1233,7 @@ function judge(array $judgeTask): bool
} else {
putenv('ENTRY_POINT');
}
- $output_storage_limit = (int) djconfig_get_value('output_storage_limit');
+ $output_storage_limit = (int)djconfig_get_value('output_storage_limit');
$cpuset_opt = "";
if (isset($options['daemonid'])) {
@@ -1272,13 +1280,13 @@ function judge(array $judgeTask): bool
// dir. Use hardlinks to preserve space with big executables.
$programdir = $testcasedir . '/execdir';
system('mkdir -p ' . dj_escapeshellarg($programdir), $retval);
- if ($retval!==0) {
+ if ($retval !== 0) {
error("Could not create directory '$programdir'");
}
foreach (glob("$workdir/compile/*") as $compile_file) {
system('cp -PRl ' . dj_escapeshellarg($compile_file) . ' ' . dj_escapeshellarg($programdir), $retval);
- if ($retval!==0) {
+ if ($retval !== 0) {
error("Could not copy program to '$programdir'");
}
}
@@ -1287,7 +1295,6 @@ function judge(array $judgeTask): bool
$hardtimelimit = $run_config['time_limit'] +
overshoot_time($run_config['time_limit'], $overshoot);
-
$combined_run_compare = $compare_config['combined_run_compare'];
list($run_runpath, $error) = fetch_executable(
$workdirpath,
@@ -1331,12 +1338,12 @@ function judge(array $judgeTask): bool
$testcasedir,
$run_runpath,
$compare_runpath,
- $compare_config['compare_args']
+ $compare_config['compare_args'],
]));
system($test_run_cmd, $retval);
// What does the exitcode mean?
- if (! isset($EXITCODES[$retval])) {
+ if (!isset($EXITCODES[$retval])) {
alert('error');
error("Unknown exitcode ($retval) from testcase_run.sh for s$judgeTask[submitid]");
}
@@ -1360,17 +1367,18 @@ function judge(array $judgeTask): bool
$description = 'compare script ' . $judgeTask['compare_script_id'] . ' crashed';
disable('compare_script', 'compare_script_id', $judgeTask['compare_script_id'], $description, $judgeTask['judgetaskid']);
}
+
return false;
}
$new_judging_run = [
'runresult' => urlencode($result),
'runtime' => urlencode((string)$runtime),
- 'output_run' => rest_encode_file($testcasedir . '/program.out', $output_storage_limit),
+ 'output_run' => rest_encode_file($testcasedir . '/program.out', $output_storage_limit),
'output_error' => rest_encode_file($testcasedir . '/program.err', $output_storage_limit),
'output_system' => rest_encode_file($testcasedir . '/system.out', $output_storage_limit),
'metadata' => rest_encode_file($testcasedir . '/program.meta', false),
- 'output_diff' => rest_encode_file($testcasedir . '/feedback/judgemessage.txt', $output_storage_limit),
+ 'output_diff' => rest_encode_file($testcasedir . '/feedback/judgemessage.txt', $output_storage_limit),
'hostname' => $myhost,
];
@@ -1432,6 +1440,7 @@ function fetchTestcase(string $workdirpath, string $testcase_id, int $judgetaski
$error = 'Download of ' . $inout . ' failed for case ' . $testcase_id . ', check your problem integrity.';
logmsg(LOG_ERR, $error);
disable('testcase', 'testcaseid', $testcase_id, $error, $judgetaskid);
+
return null;
}
$files = dj_json_decode($content);
@@ -1443,5 +1452,6 @@ function fetchTestcase(string $workdirpath, string $testcase_id, int $judgetaski
unset($files);
logmsg(LOG_INFO, " 💾 Fetched new testcase $testcase_id.");
+
return $tcfile;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment