更新评测语言,更新日志

This commit is contained in:
MeiK 2021-01-26 15:57:07 +08:00
parent 98f6458cb2
commit 085818abc1
18 changed files with 229 additions and 27 deletions

1
.gitignore vendored
View File

@ -16,3 +16,4 @@ Cargo.lock
nohup.out
config.yaml
logs

View File

@ -17,6 +17,7 @@ tempfile = "3"
libc = "0.2"
log = "0.4.0"
env_logger = "0.8.1"
log4rs = "1"
nix = "0.19.0"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.8"

View File

@ -1,7 +1,42 @@
data_dir: /data
data_dir: /root/river/runtime/data
judge_dir: /tmp
languages:
C:
compile_cmd: /usr/bin/gcc main.c -o a.out -Wall -O2 -std=c99 --static
code_file: main.c
run_cmd: ./a.out
Cpp:
compile_cmd: /usr/bin/g++ main.cpp -O2 -Wall --static -o a.out --std=gnu++17
code_file: main.cpp
run_cmd: ./a.out
Python:
compile_cmd: /usr/bin/python3.8 -m compileall main.py
code_file: main.py
run_cmd: /usr/bin/python3.8 main.py
Rust:
compile_cmd: /root/.cargo/bin/rustc main.rs -o a.out -C opt-level=2
code_file: main.rs
run_cmd: ./a.out
Node:
compile_cmd: /usr/bin/node /plugins/node/validate.js main.js
code_file: main.js
run_cmd: /usr/bin/node main.js
TypeScript:
compile_cmd: /usr/bin/tsc -p /tsconfig.json
code_file: main.ts
run_cmd: /usr/bin/node main.js
Go:
compile_cmd: /usr/bin/go build -o a.out main.go
code_file: main.go
run_cmd: ./a.out
Java:
compile_cmd: /usr/bin/javac Main.java
code_file: Main.java
run_cmd: /usr/bin/java -cp . Main

16
log4rs.yaml Normal file
View File

@ -0,0 +1,16 @@
refresh_rate: 30 seconds
appenders:
console:
kind: console
encoder:
pattern: "{d(%Y-%m-%d %H:%M:%S)} [{h({l})}] {m}{n}"
file:
kind: file
path: "logs/river.log"
encoder:
pattern: "{d(%Y-%m-%d %H:%M:%S)} [{l}] {m}{n}"
root:
level: debug
appenders:
- file
- console

View File

@ -1,11 +1,37 @@
FROM ubuntu:focal
ENV LANG C.UTF-8
RUN apt-get update -y
# install gcc g++
RUN apt-get install -y gcc g++
RUN apt-get install -y software-properties-common && \
add-apt-repository -y ppa:deadsnakes/ppa && \
apt-get install -y python3.8 python3-pip
# install python3.8
RUN apt-get install -y software-properties-common && add-apt-repository -y ppa:deadsnakes/ppa && apt-get install -y python3.8 python3-pip
# install rust
RUN apt-get install -y curl && curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y
ENV PATH="/root/.cargo/bin:${PATH}"
# install node
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - && apt-get install -y nodejs
# node compiler
COPY plugins /plugins
RUN cd /plugins/node && npm install
# node runtime
COPY node /
RUN cd / && npm install
# install typescript
RUN npm install -g ts-node typescript
# install go
RUN add-apt-repository -y ppa:longsleep/golang-backports && apt-get install -y golang-go
# install openjdk
RUN apt-get install -y default-jdk
RUN rm -rf /var/lib/apt/lists/*

View File

@ -6,3 +6,5 @@ docker stop river
docker rm river
chmod -R 755 rootfs
mknod -m 0666 rootfs/dev/null c 1 3

15
runtime/node/package.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "river",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@types/node": "^14.14.6"
}
}

View File

@ -0,0 +1,14 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "ESNext",
"skipLibCheck": true,
"strict": false,
"resolveJsonModule": true,
"esModuleInterop": true,
"noErrorTruncation": true,
"allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
}
}

1
runtime/plugins/node/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -0,0 +1,6 @@
return 42; // should be inside a function
function f() {
'use strict';
var x = 042;
with (z) { }
}

13
runtime/plugins/node/package-lock.json generated Normal file
View File

@ -0,0 +1,13 @@
{
"name": "js",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
}
}
}

View File

@ -0,0 +1,16 @@
{
"name": "js",
"version": "1.0.0",
"description": "```bash cd plugins/js ./validate.js success.js ./validate.js failure.js ```",
"main": "failure.js",
"dependencies": {
"esprima": "^4.0.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

View File

@ -0,0 +1 @@
console.log("Hello World!");

View File

@ -0,0 +1,23 @@
#!/usr/bin/node
const fs = require('fs');
const esprima = require('esprima');
const file = process.argv[2];
const code = fs.readFileSync(file).toString();
const res = esprima.parseScript(code, { tolerant: true });
if (res.errors.length != 0) {
const split = code.split('\n');
for (const error of res.errors) {
console.error(split[error.lineNumber - 1]);
for (let i = 1; i < error.column; i++) {
process.stderr.write(' ');
}
console.error('^');
console.error(`${error.toString()}
at (${file}:${error.lineNumber}:${error.column})`);
console.error('--------------------------------------------------------------------------');
}
process.exit(1);
}
process.exit(0);

View File

@ -1,5 +1,5 @@
use super::error::{Error, Result};
use std::env;
use std::collections::HashMap;
use std::ffi::CString;
use std::mem;
use std::ptr;
@ -39,17 +39,18 @@ impl ExecArgs {
argv_vec.push(ptr::null());
let argv: *const *const libc::c_char = argv_vec.as_ptr() as *const *const libc::c_char;
// env 环境变量传递当前进程环境变量
// env 传递环境变量
let mut envs: HashMap<&str, &str> = HashMap::new();
envs.insert(
"PATH",
"/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
);
envs.insert("HOME", "/tmp");
// envs.insert("GOCACHE", "/tmp/.cache");
envs.insert("TERM", "xterm");
let mut envp_vec: Vec<*const libc::c_char> = vec![];
for (key, value) in env::vars_os() {
let mut key = match key.to_str() {
Some(val) => val.to_string(),
None => return Err(Error::OsStringToStringError(key)),
};
let value = match value.to_str() {
Some(val) => val.to_string(),
None => return Err(Error::OsStringToStringError(value)),
};
for (key, value) in envs {
let mut key = String::from(key);
key.push_str("=");
key.push_str(&value);
let cstr = match CString::new(key) {

View File

@ -75,18 +75,13 @@ pub async fn judge(
} else {
status.cgroup_memory_used
};
if status.time_used > time_limit.into() {
if status.time_used > time_limit.into() || status.real_time_used as i64 > time_limit.into() {
// TLE
return Ok(time_limit_exceeded(status.time_used, mem_used));
} else if mem_used > memory_limit.into() {
// MLE
return Ok(memory_limit_exceeded(status.time_used, mem_used));
} else if status.signal != 0 {
// 因墙上时钟超时被主动中断
if status.real_time_used as i64 > time_limit.into() {
// TLE
return Ok(time_limit_exceeded(status.time_used, mem_used));
}
// RE
return Ok(runtime_error(
status.time_used,

View File

@ -2,9 +2,9 @@
#[macro_use]
extern crate log;
use env_logger::Env;
use futures::StreamExt;
use futures_core::Stream;
use log4rs;
use river::judge_request::Data;
use river::river_server::{River, RiverServer};
use river::{JudgeRequest, JudgeResponse, JudgeResultEnum};
@ -49,6 +49,7 @@ impl River for RiverService {
return;
}
};
debug!("{:?}", pwd);
// 是否通过编译
let mut compile_success = false;
let mut language = String::from("");
@ -106,11 +107,7 @@ impl River for RiverService {
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let env = Env::default()
.filter_or("LOG_LEVEL", "debug,h2=info,hyper=info")
.write_style_or("LOG_STYLE", "always");
env_logger::init_from_env(env);
log4rs::init_file("log4rs.yaml", Default::default()).unwrap();
let addr = "0.0.0.0:4003".parse()?;
let river = RiverService::default();

View File

@ -294,6 +294,15 @@ unsafe fn security(process: &Process) {
ptr::null_mut()
));
// 挂载 /proc 目录,有些语言(比如 rust依赖此目录
syscall_or_panic!(libc::mount(
c_str_ptr!("proc"),
c_str_ptr!("runtime/rootfs/proc"),
c_str_ptr!("proc"),
0,
ptr::null_mut(),
));
// 挂载运行文件夹,除此目录外程序没有其他目录的写权限
syscall_or_panic!(libc::mount(
c_str_ptr!(process.workdir.to_str().unwrap()),
@ -534,4 +543,34 @@ mod tests {
assert!(result.real_time_used >= 1000);
assert_ne!(result.signal, 0);
}
#[tokio::test]
async fn test_ls() {
let pwd = tempdir_in("/tmp").unwrap();
let process = Process::new(
String::from("/bin/ls -lah /dev"),
1000,
65535,
pwd.path().to_path_buf(),
);
let result = Runner::from(process).unwrap().await.unwrap();
assert_eq!(result.signal, 0);
let out = std::fs::read_to_string(pwd.path().join(STDOUT_FILENAME)).unwrap();
println!("{}", out);
}
#[tokio::test]
async fn test_dev_null() {
let pwd = tempdir_in("/tmp").unwrap();
let process = Process::new(
String::from("/bin/cat /dev/null"),
1000,
65535,
pwd.path().to_path_buf(),
);
let result = Runner::from(process).unwrap().await.unwrap();
assert_eq!(result.signal, 0);
let out = std::fs::read_to_string(pwd.path().join(STDOUT_FILENAME)).unwrap();
println!("{}", out);
}
}