// // СЕРВИС Olimp 1.01 // // ссылки по тексту: !stat! - статистика, !time! - время в мониторе // !A! - тестирование ACM-турнира, !N! - тестирование традиц. // !r! - ответ (reply2author) !mon! - монитор // !Nmon! - монитор для традиционных турниров // !tlim! - тайм-лимит !lang! - ошибка Invalid Lang #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "version.h" #include "sql.h" #include "logger.h" #define MAXFILES 20 #define COMPARE_PROGRAM "cmpres" #define COMPARE_DIR "../sbin/comp/" #define OK_ALL 200 #define OK_LOGIN 201 #define OK_SOURCE 202 #define OK_SCORE 249 // в параметре code1 - баллы за задачу #define OK_TESTS 250 #define OK_TEST1 251 // принят тест 1 - для школьных олимпиад #define OK_TEST99 350 // принят тест 99 - для школьных олимпиад #define OK_RESULTS 203 #define ERR_REFUSEDMIN 501 #define ERR_UNKNOWN 501 #define ERR_INVUSER 502 #define ERR_INVPASSWD 503 #define ERR_USRLOCKED 504 #define ERR_TOURLOCKED 505 #define ERR_INVTASKN 506 #define ERR_INVLANG 507 #define ERR_SRC2BIG 508 #define ERR_CANTOPENSRC 509 #define ERR_ILLEGALKEYWORD 510 #define ERR_REFUSEDMAX 511 #define ERR_NOTCOMPILED 520 //errors from testing #define ERR_RUNTIMEMIN 530 #define ERR_DIFFERENT 530 #define ERR_NOMEM 531 #define ERR_XCPU 532 #define ERR_SEGV 533 #define ERR_ABORT 534 #define ERR_RUNTIMEMAX 535 #define msgRouteOk "route accepted / command:" #define msgUserAccepted "user accepted / passwd:" #define msgLoginOk "you are logged in / task's num:" #define msgTaskAccepted "task num accepted / lang:" #define msgLangAccepted "language accepted / source (ended by '.'):" #define msgSrcAccepted "source accepted, bye" #define msgCmdUnknown "unknown command" #define msgInvalidUser "invalid user" #define msgPasswdIncorrect "password incorrect" #define msgUserLocked "user is locked" #define msgTourLocked "tour is locked" #define msgInvalidTaskN "invalid task's num" #define msgInvalidLang "invalid language" #define msgSrcTooBig "source too big" #define msgCantOpenSrc "can't open src for write" #define msgIllegalKeyword "illegal keyword" #define _msgCmdUnknown "неизвестная команда" #define _msgInvalidUser "неверный рег.номер" #define _msgPasswdIncorrect "неверный пароль" #define _msgUserLocked "пользователь заблокирован" #define _msgTourLocked "турнир заблокирован" #define _msgInvalidTaskN "неверный номер задачи" #define _msgInvalidLang "неизвестный язык программирования" #define _msgSrcTooBig "текст программы слишком велик" #define _msgCantOpenSrc "невозможно прочитать исходный текст" #define _msgIllegalKeyword "запрещенное ключевое слово" #define msgDifferent "output not match pattern" #define msgNoMem "not enought memory" #define msgXCPU "not enought CPU-times" #define msgSEGV "segmentation fault" #define msgAbort "non-zero exit code" #define _msgDifferent "результаты не совпадают с эталоном" #define _msgNoMem "переполнение памяти" #define _msgXCPU "превышение лимита времени" #define _msgSEGV "обращение к памяти по неверному адресу" #define _msgAbort "Runtime error" #define CfgName "service.cfg" //************************** FILE *in, *out; SQL *db; char lang_Prog[80]; char lang_Inp[20]; char lang_Exe[20]; char lang_Err[20]; char lang_Ext[20]; char IP[20]; int UserID; int RegN; int TaskID; char TaskNum[256]; int Score; int TourID; char TourType; char Route[1024]; char Lang[20]; char TheDate[40]; char TheTime[40]; char TimeStr[40]; int TriesCnt; char StartDT[40]; long Minutes; char LogRecord[1024]; uid_t test_uid=99; gid_t test_gid=99; char rundir[256]; char cfgdir[256]; //config для service char workdir[256]; int maxsrcline=1000; int timelimit=3; // раньше было 40, но это слишком долго int fsizelimit=102400; // ограничение на размер выходного файла int nofilelimit=2; int stacklimit=10240; int nproclimit=1; // число порождаемых процессов //************************** void reply (int code, char *p); void _shutdown (); void getstr (char *buf, int size); void reply2author (int code, char *p, int code1); void HandleTest(); void HandleResults(); void HandleProgN(int TaskID, char *fname); void HandleProgAT(); int compile(); int test(int TestID, char *fname, char *exe_name, int *abort_code, int TestNum); int my_strlen (char *p); int fix_access(); void fix_minutes(); int LoadLangCfg(char *lang); int LangCheckLine(char *str); void PrintLangCfg(); int LoadCfg(); void ShowLimits(); void SendPPID(); char Languages[1024]; //**** переменные lang-фильтра ******* #define LANG_KEYWORD_MAX 200 #define LANG_KEYWORD_LENGTH 10 #define LANG_CUTLINE_MAX 100 #define LANG_CUTLINE_LENGTH 20 #define LANG_HEADER_LENGTH 1024 #define LANG_FOOTER_LENGTH 256 #define NAME_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_" #define TIME_LIMIT_DEF 3 int lang_caseignored=0; int lang_keywordscnt=0; char lang_keywords[LANG_KEYWORD_MAX][LANG_KEYWORD_LENGTH+1]; int lang_cutlinescnt=0; char lang_cutlines[LANG_CUTLINE_MAX][LANG_CUTLINE_LENGTH+1]; char lang_header[LANG_HEADER_LENGTH+1]; char lang_footer[LANG_FOOTER_LENGTH+1]; //служебные void strlwr(char *str){ while(*str) *(str++)|=0x20; } void rtrim(char *s){ int i; if(!s) return; for(i=strlen(s)-1; i>=0 && (s[i]==' '||s[i]=='\t'||s[i]=='r'||s[i]=='\n'); i--) s[i]=0; } //получение каталогов void GetDirs(char *base, char *workdir, char *cfgdir){ int i; workdir[0]=0; strcpy(workdir,base); //удалить имя программы for(i=strlen(workdir)-1; i>=0 && workdir[i]!='/'; i--); if(i>=0) workdir[i]=0; else workdir[0]=0; strcat(workdir,"/"); if(!strcmp(workdir,"./") || !strcmp(workdir,"/")) workdir[0]=0; sprintf(cfgdir,"%s../etc/",workdir); if(!workdir[0]) strcpy(workdir,"./"); } //чтение конфигурации int LoadCfg(){ FILE *f; char fname[256]; char buf[1024]; char *kwd,*next; char *delim=" \t\r\n"; char *delimex=" \t\r\n>"; int flSkipLang=0; int res=0; Languages[0]=0; sprintf(fname,"%s%s",cfgdir,CfgName); if((f=fopen(fname,"r"))==NULL) { //!lang! sprintf(LogRecord,"Can't read CFG. fname=%s",fname); write_log(IP,LogRecord); return -1; } while(!feof(f)){ fgets(buf,sizeof(buf),f); kwd=strtok(buf,delimex); if(kwd==NULL) continue; if(*kwd=='#') continue; //пропуск комментария // пропустить секцию if(!strcmp(kwd,"= OK_TEST1 && code <= OK_TEST99) { fprintf(f,"Тест принят: %d\n", code - OK_TEST1 + 1); } //задание не принято if(code>=ERR_REFUSEDMIN && code<=ERR_REFUSEDMAX){ // fprintf(f,"Отвергнуто:\n"); if(TourType == 'N') fprintf(f,"\n"); switch(code){ case ERR_UNKNOWN : fprintf(f,"%s\n",_msgCmdUnknown); break; case ERR_INVUSER : fprintf(f,"%s\n",_msgInvalidUser); break; case ERR_INVPASSWD : fprintf(f,"%s\n",_msgPasswdIncorrect); break; case ERR_USRLOCKED : fprintf(f,"%s\n",_msgUserLocked); break; case ERR_TOURLOCKED : fprintf(f,"%s\n",_msgTourLocked); break; case ERR_INVTASKN : fprintf(f,"%s\n",_msgInvalidTaskN); break; case ERR_INVLANG : fprintf(f,"%s\n",_msgInvalidLang); break; case ERR_SRC2BIG : fprintf(f,"%s\n",_msgSrcTooBig); break; case ERR_CANTOPENSRC : fprintf(f,"%s\n",_msgCantOpenSrc); break; case ERR_ILLEGALKEYWORD : fprintf(f,"%s (%s)\n",_msgIllegalKeyword,p); break; default : fprintf(f,"????"); break; } } //ошибка при компиляции if(code==ERR_NOTCOMPILED){ FILE *err; char buf[256]; if(TourType == 'N') fprintf(f,"\n"); fprintf(f,"Ошибка компиляции:\n"); if(!(err=fopen(p,"r"))){ fprintf(f,"не могу открыть файл ошибок"); fclose(f); return; } fgets(buf,sizeof(buf),err); while(!feof(err)){ fprintf(f,buf); fgets(buf,sizeof(buf),err); } fclose(err); } //ошибка при тестировании if(code>=ERR_RUNTIMEMIN && code<=ERR_RUNTIMEMAX){ if(TourType == 'N') fprintf(f,"\n"); fprintf(f,"Ошибка выполнения на тесте %s: ",p); switch(code){ case ERR_DIFFERENT: fprintf(f,"%s\n",_msgDifferent); break; case ERR_NOMEM : fprintf(f,"%s\n",_msgNoMem); break; case ERR_XCPU : fprintf(f,"%s\n",_msgXCPU); break; case ERR_SEGV : fprintf(f,"%s\n",_msgSEGV); break; case ERR_ABORT : fprintf(f,"%s %d\n",_msgAbort,code1); break; } } fclose(f); //запустить sender... sprintf(args,"./sender %s 1>/dev/null 2>/dev/null",fname); pid=system(args); if(pid==-1){ sprintf(LogRecord,"can't do system(), errno=%d",errno); write_log("SYSINFO",LogRecord); } unlink(fname); } // Выводит в stdout строку "КОД-СООБЩЕНИЕ" void reply(int code, char *p){ fprintf (out, "%ld - %s\n", code, p); fflush (out); /* if (ferror (out)) { _shutdown (); } */ } //завершение работы сервиса void _shutdown () { int i; //записать в Log о завершении log_write(db,LOG_OK,LOG_SRC_SERVICE,LOG_SRV_STOPPED,"Service stopped"); SQL_Close (db); fclose (in); fclose (out); // exit (result); exit(0); } // Получить строку из stdin, заменить LF,CR в конце строки на '\0' void getstr (char *buf, int size) { *buf = '\0'; l1: if (ferror (in)){ write_log(IP,"connection closed by foreign host"); _shutdown (); } fgets (buf, size, in); if (buf == '\0') goto l1; while (buf[strlen (buf) - 1] == '\xA' || buf[strlen (buf) - 1] == '\xD') buf[strlen (buf) - 1] = '\0'; } //обработка результатов проверки на серваке void HandleResults(){ char Query[1024]; char Answer[1024]; char LogRecord[256]; char SqlStr[1024]; char state; char Results[10240]; char buf[512],buf1[512]; int i,TaskCnt; int place=0,_donecnt0=-1,_time0=-1,_donecnt,_time; char table_name[20]; char stopdt[13]; // время до остановки турнира char curdt[80]; // текущее время и дата char timestr[80];// строка с сообщением о времени завершения тура char dat[10],tim[10]; struct tm time1,time2; double dlt; int delta; time_t t1,t2; reply(OK_ALL,"Ok results / TourID:"); //get TourID getstr (Query, sizeof (Query)); TourID=atoi(Query); //check Tours.State if(!SQL_Query (db,"select State,Type,TaskCnt from Tours where ID=%d", TourID)){ sprintf(LogRecord,"Results: invalid TourID (%d)",TourID); write_log(IP,LogRecord); reply2author(599,"invalid tour's ID",0); reply(599,"invalid tour's ID"); _shutdown(); } if(SQL_Field(db,1)) state=*SQL_Field(db,1); else state=0; if( state!='2' && state!='4' ) //! add all valid states !!!!!! { sprintf(LogRecord,"Results: tour %d locked (%c)",TourID,state); write_log(IP,LogRecord); reply2author(ERR_TOURLOCKED,msgTourLocked,0); reply(ERR_TOURLOCKED,SQL_Field(db,1)); _shutdown(); } //get Tours.Type if(SQL_Field(db,2)) TourType=*SQL_Field(db,2); else TourType=0; if(TourType!='A' && TourType!='N' && TourType!='T'){ sprintf(LogRecord,"Results: invalid type '%c' of tour %d",TourType,TourID); write_log(IP,LogRecord); reply2author(599,"invalid tour's type",0); reply(599,"invalid tour's type"); _shutdown(); } if(!SQL_Field(db,3)) TaskCnt=0; else TaskCnt=atoi(SQL_Field(db,3)); //get results if(TourType=='T'){ sprintf(LogRecord,"Results: can't display results for test tour (%d)",TourID); write_log(IP,LogRecord); reply(OK_RESULTS,"Results: invalid tour type (T)"); reply2author(OK_RESULTS,"Тестовый турнир: таблица результатов не ведется",0); } Results[0]=0; if(TourType=='N'){ //!Nmon! Таблица для традиционных турниров buf[0] = 0; for(i=0; i38) sprintf(buf,"%s\n%38s",buf,"->"); for(i=0; i22) sprintf(buf,"%s\n%20s",buf,"->"); for(i=0; i0 - для задачи уже было послано правильное решение; любая попытка теперь приносит штрафные 20 минут. */ if((!Score) && (TaskVal<=0)){ /*ошибочное решение, задача не была сдана - штрафная попытка. учет TaskVal нужен из-за того, что если задача уже была сдана, то необходимо изменять и поле Taski, и поле Time4Solve. */ TaskVal--; sprintf(Query,"update ACMRes set Task%s=%d where RegN=%d",TaskNum,TaskVal,RegN); SQL_Query(db,Query); } else { if(TaskVal<=0){ /*правильное решение, задача не была сдана - верная попытка. изменение количества решенных задач (поле DoneCnt), вычисление штрафного времени в переменную Minutes. */ DoneCnt++; sprintf(Query,"update ACMRes set DoneCnt=%d where RegN=%d",DoneCnt,RegN); SQL_Query(db,Query); Minutes+=20*abs(TaskVal); } else Minutes=20; /*неверное решение или верное решение, задача уже была сдана - штрафная попытка. */ //зафиксировать время ! sprintf(Query,"update ACMRes set Time4Solve=Time4Solve+%d where RegN=%d",Minutes,RegN); SQL_Query(db,Query); // обновить количество попыток TaskVal=abs(TaskVal)+1; sprintf(Query,"update ACMRes set Task%s=%d where RegN=%d",TaskNum,TaskVal,RegN); SQL_Query(db,Query); // обновить статистику по участнику UserStat.TriesCnt // попытка уже зафиксирована при приеме задачи (см. выше) sprintf(Query,"update UserStat set TriesCnt=abs(TriesCnt) where TaskID=%d and UserID=%d", TaskID, UserID); if (!SQL_Query(db,Query)) { write_log(IP,"Невозможно обновить статистику по участнику (UserStat.TriesCnt)"); } } // endif ( (!Score) && (TaskVal<=0) ) (Не статистика) } //endif (TourType!='T') //!stat! Статистика - верное решение (первая верная попытка) // Если TaskVal>0, то попытка считается ошибочной. // обновление статистики (TaskStat.DoneCnt, Tasks.DoneCnt). // Для всех турниров, кроме #1 if( (TourID!=1) && Score && (TaskVal<=0)) { if (!SQL_Query(db,"update TaskStat set DoneCnt=DoneCnt+1 where TaskID=%d and TourID=%d", TaskID,TourID) ) { write_log(IP,"Невозможно обновить статистику задачи (TaskStat.DoneCnt)"); } if (!SQL_Query(db,"update Tasks set DoneCnt=DoneCnt+1 where ID=%d",TaskID)) { write_log(IP,"Невозможно обновить статистику задачи (Tasks.DoneCnt)"); } } } //!N! //Традиционный-турнир; проверить присланную программу и ответить; //Вход: Score - баллы за задачу // TaskID - ID задачи void HandleProgN(int TaskID, char *fname){ char exename[256]; int res, abort_code; int num,i; int *IDs, *Nums, *Perc, // Проценты баллов за тесты Sc, Sum, RealSum; // Баллы char buf[256]; char Query[256], q1[256]; // функция компилирует программу fname, возвращает exename. В случае ошибки // отсылает сообщения и завершает работу программы DoCompile(fname, exename); // Статистики пока нет //testing //1. get tests IDs & Nums SQL_Query(db,"select ID,Num,Percent from Tests where TaskID=%d order by Num", TaskID); num = SQL_NumRows(db); if (num == 0){ return; } IDs = malloc(num * sizeof(int)); Nums = malloc(num * sizeof(int)); Perc = calloc(num, sizeof(int)); // calloc - обнуляет память if (!IDs || !Nums || !Perc){ return; } //2.testing // Sum - пока для подсчета процентов за задачу i = 0; Sum = 0; do{ IDs[i] = atol(SQL_Field(db, 1)); if (SQL_Field(db,3)) Perc[i] = atoi(SQL_Field(db, 3)); else Perc[i] = 0; Sum += Perc[i]; Nums[i++] = atoi(SQL_Field(db, 2)); }while (SQL_NextRow(db)); //!N! // Если Sum == 0, то все тесты равнозначимы if (!Sum) for (i = 0; i < num; i++) Perc[i] = 100/num; // processing all test Sum = 0; Sc = 0; RealSum = 0; for (i = 0; i < num; i++){ if (i == num-1) Sc = Score - Sum; else { Sc = Score*Perc[i]/100; Sum += Sc; } res=test(IDs[i],fname,exename,&abort_code,Nums[i]); if(res) { sprintf(buf,"%d",Nums[i]); reply2author(res,buf,abort_code); sprintf(buf,"in test %d",Nums[i]); reply(res,buf); // Изменяется таблица результатов, хотя уже должно стоять 0 за // этот тест (ставится при запуске турнира), при перепроверке // необходимо обновлять sprintf(Query,"update NRes set t%1s%d=0 where RegN=%d", TaskNum, Nums[i], RegN); if (!SQL_Query(db,Query)){ sprintf(LogRecord,"Невозможно обновить запись в NRes: %s",Query); write_log(IP, LogRecord); } /* if (!SQL_Query(db,"insert into NoACMRes values(%d,%d,'%s',%d,0)", RegN, TourID, TaskNum, Nums[i])){ sprintf(LogRecord,"Невозможно добавить запись в NoACmRes, (" "%d,%d,'%s',%d,0)",RegN, TourID, TaskNum, Nums[i]); write_log(IP, LogRecord); } */ } else{ sprintf(LogRecord,"(regn=%d, task=%s) Test is OK: %d",RegN,TaskNum, Nums[i]); write_log(IP,LogRecord); reply2author(OK_TEST1-1+Nums[i],NULL,0); RealSum += Sc; //!N! sprintf(LogRecord,"Tests is OK: %d", Nums[i]); reply(OK_TESTS,LogRecord); sprintf(Query,"update NRes set t%1s%d=%d where RegN=%d", TaskNum, Nums[i], Sc, RegN); if (!SQL_Query(db,Query)){ sprintf(LogRecord,"Невозможно обновить запись в NRes: %s",Query); write_log(IP, LogRecord); } /* SQL_Query(db, "delete from NoACMRes where RegN=%d and TaskNum='%s' and TestNum=%d", RegN, TourID, TaskNum, Nums[i]); if (!SQL_Query(db,"insert into NoACMRes values(%d,%d,'%s',%d,%d)", RegN, TourID, TaskNum, Nums[i], Sc)){ sprintf(LogRecord,"Невозможно добавить запись в NoACMRes, (" "%d,%d,'%s',%d, Sc=%d)",RegN, TourID, TaskNum, Nums[i], Sc); write_log(IP, LogRecord); } */ } } // endfor sprintf(LogRecord,"(regn=%d, task=%s) Баллы за задачу: %d",RegN,TaskNum, RealSum); write_log(IP,LogRecord); reply2author(OK_SCORE, NULL, RealSum); free(IDs); free(Nums); free(Perc); } //вызов компилятора int compile(char *srcname, char *exename, char *errname){ char buf[1024]; int code; sprintf (buf, "%s %s%s %s%s %s%s", lang_Prog, lang_Inp, srcname, lang_Exe, exename, lang_Err, errname); code = system (buf); if (code && code != 127 && code != -1) return 0; else return 1; } //запуск на тест; сравнение с эталоном int test (int TestID, char *fname, char *exe_name, int *abort_code, int TestNum) { FILE *f; char *p; int pid, tmp, tmp1; struct rlimit rlim; char in_name[256]; char out_name[256]; char ptn_name[256]; char buf[1024]; int exitstatus; char LogRecord[256]; *abort_code=0; sprintf(in_name,"%s.inp",fname); sprintf(out_name,"%s.out",fname); sprintf(ptn_name,"%s.ptn",fname); //создать заготовку для out if (!SQL_Query (db, "select InData from Tests where ID=%ld",TestID)) { return; } //copy input data to file f = fopen (in_name, "w"); fwrite (SQL_Field (db, 1), my_strlen (SQL_Field (db, 1)), 1, f); fclose (f); SQL_Close (db); pid = fork (); if (pid == 0){ //Run program open ("/dev/null", O_RDONLY); open ("/dev/null", O_RDONLY); open ("/dev/null", O_RDONLY); // Limits for Data rlim.rlim_cur = 640 * 1024; rlim.rlim_max = 640 * 1024; if (setrlimit (RLIMIT_DATA, &rlim) < 0){ sprintf(LogRecord,"can't set DATA limit to %d",rlim.rlim_cur); write_log("SERVICE",LogRecord); exit (1); } //Limits for CPU rlim.rlim_cur = timelimit; rlim.rlim_max = rlim.rlim_cur + 2; if (setrlimit (RLIMIT_CPU, &rlim) < 0){ sprintf(LogRecord,"can't set CPU limit to %d",rlim.rlim_cur); write_log("SERVICE",LogRecord); exit (1); } //Limits for FSIZE rlim.rlim_cur = fsizelimit; rlim.rlim_max = rlim.rlim_cur; if (setrlimit (RLIMIT_FSIZE, &rlim) < 0){ sprintf(LogRecord,"can't set FSIZE limit to %d",rlim.rlim_cur); write_log("SERVICE",LogRecord); exit (1); } //Limits for NOFILE rlim.rlim_cur = nofilelimit; rlim.rlim_max = rlim.rlim_cur; if (setrlimit (RLIMIT_NOFILE, &rlim) < 0){ sprintf(LogRecord,"can't set NOFILE limit to %d",rlim.rlim_cur); write_log("SERVICE",LogRecord); exit (1); } //Limits for STACK rlim.rlim_cur = stacklimit; rlim.rlim_max = rlim.rlim_cur; if (setrlimit (RLIMIT_STACK, &rlim) < 0){ sprintf(LogRecord,"can't set STACK limit to %d",rlim.rlim_cur); write_log("SERVICE",LogRecord); exit (1); } //Limits NPROC rlim.rlim_cur = nproclimit; rlim.rlim_max = rlim.rlim_cur; if (setrlimit (RLIMIT_NPROC, &rlim) < 0){ sprintf(LogRecord,"can't set NPROC limit to %d",rlim.rlim_cur); write_log("SERVICE",LogRecord); exit (1); } /* if(chroot(workdir)){ sprintf(LogRecord,"can't chroot to %s (errno=%d) %s",workdir,errno,sys_errlist[errno]); write_log("SERVICE",LogRecord); exit (1); } */ //Change I/O (open data files) close (0); close (1); close (2); if (open (in_name, O_RDWR) < 0){ write_log(IP,"can't open file for input"); exit (1); } if (open (out_name, O_RDWR | O_CREAT | O_TRUNC, 00666) < 0){ write_log(IP,"can't open file for output"); exit (1); } if (dup2 (1, 2) < 0){ write_log(IP,"can't dup 1 to 2 file-descriptor"); exit (1); } do{ execl (exe_name, exe_name, 0); }while (errno == EAGAIN); pid = errno; sprintf(LogRecord,"can't exec %s errno=%d",exe_name,errno); write_log(IP,LogRecord); exit(1); } else if (pid > 0){ //Get results open ("/dev/null", O_RDONLY); open ("/dev/null", O_WRONLY); open ("/dev/null", O_WRONLY); if (!(db = SQL_Open (0, "olimpd", 0, "olimp", 3000))) exit (1); //waiting for process wait (&exitstatus); if (WIFEXITED (exitstatus)){ // exit code must be 0 if (WEXITSTATUS (exitstatus)){ *abort_code=WEXITSTATUS(exitstatus); sprintf(LogRecord,"(regn=%d, tasknum=%s) runtime error %d on test %d",RegN,TaskNum,*abort_code,TestNum); write_log(IP,LogRecord); return ERR_ABORT; } //compare out with pattern if (!SQL_Query (db, "select OutData,Type from Tests where ID=%ld",TestID)){ return 1; } if (SQL_Field(db,2) && strlen (SQL_Field (db, 2)) != 0){ //!!! comparing by spec program close (0); sprintf (buf, "%s%s%s %s %s %s", rundir, COMPARE_DIR, SQL_Field(db,2), in_name, out_name, ptn_name); //write_log("COMPARING",buf); /* if (open (out_name, O_RDONLY) < 0){ sprintf(LogRecord, "ПРОВЕРКА ПРОГРАММОЙ: Не могу открыть файл out_name: %s", out_name); write_log(IP, LogRecord); return ERR_UNKNOWN; } */ pid = system (buf); if (pid == -1 || pid == 127){ sprintf(LogRecord, "ПРОВЕРКА ПРОГРАММОЙ: Не могу запустить программу проверки: %s", buf); write_log(IP, LogRecord); return ERR_UNKNOWN; } } else{ //standard comparing f = fopen (ptn_name, "w"); fprintf (f, "%s", SQL_Field (db, 1)); fclose (f); // сохранили шаблон if (!(p = malloc (1024))){ return ERR_NOMEM; } sprintf (p, "%s%s %s %s", rundir, COMPARE_PROGRAM, ptn_name, out_name); pid = system (p); if (pid == -1 || pid == 127){ sprintf(LogRecord,"Can't do system(%s)",p); write_log(IP,LogRecord); free (p); return ERR_UNKNOWN; } free (p); } // else standart comparing if (pid != 0){ sprintf(LogRecord,"(regn=%d, task=%s) Wrong answer: %d",RegN,TaskNum,TestNum); write_log(IP,LogRecord); return ERR_DIFFERENT; } //All is Ok return 0; } else{ //exit by signal if (!WIFSIGNALED (exitstatus)){ sprintf(LogRecord,"(regn=%d, tasknum=%s) unknown error on test %d",RegN,TaskNum,TestNum); write_log(IP,LogRecord); return ERR_UNKNOWN; //??? } switch (WTERMSIG (exitstatus)){ case SIGXCPU: sprintf(LogRecord,"(regn=%d, tasknum=%s) time limit exceed on test %d",RegN,TaskNum,TestNum); write_log(IP,LogRecord); return ERR_XCPU; case SIGSEGV: sprintf(LogRecord,"(regn=%d, tasknum=%s) segmentation fault on test %d",RegN,TaskNum,TestNum); write_log(IP,LogRecord); return ERR_SEGV; case SIGINT: case SIGQUIT: case SIGKILL: case SIGTERM: sprintf(LogRecord,"(regn=%d, tasknum=%s) aborted on test %d",RegN,TaskNum,TestNum); write_log(IP,LogRecord); return ERR_ABORT; default: sprintf(LogRecord,"(regn=%d, tasknum=%s) signal %d on test %d",RegN,TaskNum,WTERMSIG (exitstatus),TestNum); write_log(IP,LogRecord); return WTERMSIG (exitstatus); } } return 0; } else{ //if pid<0 return ERR_UNKNOWN; } } //служебная int my_strlen (char *p){ int i; i = 0; while (*(p++)) i++; return i; } void SendPPID(void) { char str[1024]; // sprintf(str,"%d",getppid()); reply(getppid(),""); write_log("SYSTEM","PPID послан"); }