1use crate::settings::CompileAndExeSetting;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use tempfile::TempDir;
5
6#[cfg(feature = "compile")]
7use crate::result::CompileResult;
8#[cfg(feature = "compile")]
9use std::process::Stdio;
10#[cfg(any(feature = "compile", feature = "run"))]
11use tokio::io::{AsyncReadExt, AsyncWriteExt};
12
13#[cfg(feature = "run")]
14use crate::{
15 cgroup::Cgroup,
16 quantity::{MemorySize, ProcessResource, TimeSpan},
17 result::{InitExeResourceResult, RunToEndResult, RunWithInteractorResult},
18};
19#[cfg(feature = "run")]
20use std::{
21 os::fd::FromRawFd,
22 os::unix::fs::PermissionsExt,
23 time::{Duration, Instant},
24};
25
26#[derive(Debug, Serialize, Deserialize, Clone)]
27pub struct RawCode {
28 pub code: Vec<u8>,
29 pub compile_and_exe_setting: CompileAndExeSetting,
30}
31
32pub fn turn_command_into_command_and_args(command: &str) -> (String, Vec<String>) {
33 let mut command = command.split_whitespace();
34 let result_command = command.next().unwrap().to_string();
35 let mut result_args = vec![];
36 for arg in command {
37 result_args.push(arg.to_string());
38 }
39 (result_command, result_args)
40}
41
42impl RawCode {
43 pub fn new(code: &Vec<u8>, compile_and_exe_setting: &CompileAndExeSetting) -> Self {
44 Self {
45 code: code.clone(),
46 compile_and_exe_setting: compile_and_exe_setting.clone(),
47 }
48 }
49
50 #[cfg(feature = "compile")]
51 pub async fn compile(&self) -> CompileResult {
52 if self.compile_and_exe_setting.compile_command.is_empty() {
53 if self.compile_and_exe_setting.exe_files.is_empty()
54 || self.compile_and_exe_setting.exe_files.len() > 1
55 {
56 return CompileResult::SettingError;
57 }
58 let mut exe_files = HashMap::new();
59 exe_files.insert(
60 self.compile_and_exe_setting.exe_files[0].clone(),
61 self.code.clone(),
62 );
63 return CompileResult::Ok(ExeCode {
64 exe_files: exe_files,
65 compile_and_exe_setting: self.compile_and_exe_setting.clone(),
66 });
67 }
68 let id = format!(
69 "emjudge-judgecore-compile-{}",
70 uuid::Uuid::new_v4().simple().to_string()
71 );
72 let compile_dir = match TempDir::with_prefix(id.as_str()) {
73 Err(result) => {
74 return CompileResult::InternalError(result.to_string());
75 }
76 Ok(result) => result,
77 };
78 let compile_command = self.compile_and_exe_setting.compile_command.as_str();
79 let raw_code_path = format!(
80 "{}/{}",
81 compile_dir.path().to_str().unwrap(),
82 self.compile_and_exe_setting.raw_code
83 );
84 let raw_code_path = raw_code_path.as_str();
85 match tokio::fs::File::create(raw_code_path).await {
86 Err(result) => {
87 return CompileResult::InternalError(result.to_string());
88 }
89 Ok(mut file) => match file.write_all(&self.code).await {
90 Err(result) => {
91 return CompileResult::InternalError(result.to_string());
92 }
93 Ok(_) => {}
94 },
95 };
96 let (command, args) = turn_command_into_command_and_args(compile_command);
97 let p = tokio::process::Command::new(command)
98 .stdout(Stdio::null())
99 .stderr(Stdio::piped())
100 .args(args)
101 .current_dir(compile_dir.path().to_str().unwrap())
102 .spawn();
103 let mut p = match p {
104 Err(result) => return CompileResult::InternalError(result.to_string()),
105 Ok(result) => result,
106 };
107 if let Err(result) = p.wait().await {
108 return CompileResult::InternalError(result.to_string());
109 }
110 let mut stderr_output = String::new();
111 if let Err(result) = p
112 .stderr
113 .take()
114 .unwrap()
115 .read_to_string(&mut stderr_output)
116 .await
117 {
118 return CompileResult::InternalError(result.to_string());
119 }
120 let mut exe_files = HashMap::new();
121 for exe_file in &self.compile_and_exe_setting.exe_files {
122 let mut exe_code_file = Vec::new();
123 let exe_code_path = format!("{}/{}", compile_dir.path().to_str().unwrap(), exe_file);
124 let exe_code_path = exe_code_path.as_str();
125 let _ = match tokio::fs::File::open(exe_code_path).await {
126 Ok(mut result) => result.read_to_end(&mut exe_code_file).await,
127 Err(result) => match result.kind() {
128 std::io::ErrorKind::NotFound => {
129 return CompileResult::CompileError(stderr_output);
130 }
131 _ => {
132 return CompileResult::InternalError(result.to_string());
133 }
134 },
135 };
136 exe_files.insert(exe_file.clone(), exe_code_file);
137 }
138 if exe_files.is_empty() {
139 return CompileResult::SettingError;
140 }
141 CompileResult::Ok(ExeCode {
142 exe_files: exe_files,
143 compile_and_exe_setting: self.compile_and_exe_setting.clone(),
144 })
145 }
146}
147
148#[derive(Debug)]
149pub struct ExeResources {
150 pub uid: u32,
151 pub exe_dir: TempDir,
152 pub exe_command: String,
153 pub stdin_path: String,
154 pub stdout_path: String,
155 pub stderr_path: String,
156 pub interactorin_path: String,
157 pub interactorout_path: String,
158}
159
160#[cfg(feature = "run")]
161impl ExeResources {
162 async fn new(
163 uid: u32,
164 exe_files: &HashMap<String, Vec<u8>>,
165 compile_and_exe_setting: &CompileAndExeSetting,
166 ) -> InitExeResourceResult {
167 if check_admin_privilege() == false {
168 return InitExeResourceResult::PermissionDenied;
169 }
170 let id = format!(
171 "emjudge-judgecore-exe-{}",
172 uuid::Uuid::new_v4().simple().to_string()
173 );
174 let exe_dir = match TempDir::with_prefix(id.as_str()) {
175 Err(result) => {
176 return InitExeResourceResult::InternalError(result.to_string());
177 }
178 Ok(result) => result,
179 };
180 let exe_dir_path = exe_dir
181 .path()
182 .to_owned()
183 .clone()
184 .to_string_lossy()
185 .to_string();
186 let stdin_path = format!("{}/stdin", exe_dir_path);
187 let stdout_path = format!("{}/stdout", exe_dir_path);
188 let stderr_path = format!("{}/stderr", exe_dir_path);
189 let interactorin_path = format!("{}/interactorin", exe_dir_path);
190 let interactorout_path = format!("{}/interactorout", exe_dir_path);
191 let mut all_file_path_vec = vec![interactorin_path.clone(), interactorout_path.clone()];
192 match tokio::fs::File::create(interactorin_path.as_str()).await {
193 Err(result) => {
194 return InitExeResourceResult::InternalError(result.to_string());
195 }
196 Ok(_) => {}
197 };
198 match tokio::fs::metadata(interactorin_path.as_str()).await {
199 Err(result) => {
200 return InitExeResourceResult::InternalError(result.to_string());
201 }
202 Ok(metadata) => {
203 let mut permissions = metadata.permissions();
204 permissions.set_mode(0o700);
205 match tokio::fs::set_permissions(&interactorin_path, permissions.clone()).await {
206 Err(result) => {
207 return InitExeResourceResult::InternalError(result.to_string());
208 }
209 Ok(_) => {}
210 }
211 }
212 }
213
214 match tokio::fs::File::create(interactorout_path.as_str()).await {
215 Err(result) => {
216 return InitExeResourceResult::InternalError(result.to_string());
217 }
218 Ok(_) => {}
219 };
220 match tokio::fs::metadata(interactorout_path.as_str()).await {
221 Err(result) => {
222 return InitExeResourceResult::InternalError(result.to_string());
223 }
224 Ok(metadata) => {
225 let mut permissions = metadata.permissions();
226 permissions.set_mode(0o700);
227 match tokio::fs::set_permissions(&interactorout_path, permissions.clone()).await {
228 Err(result) => {
229 return InitExeResourceResult::InternalError(result.to_string());
230 }
231 Ok(_) => {}
232 }
233 }
234 }
235
236 for (exe_file, script) in exe_files {
237 let exe_code_path = format!("{}/{}", exe_dir_path, exe_file);
238 match tokio::fs::File::create(exe_code_path.as_str()).await {
239 Err(result) => {
240 return InitExeResourceResult::InternalError(result.to_string());
241 }
242 Ok(mut file) => match file.write_all(script).await {
243 Err(result) => {
244 return InitExeResourceResult::InternalError(result.to_string());
245 }
246 Ok(_) => {}
247 },
248 };
249 match tokio::fs::metadata(exe_code_path.as_str()).await {
250 Err(result) => {
251 return InitExeResourceResult::InternalError(result.to_string());
252 }
253 Ok(metadata) => {
254 let mut permissions = metadata.permissions();
255 permissions.set_mode(0o500);
256 match tokio::fs::set_permissions(&exe_code_path, permissions.clone()).await {
257 Err(result) => {
258 return InitExeResourceResult::InternalError(result.to_string());
259 }
260 Ok(_) => {}
261 }
262 }
263 }
264 all_file_path_vec.push(exe_code_path.clone());
265 }
266 match tokio::process::Command::new("chown")
267 .arg(format!("{}:{}", uid, uid))
268 .args(&all_file_path_vec)
269 .spawn()
270 {
271 Err(result) => {
272 return InitExeResourceResult::InternalError(result.to_string());
273 }
274 Ok(mut p) => match p.wait().await {
275 Err(result) => return InitExeResourceResult::InternalError(result.to_string()),
276 Ok(_) => {}
277 },
278 };
279
280 InitExeResourceResult::Ok(Self {
281 uid: uid,
282 exe_dir: exe_dir,
283 exe_command: compile_and_exe_setting.exe_command.clone(),
284 stdin_path: stdin_path,
285 stdout_path: stdout_path,
286 stderr_path: stderr_path,
287 interactorin_path: interactorin_path,
288 interactorout_path: interactorout_path,
289 })
290 }
291
292 async fn read_stdout(&self) -> Result<Vec<u8>, String> {
293 let mut buf = vec![];
294 match tokio::fs::File::open(self.stdout_path.as_str()).await {
295 Err(result) => {
296 return Err(result.to_string());
297 }
298 Ok(mut file) => match file.read_to_end(&mut buf).await {
299 Err(result) => {
300 return Err(result.to_string());
301 }
302 Ok(_) => Ok(buf),
303 },
304 }
305 }
306
307 async fn read_stderr(&self) -> Result<Vec<u8>, String> {
308 let mut buf = vec![];
309 match tokio::fs::File::open(self.stderr_path.as_str()).await {
310 Err(result) => {
311 return Err(result.to_string());
312 }
313 Ok(mut file) => match file.read_to_end(&mut buf).await {
314 Err(result) => {
315 return Err(result.to_string());
316 }
317 Ok(_) => Ok(buf),
318 },
319 }
320 }
321
322 async fn read_interactorout(&self) -> Result<Vec<u8>, String> {
323 let mut buf = vec![];
324 match tokio::fs::File::open(self.interactorout_path.as_str()).await {
325 Err(result) => {
326 return Err(result.to_string());
327 }
328 Ok(mut file) => match file.read_to_end(&mut buf).await {
329 Err(result) => {
330 return Err(result.to_string());
331 }
332 Ok(_) => Ok(buf),
333 },
334 }
335 }
336
337 pub async fn run_to_end(
338 &mut self,
339 input: &Vec<u8>,
340 cgroup: &mut Cgroup,
341 time_limit: TimeSpan,
342 output_limit: MemorySize,
343 ) -> RunToEndResult {
344 match tokio::fs::File::create(self.stdin_path.as_str()).await {
345 Err(result) => {
346 return RunToEndResult::InternalError(result.to_string());
347 }
348 Ok(mut file) => match file.write_all(input).await {
349 Err(result) => {
350 return RunToEndResult::InternalError(result.to_string());
351 }
352 Ok(_) => {}
353 },
354 };
355 match cgroup.reset_max_usage_in_bytes() {
356 Err(result) => {
357 return RunToEndResult::InternalError(result.to_string());
358 }
359 Ok(_) => {}
360 }
361 let p = {
362 let stdin = match std::fs::File::open(self.stdin_path.as_str()) {
363 Err(result) => return RunToEndResult::InternalError(result.to_string()),
364 Ok(result) => result,
365 };
366 let stdout = match std::fs::File::create(self.stdout_path.as_str()) {
367 Err(result) => return RunToEndResult::InternalError(result.to_string()),
368 Ok(result) => result,
369 };
370 let stderr = match std::fs::File::create(self.stderr_path.as_str()) {
371 Err(result) => return RunToEndResult::InternalError(result.to_string()),
372 Ok(result) => result,
373 };
374 let (command, args) = turn_command_into_command_and_args(self.exe_command.as_str());
375 tokio::process::Command::new(command)
376 .stdin(stdin)
377 .stdout(stdout)
378 .stderr(stderr)
379 .args(args)
380 .current_dir(self.exe_dir.path())
381 .uid(self.uid)
382 .spawn()
383 };
384 match p {
385 Err(result) => {
386 return RunToEndResult::InternalError(result.to_string());
387 }
388 Ok(mut p) => {
389 let start_time = Instant::now();
390 match cgroup.add_task(p.id().unwrap() as i32) {
391 Err(result) => {
392 let _ = p.kill().await;
393 return RunToEndResult::InternalError(result.to_string());
394 }
395 Ok(_) => {}
396 }
397 let result = tokio::time::timeout(Duration::from(time_limit), p.wait()).await;
398 let runtime = TimeSpan::from(start_time.elapsed());
399 let _ = p.kill().await;
400 let _ = p.wait().await;
401 let is_oom = match cgroup.update_cgroup_and_controller_and_check_oom() {
402 Err(result) => {
403 return RunToEndResult::InternalError(result.to_string());
404 }
405 Ok(result) => result,
406 };
407 let memory = match cgroup.get_max_usage_in_bytes() {
408 Err(result) => {
409 return RunToEndResult::InternalError(result.to_string());
410 }
411 Ok(result) => MemorySize::from_bytes(result as usize),
412 };
413 let stdout = {
414 match check_file_limit(self.stdout_path.as_str(), output_limit).await {
415 Err(result) => {
416 return RunToEndResult::InternalError(result);
417 }
418 Ok(result) => {
419 if result != "" {
420 return RunToEndResult::OutputLimitExceeded(ProcessResource {
421 memory: memory,
422 runtime: runtime,
423 stdout: vec![],
424 stderr: vec![],
425 });
426 }
427 }
428 }
429 match self.read_stdout().await {
430 Ok(result) => result,
431 Err(result) => return RunToEndResult::InternalError(result),
432 }
433 };
434 let stderr = {
435 match check_file_limit(self.stderr_path.as_str(), output_limit).await {
436 Err(result) => {
437 return RunToEndResult::InternalError(result);
438 }
439 Ok(result) => {
440 if result != "" {
441 return RunToEndResult::OutputLimitExceeded(ProcessResource {
442 memory: memory,
443 runtime: runtime,
444 stdout: vec![],
445 stderr: vec![],
446 });
447 }
448 }
449 }
450 match self.read_stderr().await {
451 Ok(result) => result,
452 Err(result) => return RunToEndResult::InternalError(result),
453 }
454 };
455 if is_oom {
456 return RunToEndResult::MemoryLimitExceeded(ProcessResource {
457 memory: memory,
458 runtime: runtime,
459 stdout: stdout,
460 stderr: stderr,
461 });
462 }
463 let in_time_result = if result.is_err() || runtime > time_limit {
464 return RunToEndResult::TimeLimitExceeded(ProcessResource {
465 memory: memory,
466 runtime: runtime,
467 stdout: stdout,
468 stderr: stderr,
469 });
470 } else {
471 result.unwrap()
472 };
473 if in_time_result.is_ok_and(|status| status.success()) {
474 return RunToEndResult::Ok(ProcessResource {
475 memory: memory,
476 runtime: runtime,
477 stdout: stdout,
478 stderr: stderr,
479 });
480 } else {
481 return RunToEndResult::RuntimeError(ProcessResource {
482 memory: memory,
483 runtime: runtime,
484 stdout: stdout,
485 stderr: stderr,
486 });
487 }
488 }
489 }
490 }
491
492 pub async fn run_with_interactor(
493 &mut self,
494 cgroup: &mut Cgroup,
495 time_limit: TimeSpan,
496 interactor_exe_resources: &mut ExeResources,
497 interactor_cgroup: &mut Cgroup,
498 interactor_extra_time_limit: TimeSpan,
499 interactor_input: &Vec<u8>,
500 output_limit: MemorySize,
501 ) -> RunWithInteractorResult {
502 match cgroup.reset_max_usage_in_bytes() {
503 Err(result) => {
504 return RunWithInteractorResult::InternalError(result.to_string());
505 }
506 Ok(_) => {}
507 }
508
509 match interactor_cgroup.reset_max_usage_in_bytes() {
510 Err(result) => {
511 return RunWithInteractorResult::InternalError(result.to_string());
512 }
513 Ok(_) => {}
514 }
515
516 let (pipe_to_interactor_read, pipe_to_interactor_write) = match nix::unistd::pipe() {
517 Err(result) => {
518 return RunWithInteractorResult::InternalError(result.to_string());
519 }
520 Ok(result) => result,
521 };
522
523 let (pipe_from_interactor_read, pipe_from_interactor_write) = match nix::unistd::pipe() {
524 Err(result) => {
525 return RunWithInteractorResult::InternalError(result.to_string());
526 }
527 Ok(result) => result,
528 };
529
530 match tokio::fs::File::create(interactor_exe_resources.interactorin_path.as_str()).await {
531 Err(result) => {
532 return RunWithInteractorResult::InternalError(result.to_string());
533 }
534 Ok(mut file) => match file.write_all(interactor_input).await {
535 Err(result) => {
536 return RunWithInteractorResult::InternalError(result.to_string());
537 }
538 Ok(_) => {}
539 },
540 };
541
542 let mut interactor_p = {
543 let stderr = match std::fs::File::create(interactor_exe_resources.stderr_path.as_str())
544 {
545 Err(result) => {
546 return RunWithInteractorResult::InternalError(result.to_string());
547 }
548 Ok(result) => result,
549 };
550 let (command, args) =
551 turn_command_into_command_and_args(interactor_exe_resources.exe_command.as_str());
552
553 match tokio::process::Command::new(command)
554 .stdin(unsafe { std::fs::File::from_raw_fd(pipe_to_interactor_read) })
555 .stdout(unsafe { std::fs::File::from_raw_fd(pipe_from_interactor_write) })
556 .stderr(stderr)
557 .args(args)
558 .uid(interactor_exe_resources.uid)
559 .current_dir(interactor_exe_resources.exe_dir.path())
560 .spawn()
561 {
562 Err(result) => {
563 return RunWithInteractorResult::InternalError(result.to_string());
564 }
565 Ok(result) => result,
566 }
567 };
568
569 let interactor_start_time = Instant::now();
570 match interactor_cgroup.add_task(interactor_p.id().unwrap() as i32) {
571 Err(result) => {
572 let _ = interactor_p.kill().await;
573 return RunWithInteractorResult::InternalError(result.to_string());
574 }
575 Ok(_) => {}
576 };
577
578 let mut p = {
579 let stderr = match std::fs::File::create(self.stderr_path.as_str()) {
580 Err(result) => {
581 let _ = interactor_p.kill().await;
582 return RunWithInteractorResult::InternalError(result.to_string());
583 }
584 Ok(result) => result,
585 };
586 let (command, args) = turn_command_into_command_and_args(self.exe_command.as_str());
587 match tokio::process::Command::new(command)
588 .stdin(unsafe { std::fs::File::from_raw_fd(pipe_from_interactor_read) })
589 .stdout(unsafe { std::fs::File::from_raw_fd(pipe_to_interactor_write) })
590 .stderr(stderr)
591 .args(args)
592 .uid(self.uid)
593 .current_dir(self.exe_dir.path())
594 .spawn()
595 {
596 Err(result) => {
597 let _ = interactor_p.kill().await;
598 return RunWithInteractorResult::InternalError(result.to_string());
599 }
600 Ok(result) => result,
601 }
602 };
603 let start_time = Instant::now();
604
605 match cgroup.add_task(p.id().unwrap() as i32) {
606 Err(result) => {
607 let _ = p.kill().await;
608 let _ = interactor_p.kill().await;
609 return RunWithInteractorResult::InternalError(result.to_string());
610 }
611 Ok(_) => {}
612 };
613
614 let result = tokio::time::timeout(Duration::from(time_limit), p.wait()).await;
615 let runtime = TimeSpan::from(start_time.elapsed());
616 let _ = p.kill().await;
617 let _ = p.wait().await;
618 let is_oom = match cgroup.update_cgroup_and_controller_and_check_oom() {
619 Err(result) => {
620 let _ = interactor_p.kill().await;
621 return RunWithInteractorResult::InternalError(result.to_string());
622 }
623 Ok(result) => result,
624 };
625 let interactor_result = tokio::time::timeout(
626 Duration::from(interactor_extra_time_limit),
627 interactor_p.wait(),
628 )
629 .await;
630 let interactor_runtime = TimeSpan::from(interactor_start_time.elapsed());
631 let _ = interactor_p.kill().await;
632 let _ = interactor_p.wait().await;
633 let interactor_is_oom = match interactor_cgroup.update_cgroup_and_controller_and_check_oom()
634 {
635 Err(result) => {
636 return RunWithInteractorResult::InternalError(result.to_string());
637 }
638 Ok(result) => result,
639 };
640 let memory = match cgroup.get_max_usage_in_bytes() {
641 Err(result) => {
642 return RunWithInteractorResult::InternalError(result.to_string());
643 }
644 Ok(result) => MemorySize::from_bytes(result as usize),
645 };
646 let interactor_memory = match interactor_cgroup.get_max_usage_in_bytes() {
647 Err(result) => {
648 return RunWithInteractorResult::InternalError(result.to_string());
649 }
650 Ok(result) => MemorySize::from_bytes(result as usize),
651 };
652 let p_resource = ProcessResource {
653 memory: memory,
654 runtime: runtime,
655 stdout: vec![],
656 stderr: {
657 match check_file_limit(self.stderr_path.as_str(), output_limit).await {
658 Err(result) => {
659 return RunWithInteractorResult::InternalError(result);
660 }
661 Ok(result) => {
662 if result != "" {
663 return RunWithInteractorResult::OutputLimitExceeded(
664 ProcessResource {
665 memory: memory,
666 runtime: runtime,
667 stdout: vec![],
668 stderr: vec![],
669 },
670 ProcessResource {
671 memory: interactor_memory,
672 runtime: interactor_runtime,
673 stdout: vec![],
674 stderr: vec![],
675 },
676 );
677 }
678 }
679 }
680 match self.read_stderr().await {
681 Ok(result) => result,
682 Err(result) => return RunWithInteractorResult::InternalError(result),
683 }
684 },
685 };
686 let interactor_resource = ProcessResource {
687 memory: interactor_memory,
688 runtime: interactor_runtime,
689 stdout: {
690 match check_file_limit(
691 interactor_exe_resources.interactorout_path.as_str(),
692 output_limit,
693 )
694 .await
695 {
696 Err(result) => {
697 return RunWithInteractorResult::InternalError(result);
698 }
699 Ok(result) => {
700 if result != "" {
701 return RunWithInteractorResult::InteractorOutputLimitExceeded(
702 ProcessResource {
703 memory: memory,
704 runtime: runtime,
705 stdout: vec![],
706 stderr: vec![],
707 },
708 ProcessResource {
709 memory: interactor_memory,
710 runtime: interactor_runtime,
711 stdout: vec![],
712 stderr: vec![],
713 },
714 );
715 }
716 }
717 }
718 match interactor_exe_resources.read_interactorout().await {
719 Ok(result) => result,
720 Err(result) => return RunWithInteractorResult::InternalError(result),
721 }
722 },
723 stderr: {
724 match check_file_limit(interactor_exe_resources.stderr_path.as_str(), output_limit)
725 .await
726 {
727 Err(result) => {
728 return RunWithInteractorResult::InternalError(result);
729 }
730 Ok(result) => {
731 if result != "" {
732 return RunWithInteractorResult::InteractorOutputLimitExceeded(
733 ProcessResource {
734 memory: memory,
735 runtime: runtime,
736 stdout: vec![],
737 stderr: vec![],
738 },
739 ProcessResource {
740 memory: interactor_memory,
741 runtime: interactor_runtime,
742 stdout: vec![],
743 stderr: vec![],
744 },
745 );
746 }
747 }
748 }
749 match interactor_exe_resources.read_stderr().await {
750 Ok(result) => result,
751 Err(result) => return RunWithInteractorResult::InternalError(result),
752 }
753 },
754 };
755 if is_oom {
756 RunWithInteractorResult::MemoryLimitExceeded(p_resource, interactor_resource)
757 } else if result.is_err() || runtime > time_limit {
758 RunWithInteractorResult::TimeLimitExceeded(p_resource, interactor_resource)
759 } else if result.unwrap().is_ok_and(|status| status.success()) == false {
760 RunWithInteractorResult::RuntimeError(p_resource, interactor_resource)
761 } else if interactor_is_oom {
762 RunWithInteractorResult::InteractorMemoryLimitExceeded(p_resource, interactor_resource)
763 } else if interactor_result.is_err() {
764 RunWithInteractorResult::InteractorTimeLimitExceeded(p_resource, interactor_resource)
765 } else if interactor_result
766 .unwrap()
767 .is_ok_and(|status| status.success())
768 {
769 RunWithInteractorResult::Ok(p_resource, interactor_resource)
770 } else {
771 RunWithInteractorResult::InteractorRuntimeError(p_resource, interactor_resource)
772 }
773 }
774}
775
776#[derive(Clone, Debug, Default, Deserialize, Serialize)]
777pub struct ExeCode {
778 pub exe_files: HashMap<String, Vec<u8>>,
779 pub compile_and_exe_setting: CompileAndExeSetting,
780}
781
782#[cfg(feature = "run")]
783impl ExeCode {
784 pub async fn initial_exe_resources(&self, uid: u32) -> InitExeResourceResult {
785 ExeResources::new(uid, &self.exe_files, &self.compile_and_exe_setting).await
786 }
787}
788
789#[cfg(feature = "run")]
790async fn check_file_limit(path: &str, limit: MemorySize) -> Result<String, String> {
791 let metadata = match tokio::fs::metadata(path).await {
792 Err(result) => {
793 return Err(result.to_string());
794 }
795 Ok(result) => result,
796 };
797 if metadata.len() > limit.as_bytes() as u64 {
798 return Ok("Exceed Limit".to_string());
799 }
800 Ok(String::new())
801}
802
803pub fn check_admin_privilege() -> bool {
804 users::get_current_uid() == 0
805}