#include<string.h>
#include<limits.h>
#include<unistd.h>
#include<signal.h>
#include<limits.h>
#include<errno.h>
#include<pthread.h>
#include<semaphore.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include<sys/resource.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/mman.h>
#include<map>
#include<utility>
#include"judge.h"
#include"judgk_com.h"
typedef int (*judgm_proc_check_fn)();
class judgm_proc{
private:
int init(){
int i;
int j;
struct stat st;
if(stat(exe_path,&st)){
return -1;
}
if(!S_ISREG(st.st_mode)){
return -1;
}
exe_name[NAME_MAX] = '\0';
for(i = 0,j = 0;exe_path[i] != '\0' && j < NAME_MAX;i++){
if(exe_path[i] == '/'){
j = 0;
}else{
exe_name[j] = exe_path[i];
j++;
}
}
exe_name[j] = '\0';
pid = 0;
kern_task = 0;
status = JUDGE_WAIT;
runtime = 0;
memory = 0;
return 0;
}
int protect(){
rlimit limit;
judgk_com_proc_add com_proc_add;
limit.rlim_cur = 1;
limit.rlim_max = limit.rlim_cur;
prlimit(pid,RLIMIT_NPROC,&limit,NULL);
limit.rlim_cur = 8L;
limit.rlim_max = limit.rlim_cur;
prlimit(pid,RLIMIT_NOFILE,&limit,NULL);
limit.rlim_cur = 70368744177664L;
limit.rlim_max = limit.rlim_cur;
prlimit(pid,RLIMIT_STACK,&limit,NULL);
com_proc_add.run_path[0] = '\0';
strncat(com_proc_add.run_path,run_path,sizeof(com_proc_add.run_path));
com_proc_add.pid = pid;
com_proc_add.timelimit = timelimit * 1000L;
com_proc_add.hardtimelimit = hardtimelimit * 1000L;
com_proc_add.memlimit = memlimit * 1024L + 4096L * 128L;
if(ioctl(judgk_modfd,IOCTL_PROC_ADD,&com_proc_add)){
return -1;
}
kern_task = com_proc_add.kern_task;
return 0;
}
public:
int judgk_modfd;
char run_path[PATH_MAX + 1];
char exe_path[PATH_MAX + 1];
char exe_name[NAME_MAX + 1];
unsigned long timelimit;
unsigned long hardtimelimit;
unsigned long memlimit;
judgm_proc_check_fn check_fn;
pid_t pid;
unsigned long kern_task;
int status;
unsigned long runtime;
unsigned long memory;
judgm_proc(int judgk_modfd,char *runpath,char *exe_path,unsigned long timelimit,unsigned long hardtimelimit,unsigned long memlimit,judgm_proc_check_fn check_fn){
this->judgk_modfd = judgk_modfd;
this->run_path[0] = '\0';
strncat(this->run_path,runpath,sizeof(this->run_path));
this->exe_path[0] = '\0';
strncat(this->exe_path,exe_path,sizeof(this->exe_path));
this->timelimit = timelimit;
this->hardtimelimit = hardtimelimit;
this->memlimit = memlimit;
this->check_fn = check_fn;
}
int proc_run(){
char abspath[PATH_MAX + 1];
if(init()){
return -1;
}
realpath(exe_path,abspath);
if((pid = fork()) == 0){
char *argv[] = {NULL,NULL};
char *envp[] = {NULL};
chdir(run_path);
check_fn();
setgid(99);
setuid(99);
kill(getpid(),SIGSTOP);
argv[0] = exe_name;
execve(abspath,argv,envp);
exit(0);
}
if(pid == -1){
return -1;
}
waitpid(pid,NULL,WUNTRACED);
if(protect()){
kill(pid,SIGKILL);
return -1;
}
status = JUDGE_RUN;
kill(pid,SIGCONT);
return 0;
}
int proc_wait(bool blockflag){
int wstatus;
struct judgk_com_proc_get com_proc_get;
if(blockflag == true){
if(waitpid(pid,&wstatus,WUNTRACED) == -1){
return -1;
}
}else{
if(waitpid(pid,&wstatus,WUNTRACED | WNOHANG) <= 0){
return -1;
}
}
com_proc_get.kern_task = kern_task;
if(ioctl(judgk_modfd,IOCTL_PROC_GET,&com_proc_get)){
return -1;
}
runtime = com_proc_get.runtime / 1000L;
memory = com_proc_get.memory;
printf("runtime:%lu memory:%lu\n",runtime,memory);
if(com_proc_get.status != JUDGE_AC){
status = com_proc_get.status;
}else if(memory > (memlimit * 1024L)){
status = JUDGE_MLE;
}else if(runtime > timelimit){
status = JUDGE_TLE;
}else if(WIFEXITED(wstatus) || (WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGKILL)){
status = JUDGE_AC;
}else{
status = JUDGE_RE;
}
return 0;
}
int proc_kill(){
if(kill(pid,SIGKILL)){
return -1;
}
return 0;
}
};
class judgm_hyperio{
private:
int judgk_modfd;
char *read_buf;
off_t read_off;
public:
int tty_idx;
judgm_hyperio(int judgk_modfd){
this->judgk_modfd = judgk_modfd;
this->tty_idx = ioctl(this->judgk_modfd,IOCTL_HYPERIO_ADD,0);
this->read_buf = (char*)mmap(NULL,JUDGK_COM_HYPERIO_BUFSIZE,PROT_READ,MAP_SHARED,judgk_modfd,0);
this->read_off = 0;
}
~judgm_hyperio(){
munmap(read_buf,JUDGK_COM_HYPERIO_BUFSIZE);
ioctl(judgk_modfd,IOCTL_HYPERIO_DEL,0);
}
static int get_ttyfd(int idx){
char tpath[PATH_MAX + 1];
snprintf(tpath,sizeof(tpath),"/dev/jtty%d",idx);
return open(tpath,O_RDWR);
}
size_t wait(){
return ioctl(judgk_modfd,IOCTL_HYPERIO_READ,0);
}
int compare(char *buf,size_t len){
int flag;
size_t remain;
off_t off;
size_t data_len;
size_t cmp_len;
flag = 0;
remain = len;
off = 0;
data_len = 0;
cmp_len = 0;
while(remain > 0 && flag == 0){
if(data_len == 0){
if((data_len = ioctl(judgk_modfd,IOCTL_HYPERIO_READ,cmp_len)) <= 0){
return -1;
}
}
if(remain < data_len){
cmp_len = remain;
}else{
cmp_len = data_len;
}
if((cmp_len + read_off) < JUDGK_COM_HYPERIO_BUFSIZE){
flag |= memcmp(read_buf + read_off,buf + off,cmp_len);
read_off += cmp_len;
}else{
flag |= memcmp(read_buf + read_off,buf + off,JUDGK_COM_HYPERIO_BUFSIZE - read_off);
flag |= memcmp(read_buf,buf + off + (JUDGK_COM_HYPERIO_BUFSIZE - read_off),(cmp_len + read_off) - JUDGK_COM_HYPERIO_BUFSIZE);
read_off = (cmp_len + read_off) - JUDGK_COM_HYPERIO_BUFSIZE;
}
remain -= cmp_len;
off += cmp_len;
data_len -= cmp_len;
}
if(cmp_len > 0){
ioctl(judgk_modfd,IOCTL_HYPERIO_READ,-(long)cmp_len);
}
if(flag == 0){
return 0;
}else{
return -1;
}
}
};
static int judgm_compile(int subid,char *code_path,char *exe_path,int lang,bool force_flag,char *err_msg,size_t err_len){
int ret;
int i;
char log_path[PATH_MAX + 1];
char main_path[PATH_MAX + 1];
char sem_path[PATH_MAX + 1];
struct stat st;
sem_t *wait_sem;
bool ce_flag;
char dir_path[PATH_MAX + 1];
char *out_path;
int io[2];
int pid;
int wstatus;
char buf[64];
off_t err_off;
FILE *f_log;
if(force_flag == true){
force_flag = true;
out_path = exe_path;
}else{
snprintf(log_path,sizeof(log_path),"tmp/exe/%d/log",subid);
snprintf(main_path,sizeof(main_path),"tmp/exe/%d/main",subid);
snprintf(sem_path,sizeof(sem_path),"/judgm_compile_wait_%d",subid);
if((wait_sem = sem_open(sem_path,0)) == SEM_FAILED){
if(stat(main_path,&st)){
if((wait_sem = sem_open(sem_path,O_CREAT | O_EXCL,0644,0)) != SEM_FAILED){
out_path = main_path;
goto compile;
}else if((wait_sem = sem_open(sem_path,0)) != SEM_FAILED){
sem_wait(wait_sem);
sem_close(wait_sem);
}
}
}else{
sem_wait(wait_sem);
sem_close(wait_sem);
}
if((f_log = fopen(log_path,"r")) != NULL){
err_off = fread(err_msg,1,err_len - 1,f_log);
fclose(f_log);
err_msg[err_off] = '\0';
if(!link(main_path,exe_path)){
return 0;
}else{
return -1;
}
}
}
compile:
if(force_flag == false){
snprintf(dir_path,sizeof(dir_path),"tmp/exe/%d",subid);
mkdir(dir_path,0755);
}
ce_flag = false;
err_off = 0;
if(lang == JUDGE_CPP){
pipe(io);
if((pid = fork()) == 0){
char arg_compiler[16];
char arg_static[16];
char arg_o[16];
char arg_std[16];
char arg_output[16];
char *argv[8];
arg_compiler[0] = '\0';
strncat(arg_compiler,"g++",sizeof(arg_compiler));
arg_static[0] = '\0';
strncat(arg_static,"-static",sizeof(arg_static));
arg_o[0] = '\0';
strncat(arg_o,"-O2",sizeof(arg_o));
arg_std[0] = '\0';
strncat(arg_std,"-std=c++0x",sizeof(arg_std));
arg_output[0] = '\0';
strncat(arg_output,"-o",sizeof(arg_output));
argv[0] = arg_compiler;
argv[1] = arg_static;
argv[2] = arg_o;
argv[3] = code_path;
argv[4] = arg_std;
argv[5] = arg_output;
argv[6] = out_path;
argv[7] = NULL;
dup2(io[1],1);
dup2(io[1],2);
execvp("g++",argv);
}
close(io[1]);
while((ret = read(io[0],err_msg + err_off,err_len - err_off - 1)) > 0){
err_off += ret;
}
err_msg[err_off] = '\0';
while(read(io[0],buf,64) > 0);
close(io[0]);
if(err_off > (err_len - 4)){
err_msg[err_len - 4] = '\0';
strncat(err_msg + err_len - 4,"...",4);
err_off = err_len - 1;
}
waitpid(pid,&wstatus,0);
if(wstatus != 0){
ce_flag = true;
}
}
if(force_flag == false){
f_log = fopen(log_path,"w");
fwrite(err_msg,err_off,1,f_log);
fclose(f_log);
for(i = 0;i < JUDGE_THREAD_MAX;i++){
sem_post(wait_sem);
}
sem_close(wait_sem);
sem_unlink(sem_path);
}
if(ce_flag == true){
return -1;
}
link(main_path,exe_path);
return 0;
}