void print_solution() { FM_LOG_DEBUG("-- Solution Information --"); FM_LOG_MONITOR("solution id %d", oj_solution.sid); FM_LOG_TRACE("problem id %d", oj_solution.pid); FM_LOG_TRACE("language(%d) %s", oj_solution.lang, languages[oj_solution.lang]); FM_LOG_TRACE("time limit %d ms", oj_solution.time_limit); FM_LOG_TRACE("memory limit %d KB", oj_solution.memory_limit); FM_LOG_DEBUG("work dir %s", oj_solution.work_dir); FM_LOG_DEBUG("data dir %s", oj_solution.data_dir); }
// Run spj int oj_compare_output_spj(const char *file_in, // std input file const char *file_out, // std output file const char *file_user, // user output file const char *spj_exec) // path of spj { FM_LOG_TRACE("start compare spj"); pid_t pid_spj = fork(); // create a child process for spj if (pid_spj < 0) { FM_LOG_FATAL("fork for spj failed: %s", strerror(errno)); exit(EXIT_COMPARE_SPJ); } else if (pid_spj == 0) { // child process log_add_info("spj"); // Set spj timeout if (EXIT_SUCCESS == malarm(ITIMER_REAL, spj_time_limit)) { FM_LOG_TRACE("load spj: %s", spj_exec); execlp(spj_exec, spj_exec, file_in, file_out, file_user, NULL); FM_LOG_FATAL("execute spj failed"); exit(EXIT_COMPARE_SPJ_FORK); } else { FM_LOG_FATAL("malarm for spj failed: %s", strerror(errno)); exit(EXIT_COMPARE_SPJ); } } else { int status = 0; if (waitpid(pid_spj, &status, 0) < 0) { FM_LOG_FATAL("waitpid for spj failed: %s", strerror(errno)); exit(EXIT_COMPARE_SPJ); } if (WIFEXITED(status)) { switch (WEXITSTATUS(status)) { case SPJ_AC: return OJ_AC; case SPJ_PE: return OJ_PE; case SPJ_WA: return OJ_WA; default: return OJ_VE; } } else if (WIFSIGNALED(status) && WTERMSIG(status) == SIGALRM) { // recv SIGNALRM FM_LOG_WARNING("spj: time out"); } else { // spj RE FM_LOG_WARNING("unkown termination, status = %d", status); } } return OJ_VE; }
/* * 输入输出重定向 */ static void io_redirect() { FM_LOG_TRACE("Start to redirect the IO."); stdin = freopen(PROBLEM::input_file.c_str(), "r", stdin); stdout = freopen(PROBLEM::exec_output.c_str(), "w", stdout); //stderr = freopen("/dev/null", "w", stderr); if (stdin == NULL || stdout == NULL) { FM_LOG_WARNING("It occur a error when freopen: stdin(%p) stdout(%p)", stdin, stdout); exit(JUDGE_CONF::EXIT_PRE_JUDGE); } FM_LOG_TRACE("redirect io is OK."); }
void ThreadWork() { while (isRunning) { oj_solution_t oj_solution = ProcessQueue.GetFrontAndPop(); pthread_t ptid = pthread_self(); FM_LOG_TRACE("Thread id: %d", ptid); run(oj_solution); } }
void truncate_upload_file(char *file_path) { off_t size = file_size(file_path); if (size > MAX_UPLOAD_FILE_SIZE) { FM_LOG_TRACE("truncate_upload_file: %s %d %d", file_path, size, MAX_UPLOAD_FILE_SIZE); if (truncate(file_path, MAX_UPLOAD_FILE_SIZE) != 0) { FM_LOG_WARNING("truncate upload file %s failed: %s", file_path, strerror(errno)); } } }
void SendWork() { while (isRunning) { auto item = SendQueue.GetFrontAndPop(); pthread_t ptid = pthread_self(); FM_LOG_TRACE("Send thread id: %d", ptid); if (item.first == EXIT_OK) { update_result(item.second); } else { update_system_error(item.first, item.second); } } }
void log_close() { if (log_opened) { FM_LOG_TRACE("log_close"); fclose(log_fp); free(log_filename); log_fp = NULL; log_filename = NULL; log_opened = 0; } }
void io_redirect(const char *input_file, const char *stdout_file, const char *stderr_file) { // io_redirect stdin = freopen(input_file, "r", stdin); stdout = freopen(stdout_file, "w", stdout); stderr = freopen(stderr_file, "a+", stderr); if (stdin == nullptr || stdout == nullptr || stderr == nullptr) { FM_LOG_FATAL("error freopen: stdin(%p) stdout(%p), stderr(%p)", stdin, stdout, stderr); exit(EXIT_PRE_JUDGE); } FM_LOG_TRACE("io redirect ok!"); }
int parse_arguments(char *str, oj_solution_t &oj_solution) { int number = sscanf(str, "%s %d %s %s %s %s %s", oj_solution.sid, &oj_solution.cid, oj_solution.pid, oj_solution.language, oj_solution.time_limit, oj_solution.memory_limit, oj_solution.token); FM_LOG_TRACE("sid=%s cid=%d pid=%s language=%s timeLimit=%s ms memoryLimit=%s KB %s", oj_solution.sid, oj_solution.cid, oj_solution.pid, oj_solution.language, oj_solution.time_limit, oj_solution.memory_limit, oj_solution.token); if (number < 6) { return -1; } return 0; }
void set_security_option() { if (oj_solution.lang != LANG_JAVA && oj_solution.lang != LANG_KOTLIN #ifdef FAST_JUDGE && oj_solution.lang != LANG_PYTHON3 && oj_solution.lang != LANG_PYTHON27 #endif ) { char cwd[PATH_SIZE]; char *tmp = getcwd(cwd, PATH_SIZE - 1); if (tmp == nullptr) { FM_LOG_FATAL("getcwd failed: %s", strerror(errno)); exit(EXIT_SET_SECURITY); } // chroot, current directory will be the root dir if (EXIT_SUCCESS != chroot(cwd)) { FM_LOG_FATAL("chroot(%s) failed: %s", cwd, strerror(errno)); exit(EXIT_SET_SECURITY); } FM_LOG_DEBUG("chroot(%s)", cwd); } FM_LOG_TRACE("set_security_option ok"); }
/* * 输出判题结果到结果文件 */ static void output_result() { FILE* result_file = fopen(PROBLEM::result_file.c_str(), "w"); switch (PROBLEM::result){ case 1:PROBLEM::status = "Compile Error";break; case 2:PROBLEM::status = "Time Limit Exceeded";break; case 3:PROBLEM::status = "Memory Limit Exceeded";break; case 4:PROBLEM::status = "Output Limit Exceeded";break; case 5:PROBLEM::status = "Runtime Error";break; case 6:PROBLEM::status = "Wrong Answer";break; case 7:PROBLEM::status = "Accepted";break; case 8:PROBLEM::status = "Presentation Error";break; default:PROBLEM::status = "System Error";break; } fprintf(result_file, "%s\n", PROBLEM::status.c_str()); fprintf(result_file, "%d\n", PROBLEM::time_usage); fprintf(result_file, "%d\n", PROBLEM::memory_usage); fprintf(result_file, "%s\n", PROBLEM::extra_message.c_str()); FM_LOG_TRACE("The final result is %s %d %d %s", PROBLEM::status.c_str(), PROBLEM::time_usage, PROBLEM::memory_usage, PROBLEM::extra_message.c_str()); }
void set_limit(off_t fsize) { rlimit lim{}; // Set CPU time limit round up, raise SIGXCPU lim.rlim_max = (oj_solution.time_limit + 999) / 1000 + 1; lim.rlim_cur = lim.rlim_max; if (setrlimit(RLIMIT_CPU, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_CPU failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } if (oj_solution.lang <= LANG_PASCAL) { // Memory control, raise SIGSEGV lim.rlim_cur = lim.rlim_max = (STD_MB << 10) + oj_solution.memory_limit * STD_KB; if (setrlimit(RLIMIT_AS, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_AS failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } } // Stack space, raise SIGSEGV lim.rlim_cur = lim.rlim_max = stack_size_limit * STD_KB; if (setrlimit(RLIMIT_STACK, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_STACK failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } // Output file size limit, raise SIGXFSZ lim.rlim_cur = lim.rlim_max = (rlim_t) (4 * MAX_LOG_FILE_SIZE); if (setrlimit(RLIMIT_FSIZE, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_FSIZE failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } FM_LOG_DEBUG("File size limit: %d", lim.rlim_max); FM_LOG_TRACE("set execute limit ok"); }
bool judge(const char *input_file, const char *output_file_std, const char *stdout_file_executive, const char *stderr_file_executive) { rusage rused{}; pid_t executor = fork(); // create a child process for executor if (executor < 0) { FM_LOG_FATAL("fork executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE); } else if (executor == 0) { // child process log_add_info("executor"); off_t fsize = file_size(output_file_std); // io redirect, must before set_security_option() io_redirect(input_file, stdout_file_executive, stderr_file_executive); // chroot & setuid set_security_option(); // set memory, time and file size limit etc. set_limit(fsize); // must after set_security_option() FM_LOG_DEBUG("time limit: %d, time limit addtion: %d", oj_solution.time_limit, time_limit_addtion); uint64_t real_time_limit = oj_solution.time_limit + time_limit_addtion; // time fix // set real time alarm if (EXIT_SUCCESS != malarm(ITIMER_REAL, real_time_limit)) { FM_LOG_FATAL("malarm for executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE); } FM_LOG_TRACE("begin execute"); if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) { FM_LOG_FATAL("Trace executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE_PTRACE); } // load program if (oj_solution.lang == LANG_JAVA) { print_executor(EXEC_J); execvp(EXEC_J[0], (char *const *) EXEC_J); } else if (oj_solution.lang == LANG_KOTLIN) { print_executor(EXEC_KT); execvp(EXEC_KT[0], (char *const *) EXEC_KT); } else if (oj_solution.lang == LANG_PYTHON27) { print_executor(EXEC_PY27); #ifdef FAST_JUDGE execvp(EXEC_PY27[0], (char * const *) EXEC_PY27); #else execv(EXEC_PY27[0], (char *const *) EXEC_PY27); #endif } else if (oj_solution.lang == LANG_PYTHON3) { print_executor(EXEC_PY3); #ifdef FAST_JUDGE execvp(EXEC_PY3[0], (char * const *) EXEC_PY3); #else execv(EXEC_PY3[0], (char *const *) EXEC_PY3); #endif } else { execl("./Main", "./Main", NULL); } // exec error FM_LOG_FATAL("exec error"); exit(EXIT_PRE_JUDGE_EXECLP); } else { // Judger int status = 0; user_regs_struct regs{}; stderr = freopen("error.txt", "a+", stderr); init_syscalls(oj_solution.lang); while (true) { if (wait4(executor, &status, 0, &rused) < 0) { FM_LOG_FATAL("wait4 executor failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } if (WIFEXITED(status)) { if ((oj_solution.lang != LANG_JAVA && oj_solution.lang != LANG_KOTLIN) || WEXITSTATUS(status) == EXIT_SUCCESS) { // AC PE WA FM_LOG_TRACE("normal quit"); int result; if (oj_solution.spj) { // use SPJ result = oj_compare_output_spj(input_file, output_file_std, stdout_file_executive, oj_solution.spj_exe_file); } else { // compare file result = oj_compare_output(output_file_std, stdout_file_executive); } // WA if (result == OJ_WA) { oj_solution.result = OJ_WA; } else if (oj_solution.result != OJ_PE) { // previous case is AC oj_solution.result = result; // AC or PE } else /* (oj_solution.result == OJ_PE) */ { // previous case is PE oj_solution.result = OJ_PE; } FM_LOG_NOTICE("case result: %d, problem result: %d", result, oj_solution.result); } else { // not return 0 oj_solution.result = OJ_RE; FM_LOG_NOTICE("abnormal quit, exit_code: %d", WEXITSTATUS(status)); } break; } // RE/TLE/OLE if (WIFSIGNALED(status) || (WIFSTOPPED(status) && WSTOPSIG(status) != SIGTRAP)) { int signo = 0; if (WIFSIGNALED(status)) { signo = WTERMSIG(status); FM_LOG_NOTICE("child process killed by signal %d, %s", signo, strsignal(signo)); } else { signo = WSTOPSIG(status); FM_LOG_NOTICE("child process stopped by signal %d, %s", signo, strsignal(signo)); } switch (signo) { // Ignore case SIGCHLD: oj_solution.result = OJ_AC; break; // TLE case SIGALRM: // alarm() and setitimer(ITIMER_REAL) case SIGVTALRM: // setitimer(ITIMER_VIRTUAL) case SIGXCPU: // exceeds soft processor limit oj_solution.result = OJ_TLE; FM_LOG_TRACE("Time Limit Exceeded: %s", strsignal(signo)); break; // OLE case SIGXFSZ: // exceeds file size limit oj_solution.result = OJ_OLE; FM_LOG_TRACE("Output Limit Exceeded"); break; // RE case SIGSEGV: // segmentation violation case SIGFPE: // any arithmetic exception case SIGBUS: // the process incurs a hardware fault case SIGABRT: // abort() function case SIGKILL: // exceeds hard processor limit default: oj_solution.result = OJ_RE; FILE *fp = fopen(stderr_file_executive, "a+"); if (fp == nullptr) { fprintf(stderr, "%s\n", strsignal(signo)); FM_LOG_WARNING("Runtime Error: %s", strsignal(signo)); } else { fprintf(fp, "%s\n", strsignal(signo)); fclose(fp); } break; } // end of swtich kill(executor, SIGKILL); break; } // end of "if (WIFSIGNALED(status) ...)" oj_solution.memory_usage = std::max(oj_solution.memory_usage, (unsigned long) rused.ru_maxrss); // TODO(power): check why memory exceed too much if (oj_solution.memory_usage > oj_solution.memory_limit) { oj_solution.result = OJ_MLE; kill(executor, SIGKILL); break; } // check syscall if (ptrace(PTRACE_GETREGS, executor, NULL, ®s) < 0) { FM_LOG_FATAL("ptrace(PTRACE_GETREGS) failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } int syscall_id = 0; #ifdef __i386__ syscall_id = (int)regs.orig_eax; #else syscall_id = (int) regs.orig_rax; #endif if (syscall_id > 0 && !is_valid_syscall(syscall_id)) { oj_solution.result = OJ_RF; FM_LOG_FATAL("restricted function, syscall_id: %d", syscall_id); kill(executor, SIGKILL); break; } if (ptrace(PTRACE_SYSCALL, executor, NULL, NULL) < 0) { FM_LOG_FATAL("ptrace(PTRACE_SYSCALL) failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } } // end of while } // end of fork for judge process oj_solution.memory_usage = std::max(oj_solution.memory_usage, (unsigned long) rused.ru_maxrss); if (oj_solution.memory_usage > oj_solution.memory_limit) { oj_solution.result = OJ_MLE; FM_LOG_NOTICE("memory limit exceeded: %d (fault: %d * %d)", oj_solution.memory_usage, rused.ru_minflt, page_size); } oj_solution.time_usage = std::max(oj_solution.time_usage, (unsigned long) rused.ru_utime.tv_sec * 1000 + rused.ru_utime.tv_usec / 1000); if (oj_solution.time_usage > oj_solution.time_limit) { oj_solution.result = OJ_TLE; FM_LOG_TRACE("Time Limit Exceeded"); } if (oj_solution.result != OJ_AC) { if (oj_solution.judge_type == ACM) { FM_LOG_NOTICE("not AC/PE, no need to continue"); } if (oj_solution.result == OJ_TLE) { oj_solution.time_usage = oj_solution.time_limit; } else if (oj_solution.result == OJ_WA) { if (oj_solution.lang == LANG_JAVA) { // TODO: kotlin fix_java_result(stdout_file_executive, stderr_file_executive); } else if ((oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) && file_size(stderr_file_executive)) { oj_solution.result = OJ_RE; FM_LOG_TRACE("Runtime Error"); } } return false; } return true; }
void run_solution() { FM_LOG_DEBUG("run_solution"); #ifndef FAST_JUDGE if (oj_solution.lang == LANG_PYTHON27) { copy_python_runtime_python2(oj_solution.work_dir); FM_LOG_DEBUG("copy_python_runtime"); } else if (oj_solution.lang == LANG_PYTHON3) { copy_python_runtime_python3(oj_solution.work_dir); FM_LOG_DEBUG("copy_python_runtime"); } #endif check_spj(); struct dirent **namelist; int num_of_test; num_of_test = scandir(oj_solution.data_dir, &namelist, data_filter, alphasort); if (num_of_test < 0) { FM_LOG_FATAL("scan data directory failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE_DAA); } int first_failed_test = 0; char input_file[PATH_SIZE]; char output_file_std[PATH_SIZE]; char stdout_file_executive[PATH_SIZE]; char stderr_file_executive[PATH_SIZE]; snprintf(stderr_file_executive, PATH_SIZE, "%s/stderr_executive.txt", oj_solution.work_dir); FM_LOG_DEBUG("start run solution (%d cases)", num_of_test); for (int i = 0; i < num_of_test; ++i) { update_solution_status(oj_solution.cid, oj_solution.sid, OJ_RUN, i + 1); prepare_files(namelist[i]->d_name, input_file, output_file_std, stdout_file_executive); FM_LOG_TRACE("run case: %d", i + 1); bool result = judge(input_file, output_file_std, stdout_file_executive, stderr_file_executive); if (oj_solution.result != OJ_AC && !first_failed_test) { first_failed_test = i + 1; } if (!result && oj_solution.judge_type == ACM) { break; } } for (int i = 0; i < num_of_test; ++i) { free(namelist[i]); } free(namelist); #ifndef FAST_JUDGE if (oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) { clean_workdir(oj_solution.work_dir); } #endif output_acm_result(oj_solution.result, oj_solution.time_usage, oj_solution.memory_usage, first_failed_test); }
/* * #error "This make CE" * #warning "Just warning message" * #include </dev/core> * #include </dev/zero> * #include </dev/random> * #include </etc/passwd> * #include <../../../etc/passwd> * egrep '^\s*#include\s*[<"][./].*[>"]' Main.cc */ void compile() { update_solution_status(oj_solution.cid, oj_solution.sid, OJ_COM, 0); char stdout_compiler[PATH_SIZE]; char stderr_compiler[PATH_SIZE]; snprintf(stdout_compiler, PATH_SIZE, "%s/stdout_compiler.txt", oj_solution.work_dir); snprintf(stderr_compiler, PATH_SIZE, "%s/stderr_compiler.txt", oj_solution.work_dir); pid_t compiler = fork(); // create a child process for compiler if (compiler < 0) { FM_LOG_FATAL("fork compiler failed: %s", strerror(errno)); exit(EXIT_FORK_COMPILER); } else if (compiler == 0) { // child process: run compiler log_add_info("compiler"); set_compile_limit(); stdout = freopen(stdout_compiler, "w", stdout); stderr = freopen(stderr_compiler, "w", stderr); if (stdout == nullptr || stderr == nullptr) { FM_LOG_FATAL("error freopen: stdout(%p), stderr(%p)", stdout, stderr); exit(EXIT_COMPILE_IO); } print_user_group(); print_word_dir(); switch (oj_solution.lang) { case LANG_C99: print_compiler(CP_C99); execvp(CP_C99[0], (char *const *) CP_C99); break; case LANG_C11: print_compiler(CP_C11); execvp(CP_C11[0], (char *const *) CP_C11); break; case LANG_CPP98: print_compiler(CP_CC98); execvp(CP_CC98[0], (char *const *) CP_CC98); break; case LANG_CPP11: print_compiler(CP_CC11); execvp(CP_CC11[0], (char *const *) CP_CC11); break; case LANG_CPP14: print_compiler(CP_CC14); execvp(CP_CC14[0], (char *const *) CP_CC14); break; case LANG_CPP17: print_compiler(CP_CC98); execvp(CP_CC98[0], (char *const *) CP_CC17); break; case LANG_PASCAL: print_compiler(CP_PAS); execvp(CP_PAS[0], (char *const *) CP_PAS); break; case LANG_JAVA: print_compiler(CP_J); execvp(CP_J[0], (char *const *) CP_J); break; case LANG_PYTHON27: print_compiler(CP_PY27); execvp(CP_PY27[0], (char *const *) CP_PY27); break; case LANG_PYTHON3: print_compiler(CP_PY3); execvp(CP_PY3[0], (char *const *) CP_PY3); break; case LANG_KOTLIN: print_compiler(CP_KT); execvp(CP_KT[0], (char *const *) CP_KT); break; default: FM_LOG_FATAL("Unknown language %d", oj_solution.lang); break; } // execvp error FM_LOG_FATAL("execvp compiler error"); exit(EXIT_COMPILE_EXEC); } else { // parent process: Judger int status = 0; if (waitpid(compiler, &status, WUNTRACED) == -1) { FM_LOG_FATAL("waitpid for compiler failed: %s", strerror(errno)); exit(EXIT_COMPILE_ERROR); // SE } FM_LOG_DEBUG("compiler finished"); if ((oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) && file_size(stderr_compiler)) { FM_LOG_TRACE("compile error"); output_acm_result(OJ_CE, 0, 0, 0); exit(EXIT_OK); } if (WIFEXITED(status)) { // normal termination if (EXIT_SUCCESS == WEXITSTATUS(status)) { FM_LOG_DEBUG("compile succeeded"); } else if (GCC_COMPILE_ERROR == WEXITSTATUS(status)) { FM_LOG_TRACE("compile error"); output_acm_result(OJ_CE, 0, 0, 0); exit(EXIT_OK); } else { if (fix_gcc_result(stderr_compiler)) { FM_LOG_WARNING("Compiler Limit Exceeded!"); output_acm_result(OJ_CE, 0, 0, 0); exit(EXIT_OK); } else { FM_LOG_FATAL("compiler unknown exit status %d", WEXITSTATUS(status)); output_acm_result(OJ_CE, 0, 0, 0); exit(EXIT_COMPILE_ERROR); } } } else { if (WIFSIGNALED(status)) { // killed by signal int signo = WTERMSIG(status); FM_LOG_WARNING("Compiler Limit Exceeded: %s", strsignal(signo)); output_acm_result(OJ_CE, 0, 0, 0); stderr = freopen(stderr_compiler, "w", stderr); fprintf(stderr, "Compiler Limit Exceeded: %s\n", strsignal(signo)); exit(EXIT_OK); } else if (WIFSTOPPED(status)) { // stopped by signal int signo = WSTOPSIG(status); FM_LOG_FATAL("stopped by signal: %s\n", strsignal(signo)); } else { FM_LOG_FATAL("unknown stop reason, status(%d)", status); } exit(EXIT_COMPILE_ERROR); // SE } } }
int main(int argc, char *argv[], char *envp[]) { log_open(LOG_FILE); FM_LOG_TRACE("---"); check_pid(); int sockfd; socklen_t clilen; struct sockaddr_in serv_addr{}; struct sockaddr_in cli_addr{}; const char *cfg_file; if (argc > 1) { cfg_file = argv[1]; } else { cfg_file = DEFAULT_CFG_FILE; } read_config(cfg_file); FM_LOG_TRACE("read_config"); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { fatal_error("ERROR opening socket"); } FM_LOG_TRACE("socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; if (inet_aton(oj_config.ip, &serv_addr.sin_addr) == 0) { serv_addr.sin_addr.s_addr = INADDR_ANY; } serv_addr.sin_port = htons(oj_config.port); FM_LOG_NOTICE("IP address: %s %s", oj_config.ip, inet_ntoa(serv_addr.sin_addr)); FM_LOG_NOTICE("port: %d %d", oj_config.port, ntohs(serv_addr.sin_port)); int yes = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { fatal_error("setsockopt SO_REUSEADDR failed"); } if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { fatal_error("ERROR on binding"); } FM_LOG_TRACE("bind"); clilen = sizeof(cli_addr); if (listen(sockfd, oj_config.backlog) < 0) { fatal_error("ERROR on listening"); } FM_LOG_NOTICE("listen backlog: %d", oj_config.backlog); if (daemon(0, 0) == -1) { FM_LOG_FATAL("Cannot daemonize"); pidfile_remove(pfh); exit(EXIT_FAILURE); } print_word_dir(); print_user_group(); pidfile_write(pfh); struct sigaction sa{}; sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGTERM, &sa, nullptr) == -1) { // install signal hander for timeout FM_LOG_FATAL("cannot handle SIGTERM"); exit(EXIT_FAILURE); } else { FM_LOG_DEBUG("set signal_handler"); } for (int i = 0; i < oj_config.thread_num; i++) { std::thread t(ThreadWork); t.detach(); } FM_LOG_NOTICE("thread count: %d", oj_config.thread_num); std::thread(SendWork).detach(); while (isRunning) { int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd != -1) { work(newsockfd, cli_addr); } } pidfile_remove(pfh); close(sockfd); return 0; }
void send_multi_result(char *file_path, oj_solution_t &oj_solution) { FM_LOG_TRACE("send_multi_result"); CURL *curl; CURLM *multi_handle; int still_running = 1; struct curl_httppost *formpost = nullptr; struct curl_httppost *lastptr = nullptr; struct curl_slist *headerlist = nullptr; static const char buf[] = "Expect:"; const size_t size = 25; char data[size] = {0}; curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "sid", CURLFORM_COPYCONTENTS, oj_solution.sid, CURLFORM_END); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "token", CURLFORM_COPYCONTENTS, oj_solution.token, CURLFORM_END); snprintf(data, size, "%d", oj_solution.cid); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "cid", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.result); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "result", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.time_usage); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "time", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.memory_usage); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "memory", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.test); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "test", CURLFORM_COPYCONTENTS, data, CURLFORM_END); if (file_path != NULL && access(file_path, F_OK) != -1) { truncate_upload_file(file_path); FM_LOG_NOTICE("will upload error file %s", file_path); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "error", CURLFORM_FILE, file_path, CURLFORM_END); } FM_LOG_TRACE("try curl_easy_init"); curl = curl_easy_init(); multi_handle = curl_multi_init(); headerlist = curl_slist_append(headerlist, buf); if (curl && multi_handle) { FM_LOG_TRACE("curl_multi_init OK"); curl_easy_setopt(curl, CURLOPT_URL, oj_config.api_url); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); curl_multi_add_handle(multi_handle, curl); curl_multi_perform(multi_handle, &still_running); do { struct timeval timeout{}; int rc; /* select() return code */ CURLMcode mc; /* curl_multi_fdset() return code */ fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to play around with */ timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout(multi_handle, &curl_timeo); if (curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if (timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); if (mc != CURLM_OK) { fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); break; } if (maxfd == -1) { #ifdef _WIN32 Sleep(100); rc = 0; #else /* Portable sleep for platforms other than Windows. */ struct timeval wait = {0, 100 * 1000}; /* 100ms */ rc = select(0, NULL, NULL, NULL, &wait); #endif } else { /* Note that on some platforms 'timeout' may be modified by select(). If you need access to the original value save a copy beforehand. */ rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); } switch (rc) { case -1: /* select error */ break; case 0: default: /* timeout or readable/writable sockets */ curl_multi_perform(multi_handle, &still_running); break; } } while (still_running); curl_multi_cleanup(multi_handle); curl_easy_cleanup(curl); curl_formfree(formpost); curl_slist_free_all(headerlist); FM_LOG_DEBUG("send_multi_result finished"); } else { FM_LOG_FATAL("cannot init curl: %s", strerror(errno)); update_system_error(EXIT_CURL_ERROR, oj_solution); } }
static int compare_output(std::string file_std, std::string file_exec) { //这里可以不用写的 //仔细研究一下diff及其参数即可 //实现各种功能 FILE *fp_std = fopen(file_std.c_str(), "r"); if (fp_std == NULL) { FM_LOG_WARNING("Open standard output file failed."); exit(JUDGE_CONF::EXIT_COMPARE); } FILE *fp_exe = fopen(file_exec.c_str(), "r"); if (fp_exe == NULL) { FM_LOG_WARNING("Open executive output file failed."); exit(JUDGE_CONF::EXIT_COMPARE); } int a, b, Na = 0, Nb = 0; enum { AC = JUDGE_CONF::AC, PE = JUDGE_CONF::PE, WA = JUDGE_CONF::WA }status = AC; while (true) { a = fgetc(fp_std); b = fgetc(fp_exe); Na++, Nb++; //统一\r和\n之间的区别 if (a == '\r') { a = fgetc(fp_std); Na++; } if (b == '\r') { b = fgetc(fp_std); Nb++; } #define is_space_char(a) ((a == ' ') || (a == '\t') || (a == '\n')) if (feof(fp_std) && feof(fp_exe)){ //文件结束 break; } else if (feof(fp_std) || feof(fp_exe)) { //如果只有一个文件结束 //但是另一个文件的末尾是回车 //那么也当做AC处理 FILE *fp_tmp; if (feof(fp_std)) { if (!is_space_char(b)) { FM_LOG_TRACE("Well, Wrong Answer."); status = WA; break; } fp_tmp = fp_exe; } else { if (!is_space_char(a)) { FM_LOG_TRACE("Well, Wrong Answer."); status = WA; break; } fp_tmp = fp_std; } int c; while ((c = fgetc(fp_tmp)) != EOF) { if (c == '\r') c = '\n'; if (!is_space_char(c)) { FM_LOG_TRACE("Well, Wrong Answer."); status = WA; break; } } break; } //如果两个字符不同 if (a != b) { status = PE; //过滤空白字符 if (is_space_char(a) && is_space_char(b)) { continue; } if (is_space_char(a)) { //a是空白字符,过滤,退回b以便下一轮循环 ungetc(b, fp_exe); Nb--; } else if (is_space_char(b)) { ungetc(a, fp_std); Na--; } else { FM_LOG_TRACE("Well, Wrong Answer."); status = WA; break; } } } fclose(fp_std); fclose(fp_exe); return status; }
static void run_spj() { // support ljudge style special judge const char origin_name[3][16] = {"./in.in", "./out.out", "./out.txt"}; const char target_name[4][16] = {"/input", "/output", "/user_output", "/user_code"}; for (int i = 0; i < 4; i++) { std::string origin_path = (i != 3) ? origin_name[i] : PROBLEM::code_path; std::string target_path = PROBLEM::run_dir + target_name[i]; if (EXIT_SUCCESS != symlink(origin_path.c_str(), target_path.c_str())) FM_LOG_WARNING("Create symbolic link from '%s' to '%s' failed,%d:%s.", origin_path.c_str(), target_path.c_str(), errno, strerror(errno)); } pid_t spj_pid = fork(); int status = 0; if (spj_pid < 0) { FM_LOG_WARNING("fork for special judge failed.So sad."); exit(JUDGE_CONF::EXIT_COMPARE_SPJ); } else if (spj_pid == 0) { FM_LOG_TRACE("Woo, I will start special judge!"); stdin = freopen(PROBLEM::input_file.c_str(), "r", stdin); // ljudge style stdout = freopen(PROBLEM::spj_output_file.c_str(), "w", stdout); if (stdin == NULL || stdout == NULL) { FM_LOG_WARNING("redirect io in spj failed."); exit(JUDGE_CONF::EXIT_COMPARE_SPJ); } //SPJ时间限制 if (EXIT_SUCCESS != malarm(ITIMER_REAL, JUDGE_CONF::SPJ_TIME_LIMIT)) { FM_LOG_WARNING("Set time limit for spj failed."); exit(JUDGE_CONF::EXIT_COMPARE_SPJ); } security_control_spj(); if (PROBLEM::spj_lang != JUDGE_CONF::LANG_JAVA) { execl("./SpecialJudge", "SpecialJudge", "user_output", NULL); } else { execlp("java", "java", "SpecialJudge", NULL); } exit(JUDGE_CONF::EXIT_COMPARE_SPJ_FORK); } else { if (wait4(spj_pid, &status, 0, NULL) < 0) { FM_LOG_WARNING("wait4 failed."); exit(JUDGE_CONF::EXIT_COMPARE_SPJ); } if (WIFEXITED(status)) { int spj_exit_code = WEXITSTATUS(status); if (spj_exit_code >= 0 && spj_exit_code < 4) { FM_LOG_TRACE("Well, SpecialJudge program normally quit.All is good."); // 获取SPJ结果 switch (spj_exit_code) { case 0: PROBLEM::result = JUDGE_CONF::AC; break; case 1: PROBLEM::result = JUDGE_CONF::WA; break; case 2: PROBLEM::result = JUDGE_CONF::PE; break; } return ; } else { FM_LOG_WARNING("I am sorry to tell you that the special judge program abnormally terminated. %d", WEXITSTATUS(status)); } } else if (WIFSIGNALED(status) && WTERMSIG(status) == SIGALRM) { FM_LOG_WARNING("Well, the special judge program consume too much time."); } else { FM_LOG_WARNING("Actually, I do not kwon why the special judge program dead."); } } }
/* * 编译源代码 */ static void compiler_source_code() { pid_t compiler = fork(); int status = 0; if (compiler < 0) { FM_LOG_WARNING("error fork compiler"); exit(JUDGE_CONF::EXIT_COMPILE); } else if (compiler == 0) { //子进程,编译程序 log_add_info("compiler"); stdout = freopen(PROBLEM::stdout_file_compiler.c_str(), "w", stdout); stderr = freopen(PROBLEM::stderr_file_compiler.c_str(), "w", stderr); if (stdout == NULL || stderr == NULL) { FM_LOG_WARNING("error to freopen in compiler: stdout(%p) stderr(%p)", stdout, stderr); exit(JUDGE_CONF::EXIT_COMPILE); } malarm(ITIMER_REAL, JUDGE_CONF::COMPILE_TIME_LIMIT);//设置编译时间限制 switch (PROBLEM::lang) { case JUDGE_CONF::LANG_C: FM_LOG_TRACE("Start: gcc -o %s %s -static -w -lm -std=c99 -O2 -DONLINE_JUDGE", PROBLEM::exec_file.c_str(), PROBLEM::code_path.c_str()); execlp("gcc", "gcc", "-o", PROBLEM::exec_file.c_str(), PROBLEM::code_path.c_str(), "-static", "-w", "-lm", "-std=c99", "-O2", "-DONLINE_JUDGE", NULL); break; case JUDGE_CONF::LANG_CPP: FM_LOG_TRACE("Start: g++ -o %s %s -static -w -lm -O2 -DONLINE_JUDGE", PROBLEM::exec_file.c_str(), PROBLEM::code_path.c_str()); execlp("g++", "g++", "-o", PROBLEM::exec_file.c_str(), PROBLEM::code_path.c_str(), "-static", "-w", "-lm", "-O2", "-std=c++11", "-DONLINE_JUDGE", NULL); break; case JUDGE_CONF::LANG_JAVA: FM_LOG_TRACE("Start:javac %s -d %s", PROBLEM::code_path.c_str(), PROBLEM::run_dir.c_str()); execlp("javac", "javac", PROBLEM::code_path.c_str(), "-d", PROBLEM::run_dir.c_str(), NULL); //在这里增加新的语言支持 } FM_LOG_WARNING("exec compiler error"); exit(JUDGE_CONF::EXIT_COMPILE); } else { //父进程 pid_t w = waitpid(compiler, &status, WUNTRACED); //阻塞等待子进程结束 if (w == -1) { FM_LOG_WARNING("waitpid error"); exit(JUDGE_CONF::EXIT_COMPILE); } FM_LOG_TRACE("compiler finished"); if (WIFEXITED(status)) { //编译程序自行退出 if (EXIT_SUCCESS == WEXITSTATUS(status)) { FM_LOG_TRACE("compile succeeded."); } else if (JUDGE_CONF::GCC_COMPILE_ERROR == WEXITSTATUS(status)){ //编译错误 FM_LOG_TRACE("compile error"); PROBLEM::result = JUDGE_CONF::CE; get_compile_error_message(); exit(JUDGE_CONF::EXIT_OK); } else { FM_LOG_WARNING("Unknown error occur when compiling the source code.Exit status %d", WEXITSTATUS(status)); exit(JUDGE_CONF::EXIT_COMPILE); } } else { //编译程序被终止 if (WIFSIGNALED(status)){ if (SIGALRM == WTERMSIG(status)) { FM_LOG_WARNING("Compile time out"); PROBLEM::result = JUDGE_CONF::CE; PROBLEM::extra_message = "Compile Out of Time Limit"; exit(JUDGE_CONF::EXIT_OK); } else { FM_LOG_WARNING("Unknown signal when compile the source code."); } } else if (WIFSTOPPED(status)){ FM_LOG_WARNING("The compile process stopped by signal"); } else { FM_LOG_WARNING("I don't kwon why the compile process stopped"); } exit(JUDGE_CONF::EXIT_COMPILE); } } }
/* * 执行用户提交的程序 */ static void judge() { struct rusage rused; pid_t executive = fork(); if (executive < 0) { exit(JUDGE_CONF::EXIT_PRE_JUDGE); } else if (executive == 0) { //子进程,用户程序 FM_LOG_TRACE("Start Judging."); io_redirect(); security_control(); int real_time_limit = PROBLEM::time_limit; if (EXIT_SUCCESS != malarm(ITIMER_REAL, real_time_limit)) { exit(JUDGE_CONF::EXIT_PRE_JUDGE); } set_limit(); if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) { exit(JUDGE_CONF::EXIT_PRE_JUDGE_PTRACE); } if (PROBLEM::lang != JUDGE_CONF::LANG_JAVA){ execl("./a.out", "a.out", NULL); } else { execlp("java", "java", "Main", NULL); } //走到这了说明出错了 exit(JUDGE_CONF::EXIT_PRE_JUDGE_EXECLP); } else { //父进程 int status = 0; //子进程状态 int syscall_id = 0; //系统调用号 struct user_regs_struct regs; //寄存器 init_RF_table(PROBLEM::lang); //初始化系统调用表 while (true) {//循环监控子进程 if (wait4(executive, &status, 0, &rused) < 0) { FM_LOG_WARNING("wait4 failed."); exit(JUDGE_CONF::EXIT_JUDGE); } //自行退出 if (WIFEXITED(status)) { if (PROBLEM::lang != JUDGE_CONF::LANG_JAVA || WEXITSTATUS(status) == EXIT_SUCCESS) { FM_LOG_TRACE("OK, normal quit. All is good."); //PROBLEM::result = JUDGE_CONF::PROCEED; } else { FM_LOG_WARNING("oh, some error occured.Abnormal quit."); PROBLEM::result = JUDGE_CONF::RE; } break; } //被信号终止掉了 if (WIFSIGNALED(status) || (WIFSTOPPED(status) && WSTOPSIG(status) != SIGTRAP)) { //要过滤掉SIGTRAP信号 int signo = 0; if (WIFSIGNALED(status)) { signo = WTERMSIG(status); FM_LOG_WARNING("child signaled by %d : %s", signo, strsignal(signo)); } else { signo = WSTOPSIG(status); FM_LOG_WARNING("child stop by %d : %s\n", signo, strsignal(signo)); } switch (signo) { //TLE case SIGALRM: case SIGXCPU: case SIGVTALRM: case SIGKILL: FM_LOG_TRACE("Well, Time Limit Exeeded"); PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::TLE; break; case SIGXFSZ: FM_LOG_TRACE("File Limit Exceeded"); PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::OLE; break; case SIGSEGV: case SIGFPE: case SIGBUS: case SIGABRT: //FM_LOG_TRACE("RE了"); PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::RE; break; default: //FM_LOG_TRACE("不知道哪儿跪了"); PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::RE; break; } ptrace(PTRACE_KILL, executive, NULL, NULL); break; } //MLE PROBLEM::memory_usage = std::max((long int)PROBLEM::memory_usage, rused.ru_minflt * (getpagesize() / JUDGE_CONF::KILO)); if (PROBLEM::memory_usage > PROBLEM::memory_limit) { PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::MLE; FM_LOG_TRACE("Well, Memory Limit Exceeded."); ptrace(PTRACE_KILL, executive, NULL, NULL); break; } //获得子进程的寄存器,目的是为了获知其系统调用 if (ptrace(PTRACE_GETREGS, executive, NULL, ®s) < 0) { FM_LOG_WARNING("ptrace PTRACE_GETREGS failed"); exit(JUDGE_CONF::EXIT_JUDGE); } #ifdef __i386__ syscall_id = regs.orig_eax; #else syscall_id = regs.orig_rax; #endif //检查系统调用是否合法 if (syscall_id > 0 && !is_valid_syscall(PROBLEM::lang, syscall_id, executive, regs)) { FM_LOG_WARNING("restricted fuction %d\n", syscall_id); if (syscall_id == SYS_rt_sigprocmask){ FM_LOG_WARNING("The glibc failed."); } else { //FM_LOG_WARNING("%d\n", SYS_write); FM_LOG_WARNING("restricted fuction table"); } PROBLEM::result = JUDGE_CONF::RE; ptrace(PTRACE_KILL, executive, NULL, NULL); break; } if (ptrace(PTRACE_SYSCALL, executive, NULL, NULL) < 0) { FM_LOG_WARNING("ptrace PTRACE_SYSCALL failed."); exit(JUDGE_CONF::EXIT_JUDGE); } } } //这儿关于time_usage和memory_usage计算的有点混乱 //主要是为了减轻web的任务 //只要不是AC,就把time_usage和memory_usage归0 if (PROBLEM::result == JUDGE_CONF::SE){ PROBLEM::time_usage += (rused.ru_utime.tv_sec * 1000 + rused.ru_utime.tv_usec / 1000); PROBLEM::time_usage += (rused.ru_stime.tv_sec * 1000 + rused.ru_stime.tv_usec / 1000); } }
int oj_compare_output(const char *file_out, const char *file_user) { FM_LOG_TRACE("start compare"); FILE *fp_std = fopen(file_out, "r"); if (fp_std == nullptr) { FM_LOG_FATAL("open standard output file (%s) failed: %s", file_out, strerror(errno)); exit(EXIT_COMPARE); } FILE *fp_exe = fopen(file_user, "r"); if (fp_exe == nullptr) { FM_LOG_FATAL("open user output file (%s) failed: %s", file_user, strerror(errno)); exit(EXIT_COMPARE); } int a, b, Na = 0, Nb = 0; enum { AC = OJ_AC, PE = OJ_PE, WA = OJ_WA } status = AC; while (true) { /* * Windows / DOS uses '\r\n'; * Unix / Linux / OS X uses '\n'; * Macs before OS X use '\r'; * TODO(power): out file with '\r' line ending get incorrect PE */ while ((a = fgetc(fp_std)) == '\r') {} while ((b = fgetc(fp_exe)) == '\r') {} Na++, Nb++; // deal with '\r' and '\n' if (a == '\r') a = '\n'; if (b == '\r') b = '\n'; if (feof(fp_std) && feof(fp_exe)) { break; } else if (feof(fp_std) || feof(fp_exe)) { // deal with tailing white spaces FILE *fp_tmp; if (feof(fp_std)) { FM_LOG_TRACE("std out file ended"); if (!is_space_char(b)) { FM_LOG_TRACE("WA exe['%c':0x%x @%d]", b, b, Nb); status = WA; break; } fp_tmp = fp_exe; } else { /* feof(fp_exe) */ FM_LOG_TRACE("user out file ended"); if (!is_space_char(a)) { FM_LOG_TRACE("WA std['%c':0x%x @%d]", a, a, Na); status = WA; break; } fp_tmp = fp_std; } int c; while (c = fgetc(fp_tmp), c != EOF) { if (c == '\r') c = '\n'; if (!is_space_char(c)) { FM_LOG_TRACE("WA ['%c':0x%x]", c, c); status = WA; break; } } break; } if (a != b) { status = PE; if (is_space_char(a) && is_space_char(b)) { continue; } if (is_space_char(a)) { ungetc(b, fp_exe); Nb--; } else if (is_space_char(b)) { ungetc(a, fp_std); Na--; } else { FM_LOG_TRACE("WA ['%c':0x%x @%d] : ['%c':0x%x @%d]", a, a, Na, b, b, Nb); status = WA; break; } } } // end of while fclose(fp_std); fclose(fp_exe); if (status == WA || status == PE) { make_diff_out2(file_out, file_user, oj_solution.work_dir, file_out); } FM_LOG_TRACE("compare finished, result=%s", status == AC ? "AC" : (status == PE ? "PE" : "WA")); return status; }
void run(oj_solution_t &oj_solution) { if (oj_solution.cid > 0) { snprintf(oj_solution.work_dir, PATH_SIZE, "%s/c%d", oj_config.temp_dir, oj_solution.cid); } else { strncpy(oj_solution.work_dir, oj_config.temp_dir, strlen(oj_config.temp_dir) + 1); } char stderr_file[PATH_SIZE]; snprintf(stderr_file, PATH_SIZE, "%s/%s/error.txt", oj_solution.work_dir, oj_solution.sid); FM_LOG_NOTICE("/usr/local/bin/powerjudge -s %s -p %s -l %s -t %s -m %s -w %s -D %s", oj_solution.sid, oj_solution.pid, oj_solution.language, oj_solution.time_limit, oj_solution.memory_limit, oj_solution.work_dir, oj_config.data_dir); pid_t pid = fork(); if (pid < 0) { FM_LOG_FATAL("fork judger failed: %s", strerror(errno)); SendQueue.push(std::make_pair(EXIT_FORK_ERROR, oj_solution)); } else if (pid == 0) { execl("/usr/local/bin/powerjudge", "/usr/local/bin/powerjudge", "-s", oj_solution.sid, "-p", oj_solution.pid, "-l", oj_solution.language, "-t", oj_solution.time_limit, "-m", oj_solution.memory_limit, "-w", oj_solution.work_dir, "-D", oj_config.data_dir, "-c", std::to_string(oj_solution.cid).c_str(), NULL); stderr = freopen(stderr_file, "a+", stderr); FM_LOG_FATAL("exec error: %s", strerror(errno)); SendQueue.push(std::make_pair(EXIT_EXEC_ERROR, oj_solution)); } else { int status = 0; FM_LOG_TRACE("process ID=%d", pid); if (waitpid(pid, &status, WUNTRACED) == -1) { FM_LOG_FATAL("waitpid for judger failed: %s", strerror(errno)); } if (WIFEXITED(status)) // normal termination { if (EXIT_SUCCESS == WEXITSTATUS(status)) { FM_LOG_DEBUG("judge succeeded"); SendQueue.push(std::make_pair(EXIT_OK, oj_solution)); } else if (EXIT_COMPILE_ERROR == WEXITSTATUS(status)) { FM_LOG_TRACE("compile error"); SendQueue.push(std::make_pair(EXIT_OK, oj_solution)); } else if (EXIT_JUDGE == WEXITSTATUS(status)) { FM_LOG_TRACE("judge error"); SendQueue.push(std::make_pair(OJ_SE, oj_solution)); } else { FM_LOG_TRACE("judge error"); SendQueue.push(std::make_pair(WEXITSTATUS(status), oj_solution)); } } else { if (WIFSIGNALED(status)) // killed by signal { int signo = WTERMSIG(status); FM_LOG_WARNING("judger killed by signal: %s", strsignal(signo)); SendQueue.push(std::make_pair(signo, oj_solution)); } else if (WIFSTOPPED(status)) // stopped by signal { int signo = WSTOPSIG(status); FM_LOG_FATAL("judger stopped by signal: %s\n", strsignal(signo)); SendQueue.push(std::make_pair(signo, oj_solution)); } else { FM_LOG_FATAL("judger stopped with unknown reason, status(%d)", status); SendQueue.push(std::make_pair(EXIT_UNKNOWN, oj_solution)); } } } }