X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=realtime.c;h=cf90e479d9c25842cd3ef53efc11eb9dccfede7e;hb=22774edd6523d566f539f4f633a6f276bfbd6224;hp=9d47fdd4e21b667089c791dff877ed6ffc9b9a69;hpb=ce36c3c71f89165b28f7961477c44efb2f8d0d81;p=thirdparty%2Fsarg.git diff --git a/realtime.c b/realtime.c old mode 100755 new mode 100644 index 9d47fdd..cf90e47 --- a/realtime.c +++ b/realtime.c @@ -1,6 +1,6 @@ /* * SARG Squid Analysis Report Generator http://sarg.sourceforge.net - * 1998, 2010 + * 1998, 2015 * * SARG donations: * please look at http://sarg.sourceforge.net/donations.php @@ -26,270 +26,229 @@ #include "include/conf.h" #include "include/defs.h" +#include "include/filelist.h" +#include "include/readlog.h" -static int getdata(char*, FILE*); -static void datashow(const char *); -static void getlog(void); -static void header(void); +//! Maximum length of the scheme plus host name from the url. +#define MAX_URL_HOST_LEN 260 -void realtime(void) +/*! +\brief Data read from an input log file. +*/ +struct RealtimeReadLogStruct { - - getlog(); - + //! The time corresponding to the entry. + struct tm EntryTime; + //! The IP address connecting to internet. + char Ip[48]; + //! The user's name. + char User[MAX_USER_LEN]; + /*! + The URL of the visited site. + + The pointer may be NULL if the URL doesn't exists in the log file. + */ + char Url[MAX_URL_HOST_LEN]; + //! HTTP method or NULL if the information is not stored in the log. + char HttpMethod[32]; +}; + +extern FileListObject AccessLog; + +static bool GetLatestModified(char *file_name,int file_name_size) +{ + FileListIterator FIter; + const char *file; + bool found=false; + struct stat st; + time_t latest; + + FIter=FileListIter_Open(AccessLog); + while ((file=FileListIter_Next(FIter))!=NULL) + { + if (stat(file,&st)==-1) { + debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),file,strerror(errno)); + } + if (!found) + { + found=true; + latest=st.st_mtime; + safe_strcpy(file_name,file,file_name_size); + } + else if (st.st_mtime>latest) + { + latest=st.st_mtime; + safe_strcpy(file_name,file,file_name_size); + } + } + FileListIter_Close(FIter); + return(found); } -static void getlog(void) +/*! + * \brief Store a log entry. + * + * \param Dest A pointer to the list entry where to store the entry. + * \param Entry The entry to store. + */ +static void StoreLogEntry(struct RealtimeReadLogStruct *Dest,struct ReadLogStruct *Entry) { - FILE *tmp, *fp; - char template1[255]="/var/tmp/sargtpl1.XXXXXX"; - char template2[255]="/var/tmp/sargtpl2.XXXXXX"; - char cmd[512]; - char *buf; - int fd1,fd2; - int cstatus; - longline line; - - init_usertab(UserTabFile); - - fd1 = mkstemp(template1); - fd2 = mkstemp(template2); - - if((fd1 == -1 ) || ((tmp = fdopen (fd1, "w+" )) == NULL) ) { /* failure, bail out */ - debuga(_("(realtime) mkstemp error - %s\n"),strerror(errno)); - exit(EXIT_FAILURE); - } - - if ((line=longline_create())==NULL) { - debuga(_("Not enough memory to read the log file\n")); - exit(EXIT_FAILURE); - } - - sprintf(cmd,"tail -%d \"%s\"",realtime_access_log_lines,AccessLog[0]); - fp = popen(cmd, "r"); - if (!fp) { - debuga(_("Failed to get the %d trailing lines of %s: %s\n"),realtime_access_log_lines,AccessLog[0],strerror(errno)); - debuga(_("tail command: %s\n"),cmd); - exit(EXIT_FAILURE); - } - while((buf=longline_read(fp,line)) != NULL ) - if (getdata(buf,tmp)<0) { - debuga(_("Maybe a broken record or garbage was returned by %s\n"),cmd); - exit(EXIT_FAILURE); - } - pclose(fp); - fclose(tmp); - longline_destroy(&line); - - sprintf(cmd,"sort -r -k 1,1 -k 2,2 -o \"%s\" \"%s\"",template2,template1); - cstatus=system(cmd); - if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) { - debuga(_("sort command return status %d\n"),WEXITSTATUS(cstatus)); - debuga(_("sort command: %s\n"),cmd); - exit(EXIT_FAILURE); - } - unlink(template1); - datashow(template2); + memcpy(&Dest->EntryTime,&Entry->EntryTime,sizeof(Dest->EntryTime)); + safe_strcpy(Dest->Ip,Entry->Ip,sizeof(Dest->Ip)); + if (Entry->Url) + { + int i; + const char *url=Entry->Url; + + // skip the scheme + for (i=0 ; i<8 && url[i] && (isalnum(url[i]) || url[i]=='+' || url[i]=='-' || url[i]=='.') ; i++); + if (url[i]==':' && url[i+1]=='/' && url[i+2]=='/') + { + url+=i+3; + for (i=0 ; url[i] && url[i]!='/' ; i++); + } + if (i>=sizeof(Dest->Url)) i=sizeof(Dest->Url)-1; + strncpy(Dest->Url,url,i); + Dest->Url[i]='\0'; + } + safe_strcpy(Dest->User,Entry->User,sizeof(Dest->User)); + safe_strcpy(Dest->HttpMethod,Entry->HttpMethod,sizeof(Dest->HttpMethod)); } -static int getdata(char *rec, FILE *ftmp) +static void header(void) { - time_t tt; - struct tm *t; - char dat[128]; - char tbuf[128]; - char typ[128]; - char warea[MAXLEN]; - char user[MAX_USER_LEN]; - char ip[25]; - char *url; - struct getwordstruct gwarea; - - getword_start(&gwarea,rec); - if (getword(dat,sizeof(dat),&gwarea,' ')<0) { - debuga(_("The time stamp at column 1 is too long\n")); - return(-1); - } - if (getword(warea,sizeof(warea),&gwarea,' ')<0) { - debuga(_("The connection duration at column 2 is too long\n")); - return(-1); - } - while(strcmp(warea,"") == 0 && gwarea.current[0] != '\0') - if (getword(warea,sizeof(warea),&gwarea,' ')<0) { - return(-1); - } - if (getword(ip,sizeof(ip),&gwarea,' ')<0) { - debuga(_("The IP address at column 3 is too long\n")); - return(-1); - } - if (getword_skip(MAXLEN,&gwarea,' ')<0) { - debuga(_("The status at column 4 is too long\n")); - return(-1); - } - if (getword_skip(MAXLEN,&gwarea,' ')<0) { - debuga(_("The size at column 5 is too long\n")); - return(-1); - } - if (getword(typ,sizeof(typ),&gwarea,' ')<0) { - debuga(_("The action at column 6 is too long\n")); - return(-1); - } - if(strncmp(typ,"CONNECT",7) == 0) { - if (getword_ptr(rec,&url,&gwarea,' ')<0) { - debuga(_("The URL at column 7 is too long\n")); - return(-1); - } - if (getword(user,sizeof(user),&gwarea,' ')<0) { - debuga(_("The user ID at column 8 is too long\n")); - return(-1); - } - }else { - if (getword_skip(MAXLEN,&gwarea,'/')<0) { - debuga(_("The URL at column 7 is too long\n")); - return(-1); - } - if (getword_skip(MAXLEN,&gwarea,'/')<0) { - debuga(_("The URL at column 7 is too long\n")); - return(-1); - } - if (getword_ptr(rec,&url,&gwarea,'/')<0) { - debuga(_("The URL at column 7 is too long\n")); - return(-1); - } - if (getword_skip(MAXLEN,&gwarea,' ')<0) { - debuga(_("The data at column 8 is too long\n")); - return(-1); - } - if (getword(user,sizeof(user),&gwarea,' ')<0) { - debuga(_("The user at column 9 is too long\n")); - return(-1); - } - } - - if(strncmp(user,"-",1) == 0 && RealtimeUnauthRec==REALTIME_UNAUTH_REC_IGNORE) - return(0); - - tt=atoi(dat); - t=localtime(&tt); - if(strncmp(DateFormat,"u",1) == 0) - strftime(tbuf, sizeof(tbuf), "%Y-%m-%d\t%H:%M", t); - else if(strncmp(DateFormat,"e",1) == 0) - strftime(tbuf, sizeof(tbuf), "%d-%m-%Y\t%H:%M", t); - - fprintf(ftmp,"%s\t%s\t%s\t%s\t%s\n",tbuf,ip,user,url,typ); - return(0); + puts("\n"); + puts("\n"); + puts("\n"); + if(realtime_refresh) + printf(" \n",realtime_refresh,CharSet); + else + printf(" \n",CharSet); + css(stdout); + puts("\n"); + printf("\n",FontFace,TitleFontSize,BgColor,BgImage); + puts("
\n"); + printf("\n",_("Realtime")); + printf("\n",_("Auto refresh"),realtime_refresh); + printf("\n",_("DATE/TIME"),_("IP/NAME"),_("USERID"),_("TYPE"),_("ACCESSED SITE")); } -static void datashow(const char *tmp) +static void datashow(struct RealtimeReadLogStruct *List,int Index,int Size) { - FILE *fin; - char dat[128]; - char tim[128]; - char *buf; - char *url; - char *ourl=NULL; - char ouser[MAX_USER_LEN]=""; - char typ[128]; - char user[MAX_USER_LEN]; - char u2[MAX_USER_LEN]; - char ip[25]; - int url_len; - int ourl_size=0; - struct getwordstruct gwarea; - longline line; - - if((fin=fopen(tmp,"r"))==NULL) { - debuga(_("(realtime) open error %s - %s\n"),tmp,strerror(errno)); - exit(EXIT_FAILURE); - } - - header(); - - if ((line=longline_create())==NULL) { - debuga(_("Not enough memory to read the log file\n")); - exit(EXIT_FAILURE); - } - - while((buf=longline_read(fin,line))!=NULL) { - fixendofline(buf); - getword_start(&gwarea,buf); - if (getword(dat,sizeof(dat),&gwarea,'\t')<0) { - debuga(_("Maybe you have a broken record or garbage in your %s file\n"),tmp); - exit(EXIT_FAILURE); - } - if (getword(tim,sizeof(tim),&gwarea,'\t')<0) { - debuga(_("Maybe you have a broken record or garbage in your %s file\n"),tmp); - exit(EXIT_FAILURE); - } - if (getword(ip,sizeof(ip),&gwarea,'\t')<0) { - debuga(_("Maybe you have a broken record or garbage in your %s file\n"),tmp); - exit(EXIT_FAILURE); - } - if (getword(user,sizeof(user),&gwarea,'\t')<0) { - debuga(_("Maybe you have a broken record or garbage in your %s file\n"),tmp); - exit(EXIT_FAILURE); - } - if(strlen(dat) < 3 || strlen(user) < 1) continue; - if (getword_ptr(buf,&url,&gwarea,'\t')<0) { - debuga(_("Maybe you have a broken url in your %s file\n"),tmp); - exit(EXIT_FAILURE); - } - if (getword(typ,sizeof(typ),&gwarea,'\t')<0) { - debuga(_("Maybe you have a broken record or garbage in your %s file\n"),tmp); - exit(EXIT_FAILURE); - } - if(strstr(RealtimeTypes,typ) == 0) - continue; - - if(strcmp(ouser,user) == 0 && ourl && strcmp(ourl,url) == 0) - continue; - - if(UserIp) - strcpy(user,ip); - strcpy(u2,user); - if(Ip2Name) - ip2name(u2,sizeof(u2)); - user_find(name, sizeof(name), u2); - - printf("\n",dat,tim,ip,name,typ,url,url); - strcpy(ouser,user); - - url_len=strlen(url); - if (!ourl || url_len>=ourl_size) { - ourl_size=url_len+1; - ourl=realloc(ourl,ourl_size); - if (!ourl) { - debuga(_("Not enough memory to store the url\n")); - exit(EXIT_FAILURE); - } - } - strcpy(ourl,url); - } - longline_destroy(&line); - if (ourl) free(ourl); - - puts("
SARG %s
%s: %d s
%s%s%s%s%s
%s %s%s%s%s%s
\n
\n\n\n"); - fclose(fin); - unlink(tmp); - fflush(NULL); - + char tbuf[128]; + char user[MAX_USER_LEN]; + char name[MAX_USER_LEN]; + int i; + struct RealtimeReadLogStruct *entry; + + header(); + for (i=0 ; iIp); + else + strcpy(user,entry->User); + if(Ip2Name) + ip2name(user,sizeof(user)); + user_find(name, sizeof(name), user); + + if (df=='u') + strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M", &entry->EntryTime); + else if (df=='e') + strftime(tbuf, sizeof(tbuf), "%d-%m-%Y %H:%M", &entry->EntryTime); + + printf("%s%s%s%s%s\n", + tbuf,entry->Ip,name,entry->HttpMethod,entry->Url,entry->Url); + } + + puts("\n\n\n\n"); + fflush(NULL); } -static void header(void) +void realtime(void) { - puts("\n"); - puts("\n"); - puts("\n"); - if(realtime_refresh) - printf(" \n",realtime_refresh,CharSet); - else - printf(" \n",CharSet); - css(stdout); - puts("\n"); - printf("\n",FontFace,TitleFontSize,BgColor,BgImage); - puts("
\n"); - printf("\n",_("Realtime")); - printf("\n",_("Auto refresh"),realtime_refresh); - printf("\n",_("DATE/TIME"),_("IP/NAME"),_("USERID"),_("TYPE"),_("ACCESSED SITE")); + FileObject *fp; + char file_name[2048]; + char *buf; + longline line; + struct ReadLogStruct log_entry; + enum ReadLogReturnCodeEnum log_entry_status; + struct LogLineStruct log_line; + struct RealtimeReadLogStruct *StoredLogEntries; + int StoreIndex=0; + int StoreSize=0; + int NextIndex=1; + + init_usertab(UserTabFile); + LogLine_Init(&log_line); + + /* + * Store one more entry to prepare the memory structure in place and reject it if + * it is about the same user and url as the last stored one. + */ + StoredLogEntries=calloc(realtime_access_log_lines+1,sizeof(struct RealtimeReadLogStruct)); + if (!StoredLogEntries) + { + debuga(__FILE__,__LINE__,_("Not enough memory to store %d records"),realtime_access_log_lines); + exit(EXIT_FAILURE); + } + /* + * Clear the url and user strings so that strcmp on the user and url are not + * satisfied and the first entry can be stored. + */ + memset(StoredLogEntries,0,sizeof(struct RealtimeReadLogStruct)); + + if (!GetLatestModified(file_name,sizeof(file_name))) + { + debuga(__FILE__,__LINE__,_("No log file to read the last %d lines from\n"),realtime_access_log_lines); + exit(EXIT_FAILURE); + } + fp = FileObject_Open(file_name); + if (!fp) { + debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),file_name,FileObject_GetLastOpenError()); + exit(EXIT_FAILURE); + } + + if ((line=longline_create())==NULL) { + debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),file_name); + exit(EXIT_FAILURE); + } + + while((buf=longline_read(fp,line)) != NULL ) + { + log_entry_status=LogLine_Parse(&log_line,&log_entry,buf); + if (log_entry_status==RLRC_Unknown) + { + continue; + } + if (log_entry_status==RLRC_Ignore) + { + continue; + } + if (log_entry.HttpMethod && strstr(RealtimeTypes,log_entry.HttpMethod)==0) + continue; + if (RealtimeUnauthRec==REALTIME_UNAUTH_REC_IGNORE && log_entry.User[0]=='-' && log_entry.User[1]=='\0') + continue; + StoreLogEntry(StoredLogEntries+NextIndex,&log_entry); + if (strcmp(StoredLogEntries[StoreIndex].User,StoredLogEntries[NextIndex].User)==0 && strcmp(StoredLogEntries[StoreIndex].Url,StoredLogEntries[NextIndex].Url)==0) + continue; + + StoreIndex=NextIndex; + NextIndex++; + if (NextIndex>StoreSize) StoreSize=NextIndex; + if (NextIndex>realtime_access_log_lines) NextIndex=0; + } + if (FileObject_Close(fp)) { + debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),file_name,FileObject_GetLastCloseError()); + exit(EXIT_FAILURE); + } + longline_destroy(&line); + + datashow(StoredLogEntries,StoreIndex,StoreSize); + free(StoredLogEntries); }
SARG %s
%s: %d s
%s%s%s%s%s