Ejemplo n.º 1
0
/**
 * Internal error reporting (back from judgehost)
 */
function internal_error_POST($args)
{
    global $DB;
    checkargs($args, array('description', 'judgehostlog', 'disabled'));
    global $cdatas, $api;
    // group together duplicate internal errors
    // note that it may be good to be able to ignore fields here, e.g. judgingid with compile errors
    $errorid = $DB->q('MAYBEVALUE SELECT errorid FROM internal_error
			   WHERE description=%s AND disabled=%s AND status=%s' . (isset($args['cid']) ? ' AND cid=%i' : '%_'), $args['description'], $args['disabled'], 'open', $args['cid']);
    if (isset($errorid)) {
        // FIXME: in some cases it makes sense to extend the known information, e.g. the judgehostlog
        return $errorid;
    }
    $errorid = $DB->q('RETURNID INSERT INTO internal_error
		(judgingid, cid, description, judgehostlog, time, disabled) VALUES
		(%i, %i, %s, %s, %i, %s)', $args['judgingid'], $args['cid'], $args['description'], $args['judgehostlog'], now(), $args['disabled']);
    $disabled = dj_json_decode($args['disabled']);
    // disable what needs to be disabled
    set_internal_error($disabled, $args['cid'], 0);
    if (in_array($disabled['kind'], array('problem', 'language'))) {
        // give back judging if we have to
        $submitid = $DB->q('VALUE SELECT submitid FROM judging WHERE judgingid = %i', $args['judgingid']);
        give_back_judging($args['judgingid'], $submitid);
    }
    return $errorid;
}
Ejemplo n.º 2
0
function judge($row)
{
    global $EXITCODES, $myhost, $options, $workdirpath;
    // Set configuration variables for called programs
    putenv('USE_CHROOT=' . (USE_CHROOT ? '1' : ''));
    putenv('SCRIPTTIMELIMIT=' . dbconfig_get_rest('script_timelimit'));
    putenv('SCRIPTMEMLIMIT=' . dbconfig_get_rest('script_memory_limit'));
    putenv('SCRIPTFILELIMIT=' . dbconfig_get_rest('script_filesize_limit'));
    putenv('MEMLIMIT=' . $row['memlimit']);
    putenv('FILELIMIT=' . $row['outputlimit']);
    putenv('PROCLIMIT=' . dbconfig_get_rest('process_limit'));
    $cpuset_opt = "";
    if (isset($options['daemonid'])) {
        $cpuset_opt = "-n {$options['daemonid']}";
    }
    // create workdir for judging
    $workdir = "{$workdirpath}/c{$row['cid']}-s{$row['submitid']}-j{$row['judgingid']}";
    logmsg(LOG_INFO, "Working directory: {$workdir}");
    // If a database gets reset without removing the judging
    // directories, we might hit an old directory: rename it.
    if (file_exists($workdir)) {
        $oldworkdir = $workdir . '-old-' . getmypid() . '-' . strftime('%Y-%m-%d_%H:%M');
        if (!rename($workdir, $oldworkdir)) {
            error("Could not rename stale working directory to '{$oldworkdir}'");
        }
        @chmod($oldworkdir, 0700);
        warning("Found stale working directory; renamed to '{$oldworkdir}'");
    }
    system("mkdir -p '{$workdir}/compile'", $retval);
    if ($retval != 0) {
        error("Could not create '{$workdir}/compile'");
    }
    // Make sure the workdir is accessible for the domjudge-run user.
    // Will be revoked again after this run finished.
    chmod($workdir, 0755);
    if (!chdir($workdir)) {
        error("Could not chdir to '{$workdir}'");
    }
    // Get the source code from the DB and store in local file(s)
    $sources = request('submission_files', 'GET', 'id=' . urlencode($row['submitid']));
    $sources = dj_json_decode($sources);
    $files = array();
    foreach ($sources as $source) {
        $srcfile = "{$workdir}/compile/{$source['filename']}";
        $files[] = "'{$source['filename']}'";
        if (file_put_contents($srcfile, base64_decode($source['content'])) === FALSE) {
            error("Could not create {$srcfile}");
        }
    }
    if (empty($row['compile_script'])) {
        error("No compile script specified for language " . $row['langid'] . ".");
    }
    $execrunpath = fetch_executable($workdirpath, $row['compile_script'], $row['compile_script_md5sum']);
    // Compile the program.
    system(LIBJUDGEDIR . "/compile.sh {$cpuset_opt} '{$execrunpath}' '{$workdir}' " . implode(' ', $files), $retval);
    // what does the exitcode mean?
    if (!isset($EXITCODES[$retval])) {
        alert('error');
        error("Unknown exitcode from compile.sh for s{$row['submitid']}: {$retval}");
    }
    $compile_success = $EXITCODES[$retval] != 'compiler-error';
    // pop the compilation result back into the judging table
    request('judgings/' . urlencode($row['judgingid']), 'PUT', 'judgehost=' . urlencode($myhost) . '&compile_success=' . $compile_success . '&output_compile=' . rest_encode_file($workdir . '/compile.out'));
    // compile error: our job here is done
    if (!$compile_success) {
        // revoke readablity for domjudge-run user to this workdir
        chmod($workdir, 0700);
        logmsg(LOG_NOTICE, "Judging s{$row['submitid']}/j{$row['judgingid']}: compile error");
        return;
    }
    // Optionally create chroot environment
    if (USE_CHROOT && CHROOT_SCRIPT) {
        logmsg(LOG_INFO, "executing chroot script: '" . CHROOT_SCRIPT . " start'");
        system(LIBJUDGEDIR . '/' . CHROOT_SCRIPT . ' start', $retval);
        if ($retval != 0) {
            error("chroot script exited with exitcode {$retval}");
        }
    }
    $totalcases = 0;
    while (TRUE) {
        // get the next testcase
        $testcase = request('testcases', 'GET', 'judgingid=' . urlencode($row['judgingid']));
        $tc = dj_json_decode($testcase);
        // empty means: no more testcases for this judging.
        if (empty($tc)) {
            break;
        }
        $totalcases++;
        logmsg(LOG_DEBUG, "Running testcase {$tc['rank']}...");
        $testcasedir = $workdir . "/testcase" . sprintf('%03d', $tc['rank']);
        // Get both in- and output files, only if we didn't have them already.
        $tcfile = array();
        $fetched = array();
        foreach (array('input', 'output') as $inout) {
            $tcfile[$inout] = "{$workdirpath}/testcase/testcase.{$tc['probid']}.{$tc['rank']}." . $tc['md5sum_' . $inout] . "." . substr($inout, 0, -3);
            if (!file_exists($tcfile[$inout])) {
                $content = request('testcase_files', 'GET', 'testcaseid=' . urlencode($tc['testcaseid']) . '&' . $inout);
                $content = base64_decode(dj_json_decode($content));
                if (file_put_contents($tcfile[$inout] . ".new", $content) === FALSE) {
                    error("Could not create {$tcfile[$inout]}.new");
                }
                unset($content);
                if (md5_file("{$tcfile[$inout]}.new") === $tc['md5sum_' . $inout]) {
                    rename("{$tcfile[$inout]}.new", $tcfile[$inout]);
                } else {
                    error("File corrupted during download.");
                }
                $fetched[] = $inout;
            }
            // sanity check (NOTE: performance impact is negligible with 5
            // testcases and total 3.3 MB of data)
            if (md5_file($tcfile[$inout]) !== $tc['md5sum_' . $inout]) {
                error("File corrupted: md5sum mismatch: " . $tcfile[$inout]);
            }
        }
        // Only log downloading input and/or output testdata once.
        if (count($fetched) > 0) {
            logmsg(LOG_INFO, "Fetched new " . implode($fetched, ',') . " testcase {$tc['rank']} for problem p{$tc['probid']}");
        }
        // Copy program with all possible additional files to testcase
        // dir. Use hardlinks to preserve space with big executables.
        $programdir = $testcasedir . '/execdir';
        system("mkdir -p '{$programdir}'", $retval);
        if ($retval != 0) {
            error("Could not create directory '{$programdir}'");
        }
        system("cp -PR '{$workdir}'/compile/* '{$programdir}'", $retval);
        if ($retval != 0) {
            error("Could not copy program to '{$programdir}'");
        }
        // do the actual test-run
        $hardtimelimit = $row['maxruntime'] + overshoot_time($row['maxruntime'], dbconfig_get_rest('timelimit_overshoot'));
        $compare_runpath = fetch_executable($workdirpath, $row['compare'], $row['compare_md5sum']);
        $run_runpath = fetch_executable($workdirpath, $row['run'], $row['run_md5sum']);
        system(LIBJUDGEDIR . "/testcase_run.sh {$cpuset_opt} {$tcfile['input']} {$tcfile['output']} " . "{$row['maxruntime']}:{$hardtimelimit} '{$testcasedir}' " . "'{$run_runpath}' '{$compare_runpath}' '{$row['compare_args']}'", $retval);
        // what does the exitcode mean?
        if (!isset($EXITCODES[$retval])) {
            alert('error');
            error("Unknown exitcode from testcase_run.sh for s{$row['submitid']}, " . "testcase {$tc['rank']}: {$retval}");
        }
        $result = $EXITCODES[$retval];
        // Try to read metadata from file
        $runtime = NULL;
        if (is_readable($testcasedir . '/program.meta')) {
            $metadata = spyc_load_file($testcasedir . '/program.meta');
            if (isset($metadata['time-used'])) {
                $runtime = @$metadata[$metadata['time-used']];
            }
        }
        request('judging_runs', 'POST', 'judgingid=' . urlencode($row['judgingid']) . '&testcaseid=' . urlencode($tc['testcaseid']) . '&runresult=' . urlencode($result) . '&runtime=' . urlencode($runtime) . '&judgehost=' . urlencode($myhost) . '&output_run=' . rest_encode_file($testcasedir . '/program.out', FALSE) . '&output_error=' . rest_encode_file($testcasedir . '/program.err') . '&output_system=' . rest_encode_file($testcasedir . '/system.out') . '&output_diff=' . rest_encode_file($testcasedir . '/feedback/judgemessage.txt'));
        logmsg(LOG_DEBUG, "Testcase {$tc['rank']} done, result: " . $result);
    }
    // end: for each testcase
    // revoke readablity for domjudge-run user to this workdir
    chmod($workdir, 0700);
    // Optionally destroy chroot environment
    if (USE_CHROOT && CHROOT_SCRIPT) {
        logmsg(LOG_INFO, "executing chroot script: '" . CHROOT_SCRIPT . " stop'");
        system(LIBJUDGEDIR . '/' . CHROOT_SCRIPT . ' stop', $retval);
        if ($retval != 0) {
            error("chroot script exited with exitcode {$retval}");
        }
    }
    // Sanity check: need to have had at least one testcase
    if ($totalcases == 0) {
        logmsg(LOG_WARNING, "No testcases judged for s{$row['submitid']}/j{$row['judgingid']}!");
    }
    // done!
    logmsg(LOG_NOTICE, "Judging s{$row['submitid']}/j{$row['judgingid']} finished");
}
Ejemplo n.º 3
0
 * Part of the DOMjudge Programming Contest Jury System and licenced
 * under the GNU GPL. See README and COPYING for details.
 */
require 'init.php';
$id = getRequestID();
$refresh = array('after' => 15, 'url' => 'internal_error.php?id=' . urlencode($id));
$title = 'Internal Error e' . @$id;
if (!$id) {
    error("Missing or invalid internal error id");
}
$edata = $DB->q('TUPLE SELECT * FROM internal_error
                 WHERE errorid=%i', $id);
if (!$edata) {
    error("Missing internal error data for e" . $id);
}
$disabled = dj_json_decode($edata['disabled']);
if (isset($_REQUEST['ignore']) || isset($_REQUEST['resolve'])) {
    if (isset($_REQUEST['ignore'])) {
        $status = "ignored";
    }
    if (isset($_REQUEST['resolve'])) {
        $status = "resolved";
    }
    $DB->q('UPDATE internal_error SET status=%s WHERE errorid=%i', $status, $id);
    if ($status == 'resolved') {
        set_internal_error($disabled, $edata['cid'], 1);
    }
    auditlog('internal_error', $id, 'internal error: ' + $status, '');
    header('Location: internal_error.php?id=' . urlencode($id));
}
require LIBWWWDIR . '/header.php';