/*
* SARG Squid Analysis Report Generator http://sarg.sourceforge.net
- * 1998, 2012
+ * 1998, 2015
*
* SARG donations:
* please look at http://sarg.sourceforge.net/donations.php
#include "include/conf.h"
#include "include/defs.h"
+#if defined(__MINGW32__) && defined(HAVE_DIRECT_H)
+#define NO_OLDNAMES 1
+#include <direct.h>
+#endif
+
#if defined(HAVE_BACKTRACE)
#define USE_GETWORD_BACKTRACE 1
#else
//! The list of the HTTP codes to exclude from the report.
static char *excludecode=NULL;
+//! Directory where the images are stored.
+char ImageDir[MAXLEN]=IMAGEDIR;
+
+extern char *CurrentLocale;
+
#if USE_GETWORD_BACKTRACE
static void getword_backtrace(void)
{
if (n<=0) return;
calls=backtrace_symbols(buffer,n);
if (calls) {
- debuga(_("getword backtrace:\n"));
+ debuga(__FILE__,__LINE__,_("getword backtrace:\n"));
for (i=0 ; i<n ; i++) {
fprintf(stderr,"SARG: %d:%s\n",i+1,calls[i]);
}
void getword_restart(struct getwordstruct *gwarea)
{
if (gwarea->modified) {
- debuga(_("Cannot parse again the line as it was modified\n"));
+ debuga(__FILE__,__LINE__,_("Cannot parse again the line as it was modified\n"));
exit(EXIT_FAILURE);
}
gwarea->current=gwarea->beginning;
for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
if(x>=limit) {
- printf("SARG: getword loop detected after %d bytes.\n",x);
- printf("SARG: Line=\"%s\"\n",gwarea->beginning);
- printf("SARG: Record=\"%s\"\n",gwarea->current);
- printf("SARG: searching for \'x%x\'\n",stop);
- //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
+ /*
+ TRANSLATORS: The %s is the name of the function reporting the
+ error message.
+ */
+ debuga(__FILE__,__LINE__,_("End of word not found in %s after %d bytes.\n"),__func__,x);
+ debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
+ debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
+ debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
word[(limit>0) ? limit-1 : 0]='\0';
#if USE_GETWORD_BACKTRACE
getword_backtrace();
for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
if(x>=limit) {
- printf("SARG: getword_multisep loop detected.\n");
- printf("SARG: Line=\"%s\"\n",gwarea->beginning);
- printf("SARG: Record=\"%s\"\n",gwarea->current);
- printf("SARG: searching for \'x%x\'\n",stop);
- //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
+ debuga(__FILE__,__LINE__,_("End of word not found in %s after %d bytes.\n"),__func__,x);
+ debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
+ debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
+ debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
if (limit>0) word[limit-1]='\0';
#if USE_GETWORD_BACKTRACE
getword_backtrace();
for(x=0;(gwarea->current[x] && (gwarea->current[x] != stop ));x++) {
if(x>=limit) {
- printf("SARG: getword_skip loop detected after %d bytes.\n",x);
- printf("SARG: Line=\"%s\"\n",gwarea->beginning);
- printf("SARG: Record=\"%s\"\n",gwarea->current);
- printf("SARG: searching for \'x%x\'\n",stop);
- //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
+ debuga(__FILE__,__LINE__,_("End of word not found in %s after %d bytes.\n"),__func__,x);
+ debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
+ debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
+ debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
#if USE_GETWORD_BACKTRACE
getword_backtrace();
#endif
for(x=0;isdigit(gwarea->current[x]);x++) {
digit=gwarea->current[x]-'0';
if (*number >= (LLONG_MAX-digit)/10) {
- debuga(_("Integer overflow detected in getword_atoll in line %s\n"),gwarea->beginning);
+ /*
+ TRANSLATORS: The first %s is the function name (in the source code) where the
+ overflow is detected.
+ */
+ debuga(__FILE__,__LINE__,_("Integer overflow detected in %s in line %s\n"),__func__,gwarea->beginning);
return(-1);
}
*number=(*number * 10) + digit;
}
if(gwarea->current[x] && gwarea->current[x]!=stop) {
- printf("SARG: getword_atoll loop detected after %d bytes.\n",x);
- printf("SARG: Line=\"%s\"\n",gwarea->beginning);
- printf("SARG: Record=\"%s\"\n",gwarea->current);
- printf("SARG: searching for \'x%x\'\n",stop);
- //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
+ /*
+ TRANSLATORS: The %s is the function name, in the source code, where the problem occured.
+ */
+ debuga(__FILE__,__LINE__,_("End of number not found in %s after %d bytes.\n"),__func__,x);
+ debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
+ debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
+ debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
#if USE_GETWORD_BACKTRACE
getword_backtrace();
#endif
for(x=0;isdigit(gwarea->current[x]);x++) {
digit=gwarea->current[x]-'0';
if (*number > (INT_MAX-digit)/10) {
- debuga(_("Integer overflow detected in getword_atoi in line %s\n"),gwarea->beginning);
+ debuga(__FILE__,__LINE__,_("Integer overflow detected in %s in line %s\n"),__func__,gwarea->beginning);
return(-1);
}
*number=(*number * 10) + digit;
}
if(gwarea->current[x] && gwarea->current[x]!=stop) {
- printf("SARG: getword_atoi loop detected after %d bytes.\n",x);
- printf("SARG: Line=\"%s\"\n",gwarea->beginning);
- printf("SARG: Record=\"%s\"\n",gwarea->current);
- printf("SARG: searching for \'x%x\'\n",stop);
- //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
+ debuga(__FILE__,__LINE__,_("End of number not found in %s after %d bytes.\n"),__func__,x);
+ debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
+ debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
+ debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
#if USE_GETWORD_BACKTRACE
getword_backtrace();
#endif
return(0);
}
+int getword_atol(long int *number, struct getwordstruct *gwarea, char stop)
+{
+ int x;
+ long int sign=+1;
+ int digit;
+
+ if (gwarea->current[0] == '-') {
+ gwarea->current++;
+ sign=-1;
+ } else if (gwarea->current[0] == '+') {
+ gwarea->current++;
+ }
+ *number=0;
+ for(x=0;isdigit(gwarea->current[x]);x++) {
+ digit=gwarea->current[x]-'0';
+ if (*number > (LONG_MAX-digit)/10) {
+ debuga(__FILE__,__LINE__,_("Integer overflow detected in %s in line %s\n"),__func__,gwarea->beginning);
+ return(-1);
+ }
+ *number=(*number * 10) + digit;
+ }
+ if(gwarea->current[x] && gwarea->current[x]!=stop) {
+ debuga(__FILE__,__LINE__,_("End of number not found in %s after %d bytes.\n"),__func__,x);
+ debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
+ debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
+ debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
+#if USE_GETWORD_BACKTRACE
+ getword_backtrace();
+#endif
+ return(-1);
+ }
+ *number*=sign;
+
+ if (gwarea->current[x]) ++x;
+ gwarea->current+=x;
+ return(0);
+}
+
+int getword_atolu(unsigned long int *number, struct getwordstruct *gwarea, char stop)
+{
+ int x;
+ int digit;
+
+ if (gwarea->current[0] == '-') {
+ debuga(__FILE__,__LINE__,_("getword_atolu got a negative number.\n"));
+ debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
+ debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
+ return(-1);
+ }
+ if (gwarea->current[0] == '+') {
+ gwarea->current++;
+ }
+ *number=0;
+ for(x=0;isdigit(gwarea->current[x]);x++) {
+ digit=gwarea->current[x]-'0';
+ if (*number > (ULONG_MAX-digit)/10) {
+ debuga(__FILE__,__LINE__,_("Integer overflow detected in %s in line %s\n"),__func__,gwarea->beginning);
+ return(-1);
+ }
+ *number=(*number * 10) + digit;
+ }
+ if(gwarea->current[x] && gwarea->current[x]!=stop) {
+ debuga(__FILE__,__LINE__,_("End of number not found in %s after %d bytes.\n"),__func__,x);
+ debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
+ debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
+ debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
+#if USE_GETWORD_BACKTRACE
+ getword_backtrace();
+#endif
+ return(-1);
+ }
+
+ if (gwarea->current[x]) ++x;
+ gwarea->current+=x;
+ return(0);
+}
+
int getword_ptr(char *orig_line,char **word, struct getwordstruct *gwarea, char stop)
{
int start;
if (orig_line && orig_line!=gwarea->beginning) {
- debuga(_("Invalid buffer passed to getword_ptr\n"));
+ debuga(__FILE__,__LINE__,_("Invalid buffer passed to getword_ptr\n"));
return(-1);
}
int is_absolute(const char *path)
{
if (*path=='/') return(1);
-#ifdef WINDOWS
+#ifdef _WIN32
if (isalpha(path[0]) && path[1]==':') return(1);
#endif
return(0);
}
+int PortableMkDir(const char *path,int mode)
+{
+#if defined(__linux__)
+ int mkerror=mkdir(path,mode);
+#else //mingw
+ (void)mode;
+ int mkerror=_mkdir(path);
+#endif
+ return(mkerror);
+}
+
void my_mkdir(const char *name)
{
char w0[MAXLEN];
int chars;
if(!is_absolute(name)) {
- debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name);
- debuga(_("process aborted.\n"));
+ debuga(__FILE__,__LINE__,_("Invalid path (%s). Please, use absolute paths only.\n"),name);
exit(EXIT_FAILURE);
}
chars=0;
for (i=0 ; name[i] ; i++) {
if (i>=sizeof(w0)) {
- debuga(_("directory name too long: %s\n"),name);
+ debuga(__FILE__,__LINE__,_("Path too long: "));
+ debuga_more("%s\n",name);
exit(EXIT_FAILURE);
}
if (chars>0 && name[i] == '/') {
w0[i] = '\0';
if (access(w0, R_OK) != 0) {
- if (mkdir(w0,0755)) {
- debuga(_("Cannot create directory %s - %s\n"),w0,strerror(errno));
- debuga(_("process aborted.\n"));
+ if (PortableMkDir(w0,0755)) {
+ debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),w0,strerror(errno));
exit(EXIT_FAILURE);
}
}
}
if (access(name, R_OK) != 0) {
- if (mkdir(name,0755)) {
- debuga(_("Cannot create directory %s - %s\n"),name,strerror(errno));
- debuga(_("process aborted.\n"));
+ if (PortableMkDir(name,0755)) {
+ debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),name,strerror(errno));
exit(EXIT_FAILURE);
}
}
ssize--;
if (len>ssize) {
- debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len,ssize);
+ debuga(__FILE__,__LINE__,_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len,ssize);
abort();
}
return(year*10000+month*100+day);
}
+/*!
+Compare two dates.
+
+\param date1 The first date to compare.
+\param date2 The second date to compare.
+
+\retval -1 If date1<date2.
+\retval 0 If date1==date2.
+\retval 1 if date1>date2.
+*/
+int compare_date(struct tm *date1,struct tm *date2)
+{
+ if (date1->tm_year<date2->tm_year) return(-1);
+ if (date1->tm_year>date2->tm_year) return(1);
+ if (date1->tm_mon<date2->tm_mon) return(-1);
+ if (date1->tm_mon>date2->tm_mon) return(1);
+ if (date1->tm_mday<date2->tm_mday) return(-1);
+ if (date1->tm_mday>date2->tm_mday) return(1);
+ if (date1->tm_hour<date2->tm_hour) return(-1);
+ if (date1->tm_hour>date2->tm_hour) return(1);
+ if (date1->tm_min<date2->tm_min) return(-1);
+ if (date1->tm_min>date2->tm_min) return(1);
+ if (date1->tm_sec<date2->tm_sec) return(-1);
+ if (date1->tm_sec>date2->tm_sec) return(1);
+ return(0);
+}
-void buildymd(const char *dia, const char *mes, const char *ano, char *wdata)
+void buildymd(const char *dia, const char *mes, const char *ano, char *wdata,int wdata_size)
{
int nmes;
nmes=month2num(mes);
- sprintf(wdata,"%04d%02d%02d",atoi(ano),nmes+1,atoi(dia));
+ snprintf(wdata,wdata_size,"%04d%02d%02d",atoi(ano),nmes+1,atoi(dia));
}
return(mtab1[month-1]);
}
+/*!
+Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
-void name_month(char *month,int month_len)
+\param msg The printf like message to format.
+\param ... The arguments to format in the message.
+*/
+void debuga(const char *File,int Line,const char *msg,...)
{
- int x, z=atoi(month)-1;
- char m[255];
- char w[20];
- struct getwordstruct gwarea;
-
- strcpy(m,_("January,February,March,April,May,June,July,August,September,October,November,December"));
- getword_start(&gwarea,m);
+ va_list ap;
- for(x=0; x<z; x++)
- if (getword_multisep(w,sizeof(w),&gwarea,',')<0) {
- printf("SARG: Maybe you have a broken record or garbage in the names of the months.\n");
- exit(EXIT_FAILURE);
- }
- if (getword_multisep(month,month_len,&gwarea,',')<0) {
- printf("SARG: Maybe you have a broken record or garbage in the name of the months.\n");
- exit(EXIT_FAILURE);
+ if (debugz>=LogLevel_Source) {
+ /* The path is removed because every source file is in the same directory.
+ * There is no point in reporting the full path from the build directory.
+ */
+ const char *ptr=strrchr(File,'/');
+ if (!ptr) ptr=File;
+ /* TRANSLATORS: This is the prefix to stderr messages when the debug level is
+ set to display the source file (%s) and the line number (%d). */
+ fprintf(stderr,_("SARG(%s:%d): "),ptr,Line);
+ } else {
+ /* TRANSLATORS: This is the prefix to stderr messages when the debug level
+ is low. */
+ fputs(_("SARG: "),stderr);
}
+ va_start(ap,msg);
+ vfprintf(stderr,msg,ap);
+ va_end(ap);
}
-
/*!
-Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
+Write a debug message to stderr. The message is supposed
+to be displayed after a message from debuga().
\param msg The printf like message to format.
\param ... The arguments to format in the message.
*/
-void debuga(const char *msg,...)
+void debuga_more(const char *msg,...)
{
va_list ap;
- fputs(_("SARG: "),stderr);
va_start(ap,msg);
vfprintf(stderr,msg,ap);
va_end(ap);
}
-
/*!
Write a debug message to stderr. The message is prefixed by "SARG: (info)".
\param msg The printf like message to format.
\param ... The arguments to format in the message.
*/
-void debugaz(const char *msg,...)
+void debugaz(const char *File,int Line,const char *msg,...)
{
va_list ap;
- fputs(_("SARG: (info) "),stderr);
+ if (debugz>=LogLevel_Source) {
+ /* The path is removed because every source file is in the same directory.
+ * There is no point in reporting the full path from the build directory.
+ */
+ const char *ptr=strrchr(File,'/');
+ if (!ptr) ptr=File;
+ /* TRANSLATORS: This is the prefix to information messages when the debug level is
+ set to display the source file (%s) and the line number (%d). */
+ fprintf(stderr,_("SARG(%s:%d): (info) "),ptr,Line);
+ } else {
+ /* TRANSLATORS: This is the prefix to information messages when the debug level
+ is low. */
+ fputs(_("SARG: (info) "),stderr);
+ }
va_start(ap,msg);
vfprintf(stderr,msg,ap);
va_end(ap);
char *pret;
register int i, j, k;
int numlen;
- static char abbrev[30];
+ static char abbrev[30]="";
my_lltoa(value, num, sizeof(num), 0);
if(DisplayedValues==DISPLAY_ABBREV) {
numlen = strlen(num);
if(numlen <= 3)
- sprintf(abbrev,"%s",num);
- if(numlen == 4 || numlen == 7 || numlen == 10 || numlen == 13) {
- snprintf(abbrev,2,"%s",num);
- strncat(abbrev,".",1);
- strncat(abbrev,num+1,2);
- if(!n) return(abbrev);
- if(numlen == 4)
- strncat(abbrev,"K",1);
- else if(numlen == 7)
- strncat(abbrev,"M",1);
- else if(numlen == 10)
- strncat(abbrev,"G",1);
- else if(numlen == 13)
- strncat(abbrev,"T",1);
- }
- if(numlen == 5 || numlen == 8 || numlen == 11 || numlen == 14) {
- snprintf(abbrev,3,"%s",num);
- strncat(abbrev,".",1);
- strncat(abbrev,num+2,2);
- if(!n) return(abbrev);
- if(numlen == 5)
- strncat(abbrev,"K",1);
- else if(numlen == 8)
- strncat(abbrev,"M",1);
- else if(numlen == 11)
- strncat(abbrev,"G",1);
- else if(numlen == 14)
- strncat(abbrev,"T",1);
- }
- if(numlen == 6 || numlen == 9 || numlen == 12 || numlen == 15) {
- snprintf(abbrev,4,"%s",num);
- strncat(abbrev,".",1);
- strncat(abbrev,num+3,2);
- if(!n) return(abbrev);
- if(numlen == 6)
- strncat(abbrev,"K",1);
- else if(numlen == 9)
- strncat(abbrev,"M",1);
- else if(numlen == 12)
- strncat(abbrev,"G",1);
- else if(numlen == 15)
- strncat(abbrev,"T",1);
+ strcpy(abbrev,num);
+ else if (numlen%3 == 1) {
+ abbrev[0]=num[0];
+ abbrev[1]=(UseComma) ? ',' : '.';
+ abbrev[2]=num[1];
+ abbrev[3]=num[2];
+ abbrev[4]='\0';
+ }
+ else if (numlen%3 == 2) {
+ abbrev[0]=num[0];
+ abbrev[1]=num[1];
+ abbrev[2]=(UseComma) ? ',' : '.';
+ abbrev[3]=num[2];
+ abbrev[4]=num[3];
+ abbrev[5]='\0';
+ }
+ else if (numlen%3 == 0) {
+ abbrev[0]=num[0];
+ abbrev[1]=num[1];
+ abbrev[2]=num[2];
+ abbrev[3]=(UseComma) ? ',' : '.';
+ abbrev[4]=num[3];
+ abbrev[5]=num[4];
+ abbrev[6]='\0';
+ }
+ if (n) {
+ if (numlen <= 3) {
+ //no prefix
+ }
+ else if (numlen <= 6)
+ strcat(abbrev,"K");
+ else if (numlen <= 9)
+ strcat(abbrev,"M");
+ else if (numlen <= 12)
+ strcat(abbrev,"G");
+ else if (numlen <= 15)
+ strcat(abbrev,"T");
+ else if (numlen >= 18)
+ strcat(abbrev,"P");
+ else if (numlen <= 21)
+ strcat(abbrev,"E");
+ else if (numlen <= 24)
+ strcat(abbrev,"Z");
+ else if (numlen <= 27)
+ strcat(abbrev,"Y");
+ else
+ strcat(abbrev,"???");
}
-
return(abbrev);
}
- bzero(buf, MAXLEN_FIXNUM*2);
+ memset(buf,0,MAXLEN_FIXNUM*2);
pbuf = buf;
pret = ret;
register int i, j, k;
my_lltoa(value, num, sizeof(num), 0);
- bzero(buf, MAXLEN_FIXNUM2*2);
+ memset(buf,0,MAXLEN_FIXNUM2*2);
pbuf = buf;
pret = ret;
char *buildtime(long long int elap)
{
- int num = elap / 1000;
+ long int num = elap / 1000LL;
int hor = 0;
int min = 0;
int sec = 0;
- static char buf[12];
+ static char buf[20];
- buf[0]='\0';
-
- hor=num / 3600;
- min=(num % 3600) / 60;
- sec=num % 60;
- sprintf(buf,"%02d:%02d:%02d",hor,min,sec);
+ hor=num / 3600L;
+ min=(num % 3600L) / 60L;
+ sec=num % 60L;
+ snprintf(buf,sizeof(buf),"%02d:%02d:%02d",hor,min,sec);
return(buf);
}
FILE *fp_in;
char wdir[MAXLEN];
- sprintf(wdir,"%s%s/sarg-date",dirname,name);
+ if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-date",dirname,name)>=sizeof(wdir)) {
+ debuga(__FILE__,__LINE__,_("Buffer too small to store "));
+ debuga_more("%s%s/sarg-date",dirname,name);
+ exit(EXIT_FAILURE);
+ }
if ((fp_in = fopen(wdir, "rt")) == 0) {
- sprintf(wdir,"%s%s/date",dirname,name);
+ if (snprintf(wdir,sizeof(wdir),"%s%s/date",dirname,name)>=sizeof(wdir)) {
+ debuga(__FILE__,__LINE__,_("Buffer too small to store "));
+ debuga_more("%s%s/date",dirname,name);
+ exit(EXIT_FAILURE);
+ }
if ((fp_in = fopen(wdir, "rt")) == 0) {
data[0]='\0';
return(-1);
}
if (!fgets(data,80,fp_in)) {
- debuga(_("Failed to read the date in %s\n"),wdir);
+ debuga(__FILE__,__LINE__,_("Failed to read the date in file \"%s\"\n"),wdir);
+ exit(EXIT_FAILURE);
+ }
+ if (fclose(fp_in)==EOF) {
+ debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wdir,strerror(errno));
exit(EXIT_FAILURE);
}
- fclose(fp_in);
fixendofline(data);
return(0);
char tuser[20];
int nuser;
- sprintf(wdir,"%s%s/sarg-users",dirname,name);
+ if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-users",dirname,name)>=sizeof(wdir)) {
+ debuga(__FILE__,__LINE__,_("Buffer too small to store "));
+ debuga_more("%s%s/sarg-users",dirname,name);
+ exit(EXIT_FAILURE);
+ }
if((fp_in=fopen(wdir,"r"))==NULL) {
- sprintf(wdir,"%s%s/users",dirname,name);
+ if (snprintf(wdir,sizeof(wdir),"%s%s/users",dirname,name)>=sizeof(wdir)) {
+ debuga(__FILE__,__LINE__,_("Buffer too small to store "));
+ debuga_more("%s%s/users",dirname,name);
+ exit(EXIT_FAILURE);
+ }
if((fp_in=fopen(wdir,"r"))==NULL) {
return(0);
}
}
if (!fgets(tuser,sizeof(tuser),fp_in)) {
- debuga(_("Failed to read the number of users in %s\n"),wdir);
+ debuga(__FILE__,__LINE__,_("Failed to read the number of users in file \"%s\"\n"),wdir);
+ exit(EXIT_FAILURE);
+ }
+ if (fclose(fp_in)==EOF) {
+ debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wdir,strerror(errno));
exit(EXIT_FAILURE);
}
- fclose(fp_in);
nuser=atoi(tuser);
return(nuser);
void obttotal(const char *dirname, const char *name, int nuser, long long int *tbytes, long long int *media)
{
- FILE *fp_in;
+ FileObject *fp_in;
char *buf;
char wdir[MAXLEN];
char user[MAX_USER_LEN];
*tbytes=0;
*media=0;
- sprintf(wdir,"%s%s/sarg-general",dirname,name);
- if ((fp_in = fopen(wdir, "r")) == 0) {
- sprintf(wdir,"%s%s/general",dirname,name);
- if ((fp_in = fopen(wdir, "r")) == 0) {
+ if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-general",dirname,name)>=sizeof(wdir)) {
+ debuga(__FILE__,__LINE__,_("Buffer too small to store "));
+ debuga_more("%s%s/sarg-general",dirname,name);
+ exit(EXIT_FAILURE);
+ }
+ if ((fp_in = FileObject_Open(wdir)) == NULL) {
+ if (snprintf(wdir,sizeof(wdir),"%s%s/general",dirname,name)>=sizeof(wdir)) {
+ debuga(__FILE__,__LINE__,_("Buffer too small to store "));
+ debuga_more("%s%s/general",dirname,name);
+ exit(EXIT_FAILURE);
+ }
+ if ((fp_in = FileObject_Open(wdir)) == NULL) {
return;
}
}
if ((line=longline_create())==NULL) {
- debuga(_("Not enough memory to read the file %s\n"),wdir);
+ debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),wdir);
exit(EXIT_FAILURE);
}
continue;
getword_start(&gwarea,buf);
if (getword(user,sizeof(user),&gwarea,sep)<0) {
- debuga(_("There is a invalid user in file %s\n"),wdir);
+ debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),wdir);
exit(EXIT_FAILURE);
}
if(strcmp(user,"TOTAL") != 0)
continue;
if (getword_skip(MAXLEN,&gwarea,sep)<0) {
- debuga(_("There a broken total number of access in file %s\n"),wdir);
+ debuga(__FILE__,__LINE__,_("Invalid total number of accesses in file \"%s\"\n"),wdir);
exit(EXIT_FAILURE);
}
if (getword_atoll(tbytes,&gwarea,sep)<0) {
- debuga(_("There is a broken number of bytes in file %s\n"),wdir);
+ debuga(__FILE__,__LINE__,_("Invalid number of bytes in file \"%s\"\n"),wdir);
exit(EXIT_FAILURE);
}
break;
}
- fclose(fp_in);
+ if (FileObject_Close(fp_in)) {
+ debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wdir,FileObject_GetLastCloseError());
+ exit(EXIT_FAILURE);
+ }
longline_destroy(&line);
if (nuser <= 0)
period->end.tm_year=(duntil/10000)-1900;
}
+/*!
+Update the \a main period to encompass the period in \a candidate.
+*/
+void getperiod_merge(struct periodstruct *main,struct periodstruct *candidate)
+{
+ int cdate;
+ int mdate;
+
+ mdate=(main->start.tm_year)*10000+(main->start.tm_mon)*100+main->start.tm_mday;
+ cdate=(candidate->start.tm_year)*10000+(candidate->start.tm_mon)*100+candidate->start.tm_mday;
+ if (cdate<mdate) memcpy(&main->start,&candidate->start,sizeof(struct tm));
+
+ mdate=(main->end.tm_year)*10000+(main->end.tm_mon)*100+main->end.tm_mday;
+ cdate=(candidate->end.tm_year)*10000+(candidate->end.tm_mon)*100+candidate->end.tm_mday;
+ if (cdate>mdate) memcpy(&main->end,&candidate->end,sizeof(struct tm));
+}
+
int getperiod_buildtext(struct periodstruct *period)
{
int i;
int range;
char text1[40], text2[40];
- if(df[0]=='u') {
+ if (df=='u') {
i=strftime(text1, sizeof(text1), "%Y %b %d", &period->start);
- }else if(df[0]=='e') {
+ } else if(df=='e') {
i=strftime(text1, sizeof(text1), "%d %b %Y", &period->start);
- } else /*if(df[0]=='w')*/ {
+ } else /*if (df=='w')*/ {
IndexTree=INDEX_TREE_FILE;
i=strftime(text1, sizeof(text1), "%Y.%U", &period->start);
}
period->start.tm_mon!=period->end.tm_mon ||
period->start.tm_mday!=period->end.tm_mday);
if (range) {
- if(df[0]=='u') {
+ if (df=='u') {
i=strftime(text2, sizeof(text2)-i, "%Y %b %d", &period->end);
- } else if(df[0]=='e') {
+ } else if (df=='e') {
i=strftime(text2, sizeof(text2)-i, "%d %b %Y", &period->end);
} else {
i=strftime(text2, sizeof(text2)-i, "%Y.%U", &period->end);
{
FILE *img_in, *img_ou;
char images[512];
- char imgdir[MAXLEN];
char srcfile[MAXLEN];
char dstfile[MAXLEN];
DIR *dirp;
struct stat info;
if (snprintf(images,sizeof(images),"%simages",outdir)>=sizeof(images)) {
- debuga(_("Cannot copy images to target directory %simages\n"),outdir);
+ debuga(__FILE__,__LINE__,_("Cannot copy images to target directory %simages\n"),outdir);
exit(EXIT_FAILURE);
}
if (access(images,R_OK)!=0) {
- if (mkdir(images,0755)) {
- debuga(_("Cannot create directory %s - %s\n"),images,strerror(errno));
+ if (PortableMkDir(images,0755)) {
+ debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),images,strerror(errno));
exit(EXIT_FAILURE);
}
}
- strcpy(imgdir,IMAGEDIR);
- dirp = opendir(imgdir);
+ dirp = opendir(ImageDir);
if(dirp==NULL) {
- debuga(_("(util) Can't open directory %s: %s\n"),imgdir,strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),ImageDir,strerror(errno));
return;
}
while ((direntp = readdir( dirp )) != NULL ){
if(direntp->d_name[0]=='.')
continue;
- sprintf(srcfile,"%s/%s",imgdir,direntp->d_name);
+ if (snprintf(srcfile,sizeof(srcfile),"%s/%s",ImageDir,direntp->d_name)>=sizeof(srcfile)) {
+ debuga(__FILE__,__LINE__,_("Buffer too small to store "));
+ debuga_more("%s/%s",ImageDir,direntp->d_name);
+ exit(EXIT_FAILURE);
+ }
if (stat(srcfile,&info)) {
- debuga(_("Cannot stat \"%s\" - %s\n"),srcfile,strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),srcfile,strerror(errno));
continue;
}
if (S_ISREG(info.st_mode)) {
- sprintf(dstfile,"%s/%s",images,direntp->d_name);
+ if (snprintf(dstfile,sizeof(dstfile),"%s/%s",images,direntp->d_name)>=sizeof(dstfile)) {
+ debuga(__FILE__,__LINE__,_("Buffer too small to store "));
+ debuga_more("%s/%s",images,direntp->d_name);
+ exit(EXIT_FAILURE);
+ }
img_in = fopen(srcfile, "rb");
if(img_in!=NULL) {
img_ou = fopen(dstfile, "wb");
if(img_ou!=NULL) {
while ((nread = fread(buffer,1,sizeof(buffer),img_in))>0) {
if (fwrite(buffer,1,nread,img_ou)!=nread) {
- debuga(_("Failed to copy image %s to %s\n"),srcfile,dstfile);
+ debuga(__FILE__,__LINE__,_("Failed to copy image %s to %s\n"),srcfile,dstfile);
break;
}
}
- fclose(img_ou);
+ if (fclose(img_ou)==EOF) {
+ debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),dstfile,strerror(errno));
+ exit(EXIT_FAILURE);
+ }
} else
- fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile, strerror(errno));
- fclose(img_in);
+ debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"), dstfile, strerror(errno));
+ if (fclose(img_in)==EOF) {
+ debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),srcfile,strerror(errno));
+ exit(EXIT_FAILURE);
+ }
} else
- fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile, strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"), srcfile, strerror(errno));
}
}
(void) closedir(dirp);
return;
}
-int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us, const char *form)
+/*!
+ * Check if the proposed file name conforms to the directory structure layed out
+ * as a file tree. It is used to check if the file name enumerated while scanning
+ * a directory content may have been created by sarg running with IndexTree set to
+ * INDEX_TREE_FILE.
+ */
+bool IsTreeFileDirName(const char *Name)
+{
+ char DateFormat;
+ int i;
+
+ // start year (date format u) or start day (date format e)
+ if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+
+ if (isdigit(Name[2]) && isdigit(Name[3]))
+ {
+ // date format is either u or w
+ if (Name[4]=='.')
+ {
+ // date format is w
+ if (!isdigit(Name[5]) || !isdigit(Name[6])) return(false);
+ return(true);//date format w is confirmed
+ }
+
+ // date format is u
+ Name+=4;
+
+ // start month
+ if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
+ for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
+ if (i<0) return(false);
+ Name+=3;
+
+ // start day
+ if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+ Name+=2;
+
+ DateFormat='u';
+ }
+ else if (isalpha(Name[2]) && isalpha(Name[3]) && isalpha(Name[4]))
+ {
+ // date format is e
+ Name+=2;
+
+ // start month
+ if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
+ for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
+ if (i<0) return(false);
+ Name+=3;
+
+ // start day
+ if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
+ Name+=4;
+
+ DateFormat='e';
+ }
+ else
+ return(false);
+
+ if (Name[0]!='-') return(false);
+ Name++;
+
+ if (DateFormat=='u')
+ {
+ if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
+ Name+=4;
+
+ if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
+ for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
+ if (i<0) return(false);
+ Name+=3;
+
+ if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+ Name+=2;
+ }
+ else //DateFormat=='e'
+ {
+ if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+ Name+=2;
+
+ if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
+ for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
+ if (i<0) return(false);
+ Name+=3;
+
+ if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
+ Name+=4;
+ }
+ /*
+ * The directory name may contains additional characters such as a counter if
+ * a previous report is never overwritten.
+ */
+ return(true);
+}
+
+/*!
+ * Check if the proposed file name can be the year part of a report tree build with
+ * IndexTree set to INDEX_TREE_DATE.
+ */
+bool IsTreeYearFileName(const char *Name)
+{
+ if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
+ Name+=4;
+ if (Name[0]=='-')
+ {
+ Name++;
+ if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
+ Name+=4;
+ }
+ if (Name[0]) return(false);
+ return(true);
+}
+
+/*!
+ * Check if the proposed file name can be the month part of a report tree build with
+ * IndexTree set to INDEX_TREE_DATE.
+ */
+bool IsTreeMonthFileName(const char *Name)
+{
+ int m;
+
+ if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+ m=(Name[0]-'0')*10+(Name[1]-'0');
+ if (m<1 || m>12) return(false);
+ Name+=2;
+ if (Name[0]=='-')
+ {
+ Name++;
+ if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+ m=(Name[0]-'0')*10+(Name[1]-'0');
+ if (m<1 || m>12) return(false);
+ Name+=2;
+ }
+ if (Name[0]) return(false);
+ return(true);
+}
+
+/*!
+ * Check if the proposed file name can be the day part of a report tree build with
+ * IndexTree set to INDEX_TREE_DATE.
+ */
+bool IsTreeDayFileName(const char *Name)
+{
+ int d;
+
+ if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+ d=(Name[0]-'0')*10+(Name[1]-'0');
+ if (d<1 || d>31) return(false);
+ if (Name[2]=='-')
+ {
+ Name+=3;
+ if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+ d=(Name[0]-'0')*10+(Name[1]-'0');
+ if (d<1 || d>31) return(false);
+ }
+ /*
+ * The directory name may contains additional characters such as a counter if
+ * a previous report is never overwritten.
+ */
+ return(true);
+}
+
+/*!
+ * Create a directory to generate a report for the specified connection data
+ * and populate it with the a <tt>sarg-date</tt> file containing the current
+ * date.
+ *
+ * The function also create an <tt>images</tt> directory in \a dir and copy all
+ * the files from the <tt>SYSCONFDIR/images</tt> into that directory.
+ *
+ * \param per1 The date range in the form: YYYYMMMDD-YYYYMMMDD or DDMMMYYYY-DDMMMYYYY depending on the value of
+ * ::DateFormat.
+ * \param addr The ip address or host name to which the report is limited. If the string is empty, all the addresses are accepted.
+ * \param site The destination site to which the report is limited. If the string is empty, all the sites are accepted.
+ * \param us The user to whom the report is limited. It is an empty string if all the users are accepted.
+ */
+int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us)
{
FILE *fp_ou;
- int num=1, count=0;
char wdir[MAXLEN];
- char dirname2[MAXLEN];
int y1, y2;
int m1, m2;
int d1, d2;
wlen+=sprintf(wdir+wlen,"/%02d",d1);
if(d1!=d2) wlen+=sprintf(wdir+wlen,"-%02d",d2);
} else {
- if(df[0] == 'u') {
+ if (df == 'u') {
wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%04d%s%02d-%04d%s%02d",y1,
conv_month_name(m1),d1,y2,conv_month_name(m2),d2);
- } else if(df[0] == 'e') {
+ } else if (df == 'e') {
wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%02d%s%04d-%02d%s%04d",d1,
conv_month_name(m1),y1,d2,conv_month_name(m2),y2);
- } else if(df[0] == 'w') {
+ } else if (df == 'w') {
wlen2=strftime(wdir+wlen, sizeof(wdir)-wlen, "%Y.%U", &per1->start);
if (wlen2==0) return(-1);
wlen+=wlen2;
strcpy(outdirname,wdir);
- if(IndexTree != INDEX_TREE_DATE) {
- if(!OverwriteReport) {
- while(num) {
- if(access(wdir,R_OK) == 0) {
- sprintf(wdir,"%s.%d",outdirname,num);
- num++;
- count++;
- } else
- break;
- }
+ // manufacture a new unique name if configured to keep old reports or overwrite old report if configured to do so
+ if (!OverwriteReport) {
+ int num=1;
- if(count > 0) {
- if(debug)
- debuga(_("File %s already exists, moved to %s\n"),outdirname,wdir);
- rename(outdirname,wdir);
- }
- } else {
- if(access(outdirname,R_OK) == 0) {
- unlinkdir(outdirname,1);
- }
+ while (access(wdir,R_OK)==0 || errno==EACCES) //file exist or can't be read
+ {
+ sprintf(wdir,"%s.%d",outdirname,num);
+ num++;
+ }
+ if (num>1) {
+ if(debug)
+ debuga(__FILE__,__LINE__,_("File %s already exists, moved to %s\n"),outdirname,wdir);
+ rename(outdirname,wdir);
}
- my_mkdir(outdirname);
} else {
- strcpy(dirname2,wdir);
- if(!OverwriteReport) {
- while(num) {
- if(access(wdir,R_OK) == 0) {
- sprintf(wdir,"%s.%d",dirname2,num);
- num++;
- count++;
- } else
- break;
- }
-
- if(count > 0) {
- if(debug)
- debuga(_("File %s already exists, moved to %s\n"),dirname2,wdir);
- rename(dirname2,wdir);
- strcpy(dirname2,wdir);
- }
- } else {
- if(access(wdir,R_OK) == 0) {
- unlinkdir(wdir,1);
- }
+ if(access(outdirname,R_OK) == 0) {
+ unlinkdir(outdirname,1);
}
-
- if(access(wdir, R_OK) != 0)
- my_mkdir(wdir);
}
+ my_mkdir(outdirname);
- strcpy(dirname2,wdir);
-
- sprintf(wdir,"%s/sarg-date",outdirname);
+ // create sarg-date to keep track of the report creation date
+ if (snprintf(wdir,sizeof(wdir),"%s/sarg-date",outdirname)>=sizeof(wdir)) {
+ debuga(__FILE__,__LINE__,_("Buffer too small to store "));
+ debuga_more("%s/sarg-date",outdirname);
+ exit(EXIT_FAILURE);
+ }
if ((fp_ou = fopen(wdir, "wt")) == 0) {
- debuga(_("cannot open %s for writing\n"),wdir);
+ debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wdir,strerror(errno));
perror("SARG:");
exit(EXIT_FAILURE);
}
loctm=localtime(&curtime);
strftime(wdir,sizeof(wdir),"%Y-%m-%d %H:%M:%S",loctm);
if (fprintf(fp_ou,"%s %d\n",wdir,loctm->tm_isdst)<0) {
- debuga(_("Failed to write the date in %s\n"),wdir);
+ debuga(__FILE__,__LINE__,_("Failed to write the date in %s\n"),wdir);
perror("SARG:");
exit(EXIT_FAILURE);
}
if (fclose(fp_ou)==EOF) {
- debuga(_("Failed to write the date in %s\n"),wdir);
- perror("SARG:");
+ debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),wdir,strerror(errno));
exit(EXIT_FAILURE);
}
/*!
Copy a string without overflowing the buffer. The copied string
is properly terminated by an ASCII zero.
-
+
\param dest The destination buffer.
\param src The source buffer.
\param length The size of the destination buffer. The program is aborted
void safe_strcpy(char *dest,const char *src,int length)
{
if (length<=0) {
- debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
+ debuga(__FILE__,__LINE__,_("Invalid buffer length passed to the function to safely copy a string\n"));
exit(EXIT_FAILURE);
}
strncpy(dest,src,length-1);
return;
}
-void zdate(char *ftime,int ftimesize, const char *DateFormat)
+void zdate(char *ftime,int ftimesize, char DateFormat)
{
time_t t;
struct tm *local;
t = time(NULL);
local = localtime(&t);
- if(strcmp(DateFormat,"u") == 0)
+ if (DateFormat=='u')
strftime(ftime, ftimesize, "%b/%d/%Y %H:%M", local);
- if(strcmp(DateFormat,"e") == 0)
+ else if (DateFormat=='e')
strftime(ftime, ftimesize, "%d/%b/%Y-%H:%M", local);
- if(strcmp(DateFormat,"w") == 0)
+ else if (DateFormat=='w')
strftime(ftime, ftimesize, "%W-%H-%M", local);
return;
}
char *fixtime(long long int elap)
{
- int num = elap / 1000;
+ long int num = elap / 1000LL;
int hor = 0;
int min = 0;
int sec = 0;
- static char buf[12];
+ static char buf[20];
- hor=num / 3600;
- min=(num % 3600) / 60;
- sec=num % 60;
+ hor=num / 3600L;
+ min=(num % 3600L) / 60L;
+ sec=num % 60L;
if(hor==0 && min==0 && sec==0)
strcpy(buf,"0");
else
- sprintf(buf,"%d:%02d:%02d",hor,min,sec);
+ snprintf(buf,sizeof(buf),"%d:%02d:%02d",hor,min,sec);
return buf;
}
-void date_from(char *date, int *dfrom, int *duntil)
+void date_from(char *date,int date_size, int *dfrom, int *duntil)
{
int d0=0;
int m0=0;
int next=-1;
if (sscanf(date,"%d/%d/%d%n",&d0,&m0,&y0,&next)!=3 || y0<100 || m0<1 || m0>12 || d0<1 || d0>31 || next<0) {
- debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
+ debuga(__FILE__,__LINE__,_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
exit(EXIT_FAILURE);
}
if (date[next]=='-') {
if (sscanf(date+next+1,"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
- debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
+ debuga(__FILE__,__LINE__,_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
exit(EXIT_FAILURE);
}
} else if (date[next]!='\0') {
- debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
+ debuga(__FILE__,__LINE__,_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
exit(EXIT_FAILURE);
} else {
d1=d0;
struct tm *Date0,Date1;
if (time(&Today)==(time_t)-1) {
- debuga(_("Failed to get the current time\n"));
+ debuga(__FILE__,__LINE__,_("Failed to get the current time\n"));
exit(EXIT_FAILURE);
}
if (sscanf(date,"day-%d",&i)==1) {
if (i<0) {
- debuga(_("Invalid number of days in -d parameter\n"));
+ debuga(__FILE__,__LINE__,_("Invalid number of days in -d parameter\n"));
exit(EXIT_FAILURE);
}
Today-=i*24*60*60;
Date0=localtime(&Today);
if (Date0==NULL) {
- debuga(_("Cannot convert local time: %s\n"),strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
exit(EXIT_FAILURE);
}
y0=y1=Date0->tm_year+1900;
time_t WeekBegin;
if (i<0) {
- debuga(_("Invalid number of weeks in -d parameter\n"));
+ debuga(__FILE__,__LINE__,_("Invalid number of weeks in -d parameter\n"));
exit(EXIT_FAILURE);
}
Date0=localtime(&Today);
if (Date0==NULL) {
- debuga(_("Cannot convert local time: %s\n"),strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
exit(EXIT_FAILURE);
}
WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
WeekBegin-=i*7*24*60*60;
Date0=localtime(&WeekBegin);
if (Date0==NULL) {
- debuga(_("Cannot convert local time: %s\n"),strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
exit(EXIT_FAILURE);
}
y0=Date0->tm_year+1900;
WeekBegin+=6*24*60*60;
Date0=localtime(&WeekBegin);
if (Date0==NULL) {
- debuga(_("Cannot convert local time: %s\n"),strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
exit(EXIT_FAILURE);
}
y1=Date0->tm_year+1900;
d1=Date0->tm_mday;
} else if (sscanf(date,"month-%d",&i)==1) {
if (i<0) {
- debuga(_("Invalid number of months in -d parameter\n"));
+ debuga(__FILE__,__LINE__,_("Invalid number of months in -d parameter\n"));
exit(EXIT_FAILURE);
}
Date0=localtime(&Today);
if (Date0==NULL) {
- debuga(_("Cannot convert local time: %s\n"),strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
exit(EXIT_FAILURE);
}
if (Date0->tm_mon<i%12) {
m1=Date0->tm_mon+1;
d1=Date0->tm_mday;
} else {
- debuga(_("Invalid date range passed on command line\n"));
+ debuga(__FILE__,__LINE__,_("Invalid date range passed on command line\n"));
exit(EXIT_FAILURE);
}
}
*dfrom=y0*10000+m0*100+d0;
*duntil=y1*10000+m1*100+d1;
- sprintf(date,"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
+ snprintf(date,date_size,"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
return;
}
return;
if(debug) {
- debuga(_("Purging temporary file sarg-general\n"));
+ debuga(__FILE__,__LINE__,_("Purging temporary file sarg-general\n"));
}
if (snprintf(filename,sizeof(filename),"%s/sarg-general",outdir)>=sizeof(filename)) {
- debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir);
+ debuga(__FILE__,__LINE__,_("Path too long: "));
+ debuga_more("%s/sarg-period\n",outdir);
exit(EXIT_FAILURE);
}
if((fp_gen=fopen(filename,"w"))==NULL){
- debuga(_("(removetmp) Cannot open file %s\n"),filename);
+ debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),filename,strerror(errno));
exit(EXIT_FAILURE);
}
totalger(fp_gen,filename);
if (fclose(fp_gen)==EOF) {
- debuga(_("Failed to close %s after writing the total line - %s\n"),filename,strerror(errno));
+ debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),filename,strerror(errno));
exit(EXIT_FAILURE);
}
}
return;
if((fp_in=fopen(ExcludeCodes,"r"))==NULL) {
- debuga(_("(util) Cannot open file %s (exclude_codes)\n"),ExcludeCodes);
+ debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
exit(EXIT_FAILURE);
}
if (fseek(fp_in, 0, SEEK_END)==-1) {
- debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
+ debuga(__FILE__,__LINE__,_("Failed to move till the end of file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
exit(EXIT_FAILURE);
}
MemSize = ftell(fp_in);
if (MemSize<0) {
- debuga(_("Cannot get the size of file %s\n"),ExcludeCodes);
+ debuga(__FILE__,__LINE__,_("Cannot get the size of file \"%s\"\n"),ExcludeCodes);
exit(EXIT_FAILURE);
}
if (fseek(fp_in, 0, SEEK_SET)==-1) {
- debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
+ debuga(__FILE__,__LINE__,_("Failed to rewind file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
exit(EXIT_FAILURE);
}
MemSize+=1;
if((excludecode=(char *) malloc(MemSize))==NULL) {
- debuga(_("malloc error (%ld)\n"),MemSize);
+ debuga(__FILE__,__LINE__,_("malloc error (%ld bytes required)\n"),MemSize);
exit(EXIT_FAILURE);
}
memset(excludecode,0,MemSize);
for (i=strlen(data)-1 ; i>=0 && (unsigned char)data[i]<=' ' ; i--) data[i]='\0';
if (i<0) continue;
if (Stored+i+2>=MemSize) {
- debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes);
+ debuga(__FILE__,__LINE__,_("Too many codes to exclude in file \"%s\"\n"),ExcludeCodes);
break;
}
strcat(excludecode,data);
Stored+=i+1;
}
- fclose(fp_in);
+ if (fclose(fp_in)==EOF) {
+ debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),ExcludeCodes,strerror(errno));
+ exit(EXIT_FAILURE);
+ }
return;
}
return 0;
}
-
-char *get_size(const char *path, const char *file)
-{
- FILE *fp;
- static char response[255];
- char cmd[255];
- char *ptr;
-
- if (snprintf(cmd,sizeof(cmd),"du -skh %s%s",path,file)>=sizeof(cmd)) {
- debuga(_("Cannot get disk space because the path %s%s is too long\n"),path,file);
- exit(EXIT_FAILURE);
- }
- if ((fp = popen(cmd, "r")) == NULL) {
- debuga(_("Cannot get disk space with command %s\n"),cmd);
- exit(EXIT_FAILURE);
- }
- if (!fgets(response, sizeof(response), fp)) {
- debuga(_("Cannot get disk size with command %s\n"),cmd);
- exit(EXIT_FAILURE);
- }
- ptr=strchr(response,'\t');
- if (ptr==NULL) {
- debuga(_("The command %s failed\n"),cmd);
- exit(EXIT_FAILURE);
- }
- pclose(fp);
- *ptr='\0';
-
- return (response);
-}
-
void show_info(FILE *fp_ou)
{
char ftime[127];
if(!ShowSargInfo) return;
- zdate(ftime, sizeof(ftime), DateFormat);
- fprintf(fp_ou,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL,PGM,VERSION,_("on"),ftime);
+ zdate(ftime, sizeof(ftime), df);
+ fputs("<div class=\"info\">",fp_ou);
+ fprintf(fp_ou,_("Generated by <a href=\"%s\">%s-%s</a> on %s"),URL,PGM,VERSION,ftime);
+ fputs("</div>\n",fp_ou);
}
void show_sarg(FILE *fp_ou, int depth)
fputs("</table></div>\n",fp_ou);
}
-int write_html_trailer(FILE *fp_ou)
+void write_html_trailer(FILE *fp_ou)
{
show_info(fp_ou);
- if (fputs("</body>\n</html>\n",fp_ou)==EOF) return(-1);
- return(0);
+ fputs("</body>\n</html>\n",fp_ou);
}
void output_html_string(FILE *fp_ou,const char *str,int maxlen)
Write a host name inside an A tag of a HTML file. If the host name starts
with a star, it is assumed to be an alias that cannot be put inside a link
so the A tag is not written around the host name.
-
+
\param fp_ou The handle of the HTML file.
\param url The host to display in the HTML file.
\param maxlen The maximum number of characters to print into the host name.
w2[x]='\0';
}
-void url_to_file(const char *url,char *file,int filesize)
+/*!
+Mangle an URL to produce a part that can be used as an anchor in
+a html <a name=""> tag.
+
+\param url The URL to mangle.
+\param anchor The buffer to write the mangled URL.
+\param size The size of the buffer.
+*/
+void url_to_anchor(const char *url,char *anchor,int size)
{
- int i,skip;
+ int i,j;
+ bool skip;
- filesize--;
- skip=0;
- for(i=0; i<filesize && *url; url++) {
- if(isalnum(*url) || *url=='-' || *url=='_' || *url=='.' || *url=='%') {
- file[i++]=*url;
- skip=0;
+ // find url end
+ for (i=0 ; url[i] && url[i]!='/' && url[i]!='?' ; i++);
+ i--;
+ if (i<=0) {
+ anchor[0]='\0';
+ return;
+ }
+
+ // only keep really safe characters
+ skip=false;
+ j=size-1;
+ anchor[j]='\0';
+ while (j>0 && i>=0)
+ {
+ if(isalnum(url[i]) || url[i]=='-' || url[i]=='_' || url[i]=='.') {
+ anchor[--j]=url[i];
+ skip=false;
} else {
- if (!skip) file[i++]='_';
- skip=1;
+ if (!skip) anchor[--j]='_';
+ skip=true;
}
+ i--;
+ }
+ if (j>0)
+ {
+ while ( anchor[j])
+ {
+ *anchor=anchor[j];
+ anchor++;
+ }
+ *anchor='\0';
}
- file[i]='\0';
}
void version(void)
{
printf(_("SARG Version: %s\n"),VERSION);
+#if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
+ if (debug) {
+ printf(_("\nFor the translation to work, a valid message file should be copied to "
+ "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR,PACKAGE_NAME);
+ if (CurrentLocale) {
+ printf(_("Currently effective locale is \"%s\".\n"),CurrentLocale);
+ } else {
+ printf(_("Locale is not set in the environment variable.\n"));
+ }
+ // TRANSLATORS: You may change this message to tell the reader that the language is correctly supported.
+ printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
+ }
+#endif
+ if (debug) {
+#ifdef HAVE_GLOB_H
+ printf(_("File globbing compiled in.\n"));
+#else
+ printf(_("File globbing NOT compiled in.\n"));
+#endif
+ }
exit(EXIT_SUCCESS);
}
return(line);
}
-void unlinkdir(const char *dir,int contentonly)
+void unlinkdir(const char *dir,bool contentonly)
{
struct stat st;
DIR *dirp;
(direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
continue;
if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
- debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
+ debuga(__FILE__,__LINE__,_("Path too long: "));
+ debuga_more("%s/%s\n",dir,direntp->d_name);
exit(EXIT_FAILURE);
}
#ifdef HAVE_LSTAT
err=stat(dname,&st);
#endif
if (err) {
- debuga(_("cannot stat %s\n"),dname);
+ debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
exit(EXIT_FAILURE);
}
if (S_ISREG(st.st_mode)) {
if (unlink(dname)) {
- debuga(_("cannot delete %s - %s\n"),dname,strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
exit(EXIT_FAILURE);
}
} else if (S_ISDIR(st.st_mode)) {
unlinkdir(dname,0);
} else {
- debuga(_("unknown path type %s\n"),dname);
+ debuga(__FILE__,__LINE__,_("Don't know how to delete \"%s\" (not a regular file nor a directory)\n"),dname);
}
}
closedir(dirp);
if (!contentonly) {
if (rmdir(dir)) {
- debuga(_("cannot delete %s - %s\n"),dir,strerror(errno));
+ debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),dir,strerror(errno));
exit(EXIT_FAILURE);
}
}
}
+/*!
+Delete every file from the temporary directory where sarg is told to store its
+temporary files.
+
+As any stray file left over by a previous run would be included in the report, we
+must delete every file from the temporary directory before we start processing the logs.
+
+But the temporary directory is given by the user either in the configuration file or
+on the command line. We check that the user didn't give a wrong directory by looking
+at the files stored in the directory. If a single file is not one of ours, we abort.
+
+\param dir The temporary directory to purge.
+*/
+void emptytmpdir(const char *dir)
+{
+ struct stat st;
+ DIR *dirp;
+ struct dirent *direntp;
+ int dlen;
+ int elen;
+ char dname[MAXLEN];
+ int err;
+ int i;
+ static const char *TmpExt[]=
+ {
+ ".int_unsort",
+ ".int_log",
+ ".day",
+ "htmlrel.txt",
+ ".user_unsort",
+ ".user_log",
+ ".utmp",
+ ".ip",
+ "lastlog1",
+ "lastlog",
+ "emailrep"
+ };
+
+ dirp=opendir(dir);
+ if (!dirp) return;
+
+ // make sure the temporary directory contains only our files
+ while ((direntp = readdir(dirp)) != NULL) {
+ if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
+ (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
+ continue;
+
+ // is it one of our files
+ dlen=strlen(direntp->d_name);
+ for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
+ elen=strlen(TmpExt[i]);
+ if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
+ }
+ if (i<0) {
+ debuga(__FILE__,__LINE__,_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
+ "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
+ "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
+ exit(EXIT_FAILURE);
+ }
+
+ if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
+ debuga(__FILE__,__LINE__,_("Path too long: "));
+ debuga_more("%s/%s\n",dir,direntp->d_name);
+ exit(EXIT_FAILURE);
+ }
+
+#ifdef HAVE_LSTAT
+ err=lstat(dname,&st);
+#else
+ err=stat(dname,&st);
+#endif
+ if (err) {
+ debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) {
+ debuga(__FILE__,__LINE__,_("Unknown path type for \"%s\". Check temporary directory\n"),dname);
+ exit(EXIT_FAILURE);
+ }
+ }
+ rewinddir(dirp);
+
+ // now delete our files
+ while ((direntp = readdir(dirp)) != NULL) {
+ if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
+ (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
+ continue;
+
+ // is it one of our files
+ dlen=strlen(direntp->d_name);
+ for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
+ elen=strlen(TmpExt[i]);
+ if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
+ }
+ if (i<0) {
+ debuga(__FILE__,__LINE__,_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
+ "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
+ "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
+ exit(EXIT_FAILURE);
+ }
+
+ if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
+ debuga(__FILE__,__LINE__,_("Path too long: "));
+ debuga_more("%s/%s\n",dir,direntp->d_name);
+ exit(EXIT_FAILURE);
+ }
+#ifdef HAVE_LSTAT
+ err=lstat(dname,&st);
+#else
+ err=stat(dname,&st);
+#endif
+ if (err) {
+ debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if (S_ISDIR(st.st_mode)) {
+ unlinkdir(dname,0);
+ } else if (S_ISREG(st.st_mode)) {
+ if (unlink(dname)) {
+ debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ debuga(__FILE__,__LINE__,_("Don't know how to delete \"%s\" (not a regular file)\n"),dname);
+ }
+ }
+ closedir(dirp);
+}
+
/*!
Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
prefix size.
\param buf The buffer to parse.
\param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
+ The pointer may be NULL.
\param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
\param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
\param nbits The number of prefix bits for an IP address.
int mask, max_mask;
int pad_pos;
int pad_len;
- int bracket=false;
+ bool bracket=false;
+ bool port=false;
+ bool port_num=0;
// skip leading spaces and tabs
while (*buf && (*buf==' ' || *buf=='\t')) buf++;
-
+
// find out the nature of the pattern
ip_size=0x60 | 0x04;
if (*buf=='[') {
for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && buf[i]!='?' && (!bracket || buf[i]!=']') && ip_size ; i++) {
if (ip_size & 0x04) {
if (isdigit(buf[i])) {
- value4=value4*10+(buf[i]-'0');
- if (value4>0xFFU) ip_size&=~0x04;
+ if (port) {
+ port_num=port_num*10+(buf[i]-'0');
+ if (port_num>65535) ip_size&=~0x04;
+ } else {
+ value4=value4*10+(buf[i]-'0');
+ if (value4>0xFFU) ip_size&=~0x04;
+ }
} else if (buf[i]=='.' && addr_len<4) {
addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
value4=0U;
+ } else if (!port && buf[i]==':') {
+ port=true;
} else {
ip_size&=~0x04;
}
addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
}
if (!ip_size) {
- *text=buf;
- if (bracket) (*text)--;
+ if (text) {
+ *text=buf;
+ if (bracket) (*text)--;
+ }
while ((unsigned char)buf[i]>' ') i++;
if (next) *next=buf+i;
return(1);