static void create_dir(void) { if (os_MakeDirPath(global->work_dir, 0777) < 0) { die("cannot create directory %s: %s", global->work_dir, os_ErrorMsg()); } if (os_MakeDirPath(global->spool_dir, 0777) < 0) { die("cannot create directory %s: %s", global->work_dir, os_ErrorMsg()); } if (make_all_dir(global->queue_dir, 0777) < 0) { exit(1); } if (make_all_dir(global->result_dir, 0777) < 0) { exit(1); } }
static int do_loop(void) { path_t src_name; path_t exe_name; path_t src_path; path_t exe_path; path_t log_path; path_t exe_out; path_t log_out; path_t txt_out; path_t report_dir, status_dir; path_t pkt_name, run_name, work_run_name; char *pkt_ptr; size_t pkt_len; int r, i; tpTask tsk = 0; unsigned char msgbuf[512]; int ce_flag; struct compile_request_packet *req = 0; struct compile_reply_packet rpl; void *rpl_pkt = 0; size_t rpl_size = 0; const unsigned char *tail_message = 0; #if HAVE_TRUNCATE - 0 struct stat stb; #endif /* HAVE_TRUNCATE */ FILE *log_f = 0; struct section_language_data *lang = 0; const struct section_global_data *global = serve_state.global; // if (cr_serialize_init(&serve_state) < 0) return -1; interrupt_init(); interrupt_disable(); while (1) { // terminate if signaled if (interrupt_get_status() || interrupt_restart_requested()) break; r = scan_dir(global->compile_queue_dir, pkt_name, sizeof(pkt_name)); if (r < 0) { switch (-r) { case ENOMEM: case ENOENT: case ENFILE: err("trying to recover, sleep for 5 seconds"); interrupt_enable(); os_Sleep(5000); interrupt_disable(); continue; default: err("unrecoverable error, exiting"); return -1; } } if (!r) { interrupt_enable(); os_Sleep(global->sleep_time); interrupt_disable(); continue; } pkt_ptr = 0; pkt_len = 0; r = generic_read_file(&pkt_ptr, 0, &pkt_len, SAFE | REMOVE, global->compile_queue_dir, pkt_name, ""); if (r == 0) continue; if (r < 0 || !pkt_ptr) { // it looks like there's no reasonable recovery strategy // so, just ignore the error continue; } r = compile_request_packet_read(pkt_len, pkt_ptr, &req); xfree(pkt_ptr); pkt_ptr = 0; if (r < 0) { /* * the incoming packet is completely broken, so just drop it */ goto cleanup_and_continue; } if (!req->contest_id) { // special packets r = req->lang_id; req = compile_request_packet_free(req); switch (r) { case 1: interrupt_flag_interrupt(); break; case 2: interrupt_flag_sighup(); break; } continue; } memset(&rpl, 0, sizeof(rpl)); rpl.judge_id = req->judge_id; rpl.contest_id = req->contest_id; rpl.run_id = req->run_id; rpl.ts1 = req->ts1; rpl.ts1_us = req->ts1_us; rpl.use_uuid = req->use_uuid; rpl.uuid[0] = req->uuid[0]; rpl.uuid[1] = req->uuid[1]; rpl.uuid[2] = req->uuid[2]; rpl.uuid[3] = req->uuid[3]; get_current_time(&rpl.ts2, &rpl.ts2_us); rpl.run_block_len = req->run_block_len; rpl.run_block = req->run_block; /* !!! shares memory with req */ msgbuf[0] = 0; /* prepare paths useful to report messages to the serve */ snprintf(report_dir, sizeof(report_dir), "%s/%06d/report", global->compile_dir, rpl.contest_id); snprintf(status_dir, sizeof(status_dir), "%s/%06d/status", global->compile_dir, rpl.contest_id); if (req->use_uuid > 0) { snprintf(run_name, sizeof(run_name), "%s", ej_uuid_unparse(req->uuid, NULL)); } else { snprintf(run_name, sizeof(run_name), "%06d", rpl.run_id); } snprintf(work_run_name, sizeof(work_run_name), "%06d", rpl.run_id); pathmake(log_out, report_dir, "/", run_name, NULL); snprintf(txt_out, sizeof(txt_out), "%s/%s.txt", report_dir, run_name); make_all_dir(status_dir, 0777); make_dir(report_dir, 0777); if (!r) { /* * there is something wrong, but we have contest_id, judge_id * and run_id in place, so we can report an error back * to serve */ snprintf(msgbuf, sizeof(msgbuf), "invalid compile packet\n"); goto report_internal_error; } if (req->style_check_only && req->style_checker && req->style_checker[0]) { check_style_only(global, req, &rpl, pkt_name, run_name, work_run_name, report_dir, status_dir); req = 0; continue; } if (req->lang_id <= 0 || req->lang_id > serve_state.max_lang || !(lang = serve_state.langs[req->lang_id])) { snprintf(msgbuf, sizeof(msgbuf), "invalid lang_id %d\n", req->lang_id); goto report_internal_error; } pathmake(src_name, work_run_name, lang->src_sfx, NULL); pathmake(exe_name, work_run_name, lang->exe_sfx, NULL); pathmake(src_path, global->compile_work_dir, "/", src_name, NULL); pathmake(exe_path, global->compile_work_dir, "/", exe_name, NULL); pathmake(log_path, global->compile_work_dir, "/", "log", NULL); /* the resulting executable file */ snprintf(exe_out, sizeof(exe_out), "%s/%s%s", report_dir, run_name, lang->exe_sfx); /* move the source file into the working dir */ r = generic_copy_file(REMOVE, global->compile_src_dir, pkt_name, lang->src_sfx, 0, global->compile_work_dir, src_name, ""); if (!r) { snprintf(msgbuf, sizeof(msgbuf), "the source file is missing\n"); err("the source file is missing"); goto report_internal_error; } if (r < 0) { snprintf(msgbuf, sizeof(msgbuf), "error reading the source file\n"); err("cannot read the source file"); goto report_internal_error; } tail_message = 0; ce_flag = 0; if (req->output_only) { // copy src_path -> exe_path generic_copy_file(0, NULL, src_path, NULL, 0, NULL, exe_path, NULL); ce_flag = 0; rpl.status = RUN_OK; } else { if (req->style_checker) { /* run style checker */ //info("Starting: %s %s", req->style_checker, src_path); tsk = task_New(); task_AddArg(tsk, req->style_checker); task_AddArg(tsk, src_path); task_SetPathAsArg0(tsk); task_SetWorkingDir(tsk, global->compile_work_dir); task_EnableProcessGroup(tsk); task_SetRedir(tsk, 0, TSR_FILE, "/dev/null", TSK_READ); task_SetRedir(tsk, 1, TSR_FILE, log_path, TSK_REWRITE, 0777); task_SetRedir(tsk, 2, TSR_DUP, 1); if (req->sc_env_num > 0) { for (i = 0; i < req->sc_env_num; i++) task_PutEnv(tsk, req->sc_env_vars[i]); } if (lang->compile_real_time_limit > 0) { task_SetMaxRealTime(tsk, lang->compile_real_time_limit); } task_EnableAllSignals(tsk); task_PrintArgs(tsk); if (task_Start(tsk) < 0) { err("Failed to start style checker process"); tail_message = "\n\nFailed to start style checker"; ce_flag = 1; rpl.status = RUN_STYLE_ERR; } else { task_Wait(tsk); if (task_IsTimeout(tsk)) { err("Style checker process timed out"); tail_message = "\n\nStyle checker process timed out"; ce_flag = 1; rpl.status = RUN_STYLE_ERR; } else if (task_IsAbnormal(tsk)) { info("Style checker failed"); ce_flag = 1; rpl.status = RUN_STYLE_ERR; } else { info("Style checker sucessful"); ce_flag = 0; rpl.status = RUN_OK; } } task_Delete(tsk); tsk = 0; } if (!ce_flag) { //info("Starting: %s %s %s", lang->cmd, src_name, exe_name); tsk = task_New(); task_AddArg(tsk, lang->cmd); task_AddArg(tsk, src_name); task_AddArg(tsk, exe_name); task_SetPathAsArg0(tsk); task_EnableProcessGroup(tsk); if (((ssize_t) req->max_vm_size) > 0) { task_SetVMSize(tsk, req->max_vm_size); } else if (((ssize_t) lang->max_vm_size) > 0) { task_SetVMSize(tsk, lang->max_vm_size); } else if (((ssize_t) global->compile_max_vm_size) > 0) { task_SetVMSize(tsk, global->compile_max_vm_size); } if (((ssize_t) req->max_stack_size) > 0) { task_SetStackSize(tsk, req->max_stack_size); } else if (((ssize_t) lang->max_stack_size) > 0) { task_SetStackSize(tsk, lang->max_stack_size); } else if (((ssize_t) global->compile_max_stack_size) > 0) { task_SetStackSize(tsk, global->compile_max_stack_size); } if (((ssize_t) req->max_file_size) > 0) { task_SetMaxFileSize(tsk, req->max_file_size); } else if (((ssize_t) lang->max_file_size) > 0) { task_SetMaxFileSize(tsk, lang->max_file_size); } else if (((ssize_t) global->compile_max_file_size) > 0) { task_SetMaxFileSize(tsk, global->compile_max_file_size); } if (req->env_num > 0) { for (i = 0; i < req->env_num; i++) task_PutEnv(tsk, req->env_vars[i]); } task_SetWorkingDir(tsk, global->compile_work_dir); task_SetRedir(tsk, 0, TSR_FILE, "/dev/null", TSK_READ); task_SetRedir(tsk, 1, TSR_FILE, log_path, TSK_APPEND, 0777); task_SetRedir(tsk, 2, TSR_DUP, 1); if (lang->compile_real_time_limit > 0) { task_SetMaxRealTime(tsk, lang->compile_real_time_limit); } task_EnableAllSignals(tsk); /* if (cr_serialize_lock(&serve_state) < 0) { // FIXME: propose reasonable recovery? return -1; } */ task_PrintArgs(tsk); task_Start(tsk); task_Wait(tsk); /* if (cr_serialize_unlock(&serve_state) < 0) { // FIXME: propose reasonable recovery? return -1; } */ if (task_IsTimeout(tsk)) { err("Compilation process timed out"); tail_message = "\n\nCompilation process timed out"; ce_flag = 1; rpl.status = RUN_COMPILE_ERR; } else if (task_IsAbnormal(tsk)) { info("Compilation failed"); ce_flag = 1; rpl.status = RUN_COMPILE_ERR; } else { info("Compilation sucessful"); ce_flag = 0; rpl.status = RUN_OK; } } } get_current_time(&rpl.ts3, &rpl.ts3_us); if (compile_reply_packet_write(&rpl, &rpl_size, &rpl_pkt) < 0) goto cleanup_and_continue; while (1) { if (ce_flag) { #if HAVE_TRUNCATE - 0 // truncate log file at size 1MB if (stat(log_path, &stb) >= 0 && stb.st_size > MAX_LOG_SIZE) { truncate(log_path, MAX_LOG_SIZE); if ((log_f = fopen(log_path, "a"))) { fprintf(log_f, "\n\nCompilation log is truncated by ejudge!\n"); fclose(log_f); log_f = 0; } } #endif // append tail_message if (tail_message && (log_f = fopen(log_path, "a"))) { fprintf(log_f, "%s\n", tail_message); fclose(log_f); log_f = 0; } r = generic_copy_file(0, 0, log_path, "", 0, 0, log_out, ""); } else { r = generic_copy_file(0, 0, exe_path, "", 0, 0, exe_out, ""); generic_copy_file(0, 0, log_path, "", 0, 0, txt_out, ""); } if (r >= 0 && generic_write_file(rpl_pkt, rpl_size, SAFE, status_dir, run_name, "") >= 0) break; info("waiting 5 seconds hoping for things to change"); interrupt_enable(); os_Sleep(5000); interrupt_disable(); } goto cleanup_and_continue; report_internal_error:; rpl.status = RUN_CHECK_FAILED; get_current_time(&rpl.ts3, &rpl.ts3_us); if (compile_reply_packet_write(&rpl, &rpl_size, &rpl_pkt) < 0) goto cleanup_and_continue; if (generic_write_file(msgbuf, strlen(msgbuf), 0, 0, log_out, 0) < 0) goto cleanup_and_continue; if (generic_write_file(rpl_pkt, rpl_size, SAFE, status_dir, run_name, 0) < 0) unlink(log_out); goto cleanup_and_continue; cleanup_and_continue:; task_Delete(tsk); tsk = 0; clear_directory(global->compile_work_dir); xfree(rpl_pkt); rpl_pkt = 0; req = compile_request_packet_free(req); } /* while (1) */ return 0; }
static void read_packet(const unsigned char *dir_path) { unsigned char packet_conf_file[EJ_PATH_MAX]; FILE *f = 0; struct generic_section_config *packet_config = 0; struct nwrun_in_packet *packet = 0; unsigned char result_name[EJ_PATH_MAX]; unsigned char result_in_dir[EJ_PATH_MAX]; unsigned char result_dir_dir[EJ_PATH_MAX]; unsigned char contest_dir[EJ_PATH_MAX]; struct nwrun_out_packet result; unsigned char result_packet_path[EJ_PATH_MAX]; int clean_result_dir = 0; memset(&result, 0, sizeof(result)); snprintf(packet_conf_file,sizeof(packet_conf_file),"%s/packet.cfg",dir_path); packet_config = nwrun_in_packet_parse(packet_conf_file, &packet); if (!packet_config) goto cleanup; nwrun_in_packet_print(stderr, (const struct nwrun_in_packet *) packet_config); /* setup packet defaults */ if (packet->contest_id <= 0) { err("contest_id is not set"); goto cleanup; } if (packet->prob_id <= 0) { err("prob_id is not set"); goto cleanup; } if (packet->test_num <= 0) { err("test_num is not set"); goto cleanup; } if (packet->judge_id <= 0) { err("judge_id is not set"); goto cleanup; } if (!packet->program_name[0]) { err("program_name is not set"); goto cleanup; } if (!packet->test_file_name[0]) { err("test_file_name is not set"); goto cleanup; } if (!packet->input_file_name[0]) { snprintf(packet->input_file_name, sizeof(packet->input_file_name), "%s", DEFAULT_INPUT_FILE_NAME); } if (!packet->result_file_name[0]) { err("result_file_name is not set"); goto cleanup; } if (!packet->output_file_name[0]) { snprintf(packet->output_file_name, sizeof(packet->output_file_name), "%s", DEFAULT_OUTPUT_FILE_NAME); } if (!packet->error_file_name[0]) { snprintf(packet->error_file_name, sizeof(packet->error_file_name), "%s", DEFAULT_ERROR_FILE_NAME); } if (packet->max_output_file_size <= 0) { packet->max_output_file_size = DEFAULT_MAX_OUTPUT_FILE_SIZE; } if (packet->max_error_file_size <= 0) { packet->max_error_file_size = DEFAULT_MAX_ERROR_FILE_SIZE; } if (packet->time_limit_millis <= 0) { err("time_limit_millis is invalid (%d)", packet->time_limit_millis); goto cleanup; } /* create the output directory */ snprintf(result_name, sizeof(result_name), "%c%c%d%c%d%c%d%c%d%c%d", get_priority_code(packet->priority - 17), get_num_prefix(packet->contest_id), packet->contest_id, get_num_prefix(packet->run_id - 1), packet->run_id - 1, get_num_prefix(packet->prob_id), packet->prob_id, get_num_prefix(packet->test_num), packet->test_num, get_num_prefix(packet->judge_id), packet->judge_id); if (packet->use_contest_id_in_reply) { snprintf(contest_dir, sizeof(contest_dir), "%s/%06d", global->result_dir, packet->contest_id); if (make_all_dir(contest_dir, 0777) < 0) { goto cleanup; } snprintf(result_in_dir, sizeof(result_in_dir), "%s/in/%s_%s", contest_dir, os_NodeName(), result_name); snprintf(result_dir_dir, sizeof(result_dir_dir), "%s/dir/%s", contest_dir, result_name); } else { snprintf(result_in_dir, sizeof(result_in_dir), "%s/in/%s_%s", global->result_dir, os_NodeName(), result_name); snprintf(result_dir_dir, sizeof(result_dir_dir), "%s/dir/%s", global->result_dir, result_name); } if (make_dir(result_in_dir, 0777) < 0) { goto cleanup; } clean_result_dir = 1; // set default values snprintf(result.hostname, sizeof(result.hostname), "%s", os_NodeName()); result.contest_id = packet->contest_id; result.run_id = packet->run_id; result.prob_id = packet->prob_id; result.test_num = packet->test_num; result.judge_id = packet->judge_id; result.status = RUN_CHECK_FAILED; snprintf(result.comment, sizeof(result.comment), "Default status was not changed"); handle_packet(dir_path, packet, result_in_dir, &result); snprintf(result_packet_path, sizeof(result_packet_path), "%s/packet.cfg", result_in_dir); if (!(f = fopen(result_packet_path, "wb"))) { err("cannot open file %s: %s", result_packet_path, os_ErrorMsg()); goto cleanup; } nwrun_out_packet_print(f, &result); fclose(f); f = 0; nwrun_out_packet_print(stderr, &result); if (rename(result_in_dir, result_dir_dir) < 0) { err("rename: %s -> %s failed: %s", result_in_dir, result_dir_dir, os_ErrorMsg()); goto cleanup; } clean_result_dir = 0; cleanup: if (clean_result_dir) { remove_directory_recursively(result_in_dir, 0); } nwrun_in_packet_free(packet_config); if (f) fclose(f); }