diff options
Diffstat (limited to 'judge/judgm_lib.h')
-rw-r--r-- | judge/judgm_lib.h | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/judge/judgm_lib.h b/judge/judgm_lib.h new file mode 100644 index 0000000..041901d --- /dev/null +++ b/judge/judgm_lib.h @@ -0,0 +1,418 @@ +#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" + +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; +} |