emjudge_judgecore/
program.rs

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}