コード例 #1
0
ファイル: compile.c プロジェクト: stden/ejudge
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;
}
コード例 #2
0
ファイル: ctdb_event_helper.c プロジェクト: samba-team/samba
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);
}
コード例 #3
0
ファイル: jobinfo.c プロジェクト: pegasus-isi/pegasus
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);
    }
}
コード例 #4
0
ファイル: run.c プロジェクト: NUOG/ejudge
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;
}
コード例 #5
0
ファイル: run.c プロジェクト: NUOG/ejudge
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;
}