static void setup_log_file(void) { path_t buf; const unsigned char *s1, *s2; if (ejudge_config->new_server_log && os_IsAbsolutePath(ejudge_config->new_server_log)) return; if (ejudge_config->var_dir && os_IsAbsolutePath(ejudge_config->var_dir)) { if (!(s1 = ejudge_config->new_server_log)) s1 = "ej-contests.log"; snprintf(buf, sizeof(buf), "%s/%s", ejudge_config->var_dir, s1); xfree(ejudge_config->new_server_log); ejudge_config->new_server_log = xstrdup(buf); return; } if (ejudge_config->contests_home_dir && os_IsAbsolutePath(ejudge_config->contests_home_dir)){ if (!(s1 = ejudge_config->new_server_log)) s1 = "ej-contests.log"; if (!(s2 = ejudge_config->var_dir)) s2 = "var"; snprintf(buf, sizeof(buf), "%s/%s/%s", ejudge_config->contests_home_dir, s2, s1); xfree(ejudge_config->new_server_log); ejudge_config->new_server_log = xstrdup(buf); return; } ejudge_config->new_server_log = xstrdup("/tmp/ej-contests.log"); }
int pathmake3(char *dst, ...) { va_list args; char *p; path_t temp; temp[0] = 0; va_start(args, dst); while ((p = va_arg(args, char*))) { if (p[0] == '/' && p[1] == 0) { strmcat(temp, PATH_SEP, PATH_MAX); } else { strmcat(temp, p, PATH_MAX); } } va_end(args); dst[0] = 0; if (!os_IsAbsolutePath(temp)) { os_rGetWorkingDir(dst, PATH_MAX, 1); pathcat(dst, PATH_SEP); } pathcat(dst, temp); return strlen(dst); }
void path_make_relative( unsigned char *out, size_t size, const unsigned char *path, const unsigned char *relto, const unsigned char *prefix) { path_t path1, relto1, prefix1; unsigned char **s_path = 0, **s_relto = 0, **s_prefix = 0; ASSERT(path); snprintf(path1, sizeof(path1), "%s", path); if (!relto || !prefix) goto do_nothing; snprintf(relto1, sizeof(relto1), "%s", relto); snprintf(prefix1, sizeof(prefix1), "%s", prefix); if (!os_IsAbsolutePath(path1) || !os_IsAbsolutePath(relto1) || !os_IsAbsolutePath(prefix1)) goto do_nothing; path_split(path1, &s_path); path_normalize_split(s_path); path_split(relto1, &s_relto); path_normalize_split(s_relto); path_split(prefix1, &s_prefix); path_normalize_split(s_prefix); if (!path_is_prefix(s_path, s_prefix) || !path_is_prefix(s_relto, s_prefix)) goto do_nothing; do_relative(out, size, s_path, s_relto); goto cleanup; do_nothing: snprintf(out, size, "%s", path1); cleanup: path_split_free(s_path); path_split_free(s_relto); path_split_free(s_prefix); }
void path_normalize(unsigned char *path, size_t size) { unsigned char **split = 0; int i, j, len; unsigned char *t; if (!os_IsAbsolutePath(path)) return; path_split(path, &split); i = j = 1; while (split[i]) { if (!strcmp(split[i], "..")) { if (j > 1) j--; i++; } else if (!strcmp(split[i], ".")) { i++; } else { if (i == j) { i++; j++; } else { t = split[j]; split[j] = split[i]; split[i] = t; i++; j++; } } } if (i != j) { t = split[j]; split[j] = split[i]; split[i] = t; } for (; i > j; i--) { xfree(split[i]); split[i] = 0; } len = 0; if (split[0][0] != '/') len += strlen(split[0]); for (len = 0, i = 1; split[i]; i++) len += strlen(split[i]) + 1; if (len >= size) goto cleanup; t = path; if (split[0][0] != '/') t += sprintf(t, "%s", split[0]); for (i = 1; split[i]; i++) t += sprintf(t, "/%s", split[i]); cleanup: for (i = 0; split[i]; i++) xfree(split[i]); xfree(split); }
static void get_program_dir(const unsigned char *program_path) { unsigned char *workdir = 0; unsigned char fullpath[EJ_PATH_MAX]; if (os_IsAbsolutePath(program_path)) { program_dir = os_DirName(program_path); os_normalize_path(program_dir); return; } workdir = os_GetWorkingDir(); snprintf(fullpath, sizeof(fullpath), "%s/%s", workdir, program_path); xfree(workdir); workdir = 0; os_normalize_path(fullpath); program_dir = os_DirName(fullpath); }
static unsigned char * do_load_file(const unsigned char *conf_path, const unsigned char *file) { unsigned char full_path[PATH_MAX]; char *buf = 0; size_t buf_size = 0; if (!file || !*file) return 0; if (!os_IsAbsolutePath(file)) { snprintf(full_path, sizeof(full_path), "%s/%s", conf_path, file); } else { snprintf(full_path, sizeof(full_path), "%s", file); } if (generic_read_file(&buf, 0, &buf_size, 0, 0, full_path, 0) < 0) return 0; return buf; }
int pathmake2(char *dst, ...) { va_list args; char *p; path_t temp; if (os_IsAbsolutePath(dst)) return strlen(dst); temp[0] = 0; va_start(args, dst); while ((p = va_arg(args, char*))) { if (p[0] == '/' && p[1] == 0) { strmcat(temp, PATH_SEP, PATH_MAX); } else { strmcat(temp, p, PATH_MAX); } } va_end(args); pathcpy(dst, temp); return strlen(dst); }
static int process_contest(int contest_id) { const struct contest_desc *cnts = 0; unsigned char config_path[PATH_MAX]; unsigned char out_config_path[PATH_MAX]; unsigned char old_config_path[PATH_MAX]; const unsigned char *conf_dir = 0; struct stat stbuf; serve_state_t state = 0; struct section_global_data *global = 0; int lang_id; struct section_language_data *lang, *cs_lang_by_short, *cs_lang_by_id, *cs_lang; int compile_id; int i; int has_to_convert = 0, has_errors = 0; int *lang_map = 0; unsigned char **lang_shorts = 0; unsigned char short_name[1024]; struct textfile config_text; FILE *config_file = NULL; FILE *out_config_file = NULL; unsigned char cmd_buf[PATH_MAX]; memset(&config_text, 0, sizeof(config_text)); fprintf(stderr, "Processing contest %d\n", contest_id); if (contests_get(contest_id, &cnts) < 0 || !cnts) { error("cannot read contest XML for contest %d", contest_id); goto failure; } if (cnts->conf_dir && os_IsAbsolutePath(cnts->conf_dir)) { snprintf(config_path, sizeof(config_path), "%s/serve.cfg", cnts->conf_dir); } else { if (!cnts->root_dir) { error("contest %d root_dir is not set", contest_id); goto failure; } else if (!os_IsAbsolutePath(cnts->root_dir)) { error("contest %d root_dir %s is not absolute", contest_id, cnts->root_dir); goto failure; } if (!(conf_dir = cnts->conf_dir)) conf_dir = "conf"; snprintf(config_path, sizeof(config_path), "%s/%s/serve.cfg", cnts->root_dir, conf_dir); } if (stat(config_path, &stbuf) < 0) { error("contest %d config file %s does not exist", contest_id, config_path); goto failure; } if (!S_ISREG(stbuf.st_mode)) { error("contest %d config file %s is not a regular file", contest_id, config_path); goto failure; } if (access(config_path, R_OK) < 0) { error("contest %d config file %s is not readable", contest_id, config_path); goto failure; } state = serve_state_init(contest_id); state->config_path = xstrdup(config_path); state->current_time = time(0); state->load_time = state->current_time; if (prepare(NULL, state, state->config_path, 0, PREPARE_SERVE, "", 1, 0, 0) < 0) goto failure; global = state->global; if (!global) { error("contest %d has no global section", contest_id); goto failure; } if (strcmp(global->rundb_plugin, "mysql") != 0) { fprintf(stderr, "contest %d does not use mysql\n", contest_id); goto failure; } if (state->max_lang >= 0) { XCALLOC(lang_map, state->max_lang + 1); XCALLOC(lang_shorts, state->max_lang + 1); } for (lang_id = 1; lang_id <= state->max_lang; ++lang_id) { if (!(lang = state->langs[lang_id])) continue; compile_id = lang->compile_id; if (compile_id <= 0) compile_id = lang->id; if (lang->id > 1000) { fprintf(stderr, " language %s id > 1000 (%d)\n", lang->short_name, lang->id); has_errors = 1; continue; } snprintf(short_name, sizeof(short_name), "%s", lang->short_name); map_lang_aliases(short_name, sizeof(short_name)); /* search the language in the compilation server by short_name and by id */ cs_lang_by_short = 0; cs_lang_by_id = 0; for (i = 1; i < cs_lang_total; ++i) { if ((cs_lang = cs_langs[i]) && cs_lang->id == compile_id) { cs_lang_by_id = cs_lang; break; } } for (i = 1; i < cs_lang_total; ++i) { if ((cs_lang = cs_langs[i]) && !strcmp(cs_lang->short_name, short_name)) { cs_lang_by_short = cs_lang; break; } } /* condition to convert: 1) contest language id does not match to compilation server language id; 2) contest language short name, compilation server language short name match. */ if (lang->id != compile_id && cs_lang_by_short != NULL && cs_lang_by_short == cs_lang_by_id) { has_to_convert = 1; fprintf(stderr, " language %s id %d to be changed to %d\n", lang->short_name, lang->id, compile_id); lang_map[lang_id] = compile_id; lang_shorts[lang_id] = xstrdup(lang->short_name); } else if (lang->id == compile_id && cs_lang_by_short != NULL && cs_lang_by_short == cs_lang_by_id) { /* condition to do nothing: 1) contest language id match compilation server language id; 2) contest language short name, compilation server language short name match. */ } else { has_errors = 1; fprintf(stderr, " unexpected language %s, id %d, compile id %d\n", lang->short_name, lang->id, lang->compile_id); if (cs_lang_by_id) { fprintf(stderr, " CS lang by id: id %d, short %s\n", cs_lang_by_id->id, cs_lang_by_id->short_name); } else { fprintf(stderr, " CS lang by id: NULL\n"); } if (cs_lang_by_short) { fprintf(stderr, " CS lang by short name: id %d, short %s\n", cs_lang_by_short->id, cs_lang_by_short->short_name); } else { fprintf(stderr, " CS lang by short name: NULL\n"); } } } if (has_errors) { fprintf(stderr, "contest %d cannot be converted\n", contest_id); return 0; } if (!has_to_convert) { fprintf(stderr, "contest %d is ok\n", contest_id); return 0; } config_file = fopen(config_path, "r"); if (!config_file) { fprintf(stderr, "cannot open %s\n", config_path); return 0; } if (gettextfile(config_file, &config_text) <= 0) { fprintf(stderr, "configuration file %s is empty\n", config_path); return 0; } fclose(config_file); config_file = NULL; normalize_text(&config_text); process_text(&config_text, state->max_lang + 1, lang_map, lang_shorts); snprintf(out_config_path, sizeof(out_config_path), "%s.out", config_path); out_config_file = fopen(out_config_path, "w"); if (!out_config_file) { fprintf(stderr, "cannot open %s\n", out_config_path); return 0; } puttext(out_config_file, &config_text); fclose(out_config_file); out_config_file = NULL; snprintf(cmd_buf, sizeof(cmd_buf), "diff -u %s %s", config_path, out_config_path); //fprintf(stderr, ">>%s\n", cmd_buf); system(cmd_buf); process_db(contest_id, state->max_lang + 1, lang_map); snprintf(old_config_path, sizeof(old_config_path), "%s.old", config_path); fprintf(stderr, "Rename: %s->%s, %s->%s\n", config_path, old_config_path, out_config_path, config_path); if (rename(config_path, old_config_path) < 0) { fprintf(stderr, "Rename: %s->%s failed\n", config_path, old_config_path); } if (rename(out_config_path, config_path) < 0) { fprintf(stderr, "Rename: %s->%s failed\n", out_config_path, config_path); } return 0; failure: return 1; }
int super_load_cs_languages( const struct ejudge_cfg *config, struct sid_state *sstate, char **extra_compile_dirs, int check_version_flag, unsigned char *cs_conf_file_buf, int cs_conf_file_len) { path_t extra_cs_conf_path; struct generic_section_config *cfg = 0, *p; struct section_language_data *lp; int max_lang = -1; int cur_lang = 1; path_t cmdpath; path_t script_dir; sstate->cs_langs_loaded = 1; if (!sstate->compile_home_dir) { sstate->compile_home_dir = xstrdup(config->compile_home_dir); } snprintf(cs_conf_file_buf, cs_conf_file_len, "%s/conf/compile.cfg", sstate->compile_home_dir); if (!(cfg = prepare_parse_config_file(cs_conf_file_buf, 0))) return -1; sstate->cs_cfg = cfg; if (extra_compile_dirs) { int extra_cs_total = sarray_len(extra_compile_dirs); if (extra_cs_total > 0) { sstate->extra_cs_cfgs_total = extra_cs_total; XCALLOC(sstate->extra_cs_cfgs, sstate->extra_cs_cfgs_total + 1); } } if (sstate->extra_cs_cfgs_total > 0) { for (int i = 0; i < sstate->extra_cs_cfgs_total; ++i) { // check for win32_compile if (!strcmp(extra_compile_dirs[i], "win32_compile")) { sstate->enable_win32_languages = 1; } extra_cs_conf_path[0] = 0; if (os_IsAbsolutePath(extra_compile_dirs[i])) { snprintf(extra_cs_conf_path, sizeof(extra_cs_conf_path), "%s/conf/compile.cfg", extra_compile_dirs[i]); } else if (config && config->contests_home_dir) { snprintf(extra_cs_conf_path, sizeof(extra_cs_conf_path), "%s/%s/conf/compile.cfg", config->contests_home_dir, extra_compile_dirs[i]); } else { #if defined EJUDGE_CONTESTS_HOME_DIR snprintf(extra_cs_conf_path, sizeof(extra_cs_conf_path), "%s/%s/conf/compile.cfg", EJUDGE_CONTESTS_HOME_DIR, extra_compile_dirs[i]); #endif } if (extra_cs_conf_path[0]) { sstate->extra_cs_cfgs[i] = prepare_parse_config_file(extra_cs_conf_path, 0); } } } cfg = sstate->cs_cfg; for (p = cfg; p; p = p->next) { if (strcmp(p->name, "language") != 0) continue; lp = (typeof(lp)) p; if (lp->id < 0) { fprintf(stderr, "%s: language identifier is negative\n", cs_conf_file_buf); goto failed; } if (!lp->id) lp->id = cur_lang++; if (lp->id > max_lang) max_lang = lp->id; } if (max_lang <= 0) { fprintf(stderr, "%s: no languages defined\n", cs_conf_file_buf); goto failed; } if (sstate->extra_cs_cfgs_total > 0) { for (int i = 0; i < sstate->extra_cs_cfgs_total; ++i) { cfg = sstate->extra_cs_cfgs[i]; for (p = cfg; p; p = p->next) { if (strcmp(p->name, "language") != 0) continue; lp = (typeof(lp)) p; if (lp->id > 0 && lp->id > max_lang) max_lang = lp->id; } } } sstate->cs_lang_total = max_lang + 1; XCALLOC(sstate->cs_langs, sstate->cs_lang_total); XCALLOC(sstate->cs_loc_map, sstate->cs_lang_total); XCALLOC(sstate->cs_lang_names, sstate->cs_lang_total); cfg = sstate->cs_cfg; for (p = cfg; p; p = p->next) { if (strcmp(p->name, "language") != 0) continue; lp = (typeof(lp)) p; if (sstate->cs_langs[lp->id]) { fprintf(stderr, "%s: duplicated language id %d\n", cs_conf_file_buf, lp->id); goto failed; } sstate->cs_langs[lp->id] = lp; } if (sstate->extra_cs_cfgs_total > 0) { for (int i = 0; i < sstate->extra_cs_cfgs_total; ++i) { cfg = sstate->extra_cs_cfgs[i]; for (p = cfg; p; p = p->next) { if (strcmp(p->name, "language") != 0) continue; lp = (typeof(lp)) p; if (lp->id > 0 && !sstate->cs_langs[lp->id]) { sstate->cs_langs[lp->id] = lp; lp->compile_dir_index = i + 1; } } } } /* script_dir[0] = 0; if (config->script_dir) { snprintf(script_dir, sizeof(script_dir), "%s", config->script_dir); } #if defined EJUDGE_SCRIPT_DIR if (!*script_dir) { snprintf(script_dir, sizeof(script_dir), "%s", EJUDGE_SCRIPT_DIR); } #endif */ script_dir[0] = 0; if (config->compile_home_dir) { snprintf(script_dir, sizeof(script_dir), "%s/scripts", config->compile_home_dir); } if (!script_dir[0] && config->contests_home_dir) { snprintf(script_dir, sizeof(script_dir), "%s/compile/scripts", config->contests_home_dir); } #if defined EJUDGE_CONTESTS_HOME_DIR if (!script_dir[0]) { snprintf(script_dir, sizeof(script_dir), "%s/compile/scripts", EJUDGE_CONTESTS_HOME_DIR); } #endif if (*script_dir) { // detect actual language versions for (cur_lang = 1; cur_lang < sstate->cs_lang_total; cur_lang++) { if (!(lp = sstate->cs_langs[cur_lang])) continue; if (lp->compile_dir_index > 0) { sstate->cs_lang_names[cur_lang] = xstrdup(lp->long_name); continue; } snprintf(cmdpath, sizeof(cmdpath), "%s/%s-version", script_dir, lp->cmd); if (access(cmdpath, X_OK) >= 0) { char *args[4]; args[0] = cmdpath; args[1] = "-f"; args[2] = NULL; unsigned char *stdout_text = NULL; unsigned char *stderr_text = NULL; int r = ejudge_invoke_process(args, NULL, NULL, "/dev/null", NULL, 0, &stdout_text, &stderr_text); if (!r) { if (!stdout_text) stdout_text = xstrdup(""); sstate->cs_lang_names[cur_lang] = chop2(stdout_text); stdout_text = NULL; } else { sstate->cs_lang_names[cur_lang] = xstrdup(""); if (!stderr_text) stderr_text = xstrdup(""); for (unsigned char *s = stderr_text; *s; ++s) { if (*s < ' ') *s = ' '; } fprintf(stderr, "%s: %s\n", sstate->cs_langs[cur_lang]->short_name, stderr_text); } xfree(stdout_text); stdout_text = NULL; xfree(stderr_text); stderr_text = NULL; } } } return 0; failed: return -1; }
int super_html_read_serve( FILE *flog, const unsigned char *path, const struct ejudge_cfg *config, const struct contest_desc *cnts, struct sid_state *sstate) { struct stat sb; int cond_count = 0, total, i, cur_id, j, arch, k; struct generic_section_config *pg; struct section_global_data *global; struct section_problem_data *prob, *aprob; struct section_tester_data *tst, *atst; struct section_language_data *lang; size_t vm_size, st_size; size_t *mem_lims, *st_lims; int *mem_cnt, *st_cnt; //int mem_u, st_u, max_i; path_t check_cmd = { 0 }; FILE *fuh; char *fuh_text = 0; size_t fuh_size = 0; path_t cs_spool_dir; path_t conf_dir; path_t tmppath; unsigned char *prob_no_any = 0; size_t cs_spool_dir_len = 0; unsigned char cs_conf_file[PATH_MAX]; if (!cnts) { fprintf(flog, "No contest XML description\n"); return -1; } if (!cnts->conf_dir || !*cnts->conf_dir) { snprintf(conf_dir, sizeof(conf_dir), "%s/%s", cnts->root_dir, "conf"); } else if (!os_IsAbsolutePath(cnts->conf_dir)) { snprintf(conf_dir, sizeof(conf_dir), "%s/%s", cnts->root_dir, cnts->conf_dir); } else { snprintf(conf_dir, sizeof(conf_dir), "%s", cnts->conf_dir); } if (stat(path, &sb) < 0) { // file do not exist return 0; } if (!S_ISREG(sb.st_mode)) { fprintf(flog, "File `%s' not a regular file\n", path); return -1; } if (access(path, R_OK) < 0) { fprintf(flog, "File `%s' is not readable\n", path); return -1; } // FIXME: redirect output? if (!(sstate->cfg = prepare_parse_config_file(path, &cond_count))) { fprintf(flog, "Parsing of `%s' failed\n", path); return -1; } if (cond_count > 0) { fprintf(flog, "The configuration file uses conditional compilation directives\n"); return -1; } // find global section for (pg = sstate->cfg; pg; pg = pg->next) if (!pg->name[0] || !strcmp(pg->name, "global")) break; if (!pg) { fprintf(flog, "The global section is not defined\n"); return -1; } global = sstate->global = (struct section_global_data *) pg; // set up the default value of the root_dir if (!global->root_dir[0]) { snprintf(global->root_dir, sizeof(global->root_dir), "%06d", global->contest_id); } if (!os_IsAbsolutePath(global->root_dir) && config && config->contests_home_dir && os_IsAbsolutePath(config->contests_home_dir)) { snprintf(tmppath, sizeof(tmppath), "%s/%s", config->contests_home_dir, global->root_dir); snprintf(global->root_dir, sizeof(global->root_dir), "%s", tmppath); } #if defined EJUDGE_CONTESTS_HOME_DIR if (!os_IsAbsolutePath(global->root_dir)) { snprintf(tmppath, sizeof(tmppath), "%s/%s", EJUDGE_CONTESTS_HOME_DIR, global->root_dir); snprintf(global->root_dir, sizeof(global->root_dir), "%s", tmppath); } #endif if (!os_IsAbsolutePath(global->root_dir)) { err("global.root_dir must be absolute directory!"); return -1; } // check variables that we don't want to be ever set if (prepare_check_forbidden_global(flog, global) < 0) return -1; // contest_id, conf_dir, root_dir must match if (global->contest_id != cnts->id) { fprintf(flog, "contest_id does not match\n"); return -1; } if (strcmp(global->root_dir, cnts->root_dir)) { fprintf(flog, "root_dir does not match\n"); return -1; } /* if ((!cnts->conf_dir && global->conf_dir) || (cnts->conf_dir && strcmp(cnts->conf_dir, global->conf_dir))) { fprintf(flog, "conf_dir does not match\n"); return -1; } */ // compile server must be used if (!global->compile_dir[0]) { fprintf(flog, "compilation server is not used\n"); return -1; } if (!os_IsAbsolutePath(global->compile_dir)) { snprintf(tmppath, sizeof(tmppath), "%s/var/%s", global->root_dir, global->compile_dir); path_normalize(tmppath, sizeof(tmppath)); snprintf(global->compile_dir, sizeof(global->compile_dir), "%s", tmppath); } if (!config->compile_home_dir) { fprintf(flog, "compile server home dir is not set\n"); return -1; } // cut off "/var/compile" suffix from the compile dir snprintf(cs_spool_dir, sizeof(cs_spool_dir), "%s", global->compile_dir); cs_spool_dir_len = strlen(cs_spool_dir); if (cs_spool_dir_len < sizeof(compile_dir_suffix) || strcmp(cs_spool_dir+cs_spool_dir_len-sizeof(compile_dir_suffix)+1, compile_dir_suffix) != 0) { fprintf(flog, "invalid `compile_dir' %s\n", cs_spool_dir); return -1; } cs_spool_dir[cs_spool_dir_len-sizeof(compile_dir_suffix)+1] = 0; sstate->compile_home_dir = xstrdup(cs_spool_dir); //fprintf(stderr, "compile_home_dir>>%s<<\n", sstate->compile_home_dir); /* snprintf(cs_spool_dir, sizeof(cs_spool_dir), "%s/var/compile", config->compile_home_dir); if (strcmp(cs_spool_dir, global->compile_dir)) { fprintf(flog, "non-default compilation server is used\n"); return -1; } */ prepare_set_global_defaults(global); if (global->stand2_file_name[0]) sstate->enable_stand2 = 1; if (global->plog_file_name[0]) sstate->enable_plog = 1; if (global->stand_extra_format[0]) sstate->enable_extra_col = 1; fuh = open_memstream(&fuh_text, &fuh_size); prepare_unparse_unhandled_global(fuh, global); close_memstream(fuh); fuh = 0; if (fuh_text && *fuh_text) { global->unhandled_vars = fuh_text; } else { xfree(fuh_text); } fuh_text = 0; fuh_size = 0; // collect languages total = 0; cur_id = 0; for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "language") != 0) continue; lang = (struct section_language_data*) pg; if (!lang->id) lang->id = cur_id + 1; cur_id = lang->id; if (lang->id <= 0 || lang->id > EJ_MAX_LANG_ID) { fprintf(flog, "Invalid language ID\n"); return -1; } if (lang->id >= total) total = lang->id + 1; } sstate->lang_a = 0; sstate->langs = 0; sstate->loc_cs_map = 0; sstate->lang_opts = 0; sstate->lang_flags = 0; if (total > 0) { sstate->lang_a = 4; while (total > sstate->lang_a) sstate->lang_a *= 2; XCALLOC(sstate->langs, sstate->lang_a); XCALLOC(sstate->loc_cs_map, sstate->lang_a); XCALLOC(sstate->lang_opts, sstate->lang_a); XCALLOC(sstate->lang_flags, sstate->lang_a); for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "language") != 0) continue; lang = (struct section_language_data*) pg; if (sstate->langs[lang->id]) { fprintf(flog, "Duplicated language ID %d\n", lang->id); return -1; } sstate->langs[lang->id] = lang; } } // load the compilation server state and establish correspondence if (super_load_cs_languages(config, sstate, global->extra_compile_dirs, 0, cs_conf_file, sizeof(cs_conf_file)) < 0) { fprintf(flog, "Failed to load compilation server configuration\n"); return -1; } for (i = 1; i < sstate->lang_a; i++) { if (!(lang = sstate->langs[i])) continue; if (!lang->compile_id) lang->compile_id = lang->id; if (prepare_check_forbidden_lang(flog, lang) < 0) return -1; /* if (lang->compile_id <= 0 || lang->compile_id >= sstate->cs_lang_total || !sstate->cs_langs[lang->compile_id]) { } */ // improve error messaging if (lang->compile_id > 0 && lang->compile_id < sstate->cs_lang_total && sstate->cs_langs[lang->compile_id] && strcmp(lang->short_name, sstate->cs_langs[lang->compile_id]->short_name) != 0) { fprintf(flog, "contest configuration file '%s' specifies language short name '%s' for language %d\n" "and it is different from language short name '%s' in compilation configuration file '%s'\n", path, lang->short_name, lang->compile_id, sstate->cs_langs[lang->compile_id]->short_name, cs_conf_file); return -1; } if (lang->compile_id <= 0 || lang->compile_id >= sstate->cs_lang_total || !sstate->cs_langs[lang->compile_id] || strcmp(lang->short_name, sstate->cs_langs[lang->compile_id]->short_name) != 0) { lang->compile_id = 0; } for (int j = 1; j < sstate->cs_lang_total; ++j) { if (sstate->cs_langs[j] && !strcmp(lang->short_name, sstate->cs_langs[j]->short_name)) { lang->compile_id = j; break; } } if (lang->compile_id <= 0) { fprintf(flog, "Invalid compile_id\n"); return -1; } sstate->loc_cs_map[lang->id] = lang->compile_id; sstate->cs_loc_map[lang->compile_id] = lang->id; fuh = open_memstream(&fuh_text, &fuh_size); prepare_unparse_unhandled_lang(fuh, lang); close_memstream(fuh); fuh = 0; if (fuh_text && *fuh_text) { lang->unhandled_vars = fuh_text; } else { xfree(fuh_text); } fuh_text = 0; fuh_size = 0; if (lang->compiler_env) { for (j = 0; lang->compiler_env[j]; j++) { if (!strncmp(lang->compiler_env[j], "EJUDGE_FLAGS=", 13)) { sstate->lang_opts[lang->id] = xstrmerge1(sstate->lang_opts[lang->id], lang->compiler_env[j] + 13); } } for (--j; j >= 0; --j) { if (!strncmp(lang->compiler_env[j], "EJUDGE_FLAGS=", 13)) { xfree(lang->compiler_env[j]); lang->compiler_env[j] = 0; for (k = j + 1; lang->compiler_env[k]; k++) { lang->compiler_env[k - 1] = lang->compiler_env[k]; } lang->compiler_env[k - 1] = lang->compiler_env[k]; } } } } // collect abstract problems for (pg = sstate->cfg, total = 0; pg; pg = pg->next) { if (!strcmp(pg->name, "problem") && (prob = (struct section_problem_data*) pg)->abstract) total++; } sstate->aprob_a = 0; sstate->aprob_u = 0; sstate->aprobs = 0; sstate->aprob_flags = 0; if (total) { sstate->aprob_a = 4; while (total > sstate->aprob_a) sstate->aprob_a *= 2; XCALLOC(sstate->aprobs, sstate->aprob_a); XCALLOC(sstate->aprob_flags, sstate->aprob_a); for (pg = sstate->cfg, i = 0; pg; pg = pg->next) { if (strcmp(pg->name, "problem") != 0) continue; prob = (struct section_problem_data*) pg; if (!prob->abstract) continue; sstate->aprobs[i++] = prob; if (!prob->short_name[0]) { fprintf(flog, "Abstract problem must have `short_name' field set\n"); return -1; } if (prob->super[0]) { fprintf(flog, "Abstract problem must not have a superproblem\n"); return -1; } if (prepare_check_forbidden_prob(flog, prob) < 0) return -1; prepare_set_abstr_problem_defaults(prob, global); fuh = open_memstream(&fuh_text, &fuh_size); prepare_unparse_unhandled_prob(fuh, prob, global); close_memstream(fuh); fuh = 0; if (fuh_text && *fuh_text) { prob->unhandled_vars = fuh_text; } else { xfree(fuh_text); } fuh_text = 0; fuh_size = 0; } ASSERT(i == total); sstate->aprob_u = total; } // collect concrete problems total = 0; cur_id = 0; for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "problem") != 0) continue; prob = (struct section_problem_data*) pg; if (prob->abstract) continue; if (!prob->id) prob->id = cur_id + 1; cur_id = prob->id; if (prob->id <= 0 || prob->id > EJ_MAX_PROB_ID) { fprintf(flog, "Invalid problem ID\n"); return -1; } if (prob->id >= total) total = prob->id + 1; } sstate->probs = 0; sstate->prob_a = 0; sstate->prob_flags = 0; if (total > 0) { sstate->prob_a = 4; while (total > sstate->prob_a) sstate->prob_a *= 2; XCALLOC(sstate->probs, sstate->prob_a); XCALLOC(sstate->prob_flags, sstate->prob_a); XALLOCAZ(prob_no_any, sstate->prob_a); for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "problem") != 0) continue; prob = (struct section_problem_data*) pg; if (prob->abstract) continue; if (sstate->probs[prob->id]) { fprintf(flog, "Duplicated problem id %d\n", prob->id); return -1; } sstate->probs[prob->id] = prob; if (prob->super[0]) { for (i = 0; i < sstate->aprob_u; i++) if (!strcmp(prob->super, sstate->aprobs[i]->short_name)) break; if (i == sstate->aprob_u) { fprintf(flog, "Abstract problem `%s' not found\n", prob->super); return -1; } } if (prepare_check_forbidden_prob(flog, prob) < 0) return -1; prepare_set_concr_problem_defaults(prob, global); fuh = open_memstream(&fuh_text, &fuh_size); prepare_unparse_unhandled_prob(fuh, prob, global); close_memstream(fuh); fuh = 0; if (fuh_text && *fuh_text) { prob->unhandled_vars = fuh_text; } else { xfree(fuh_text); } fuh_text = 0; fuh_size = 0; } } // collect abstract testers total = 0; for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "tester")) continue; tst = (struct section_tester_data*) pg; if (!tst->abstract) continue; // check, that we know such abstract tester if ((arch = prepare_unparse_is_supported_tester(tst->name)) < 0) { fprintf(flog, "Unsupported abstract tester `%s'\n", tst->name); return -1; } if ((i = prepare_unparse_is_supported_arch(tst->arch)) < 0) { fprintf(flog, "Unsupported tester architecture `%s'\n", tst->arch); return -1; } if (i != arch) { fprintf(flog, "Abstract tester name does not match tester arch\n"); return -1; } if (tst->id) { fprintf(flog, "Abstract tester must not define tester ID\n"); return -1; } if (tst->problem_name[0]) { fprintf(flog, "Abstract tester must not define problem name\n"); return -1; } if (tst->problem) { fprintf(flog, "Abstract tester must not define problem ID\n"); return -1; } total++; } /* Relax, try to work without testers... */ /* if (!total) { fprintf(flog, "No abstract testers defined\n"); return -1; } */ sstate->atester_total = total; if (total > 0) { XCALLOC(sstate->atesters, sstate->atester_total); for (pg = sstate->cfg, i = 0; pg; pg = pg->next) { if (strcmp(pg->name, "tester")) continue; tst = (struct section_tester_data*) pg; if (!tst->abstract) continue; sstate->atesters[i++] = tst; // FIXME: check for unhandled fields } } // collect concrete testers, attempting to recover vm limit, stack limit // and checker name total = 0; cur_id = 0; for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "tester") != 0) continue; tst = (struct section_tester_data*) pg; if (tst->abstract) continue; if (!tst->id) tst->id = cur_id + 1; cur_id = tst->id; if (tst->id <= 0 || tst->id > EJ_MAX_TESTER) { fprintf(flog, "Invalid tester ID\n"); return -1; } if (tst->id >= total) total = tst->id + 1; } sstate->tester_total = total; if (total > 0) { XCALLOC(sstate->testers, sstate->tester_total); } for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "tester") != 0) continue; tst = (struct section_tester_data*) pg; if (tst->abstract) continue; if (sstate->testers[tst->id]) { fprintf(flog, "Duplicated tester ID %d\n", tst->id); return -1; } sstate->testers[tst->id] = tst; if (tst->super && tst->super[0] && tst->super[1]) { fprintf(flog, "Tester %d has several supertesters\n", tst->id); return -1; } atst = 0; if (tst->super) { for (i = 0; i < sstate->atester_total; i++) if (!strcmp(sstate->atesters[i]->name, tst->super[0])) break; if (i == sstate->atester_total) { fprintf(flog, "Abstract tester `%s' not found\n", tst->super[0]); return -1; } atst = sstate->atesters[i]; } if (tst->any) { continue; } prob = 0; if (tst->problem && tst->problem_name[0]) { fprintf(flog, "Both problem and problem_name fields cannot be set\n"); return -1; } else if (tst->problem) { if (tst->problem <= 0 || tst->problem >= sstate->prob_a || !sstate->probs[tst->problem]) { fprintf(flog, "problem %d is invalid\n", tst->problem); return -1; } prob = sstate->probs[tst->problem]; } else if (tst->problem_name[0]) { for (i = 1; i < sstate->prob_a; i++) if (sstate->probs[i] && !strcmp(sstate->probs[i]->short_name, tst->problem_name)) break; if (i == sstate->prob_a) { fprintf(flog, "Problem `%s' does not exist\n", tst->problem_name); return -1; } prob = sstate->probs[i]; } else { fprintf(flog, "Neither problem not problem_name are set\n"); return -1; } prob_no_any[prob->id] = 1; vm_size = tst->max_vm_size; if (vm_size == -1L && atst) vm_size = atst->max_vm_size; st_size = tst->max_stack_size; if (st_size == -1L && atst) st_size = atst->max_stack_size; if (vm_size != -1L) { if (prob->max_vm_size == -1L) prob->max_vm_size = vm_size; if (prob->max_vm_size != vm_size) { fprintf(flog, "Conflicting max_vm_size specifications for problem `%s'\n", prob->short_name); return -1; } } if (st_size != -1L) { if (prob->max_stack_size == -1L) prob->max_stack_size = st_size; if (prob->max_stack_size != st_size) { fprintf(flog, "Conflicting max_stack_size specifications for problem `%s'\n", prob->short_name); return -1; } } } for (i = 0; i < sstate->tester_total; i++) { if (!(tst = sstate->testers[i])) continue; atst = 0; if (tst->super) { for (j = 0; j < sstate->atester_total; j++) if (!strcmp(sstate->atesters[j]->name, tst->super[0])) break; if (j == sstate->atester_total) { fprintf(flog, "Abstract tester `%s' not found\n", tst->super[0]); return -1; } atst = sstate->atesters[j]; } if (!tst->any) continue; for (j = 0; j < sstate->prob_a; j++) { if (!(prob = sstate->probs[j])) continue; if (prob_no_any[j]) continue; vm_size = tst->max_vm_size; if (vm_size == -1L && atst) vm_size = atst->max_vm_size; st_size = tst->max_stack_size; if (st_size == -1L && atst) st_size = atst->max_stack_size; if (vm_size != -1L) { if (prob->max_vm_size == -1L) prob->max_vm_size = vm_size; if (prob->max_vm_size != vm_size) { fprintf(flog, "Conflicting max_vm_size specifications for problem `%s'\n", prob->short_name); return -1; } } if (st_size != -1L) { if (prob->max_stack_size == -1L) prob->max_stack_size = st_size; if (prob->max_stack_size != st_size) { fprintf(flog, "Conflicting max_stack_size specifications for problem `%s'\n", prob->short_name); return -1; } } } } XALLOCA(mem_lims, sstate->prob_a); XALLOCA(st_lims, sstate->prob_a); XALLOCA(mem_cnt, sstate->prob_a); XALLOCA(st_cnt, sstate->prob_a); // propagate most used memory limit to superproblem /* for (i = 0; i < sstate->aprob_u; i++) { aprob = sstate->aprobs[i]; mem_u = 0; st_u = 0; XMEMZERO(mem_cnt, sstate->prob_a); XMEMZERO(st_cnt, sstate->prob_a); for (j = 1; j < sstate->prob_a; j++) { if (!(prob = sstate->probs[j]) || !prob->super[0] || strcmp(prob->super, aprob->short_name)) continue; if (prob->max_vm_size != -1L) { for (k = 0; k < mem_u; k++) if (mem_lims[k] == prob->max_vm_size) break; if (k == mem_u) mem_u++; mem_lims[k] = prob->max_vm_size; mem_cnt[k]++; } if (prob->max_stack_size != -1L) { for (k = 0; k < st_u; k++) if (st_lims[k] == prob->max_stack_size) break; if (k == st_u) st_u++; st_lims[k] = prob->max_stack_size; st_cnt[k]++; } } if (mem_u > 0) { max_i = 0; for (i = 1; i < mem_u; i++) if (mem_cnt[i] > mem_cnt[max_i]) max_i = i; aprob->max_vm_size = mem_lims[max_i]; for (j = 1; j < sstate->prob_a; j++) { if (!(prob = sstate->probs[j]) || !prob->super[0] || strcmp(prob->super, aprob->short_name)) continue; if (prob->max_vm_size == -1L) { prob->max_vm_size = 0; } else if (prob->max_vm_size == aprob->max_vm_size) { prob->max_vm_size = -1L; } } } if (st_u > 0) { max_i = 0; for (i = 1; i < st_u; i++) if (st_cnt[i] > st_cnt[max_i]) max_i = i; aprob->max_stack_size = st_lims[max_i]; for (j = 1; j < sstate->prob_a; j++) { if (!(prob = sstate->probs[j]) || !prob->super[0] || strcmp(prob->super, aprob->short_name)) continue; if (prob->max_stack_size == -1L) { prob->max_stack_size = 0; } else if (prob->max_stack_size == aprob->max_stack_size) { prob->max_stack_size = -1L; } } } } */ // assign this check_cmd to all abstract problems without check_cmd for (i = 0; i < sstate->aprob_u; i++) if (!(aprob = sstate->aprobs[i])->check_cmd[0]) snprintf(aprob->check_cmd, sizeof(aprob->check_cmd), "%s", check_cmd); sstate->contest_start_cmd_text = do_load_file(conf_dir, global->contest_start_cmd); sstate->contest_stop_cmd_text = do_load_file(conf_dir, global->contest_stop_cmd); sstate->stand_header_text = do_load_file(conf_dir, global->stand_header_file); sstate->stand_footer_text = do_load_file(conf_dir, global->stand_footer_file); sstate->stand2_header_text = do_load_file(conf_dir, global->stand2_header_file); sstate->stand2_footer_text = do_load_file(conf_dir, global->stand2_footer_file); sstate->plog_header_text = do_load_file(conf_dir, global->plog_header_file); sstate->plog_footer_text = do_load_file(conf_dir, global->plog_footer_file); return 0; }
static int run_all_tests(int argc, char *argv[]) { unsigned char tmp_work_dir[PATH_MAX]; unsigned char abs_prog_name[PATH_MAX]; unsigned char abs_test_dir[PATH_MAX]; unsigned char abs_work_dir[PATH_MAX]; unsigned char test_base[PATH_MAX]; unsigned char test_path[PATH_MAX]; unsigned char corr_base[PATH_MAX]; unsigned char corr_path[PATH_MAX]; unsigned char info_base[PATH_MAX]; unsigned char info_path[PATH_MAX]; unsigned char tgzdir_base[PATH_MAX]; unsigned char tgzdir_path[PATH_MAX]; const unsigned char *s; int pid = getpid(), serial = 0; int retval = 0, status; long cpu_time, real_time; tmp_work_dir[0] = 0; if (!working_dir || !*working_dir) { s = getenv("TMPDIR"); if (!s) s = getenv("TEMPDIR"); #if defined P_tmpdir if (!s) s = P_tmpdir; #endif if (!s) s = "/tmp"; while (1) { snprintf(tmp_work_dir, sizeof(tmp_work_dir), "%s/%d.%d", s, pid, ++serial); if (mkdir(tmp_work_dir, 0700) >= 0) break; if (errno != EEXIST) { fatal("cannot create directory %s: %s", tmp_work_dir, os_ErrorMsg()); } } working_dir = xstrdup(tmp_work_dir); } if (!os_IsAbsolutePath(working_dir)) { snprintf(abs_work_dir, sizeof(abs_work_dir), "%s/%s", current_dir, working_dir); working_dir = xstrdup(abs_work_dir); } if (!os_IsAbsolutePath(argv[0])) { snprintf(abs_prog_name, sizeof(abs_prog_name), "%s/%s", current_dir, argv[0]); argv[0] = xstrdup(abs_prog_name); } if (!os_IsAbsolutePath(test_dir)) { snprintf(abs_test_dir, sizeof(abs_test_dir), "%s/%s", current_dir, test_dir); test_dir = xstrdup(abs_test_dir); } serial = 0; while (1) { snprintf(test_base, sizeof(test_base), test_pattern, ++serial); snprintf(test_path, sizeof(test_path), "%s/%s", test_dir, test_base); test_file = xstrdup(test_path); if (os_CheckAccess(test_path, REUSE_F_OK) < 0) break; corr_path[0] = 0; info_path[0] = 0; corr_file = NULL; info_file = NULL; if (corr_pattern && corr_pattern[0]) { snprintf(corr_base, sizeof(corr_base), corr_pattern, serial); snprintf(corr_path, sizeof(corr_path), "%s/%s", test_dir, corr_base); corr_file = xstrdup(corr_path); } if (info_pattern && info_pattern[0]) { snprintf(info_base, sizeof(info_base), info_pattern, serial); snprintf(info_path, sizeof(info_path), "%s/%s", test_dir, info_base); info_file = xstrdup(info_path); } if (tgzdir_pattern && tgzdir_pattern[0]) { snprintf(tgzdir_base, sizeof(tgzdir_base), tgzdir_pattern, serial); snprintf(tgzdir_path, sizeof(tgzdir_path), "%s/%s", test_dir, tgzdir_path); tgzdir_file = xstrdup(tgzdir_path); } cpu_time = 0; real_time = 0; status = run_program(argc, argv, &cpu_time, &real_time); if (status == RUN_CHECK_FAILED) retval = RUN_CHECK_FAILED; if (status != RUN_OK && retval == RUN_OK) retval = RUN_PARTIAL; if (quiet_flag <= 0) { printf("%-8d%-8.8s%-8ld%-8ld\n", serial, get_run_status_str(status), cpu_time, real_time); } } if (tmp_work_dir[0]) { remove_directory_recursively(tmp_work_dir, 0); } return retval; }