From d4a454683d72cb52a29fccd8ea656143833a61f7 Mon Sep 17 00:00:00 2001 From: MeiK Date: Wed, 2 Sep 2020 19:36:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=BC=96=E8=AF=91=E7=9A=84?= =?UTF-8?q?=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/error.rs | 2 +- src/judger.rs | 7 +++++ src/main.rs | 6 ++-- src/process.rs | 76 +++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 77 insertions(+), 14 deletions(-) diff --git a/src/error.rs b/src/error.rs index d0464dc..ad5baf9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -18,7 +18,7 @@ pub enum Error { pub type Result = result::Result; -pub fn _errno_str(errno: Option) -> String { +pub fn errno_str(errno: Option) -> String { match errno { Some(no) => { let stre = unsafe { strerror(no) }; diff --git a/src/judger.rs b/src/judger.rs index 8585ccf..0937d9c 100644 --- a/src/judger.rs +++ b/src/judger.rs @@ -25,6 +25,7 @@ impl JudgeResponse { pub async fn judger(request: &JudgeRequest) -> Result { let mut resp = JudgeResponse::new(); resp.time_used = request.time_limit; + resp.status = JudgeStatus::Ended as i32; return Ok(resp); } @@ -52,6 +53,7 @@ pub async fn compile(request: &JudgeRequest, path: &Path) -> Result "/usr/bin/python3 -m compileall main.py", Some(Language::Rust) => "rustc main.rs", // 无需编译的语言直接返回 + // TODO: eslint...... Some(Language::Node) => return Ok(resp), Some(Language::TypeScript) => "tsc", Some(Language::Go) => "main.go", @@ -61,9 +63,14 @@ pub async fn compile(request: &JudgeRequest, path: &Path) -> Result Result<(), Box> { let addr = "127.0.0.1:4003".parse()?; - let greeter = RiverService::default(); + let river = RiverService::default(); Server::builder() - .add_service(RiverServer::new(greeter)) + .concurrency_limit_per_connection(5) + .add_service(RiverServer::new(river)) .serve(addr) .await?; diff --git a/src/process.rs b/src/process.rs index cea5e55..b219ac4 100644 --- a/src/process.rs +++ b/src/process.rs @@ -1,8 +1,10 @@ -use super::error::{Error, Result}; +use super::error::{errno_str, Error, Result}; use libc; use std::env; use std::ffi::CString; +use std::fs; use std::future::Future; +use std::io; use std::mem; use std::path::PathBuf; use std::pin::Pin; @@ -19,9 +21,9 @@ pub struct Process { pub workdir: PathBuf, pub time_limit: i32, pub memory_limit: i32, - pub stdin_fd: i32, - pub stdout_fd: i32, - pub stderr_fd: i32, + pub stdin_file: Option, + pub stdout_file: Option, + pub stderr_file: Option, pub cmd: String, tx: Arc>>, rx: Arc>>, @@ -34,9 +36,9 @@ impl Process { pid: -1, time_limit: -1, memory_limit: -1, - stdin_fd: -1, - stdout_fd: -1, - stderr_fd: -1, + stdin_file: None, + stdout_file: None, + stderr_file: None, cmd: "".to_string(), workdir: PathBuf::from(""), tx: Arc::new(Mutex::new(tx)), @@ -67,7 +69,7 @@ impl Future for Process { run(process_clone); } else if pid > 0 { tx.send(pid).unwrap(); - let status = wait(pid); + let status = wait(pid, process_clone.workdir); let status_tx = process_clone.tx.lock().unwrap(); status_tx.send(status).unwrap(); waker.wake(); @@ -167,20 +169,62 @@ impl ExecArgs { } } +impl Drop for ExecArgs { + fn drop(&mut self) { + // TODO: 将不安全的指针类型转换回内置类型,以便由 Rust 自动回收资源 + println!("Dropping!"); + } +} + fn run(process: Process) { // 子进程里崩溃也无法返回,崩溃就直接崩溃了 let exec_args = ExecArgs::build(&process.cmd).unwrap(); // 修改工作目录 env::set_current_dir(process.workdir).unwrap(); - println!("{}", process.cmd); unsafe { // TODO: 资源限制等 + // 重定向文件描述符 + if let Some(file) = process.stdin_file { + dup(&file, libc::STDIN_FILENO, libc::O_RDONLY, 0o644) + } + if let Some(file) = process.stdout_file { + dup( + &file, + libc::STDOUT_FILENO, + libc::O_CREAT | libc::O_RDWR, + 0o644, + ) + } + if let Some(file) = process.stderr_file { + dup( + &file, + libc::STDERR_FILENO, + libc::O_CREAT | libc::O_RDWR, + 0o644, + ) + } libc::execve(exec_args.pathname, exec_args.argv, exec_args.envp); } panic!("How dare you!"); } -fn wait(pid: i32) -> ProcessStatus { +unsafe fn dup(filename: &str, to: libc::c_int, flag: libc::c_int, mode: libc::c_int) { + let filename_str = CString::new(filename).unwrap(); + let filename = filename_str.as_ptr(); + let fd = libc::open(filename, flag, mode); + if fd < 0 { + let err = io::Error::last_os_error().raw_os_error(); + eprintln!("open failure!"); + panic!(errno_str(err)); + } + if libc::dup2(fd, to) < 0 { + let err = io::Error::last_os_error().raw_os_error(); + eprintln!("dup2 failure!"); + panic!(errno_str(err)); + } +} + +fn wait(pid: i32, workdir: PathBuf) -> ProcessStatus { let start = SystemTime::now(); let mut status = 0; let mut rusage = libc::rusage { @@ -233,12 +277,22 @@ fn wait(pid: i32) -> ProcessStatus { // How dare you! Err(_) => panic!("How dare you!"), }; + let stdout = match fs::read_to_string(workdir.join("stdout.txt")) { + Ok(val) => val, + Err(_) => panic!("How dare you!"), + }; + let stderr = match fs::read_to_string(workdir.join("stderr.txt")) { + Ok(val) => val, + Err(_) => panic!("How dare you!"), + }; return ProcessStatus { rusage: rusage, exit_code: exit_code, status: status, signal: signal, real_time_used: real_time_used, + stdout: stdout, + stderr: stderr, }; } @@ -249,4 +303,6 @@ pub struct ProcessStatus { pub status: i32, pub signal: i32, pub real_time_used: u128, + pub stdout: String, + pub stderr: String, }