Skip to content

Instantly share code, notes, and snippets.

@fanzeyi
Created February 17, 2012 03:42
Show Gist options
  • Save fanzeyi/1850402 to your computer and use it in GitHub Desktop.
Save fanzeyi/1850402 to your computer and use it in GitHub Desktop.
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#ifdef EXIT_FAILURE
#undef EXIT_FAILURE
#endif
#define EXIT_FAILURE 123
#define EXIT_TIMEDOUT 124
pid_t cpid = -2;
char *self;
int timed_out = 0;
void err(const char *s) {
char prefix[1024];
sprintf(prefix, "%s: %s", self, s);
perror(prefix);
}
void killchild() {
if (0 != kill(cpid, SIGKILL)) {
if (!(ESRCH == errno)) {
err("kill");
exit(EXIT_FAILURE);
}
}
}
void sig_alrm(int signum) {
killchild();
timed_out = 1;
}
int main(int argc, char *argv[]) {
self = argv[0];
if (0 != geteuid()) {
fprintf(stderr, "%s: need superuser privileges.\n", self);
exit(EXIT_FAILURE);
}
if (4 != argc) {
fprintf(stderr, "usage: %s timelimit memlimit a.out\n", self);
exit(EXIT_FAILURE);
}
unsigned int timelimit;
unsigned long memlimit;
if ((0 == sscanf(argv[1], "%u", &timelimit) || 0 == timelimit) || (0 == sscanf(argv[2], "%lu", &memlimit) || 0 == memlimit)) {
fprintf(stderr, "usage: %s timelimit memlimit a.out\n", self);
exit(EXIT_FAILURE);
}
char *basec, *base;
basec = strdup(argv[3]);
base = basename(basec);
char newpath[256] = "root/";
DIR *dp;
struct dirent *ep;
if (-1 == chdir(newpath)) {
err("chdir");
exit(EXIT_FAILURE);
}
if (NULL == (dp = opendir("./"))) {
err("opendir");
exit(EXIT_FAILURE);
}
while ((ep = readdir(dp))) {
if (!strcmp("a.out", ep->d_name)) {
if (-1 == unlink(ep->d_name)) {
err("unlink");
exit(EXIT_FAILURE);
}
}
}
closedir(dp);
if (-1 == chdir("../")) {
err("chdir");
exit(EXIT_FAILURE);
}
strcat(newpath, base);
if (-1 == link(argv[3], newpath)) {
err("link");
exit(EXIT_FAILURE);
}
if (-1 == (cpid = fork())) {
err("fork");
exit(EXIT_FAILURE);
} else if (0 == cpid) {
struct rlimit rlim;
// rlim.rlim_cur = 100000000;
// rlim.rlim_max = 100000000;
// if (-1 == setrlimit(RLIMIT_FSIZE, &rlim)) {
// err("setrlimit");
// exit(EXIT_FAILURE);
// }
rlim.rlim_cur = 1;
rlim.rlim_max = 1;
if (-1 == setrlimit(RLIMIT_NPROC, &rlim)) {
err("setrlimit");
exit(EXIT_FAILURE);
}
rlim.rlim_cur = memlimit;
rlim.rlim_max = memlimit;
if (-1 == setrlimit(RLIMIT_AS, &rlim)) {
err("setrlimit");
exit(EXIT_FAILURE);
}
if (-1 == nice(10)) {
err("nice");
exit(EXIT_FAILURE);
}
if (-1 == chroot("root")) {
err("chroot");
exit(EXIT_FAILURE);
}
if (-1 == chdir("/")) {
err("chdir");
exit(EXIT_FAILURE);
}
// if (-1 == setuid(65534)) {
// err("setuid");
// exit(EXIT_FAILURE);
// }
char execpath[256] = "/";
strcat(execpath, base);
char *newargv[] = { base, NULL };
char *newenvp[] = { NULL };
execve(execpath, newargv, newenvp);
err("execve");
exit(EXIT_FAILURE);
} else {
atexit(killchild);
if (SIG_ERR == signal(SIGALRM, sig_alrm)) {
err("signal");
exit(EXIT_FAILURE);
}
alarm(timelimit);
int status = 0;
if (-1 == waitpid(cpid, &status, 0)) {
err("waitpid");
exit(EXIT_FAILURE);
}
if (SIG_ERR == signal(SIGALRM, SIG_DFL)) {
err("signal");
exit(EXIT_FAILURE);
}
if (-1 == unlink(newpath)) {
err("unlink");
exit(EXIT_FAILURE);
}
if (timed_out) {
exit(EXIT_TIMEDOUT);
}
if (WIFEXITED(status)) {
exit(WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
raise(WTERMSIG(status));
} else {
exit(EXIT_SUCCESS);
}
}
assert(0);
}
# -*- coding: UTF-8 -*-
import re
import os
import sys
import base64
import subprocess
import tornado.web
import tornado.ioloop
import tornado.options
import tornado.httpserver
GRADE_NAME = "Ptolemy"
GRADE_VERSION = "0.01"
COMPILE_DIR = "/home/fanzeyi/cogs_data/comp/"
ROOT_DIR = COMPILE_DIR + "root/"
TESTDATA_DIR = "/home/fanzeyi/cogs_data/testdata/"
LOCK_FILE = '/tmp/ptolemy.lock'
tornado.options.parse_command_line()
def get_status():
try:
lock = open(LOCK_FILE, 'r')
except IOError:
with open(LOCK_FILE, 'w') as lock:
lock.write('free')
return 'free'
else:
return lock.read().replace('\n', '')
def set_status(status):
assert isinstance(status, (unicode, str))
with open(LOCK_FILE, 'w') as lock:
lock.write(status)
def array_encode(arr):
sa = []
for k in arr:
sa.append(base64.b64encode(str(k)))
sa.append(base64.b64encode(str(arr[k])))
s = "?".join(sa)
return base64.b64encode(s)
def array_decode(s):
arr = {}
s = base64.b64decode(s)
sa = s.split("?")
for k, v in zip(sa[::2], sa[1::2]):
arr[base64.b64decode(k)] = base64.b64decode(v)
return arr
def GetCompileStr(ty, filename):
if ty == '0':
return "fpc %s -So -XS -v0 -O1 -o\"a.out\"" % (filename)
elif ty == '1':
return "gcc %s -lm -w -static -o a.out" % (filename)
elif ty == '2':
return "g++ %s -lm -static -o a.out" % (filename)
def _get_time(time):
return int((int(time) + 1000 - 1) / 1000)
def _clean(dir_path):
for root, dirs, files in os.walk(dir_path):
for name in files:
os.remove(os.path.join(root, name))
def _compile(query):
result = {}
_clean(COMPILE_DIR)
os.chdir(COMPILE_DIR)
with open(COMPILE_DIR + query['src'], "w+") as code:
code.write(query['code'])
cmd = "timeout 30 " + GetCompileStr(query['language'], query['src'])
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
(stdoutput,erroutput) = proc.communicate()
result['msg'] = "".join(["STDOUT:\n--------\n", stdoutput, "\n--------\nSTDERR\n--------\n", erroutput])
result['cmd'] = cmd
if proc.returncode != 0:
result['compilesucc'] = 0
else:
result['compilesucc'] = 1
return result
def _run(mem, time):
os.chdir(COMPILE_DIR)
cmd = "/usr/bin/time -f \"%%e %%x %%M\" /usr/bin/fork %d %d a.out" % (_get_time(time), int(mem) * 1024 * 1024)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
(stdoutput,erroutput) = proc.communicate()
re_signal = re.compile(r'^Command terminated by signal ([0-9])*$')
time_cmd_opt = erroutput.split('\n')
signal = None
for line in time_cmd_opt:
if re_signal.findall(line):
signal = re_signal.findall(line)
print time_cmd_opt
return signal, time_cmd_opt[-2].split(' ')
def _compare(fout, fans):
out = [line.strip() for line in fout if line.strip()]
ans = [line.strip() for line in fans if line.strip()]
return ans == out
'''
About Exitcode
SIGNAL 9 - MLE
124 - TLE
'''
def _grade(query):
result = {}
result['memoryout'] = 0
result['timeout'] = 0
result['runerr'] = 0
result['noreport'] = 0
# 初始化错误
base_filename = "".join([TESTDATA_DIR, query['pname'], "/", query['pname'], query['grade']])
with open("".join([base_filename, ".in"]), "r") as input_fp:
input_data = input_fp.read()
with open("".join([ROOT_DIR, query['pname'], ".in"]), "w") as input_fp:
input_fp.write(input_data)
signal, [rtime, result['exitcode'], result['memory']] = _run(query['memorylimit'], query['timelimit'])
result['rtime'] = float(rtime) * 1000
if result['rtime'] > query['timelimit']:
result['timeout'] = 1
if signal and signal[0] == '9':
result['memoryout'] = 1
result['exitcode'] = 9
if result['exitcode'] == '124':
result['timeout'] = 1
print signal, result
if signal or result['exitcode'] != '0':
result['runerr'] = 1
try:
output_fp = open("".join([ROOT_DIR, query['pname'], '.out']), 'r')
except IOError:
result['noreport'] = 1
else:
output = output_fp.read()
output_fp.close()
with open("".join([base_filename, ".ans"]), "r") as answer_fp:
answer = answer_fp.read()
if not result['noreport']:
if not _compare(output, answer):
result['score'] = 0
else:
result['score'] = 1
_clean(ROOT_DIR)
return result
class GradeHandler(tornado.web.RequestHandler):
def post(self):
query = array_decode(self.get_argument('query'))
if not query:
return
self.write("<return>")
result = {}
if query['action'] == 'state':
result['cnt'] = "0"
result['name'] = GRADE_NAME
result['state'] = get_status()
result['ver'] = GRADE_VERSION
elif query['action'] == 'lock':
set_status('locked')
result['state'] = "successful"
elif query['action'] == 'unlock':
set_status('free')
result['state'] = 'successful'
elif query['action'] == "shutdown":
set_status('free')
result['state'] = "successful"
elif query['action'] == 'shutdown':
set_status('closed')
result['state'] = "successful"
elif query['action'] == 'compile':
result = _compile(query)
elif query['action'] == "grade":
result = _grade(query)
self.write(array_encode(result))
class Ptolemy(tornado.web.Application):
def __init__(self):
handlers = [
(r'/', GradeHandler),
]
settings = {
'site_title' : "COGS Grading",
'debug' : True,
}
tornado.web.Application.__init__(self, handlers, **settings)
if __name__ == '__main__':
http_server = tornado.httpserver.HTTPServer(Ptolemy())
http_server.listen(8889)
tornado.ioloop.IOLoop.instance().start()
@upsuper
Copy link

upsuper commented Feb 17, 2012

这么快就把测评服务器的代码做出来了啊

@fanzeyi
Copy link
Author

fanzeyi commented Feb 17, 2012

@upsuper 这是我之前做的。。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment