static int check_config(void) { int i; int total = 0; if (check_writable_spool(serve_state.global->compile_queue_dir, SPOOL_OUT) < 0) return -1; for (i = 1; i <= serve_state.max_lang; i++) { if (!serve_state.langs[i]) continue; /* script must exist and be executable */ total++; if (check_executable(serve_state.langs[i]->cmd) < 0) return -1; } if (!total) { err("no languages"); return -1; } return 0; }
int main(int argc, char *argv[]) { int log_fd, write_fd; pid_t pid; int status, output, ret; progname = argv[0]; if (argc < 5) { usage(); exit(1); } reset_scheduler(); log_fd = atoi(argv[1]); write_fd = atoi(argv[2]); set_close_on_exec(write_fd); close(STDOUT_FILENO); close(STDERR_FILENO); dup2(log_fd, STDOUT_FILENO); dup2(log_fd, STDERR_FILENO); close(log_fd); if (setpgid(0, 0) != 0) { fprintf(stderr, "Failed to create process group for event script - %s\n", strerror(errno)); exit(1); } signal(SIGTERM, sigterm); pid = fork(); if (pid < 0) { int save_errno = errno; fprintf(stderr, "Failed to fork - %s\n", strerror(errno)); sys_write(write_fd, &save_errno, sizeof(save_errno)); exit(1); } if (pid == 0) { ret = check_executable(argv[3]); if (ret != 0) { _exit(ret); } ret = execv(argv[3], &argv[3]); if (ret != 0) { int save_errno = errno; fprintf(stderr, "Error executing '%s' - %s\n", argv[3], strerror(save_errno)); } /* This should never happen */ _exit(ENOEXEC); } ret = waitpid(pid, &status, 0); if (ret == -1) { output = -errno; fprintf(stderr, "waitpid() failed - %s\n", strerror(errno)); sys_write(write_fd, &output, sizeof(output)); exit(1); } if (WIFEXITED(status)) { output = WEXITSTATUS(status); /* Only errors should be returned as -ve values */ if (output == ENOENT || output == ENOEXEC) { output = -output; } sys_write(write_fd, &output, sizeof(output)); exit(0); } if (WIFSIGNALED(status)) { output = -EINTR; fprintf(stderr, "Process terminated with signal - %d\n", WTERMSIG(status)); sys_write(write_fd, &output, sizeof(output)); exit(0); } fprintf(stderr, "waitpid() status=%d\n", status); exit(1); }
static void __initJobInfo(JobInfo *jobinfo, Node *head) { size_t i; char* t; /* reset everything */ memset(jobinfo, 0, sizeof(JobInfo)); /* only continue in ok state AND if there is anything to do */ if (head != NULL) { size_t size, argc = size = 0; Node* temp = head; while (temp) { size += (strlen(temp->data) + 1); argc++; temp = temp->next; } /* prepare copy area */ jobinfo->copy = (char*) malloc(size+argc); if (jobinfo->copy == NULL) { printerr("malloc: %s\n", strerror(errno)); return; } /* prepare argument vector */ jobinfo->argc = argc; jobinfo->argv = (char* const*) calloc(argc+1, sizeof(char*)); if (jobinfo->argv == NULL) { printerr("calloc: %s\n", strerror(errno)); return; } /* copy list while updating argument vector and freeing lose arguments */ t = jobinfo->copy; for (i=0; i < argc && (temp=head); ++i) { /* append string to copy area */ size_t len = strlen(temp->data)+1; memcpy(t, temp->data, len); /* I hate nagging compilers which think they know better */ memcpy((void*) &jobinfo->argv[i], &t, sizeof(char*)); t += len; /* clear parse list while we are at it */ head = temp->next; free((void*) temp->data); free((void*) temp); } /* free list of argv */ deleteNodes(head); } /* this is a valid (and initialized) entry */ if (jobinfo->argc > 0) { /* check out path to job */ char* realpath = pathfind(jobinfo->argv[0]); if (realpath == NULL || check_executable(realpath) < 0) { jobinfo->status = -127; jobinfo->saverr = errno; jobinfo->isValid = 2; } else { memcpy((void*) &jobinfo->argv[0], &realpath, sizeof(char*)); jobinfo->isValid = 1; } initStatInfoFromName(&jobinfo->executable, jobinfo->argv[0], O_RDONLY, 0); } }
static int check_config(void) { int i, n1 = 0, n2, j, k; int total = 0; struct section_problem_data *prb = 0; struct section_tester_data *tst = 0; unsigned char *var_test_dir; unsigned char *var_corr_dir; unsigned char *var_info_dir; unsigned char *var_tgz_dir; problem_xml_t px; const struct section_global_data *global = serve_state.global; if (skip_arch_count > 0) { for (i = 0; i < serve_state.max_abstr_tester; ++i) { tst = serve_state.abstr_testers[i]; if (!tst) continue; tst->skip_testing = -1; for (j = 0; j < skip_arch_count; ++j) { if (!strcmp(skip_archs[j], tst->arch)) { break; } } if (j < skip_arch_count) { tst->skip_testing = 1; } } } /* check spooler dirs */ if (check_writable_spool(global->run_queue_dir, SPOOL_OUT) < 0) return -1; if (check_writable_dir(global->run_exe_dir) < 0) return -1; /* check working dirs */ if (make_writable(global->run_work_dir) < 0) return -1; if (check_writable_dir(global->run_work_dir) < 0) return -1; for (i = 1; i <= serve_state.max_prob; i++) { prb = serve_state.probs[i]; if (!prb) continue; if (prb->disable_testing) continue; if (prb->manual_checking) continue; /* ignore output-only problems with XML and answer variants */ px = 0; if (prb->variant_num > 0 && prb->xml.a) { px = prb->xml.a[0]; } else { px = prb->xml.p; } if (px && px->answers) { prb->disable_testing = 1; continue; } // check if there exists a tester for this problem for (j = 1; j <= serve_state.max_tester; j++) { if (!serve_state.testers[j]) continue; if (serve_state.testers[j]->any) break; if (serve_state.testers[j]->problem == i) break; } if (j > serve_state.max_tester) { // no checker for the problem :-( info("no checker found for problem %d", i); continue; } if (prb->type > 0 && prb->type != PROB_TYPE_TESTS) { // output-only problems have no input file if (prb->variant_num <= 0) { if (prb->use_corr) { if (!prb->corr_dir[0]) { err("directory with answers is not defined"); return -1; } if (global->advanced_layout > 0) { var_corr_dir = (unsigned char*) alloca(sizeof(path_t)); get_advanced_layout_path(var_corr_dir, sizeof(path_t), global, prb, DFLT_P_CORR_DIR, -1); } else { var_corr_dir = prb->corr_dir; } if (check_readable_dir(var_corr_dir) < 0) return -1; if ((n2 = count_files(var_corr_dir,prb->corr_sfx,prb->corr_pat)) < 0) return -1; n1 = n2; info("found %d answers for problem %s", n2, prb->short_name); if (n2 != 1) { err("output-only problem must define only one answer file"); return -1; } } if (prb->use_info) { if (!prb->info_dir[0]) { err("directory with test information is not defined"); return -1; } if (global->advanced_layout > 0) { var_info_dir = (unsigned char*) alloca(sizeof(path_t)); get_advanced_layout_path(var_info_dir, sizeof(path_t), global, prb, DFLT_P_INFO_DIR, -1); } else { var_info_dir = prb->info_dir; } if (check_readable_dir(var_info_dir) < 0) return -1; if ((n2 = count_files(var_info_dir,prb->info_sfx,prb->info_pat)) < 0) return -1; info("found %d info files for problem %s", n2, prb->short_name); if (n2 != 1) { err("output-only problem must define only one info file"); return -1; } } if (prb->use_tgz) { if (!prb->tgz_dir[0]) { err("directory with tgz information is not defined"); return -1; } if (global->advanced_layout > 0) { var_tgz_dir = (unsigned char*) alloca(sizeof(path_t)); get_advanced_layout_path(var_tgz_dir, sizeof(path_t), global, prb, DFLT_P_TGZ_DIR, -1); } else { var_tgz_dir = prb->tgz_dir; } if (check_readable_dir(var_tgz_dir) < 0) return -1; if ((n2 = count_files(var_tgz_dir, prb->tgz_sfx, 0)) < 0) return -1; info("found %d tgz files for problem %s", n2, prb->short_name); if (n2 != 1) { err("output-only problem must define only one tgz file"); return -1; } } } else { var_test_dir = (unsigned char *) alloca(sizeof(path_t)); var_corr_dir = (unsigned char *) alloca(sizeof(path_t)); var_info_dir = (unsigned char *) alloca(sizeof(path_t)); var_tgz_dir = (unsigned char *) alloca(sizeof(path_t)); for (k = 1; k <= prb->variant_num; k++) { if (global->advanced_layout > 0) { get_advanced_layout_path(var_test_dir, sizeof(path_t), global, prb, DFLT_P_TEST_DIR, k); get_advanced_layout_path(var_corr_dir, sizeof(path_t), global, prb, DFLT_P_CORR_DIR, k); get_advanced_layout_path(var_info_dir, sizeof(path_t), global, prb, DFLT_P_INFO_DIR, k); get_advanced_layout_path(var_tgz_dir, sizeof(path_t), global, prb, DFLT_P_TGZ_DIR, k); } else { snprintf(var_test_dir, sizeof(path_t), "%s-%d", prb->test_dir, k); snprintf(var_corr_dir, sizeof(path_t), "%s-%d", prb->corr_dir, k); snprintf(var_info_dir, sizeof(path_t), "%s-%d", prb->info_dir, k); snprintf(var_tgz_dir, sizeof(path_t), "%s-%d", prb->tgz_dir, k); } if (prb->use_corr) { if (!prb->corr_dir[0]) { err("directory with answers is not defined"); return -1; } if (check_readable_dir(var_corr_dir) < 0) return -1; if ((j = count_files(var_corr_dir,prb->corr_sfx,prb->corr_pat)) < 0) return -1; if (j != 1) { err("output-only problem must define only one answer file"); return -1; } } if (prb->use_info) { if (!prb->info_dir[0]) { err("directory with test infos is not defined"); return -1; } if (check_readable_dir(var_info_dir) < 0) return -1; if ((j = count_files(var_info_dir,prb->info_sfx,prb->info_pat)) < 0) return -1; if (j != 1) { err("output-only problem must define only one info file"); return -1; } } if (prb->use_tgz) { if (!prb->tgz_dir[0]) { err("directory with tgz is not defined"); return -1; } if (check_readable_dir(var_tgz_dir) < 0) return -1; if ((j = count_files(var_tgz_dir, prb->tgz_sfx, 0)) < 0) return -1; if (j != 1) { err("output-only problem must define only one info file"); return -1; } } } n1 = n2 = 1; } } else if (!prb->type) { /* check existence of tests */ if (prb->variant_num <= 0) { if (global->advanced_layout > 0) { var_test_dir = (unsigned char *) alloca(sizeof(path_t)); get_advanced_layout_path(var_test_dir, sizeof(path_t), global, prb, DFLT_P_TEST_DIR, -1); } else { var_test_dir = prb->test_dir; } if (check_readable_dir(var_test_dir) < 0) return -1; if ((n1 = count_files(var_test_dir, prb->test_sfx, prb->test_pat)) < 0) return -1; if (!n1) { err("'%s' does not contain any tests", var_test_dir); return -1; } /* if (prb->type_val > 0 && n1 != 1) { err("`%s' must have only one test (as output-only problem)", prb->short_name); return -1; } */ info("found %d tests for problem %s", n1, prb->short_name); if (n1 < prb->tests_to_accept) { err("%d tests required for problem acceptance!",prb->tests_to_accept); return -1; } if (prb->use_corr) { if (!prb->corr_dir[0]) { err("directory with answers is not defined"); return -1; } if (global->advanced_layout > 0) { var_corr_dir = (unsigned char *) alloca(sizeof(path_t)); get_advanced_layout_path(var_corr_dir, sizeof(path_t), global, prb, DFLT_P_CORR_DIR, -1); } else { var_corr_dir = prb->corr_dir; } if (check_readable_dir(var_corr_dir) < 0) return -1; if ((n2 = count_files(var_corr_dir,prb->corr_sfx,prb->corr_pat)) < 0) return -1; info("found %d answers for problem %s", n2, prb->short_name); if (n1 != n2) { err("number of test does not match number of answers"); return -1; } } if (prb->use_info) { if (!prb->info_dir[0]) { err("directory with test information is not defined"); return -1; } if (global->advanced_layout > 0) { var_info_dir = (unsigned char *) alloca(sizeof(path_t)); get_advanced_layout_path(var_info_dir, sizeof(path_t), global, prb, DFLT_P_INFO_DIR, -1); } else { var_info_dir = prb->info_dir; } if (check_readable_dir(var_info_dir) < 0) return -1; if ((n2 = count_files(var_info_dir,prb->info_sfx,prb->info_pat)) < 0) return -1; info("found %d info files for problem %s", n2, prb->short_name); if (n1 != n2) { err("number of test does not match number of info files"); return -1; } } if (prb->use_tgz) { if (!prb->tgz_dir[0]) { err("directory with tgz information is not defined"); return -1; } if (global->advanced_layout > 0) { var_tgz_dir = (unsigned char *) alloca(sizeof(path_t)); get_advanced_layout_path(var_tgz_dir, sizeof(path_t), global, prb, DFLT_P_TGZ_DIR, -1); } else { var_tgz_dir = prb->tgz_dir; } if (check_readable_dir(var_tgz_dir) < 0) return -1; if ((n2 = count_files(var_tgz_dir, prb->tgz_sfx, 0)) < 0) return -1; info("found %d tgz files for problem %s", n2, prb->short_name); if (n1 != n2) { err("number of test does not match number of tgz files"); return -1; } } } else { n1 = n2 = -1; var_test_dir = (unsigned char *) alloca(sizeof(path_t)); var_corr_dir = (unsigned char *) alloca(sizeof(path_t)); var_info_dir = (unsigned char *) alloca(sizeof(path_t)); var_tgz_dir = (unsigned char *) alloca(sizeof(path_t)); for (k = 1; k <= prb->variant_num; k++) { if (global->advanced_layout > 0) { get_advanced_layout_path(var_test_dir, sizeof(path_t), global, prb, DFLT_P_TEST_DIR, k); get_advanced_layout_path(var_corr_dir, sizeof(path_t), global, prb, DFLT_P_CORR_DIR, k); get_advanced_layout_path(var_info_dir, sizeof(path_t), global, prb, DFLT_P_INFO_DIR, k); get_advanced_layout_path(var_tgz_dir, sizeof(path_t), global, prb, DFLT_P_TGZ_DIR, k); } else { snprintf(var_test_dir, sizeof(path_t), "%s-%d", prb->test_dir, k); snprintf(var_corr_dir, sizeof(path_t), "%s-%d", prb->corr_dir, k); snprintf(var_info_dir, sizeof(path_t), "%s-%d", prb->info_dir, k); snprintf(var_tgz_dir, sizeof(path_t), "%s-%d", prb->tgz_dir, k); } if (check_readable_dir(var_test_dir) < 0) return -1; if ((j = count_files(var_test_dir, prb->test_sfx, prb->test_pat)) < 0) return -1; if (!j) { err("'%s' does not contain any tests", var_test_dir); return -1; } /* if (prb->type_val > 0 && n1 != 1) { err("`%s', variant %d must have only one test (as output-only problem)", prb->short_name, j); return -1; } */ if (n1 < 0) n1 = j; if (n1 != j) { err("number of tests %d for variant %d does not equal %d", j, k, n1); return -1; } info("found %d tests for problem %s, variant %d", n1, prb->short_name, k); if (n1 < prb->tests_to_accept) { err("%d tests required for problem acceptance!", prb->tests_to_accept); return -1; } if (prb->use_corr) { if (!prb->corr_dir[0]) { err("directory with answers is not defined"); return -1; } if (check_readable_dir(var_corr_dir) < 0) return -1; if ((j = count_files(var_corr_dir,prb->corr_sfx,prb->corr_pat)) < 0) return -1; info("found %d answers for problem %s, variant %d", j, prb->short_name, k); if (n1 != j) { err("number of tests %d does not match number of answers %d", n1, j); return -1; } } if (prb->use_info) { if (!prb->info_dir[0]) { err("directory with test infos is not defined"); return -1; } if (check_readable_dir(var_info_dir) < 0) return -1; if ((j = count_files(var_info_dir,prb->info_sfx,prb->info_pat)) < 0) return -1; info("found %d test infos for problem %s, variant %d", j, prb->short_name, k); if (n1 != j) { err("number of tests %d does not match number of test infos %d", n1, j); return -1; } } if (prb->use_tgz) { if (!prb->tgz_dir[0]) { err("directory with tgz is not defined"); return -1; } if (check_readable_dir(var_tgz_dir) < 0) return -1; if ((j = count_files(var_tgz_dir, prb->tgz_sfx, 0)) < 0) return -1; info("found %d tgzs for problem %s, variant %d", j, prb->short_name, k); if (n1 != j) { err("number of tests %d does not match number of tgz %d", n1, j); return -1; } } n2 = n1; } } } if (n1 >= tests_a - 1) { if (!tests_a) tests_a = 128; while (n1 >= tests_a - 1) tests_a *= 2; xfree(tests); XCALLOC(tests, tests_a); } ASSERT(prb->test_score >= 0); if (global->score_system == SCORE_MOSCOW) { if (prb->full_score <= 0) { err("problem %s: problem full_score is not set", prb->short_name); return -1; } prb->ntests = n1; if (!prb->scoring_checker) { if (!(prb->x_score_tests = prepare_parse_score_tests(prb->score_tests, prb->full_score))){ err("problem %s: parsing of score_tests failed", prb->short_name); return -1; } prb->x_score_tests[prb->full_score - 1] = n1 + 1; if (prb->full_score > 1 && prb->x_score_tests[prb->full_score - 2] > n1 + 1) { err("problem %s: score_tests[%d] > score_tests[%d]", prb->short_name, prb->full_score - 2, prb->full_score - 1); return -1; } } } else if (prb->test_score >= 0 && global->score_system != SCORE_ACM) { int score_summ = 0; prb->ntests = n1; XCALLOC(prb->tscores, prb->ntests + 1); for (j = 1; j <= prb->ntests; j++) prb->tscores[j] = prb->test_score; // test_score_list overrides test_score if (prb->test_score_list && prb->test_score_list[0]) { char const *s = prb->test_score_list; int tn = 1; int was_indices = 0; int n; int index, score; while (1) { while (*s > 0 && *s <= ' ') s++; if (!*s) break; if (*s == '[') { if (sscanf(s, "[ %d ] %d%n", &index, &score, &n) != 2) { err("cannot parse test_score_list for problem %s", prb->short_name); return -1; } if (index < 1 || index > prb->ntests) { err("problem %s: test_score_list: index out of range", prb->short_name); return -1; } if (score < 0) { err("problem %s: test_score_list: invalid score", prb->short_name); return -1; } tn = index; was_indices = 1; prb->tscores[tn++] = score; s += n; } else { if (sscanf(s, "%d%n", &score, &n) != 1) { err("cannot parse test_score_list for problem %s", prb->short_name); return -1; } if (score < 0) { err("problem %s: test_score_list: invalid score", prb->short_name); return -1; } if (tn > prb->ntests) { err("problem %s: too many scores specified", prb->short_name); return -1; } prb->tscores[tn++] = score; s += n; } } if (!was_indices && tn <= prb->ntests) { info("test_score_list for problem %s defines only %d tests", prb->short_name, tn - 1); } } for (j = 1; j <= prb->ntests; j++) score_summ += prb->tscores[j]; if (score_summ > prb->full_score && !prb->valuer_cmd[0]) { err("total score (%d) > full score (%d) for problem %s", score_summ, prb->full_score, prb->short_name); return -1; } } } for (i = 1; i <= serve_state.max_tester; i++) { if (!serve_state.testers[i]) continue; if (serve_state.testers[i]->any) continue; prb = serve_state.probs[serve_state.testers[i]->problem]; total++; /* check working dirs */ if (make_writable(serve_state.testers[i]->check_dir) < 0) return -1; if (check_writable_dir(serve_state.testers[i]->check_dir) < 0) return -1; if (serve_state.testers[i]->prepare_cmd[0] && check_executable(serve_state.testers[i]->prepare_cmd) < 0) return -1; if (serve_state.testers[i]->start_cmd[0] && check_executable(serve_state.testers[i]->start_cmd) < 0) return -1; } info("checking default testers..."); if ((i = process_default_testers()) < 0) return -1; info("checking default testers done"); total += i; if (!total) info("no testers"); #if CONF_HAS_LIBINTL - 0 == 1 // bind message catalogs, if specified if (global->enable_l10n && global->l10n_dir[0]) { bindtextdomain("ejudge", global->l10n_dir); textdomain("ejudge"); } #endif return 0; }
static int process_default_testers(void) { int total = 0; int i, j, k; unsigned char *prob_flags = 0; struct section_tester_data *tp, *tq; struct section_problem_data *ts; struct section_tester_data tn; //temporary entry prob_flags = (unsigned char *) alloca(serve_state.max_prob + 1); /* scan all the 'any' testers */ for (i = 1; i <= serve_state.max_tester; i++) { tp = serve_state.testers[i]; if (!tp || !tp->any) continue; // check architecture uniqueness for (j = 1; j <= serve_state.max_tester; j++) { tq = serve_state.testers[j]; if (i == j || !tq || !tq->any) continue; if (strcmp(serve_state.testers[j]->arch, tp->arch) != 0) continue; err("default testers %d and %d has the same architecture '%s'", i, j, tp->arch); return -1; } // mark the problems with explicit testers for this architecture memset(prob_flags, 0, serve_state.max_prob + 1); for (j = 1; j <= serve_state.max_tester; j++) { tq = serve_state.testers[j]; if (!tq || tq->any) continue; if (strcmp(tp->arch, tq->arch) != 0) continue; // tq is specific tester with the same architecture ASSERT(tq->problem > 0 && tq->problem <= serve_state.max_prob); ASSERT(serve_state.probs[tq->problem]); prob_flags[tq->problem] = 1; } // scan all problems, which have no default tester for (k = 1; k <= serve_state.max_prob; k++) { ts = serve_state.probs[k]; if (!ts || prob_flags[k]) continue; if (ts->disable_testing) continue; if (ts->manual_checking) continue; // so at this point: tp - pointer to the default tester, // k is the problem number // ts - pointer to the problem which should be handled by the // default tester if (prepare_tester_refinement(&serve_state, &tn, i, k) < 0) return -1; if (create_tester_dirs(&tn) < 0) return -1; /* check working dirs */ if (make_writable(tn.check_dir) < 0) return -1; if (check_writable_dir(tn.check_dir) < 0) return -1; if (tn.prepare_cmd[0] && check_executable(tn.prepare_cmd) < 0) return -1; if (tn.start_cmd[0] && check_executable(tn.start_cmd) < 0) return -1; total++; sarray_free(tn.start_env); sarray_free(tn.super); } } return total; }