Ejemplo n.º 1
0
void
run_reply_packet_dump(
        const struct run_reply_packet *in_data)
{
  fprintf(stderr, "=== packet dump ===\n");
  fprintf(stderr, "judge_id = %d\n", in_data->judge_id);
  fprintf(stderr, "contest_id = %d\n", in_data->contest_id);
  fprintf(stderr, "status = %d\n", in_data->status);
  fprintf(stderr, "failed_test = %d\n", in_data->failed_test);
  fprintf(stderr, "tests_passed = %d\n", in_data->tests_passed);
  fprintf(stderr, "score = %d\n", in_data->score);
  fprintf(stderr, "notify_flag = %d\n", in_data->notify_flag);
  fprintf(stderr, "marked_flag = %d\n", in_data->marked_flag);
  fprintf(stderr, "has_user_score = %d\n", in_data->has_user_score);
  fprintf(stderr, "user_status = %d\n", in_data->user_status);
  fprintf(stderr, "user_tests_passed = %d\n", in_data->user_tests_passed);
  fprintf(stderr, "user_score = %d\n", in_data->user_score);
  fprintf(stderr, "ts1 = \"%s.%06d\"\n", xml_unparse_date(in_data->ts1), in_data->ts1_us);
  fprintf(stderr, "ts2 = \"%s.%06d\"\n", xml_unparse_date(in_data->ts2), in_data->ts2_us);
  fprintf(stderr, "ts3 = \"%s.%06d\"\n", xml_unparse_date(in_data->ts3), in_data->ts3_us);
  fprintf(stderr, "ts4 = \"%s.%06d\"\n", xml_unparse_date(in_data->ts4), in_data->ts4_us);
  fprintf(stderr, "ts5 = \"%s.%06d\"\n", xml_unparse_date(in_data->ts5), in_data->ts5_us);
  fprintf(stderr, "ts6 = \"%s.%06d\"\n", xml_unparse_date(in_data->ts6), in_data->ts6_us);
  fprintf(stderr, "ts7 = \"%s.%06d\"\n", xml_unparse_date(in_data->ts7), in_data->ts7_us);
  fprintf(stderr, "uuid = \"%s\"\n", ej_uuid_unparse(&in_data->uuid, "NULL"));
}
Ejemplo n.º 2
0
void
ej_bson_unparse(
        FILE *out,
        const struct _bson *b,
        int is_array)
{
    if (!b) {
        fprintf(out, "NULL");
        return;
    }
    if (is_array) {
        fprintf(out, "[ ");
    } else {
        fprintf(out, "{ ");
    }
    bson_cursor *cursor = bson_cursor_new(b);
    int first = 1;
    while (bson_cursor_next(cursor)) {
        if (!first) fprintf(out, ", ");
        if (!is_array) {
            fprintf(out, "%s : ", bson_cursor_key(cursor));
        }
        bson_type t = bson_cursor_type(cursor);
        switch (t) {
        case BSON_TYPE_DOUBLE:
            break;
        case BSON_TYPE_STRING:
            {
                const char *value = NULL;
                if (bson_cursor_get_string(cursor, &value)) {
                    fprintf(out, "\"%s\"", value);
                }
            }
            break;
        case BSON_TYPE_DOCUMENT:
            {
                bson *doc = NULL;
                if (bson_cursor_get_document(cursor, &doc)) {
                    ej_bson_unparse(out, doc, 0);
                    bson_free(doc);
                }
            }
            break;
        case BSON_TYPE_ARRAY:
            {
                bson *doc = NULL;
                if (bson_cursor_get_array(cursor, &doc)) {
                    ej_bson_unparse(out, doc, 1);
                    bson_free(doc);
                }
            }
            break;
        case BSON_TYPE_BINARY:
            {
                bson_binary_subtype bt = 0;
                const unsigned char *bd = NULL;
                int bz = 0;
                if (bson_cursor_get_binary(cursor, &bt, &bd, &bz)
                    && bt == BSON_BINARY_SUBTYPE_UUID && bz == sizeof(ej_uuid_t)) {
                    ej_uuid_t value;
                    memcpy(&value, bd, sizeof(value));
                    fprintf(out, "\"%s\"", ej_uuid_unparse(&value, NULL));
                }
            }
            break;
        case BSON_TYPE_OID:
        case BSON_TYPE_BOOLEAN:
            break;
        case BSON_TYPE_UTC_DATETIME:
            {
                gint64 ts = 0;
                if (bson_cursor_get_utc_datetime(cursor, &ts)) {
                    time_t tt = (time_t) (ts / 1000);
                    int ms = (int) (ts % 1000);
                    struct tm *ptm = gmtime(&tt);
                    fprintf(out, "\"%d/%02d/%02d %02d:%02d:%02d.%04d\"",
                            ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday,
                            ptm->tm_hour, ptm->tm_min, ptm->tm_sec, ms);
                }
            }
            break;
        case BSON_TYPE_NULL:
            break;
        case BSON_TYPE_INT32:
            {
                int value = 0;
                if (bson_cursor_get_int32(cursor, &value)) {
                    fprintf(out, "%d", value);
                }
            }
            break;
        case BSON_TYPE_INT64:
            {
                gint64 value = 0;
                if (bson_cursor_get_int64(cursor, &value)) {
                    fprintf(out, "%lld", (long long) value);
                }
            }
            break;
        default:
            break;
        }
        first = 0;
    }
    bson_cursor_free(cursor); cursor = NULL;
    if (is_array) {
        fprintf(out, " ]");
    } else {
        fprintf(out, " }");
    }
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
static int
do_eval(struct filter_env *env,
        struct filter_tree *t,
        struct filter_tree *res)
{
  int c;
  struct filter_tree r1, r2;
  int lang_id, prob_id, user_id, flags;
  const struct userlist_user *u;
  const struct userlist_member *m;
  const unsigned char *s;

  memset(res, 0, sizeof(*res));
  switch (t->kind) {
  case TOK_LOGOR:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    ASSERT(r1.kind == TOK_BOOL_L);
    if (!r1.v.b) {
      if ((c = do_eval(env, t->v.t[1], &r2)) < 0) return c;
      ASSERT(r2.kind == TOK_BOOL_L);
      res->v.b = r2.v.b;
    } else {
      res->v.b = 1;
    }
    break;
    
  case TOK_LOGAND:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    ASSERT(r1.kind == TOK_BOOL_L);
    if (r1.v.b) {
      if ((c = do_eval(env, t->v.t[1], &r2)) < 0) return c;
      ASSERT(r2.kind == TOK_BOOL_L);
      res->v.b = r2.v.b;
    } else {
      res->v.b = 0;
    }
    break;

    /* binary */
  case '^':
  case '|':
  case '&':
  case '*':
  case '/':
  case '%':
  case '+':
  case '-':
  case '>':
  case '<':
  case TOK_EQ:
  case TOK_NE:
  case TOK_LE:
  case TOK_GE:
  case TOK_ASL:
  case TOK_ASR:
  case TOK_REGEXP:
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    if ((c = do_eval(env, t->v.t[1], &r2)) < 0) return c;
    return filter_tree_eval_node(env->mem, t->kind, res, &r1, &r2);

    /* unary */
  case '~':
  case '!':
  case TOK_UN_MINUS:
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    return filter_tree_eval_node(env->mem, t->kind, res, &r1, 0);

  case TOK_TIME:
  case TOK_DUR:
  case TOK_SIZE:
  case TOK_HASH:
  case TOK_UUID:
  case TOK_IP:
  case TOK_PROB:
  case TOK_UID:
  case TOK_LOGIN:
  case TOK_NAME:
  case TOK_GROUP:
  case TOK_LANG:
  case TOK_ARCH:
  case TOK_RESULT:
  case TOK_SCORE:
  case TOK_TEST:
  case TOK_IMPORTED:
  case TOK_HIDDEN:
  case TOK_READONLY:
  case TOK_MARKED:
  case TOK_SAVED:
  case TOK_VARIANT:
  case TOK_RAWVARIANT:
  case TOK_USERINVISIBLE:
  case TOK_USERBANNED:
  case TOK_USERLOCKED:
  case TOK_USERINCOMPLETE:
  case TOK_USERDISQUALIFIED:
  case TOK_LATEST:
  case TOK_LATESTMARKED:
  case TOK_AFTEROK:
  case TOK_EXAMINABLE:
  case TOK_CYPHER:
  case TOK_MISSINGSOURCE:
  case TOK_JUDGE_ID:
  case TOK_PASSED_MODE:
  case TOK_EOLN_TYPE:
  case TOK_STORE_FLAGS:
  case TOK_TOKEN_FLAGS:
  case TOK_TOKEN_COUNT:
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    ASSERT(r1.kind == TOK_INT_L);
    if (r1.v.i < 0) r1.v.i = env->rtotal + r1.v.i;
    if (r1.v.i >= env->rtotal) return -FILTER_ERR_RANGE;
    if (r1.v.i < 0) return -FILTER_ERR_RANGE;
    switch (t->kind) {
    case TOK_TIME:
      res->kind = TOK_TIME_L;
      res->type = FILTER_TYPE_TIME;
      res->v.a = env->rentries[r1.v.i].time;
      break;
    case TOK_DUR:
      res->kind = TOK_DUR_L;
      res->type = FILTER_TYPE_DUR;
      res->v.u = env->rentries[r1.v.i].time - env->rhead.start_time;
      break;
    case TOK_SIZE:
      res->kind = TOK_SIZE_L;
      res->type = FILTER_TYPE_SIZE;
      res->v.z = env->rentries[r1.v.i].size;
      break;
    case TOK_HASH:
      res->kind = TOK_HASH_L;
      res->type = FILTER_TYPE_HASH;
      memcpy(res->v.h, env->rentries[r1.v.i].sha1, sizeof(env->cur->sha1));
      break;
    case TOK_UUID:
      res->kind = TOK_STRING_L;
      res->type = FILTER_TYPE_STRING;
      res->v.s = envdup(env, ej_uuid_unparse(&env->rentries[r1.v.i].run_uuid, ""));
      break;
    case TOK_IP:
      res->kind = TOK_IP_L;
      res->type = FILTER_TYPE_IP;
      run_entry_to_ipv6(&env->rentries[r1.v.i], &res->v.p);
      break;
    case TOK_PROB:
      res->kind = TOK_STRING_L;
      res->type = FILTER_TYPE_STRING;
      prob_id = env->rentries[r1.v.i].prob_id;
      if (prob_id <= 0 || prob_id > env->maxprob || !env->probs[prob_id]) {
        res->v.s = envdup(env, "");
      } else {
        res->v.s = envdup(env, env->probs[prob_id]->short_name);
      }
      break;
    case TOK_UID:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      res->v.i = env->rentries[r1.v.i].user_id;
      break;
    case TOK_LOGIN:
      res->kind = TOK_STRING_L;
      res->type = FILTER_TYPE_STRING;
      user_id = env->rentries[r1.v.i].user_id;
      if (!user_id) {
        res->v.s = envdup(env, "");
      } else {
        res->v.s = envdup(env, teamdb_get_login(env->teamdb_state, user_id));
      }
      break;
    case TOK_NAME:
      res->kind = TOK_STRING_L;
      res->type = FILTER_TYPE_STRING;
      user_id = env->rentries[r1.v.i].user_id;
      if (!user_id) {
        res->v.s = envdup(env, "");
      } else {
        res->v.s = envdup(env, teamdb_get_name(env->teamdb_state, user_id));
      }
      break;
    case TOK_GROUP:
      res->kind = TOK_STRING_L;
      res->type = FILTER_TYPE_STRING;
      user_id = env->rentries[r1.v.i].user_id;
      if (user_id > 0
          && (u = teamdb_get_userlist(env->teamdb_state, user_id))
          && u->cnts0
          && (m = userlist_members_get_first(u->cnts0->members))) {
        res->v.s = envdup(env, m->group);
      } else {
        res->v.s = envdup(env, "");
      }
      break;
    case TOK_LANG:
      res->kind = TOK_STRING_L;
      res->type = FILTER_TYPE_STRING;
      lang_id = env->rentries[r1.v.i].lang_id;
      if (lang_id <= 0 || lang_id > env->maxlang || !env->langs[lang_id]) {
        res->v.s = envdup(env, "");
      } else {
        res->v.s = envdup(env, env->langs[lang_id]->short_name);
      }
      break;
    case TOK_ARCH:
      res->kind = TOK_STRING_L;
      res->type = FILTER_TYPE_STRING;
      lang_id = env->rentries[r1.v.i].lang_id;
      if (lang_id <= 0 || lang_id > env->maxlang || !env->langs[lang_id]) {
        res->v.s = envdup(env, "");
      } else {
        res->v.s = envdup(env, env->langs[lang_id]->arch);
      }
      break;
    case TOK_RESULT:
      res->kind = TOK_RESULT_L;
      res->type = FILTER_TYPE_RESULT;
      res->v.r = env->rentries[r1.v.i].status;
      break;
    case TOK_SCORE:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      res->v.i = env->rentries[r1.v.i].score;
      break;
    case TOK_TEST:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      res->v.i = env->rentries[r1.v.i].test;
      break;
    case TOK_IMPORTED:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.b = env->rentries[r1.v.i].is_imported;
      break;
    case TOK_HIDDEN:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.b = env->rentries[r1.v.i].is_hidden;
      break;
    case TOK_READONLY:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.b = env->rentries[r1.v.i].is_readonly;
      break;
    case TOK_MARKED:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.b = env->rentries[r1.v.i].is_marked;
      break;
    case TOK_SAVED:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.b = env->rentries[r1.v.i].is_saved;
      break;
    case TOK_VARIANT:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      c = env->rentries[r1.v.i].variant;
      if (!c) {
        c = find_variant(env->serve_state, env->rentries[r1.v.i].user_id,
                         env->rentries[r1.v.i].prob_id, 0);
      }
      res->v.i = c;
      break;
    case TOK_RAWVARIANT:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      c = env->rentries[r1.v.i].variant;
      res->v.i = c;
      break;
    case TOK_USERINVISIBLE:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      user_id = env->rentries[r1.v.i].user_id;
      if (!user_id) {
        res->v.b = 0;
      } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
        res->v.b = 0;
      } else if ((flags & TEAM_INVISIBLE)) {
        res->v.b = 1;
      } else {
        res->v.b = 0;
      }
      break;
    case TOK_USERBANNED:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      user_id = env->rentries[r1.v.i].user_id;
      if (!user_id) {
        res->v.b = 0;
      } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
        res->v.b = 0;
      } else if ((flags & TEAM_BANNED)) {
        res->v.b = 1;
      } else {
        res->v.b = 0;
      }
      break;
    case TOK_USERLOCKED:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      user_id = env->rentries[r1.v.i].user_id;
      if (!user_id) {
        res->v.b = 0;
      } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
        res->v.b = 0;
      } else if ((flags & TEAM_LOCKED)) {
        res->v.b = 1;
      } else {
        res->v.b = 0;
      }
      break;
    case TOK_USERINCOMPLETE:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      user_id = env->rentries[r1.v.i].user_id;
      if (!user_id) {
        res->v.b = 0;
      } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
        res->v.b = 0;
      } else if ((flags & TEAM_INCOMPLETE)) {
        res->v.b = 1;
      } else {
        res->v.b = 0;
      }
      break;
    case TOK_USERDISQUALIFIED:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      user_id = env->rentries[r1.v.i].user_id;
      if (!user_id) {
        res->v.b = 0;
      } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
        res->v.b = 0;
      } else if ((flags & TEAM_DISQUALIFIED)) {
        res->v.b = 1;
      } else {
        res->v.b = 0;
      }
      break;
    case TOK_LATEST:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.b = is_latest(env, r1.v.i);
      break;
    case TOK_LATESTMARKED:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.b = is_latestmarked(env, r1.v.i);
      break;
    case TOK_AFTEROK:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.b = is_afterok(env, r1.v.i);
      break;
    case TOK_EXAMINABLE:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      //res->v.b = env->rentries[r1.v.i].is_examinable;
      res->v.b = 0;
      break;
    case TOK_CYPHER:
      res->kind = TOK_STRING_L;
      res->type = FILTER_TYPE_STRING;
      user_id = env->rentries[r1.v.i].user_id;
      u = 0; s = 0;
      if (user_id > 0) u = teamdb_get_userlist(env->teamdb_state, user_id);
      if (u && u->cnts0) s = u->cnts0->exam_cypher;
      res->v.s = envdup(env, s);
      break;
    case TOK_MISSINGSOURCE:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.b = is_missing_source(env, &env->rentries[r1.v.i]);
      break;
    case TOK_JUDGE_ID:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      res->v.i = env->rentries[r1.v.i].judge_id;
      break;
    case TOK_PASSED_MODE:
      res->kind = TOK_BOOL_L;
      res->type = FILTER_TYPE_BOOL;
      res->v.i = !!env->rentries[r1.v.i].passed_mode;
      break;
    case TOK_EOLN_TYPE:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      res->v.i = !!env->rentries[r1.v.i].eoln_type;
      break;
    case TOK_STORE_FLAGS:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      res->v.i = !!env->rentries[r1.v.i].store_flags;
      break;
    case TOK_TOKEN_FLAGS:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      res->v.i = !!env->rentries[r1.v.i].token_flags;
      break;
    case TOK_TOKEN_COUNT:
      res->kind = TOK_INT_L;
      res->type = FILTER_TYPE_INT;
      res->v.i = !!env->rentries[r1.v.i].token_count;
      break;
    default:
      abort();
    }
    break;

  case TOK_INT:
  case TOK_STRING:
  case TOK_BOOL:
  case TOK_TIME_T:
  case TOK_DUR_T:
  case TOK_SIZE_T:
  case TOK_RESULT_T:
  case TOK_HASH_T:
  case TOK_IP_T:
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    return filter_tree_eval_node(env->mem, t->kind, res, &r1, 0);

    /* variables */
  case TOK_ID:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->rid;
    break;
  case TOK_CURTIME:
    res->kind = TOK_TIME_L;
    res->type = FILTER_TYPE_TIME;
    res->v.a = env->cur->time;
    break;
  case TOK_CURDUR:
    res->kind = TOK_DUR_L;
    res->type = FILTER_TYPE_DUR;
    res->v.u = env->cur->time - env->rhead.start_time;
    break;
  case TOK_CURSIZE:
    res->kind = TOK_SIZE_L;
    res->type = FILTER_TYPE_SIZE;
    res->v.z = env->cur->size;
    break;
  case TOK_CURHASH:
    res->kind = TOK_HASH_L;
    res->type = FILTER_TYPE_HASH;
    memcpy(res->v.h, env->cur->sha1, sizeof(env->cur->sha1));
    break;
  case TOK_CURUUID:
    res->kind = TOK_STRING_L;
    res->type = FILTER_TYPE_STRING;
    res->v.s = envdup(env, ej_uuid_unparse(&env->cur->run_uuid, ""));
    break;
  case TOK_CURIP:
    res->kind = TOK_IP_L;
    res->type = FILTER_TYPE_IP;
    run_entry_to_ipv6(env->cur, &res->v.p);
    break;
  case TOK_CURPROB:
    res->kind = TOK_STRING_L;
    res->type = FILTER_TYPE_STRING;
    if (env->cur->prob_id <= 0 || env->cur->prob_id > env->maxprob || !env->probs[env->cur->prob_id]) {
      res->v.s = envdup(env, "");
    } else {
      res->v.s = envdup(env, env->probs[env->cur->prob_id]->short_name);
    }
    break;
  case TOK_CURUID:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->cur->user_id;
    break;
  case TOK_CURLOGIN:
    res->kind = TOK_STRING_L;
    res->type = FILTER_TYPE_STRING;
    if (!env->cur->user_id) {
      res->v.s = envdup(env, "");
    } else {
      res->v.s = envdup(env, teamdb_get_login(env->teamdb_state, env->cur->user_id));
    }
    break;
  case TOK_CURNAME:
    res->kind = TOK_STRING_L;
    res->type = FILTER_TYPE_STRING;
    if (!env->cur->user_id) {
      res->v.s = envdup(env, "");
    } else {
      res->v.s = envdup(env, teamdb_get_name(env->teamdb_state, env->cur->user_id));
    }
    break;
  case TOK_CURGROUP:
    res->kind = TOK_STRING_L;
    res->type = FILTER_TYPE_STRING;
    user_id = env->cur->user_id;
    if (user_id > 0
        && (u = teamdb_get_userlist(env->teamdb_state, user_id))
        && u->cnts0
        && (m = userlist_members_get_first(u->cnts0->members))) {
      res->v.s = envdup(env, m->group);
    } else {
      res->v.s = envdup(env, "");
    }
    break;
  case TOK_CURLANG:
    res->kind = TOK_STRING_L;
    res->type = FILTER_TYPE_STRING;
    if (env->cur->lang_id <= 0 || env->cur->lang_id > env->maxlang || !env->langs[env->cur->lang_id]) {
      res->v.s = envdup(env, "");
    } else {
      res->v.s = envdup(env, env->langs[env->cur->lang_id]->short_name);
    }
    break;
  case TOK_CURARCH:
    res->kind = TOK_STRING_L;
    res->type = FILTER_TYPE_STRING;
    if (env->cur->lang_id <= 0 || env->cur->lang_id > env->maxlang || !env->langs[env->cur->lang_id]) {
      res->v.s = envdup(env, "");
    } else {
      res->v.s = envdup(env, env->langs[env->cur->lang_id]->arch);
    }
    break;
  case TOK_CURRESULT:
    res->kind = TOK_RESULT_L;
    res->type = FILTER_TYPE_RESULT;
    res->v.r = env->cur->status;
    break;
  case TOK_CURSCORE:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->cur->score;
    break;
  case TOK_CURTEST:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->cur->test;
    break;
  case TOK_CURIMPORTED:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = env->cur->is_imported;
    break;
  case TOK_CURHIDDEN:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = env->cur->is_hidden;
    break;
  case TOK_CURREADONLY:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = env->cur->is_readonly;
    break;
  case TOK_CURMARKED:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = env->cur->is_marked;
    break;
  case TOK_CURSAVED:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = env->cur->is_saved;
    break;
  case TOK_CURVARIANT:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    c = env->cur->variant;
    if (!c) c = find_variant(env->serve_state, env->cur->user_id,
                             env->cur->prob_id, 0);
    res->v.i = c;
    break;
  case TOK_CURRAWVARIANT:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    c = env->cur->variant;
    res->v.i = c;
    break;
  case TOK_CURUSERINVISIBLE:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    user_id = env->cur->user_id;
    if (!user_id) {
      res->v.b = 0;
    } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
      res->v.b = 0;
    } else if ((flags & TEAM_INVISIBLE)) {
      res->v.b = 1;
    } else {
      res->v.b = 0;
    }
    break;
  case TOK_CURUSERBANNED:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    user_id = env->cur->user_id;
    if (!user_id) {
      res->v.b = 0;
    } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
      res->v.b = 0;
    } else if ((flags & TEAM_BANNED)) {
      res->v.b = 1;
    } else {
      res->v.b = 0;
    }
    break;
  case TOK_CURUSERLOCKED:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    user_id = env->cur->user_id;
    if (!user_id) {
      res->v.b = 0;
    } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
      res->v.b = 0;
    } else if ((flags & TEAM_LOCKED)) {
      res->v.b = 1;
    } else {
      res->v.b = 0;
    }
    break;
  case TOK_CURUSERINCOMPLETE:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    user_id = env->cur->user_id;
    if (!user_id) {
      res->v.b = 0;
    } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
      res->v.b = 0;
    } else if ((flags & TEAM_INCOMPLETE)) {
      res->v.b = 1;
    } else {
      res->v.b = 0;
    }
    break;
  case TOK_CURUSERDISQUALIFIED:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    user_id = env->cur->user_id;
    if (!user_id) {
      res->v.b = 0;
    } else if ((flags = teamdb_get_flags(env->teamdb_state, user_id)) < 0) {
      res->v.b = 0;
    } else if ((flags & TEAM_DISQUALIFIED)) {
      res->v.b = 1;
    } else {
      res->v.b = 0;
    }
    break;
  case TOK_CURLATEST:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = is_latest(env, env->cur->run_id);
    break;
  case TOK_CURLATESTMARKED:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = is_latestmarked(env, env->cur->run_id);
    break;
  case TOK_CURAFTEROK:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = is_afterok(env, env->cur->run_id);
    break;
  case TOK_CUREXAMINABLE:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    //res->v.b = env->cur->is_examinable;
    res->v.b = 0;
    break;
  case TOK_CURCYPHER:
    res->kind = TOK_STRING_L;
    res->type = FILTER_TYPE_STRING;
    user_id = env->cur->user_id;
    u = 0; s = 0;
    if (user_id > 0) u = teamdb_get_userlist(env->teamdb_state, user_id);
    if (u && u->cnts0) s = u->cnts0->exam_cypher;
    res->v.s = envdup(env, s);
    break;
  case TOK_CURMISSINGSOURCE:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = is_missing_source(env, env->cur);
    break;
  case TOK_CURJUDGE_ID:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->cur->judge_id;
    break;
  case TOK_CURPASSED_MODE:
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.i = !!env->cur->passed_mode;
    break;
  case TOK_CUREOLN_TYPE:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->cur->eoln_type;
    break;
  case TOK_CURSTORE_FLAGS:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->cur->store_flags;
    break;
  case TOK_CURTOKEN_FLAGS:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->cur->token_flags;
    break;
  case TOK_CURTOKEN_COUNT:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->cur->token_count;
    break;
  case TOK_CURTOTAL_SCORE:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = serve_get_user_result_score(env->serve_state,env->cur->user_id);
    break;

  case TOK_NOW:
    res->kind = TOK_TIME_L;
    res->type = FILTER_TYPE_TIME;
    res->v.a = env->cur_time;
    break;
  case TOK_START:
    res->kind = TOK_TIME_L;
    res->type = FILTER_TYPE_TIME;
    res->v.a = env->rhead.start_time;
    break;
  case TOK_FINISH:
    res->kind = TOK_TIME_L;
    res->type = FILTER_TYPE_TIME;
    res->v.a = env->rhead.stop_time;
    break;
  case TOK_TOTAL:
    res->kind = TOK_INT_L;
    res->type = FILTER_TYPE_INT;
    res->v.i = env->rtotal;
    break;

  case TOK_INT_L:
  case TOK_STRING_L:
  case TOK_BOOL_L:
  case TOK_TIME_L:
  case TOK_DUR_L:
  case TOK_SIZE_L:
  case TOK_RESULT_L:
  case TOK_HASH_L:
  case TOK_IP_L:
    *res = *t;
    return 0;

  case TOK_EXAMINATOR:
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    ASSERT(r1.kind == TOK_INT_L);
    if (r1.v.i < 0) r1.v.i = env->rtotal + r1.v.i;
    if (r1.v.i >= env->rtotal) return -FILTER_ERR_RANGE;
    if (r1.v.i < 0) return -FILTER_ERR_RANGE;
    if ((c = do_eval(env, t->v.t[1], &r2)) < 0) return c;
    ASSERT(r2.kind == TOK_INT_L);
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = 0;
    /*
    for (c = 0; c < 3; c++) {
      if (env->rentries[r1.v.i].examiners[c] == r2.v.i) {
        res->v.b = 1;
        break;
      }
    }
    */
    break;

  case TOK_CUREXAMINATOR:
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    ASSERT(r1.kind == TOK_INT_L);
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = 0;
    /*
    for (c = 0; c < 3; c++) {
      if (env->cur->examiners[c] == r1.v.i) {
        res->v.b = 1;
        break;
      }
    }
    */
    break;

  case TOK_INUSERGROUP:
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    ASSERT(r1.kind == TOK_STRING_L);
    if ((c = find_user_group(env, r1.v.s)) < 0) return c;
    t->kind = TOK_INUSERGROUPINT;
    t->v.t[0] = filter_tree_new_int(env->mem, c);
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = check_user_group(env, env->cur->user_id, c);
    break;

  case TOK_INUSERGROUPINT:
    if ((c = do_eval(env, t->v.t[0], &r1)) < 0) return c;
    ASSERT(r1.kind == TOK_INT_L); 
    res->kind = TOK_BOOL_L;
    res->type = FILTER_TYPE_BOOL;
    res->v.b = check_user_group(env, env->cur->user_id, r1.v.i);
    break;   

  default:
    SWERR(("unhandled kind: %d", t->kind));
  }

  return 0;
}