2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
6 * please look at http://sarg.sourceforge.net/donations.php
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
27 #include "include/conf.h"
28 #include "include/defs.h"
29 #include "include/readlog.h"
32 A new file is being read. The name of the file is \a FileName.
34 static void Common_NewFile(const char *FileName
)
39 Extract a column containing a long long int from \a Line.
41 The extracted value is stored in \a Value.
43 The pointer to the next byte just after the number is returned
46 static char *Common_GetLongLongInt(char *Line
,long long int *Value
)
52 while (isdigit(*Line
)) *Value
=*Value
*10+(*Line
++-'0');
58 Read one entry from a standard squid log format.
60 \param Line One line from the input log file.
61 \param Entry Where to store the information parsed from the line.
63 \retval RLRC_NoError One valid entry is parsed.
64 \retval RLRC_Unknown The line is invalid.
65 \retval RLRC_InternalError An internal error was encountered.
67 static enum ReadLogReturnCodeEnum
Common_ReadEntry(char *Line
,struct ReadLogStruct
*Entry
)
87 for (IpLen
=0 ; *Line
&& *Line
!=' ' ; IpLen
++) Line
++;
88 if (*Line
!=' ' || IpLen
==0) return(RLRC_Unknown
);
91 // squid version <= 2.4 store the user ID in the second column: skip the first column here
93 while (*Line
&& *Line
!=' ') Line
++;
94 if (*Line
!=' '|| Line
==Begin
) return(RLRC_Unknown
);
97 // the ID of the user or - if the user is unidentified
98 Entry
->User
=User
=++Line
;
99 for (UserLen
=0 ; *Line
&& *Line
!=' ' ; UserLen
++) Line
++;
100 if (*Line
!=' ' || UserLen
==0) return(RLRC_Unknown
);
103 // squid version > 2.4 store the user ID in the first column: skip the second column here
105 while (*Line
&& *Line
!=' ') Line
++;
106 if (*Line
!=' '|| Line
==Begin
) return(RLRC_Unknown
);
109 // get the date enclosed within square brackets
111 if (*Line
!='[') return(RLRC_Unknown
);
114 while (isdigit(*Line
)) Day
=Day
*10+(*Line
++-'0');
115 if (*Line
!='/' || Day
<1 || Day
>31) return(RLRC_Unknown
);
118 for (MonthNameLen
=0 ; MonthNameLen
<sizeof(MonthName
)-1 && isalpha(*Line
) ; MonthNameLen
++) MonthName
[MonthNameLen
]=*Line
++;
119 if (*Line
!='/') return(RLRC_Unknown
);
120 MonthName
[MonthNameLen
]='\0';
121 Month
=month2num(MonthName
);
122 if (Month
>=12) return(RLRC_Unknown
);
126 while (isdigit(*Line
)) Year
=Year
*10+(*Line
++-'0');
127 if (*Line
!=':' || Year
<1900 || Year
>2200) return(RLRC_Unknown
);
132 while (isdigit(*Line
)) Hour
=Hour
*10+(*Line
++-'0');
133 if (*Line
!=':' || Hour
>=24) return(RLRC_Unknown
);
136 while (isdigit(*Line
)) Minute
=Minute
*10+(*Line
++-'0');
137 if (*Line
!=':' || Minute
>=60) return(RLRC_Unknown
);
140 while (isdigit(*Line
)) Second
=Second
*10+(*Line
++-'0');
141 if (*Line
!=' ' || Second
>60) return(RLRC_Unknown
); //second can be 60 due to a leap second
143 // skip the timezone up to the closing ]
144 while (*Line
&& *Line
!=']') Line
++;
145 if (*Line
!=']') return(RLRC_Unknown
);
147 Entry
->EntryTime
.tm_year
=Year
-1900;
148 Entry
->EntryTime
.tm_mon
=Month
;
149 Entry
->EntryTime
.tm_mday
=Day
;
150 Entry
->EntryTime
.tm_hour
=Hour
;
151 Entry
->EntryTime
.tm_min
=Minute
;
152 Entry
->EntryTime
.tm_sec
=Second
;
153 Entry
->EntryTime
.tm_isdst
=-1;
155 // the URL is enclosed between double qhotes
157 if (*Line
!=' ') return(RLRC_Unknown
);
159 if (*Line
!='\"') return(RLRC_Unknown
);
161 // skip the HTTP function
163 while (isalpha(*Line
)) Line
++;
164 if (*Line
!=' ' || Line
==Begin
) return(RLRC_Unknown
);
168 for (UrlLen
=0 ; *Line
&& *Line
!=' ' ; UrlLen
++) Line
++;
169 if (*Line
!=' ' || UrlLen
==0) return(RLRC_Unknown
);
173 while (*Line
&& *Line
!='\"') Line
++;
174 if (*Line
!='\"') return(RLRC_Unknown
);
176 if (*Line
!=' ') return(RLRC_Unknown
);
178 // get the HTTP code.
179 Entry
->HttpCode
=++Line
;
180 for (HttpCodeLen
=0 ; *Line
&& *Line
!=' ' ; HttpCodeLen
++) Line
++;
181 if (*Line
!=' ' || HttpCodeLen
==0) return(RLRC_Unknown
);
183 // get the number of transfered bytes.
185 Line
=Common_GetLongLongInt(Line
,&Entry
->DataSize
);
186 // some log contains more columns
187 if ((*Line
&& *Line
!=' ') || Begin
==Line
) return(RLRC_Unknown
);
189 // check the entry time
190 if (mktime(&Entry
->EntryTime
)==-1) {
191 debuga(__FILE__
,__LINE__
,_("Invalid date or time found in the common log file\n"));
192 return(RLRC_InternalError
);
195 // it is safe to alter the line buffer now that we are returning a valid entry
197 Entry
->HttpCode
[HttpCodeLen
]='\0';
198 Entry
->Url
[UrlLen
]='\0';
201 return(RLRC_NoError
);
204 //! \brief Object to read a standard common log format.
205 const struct ReadLogProcessStruct ReadCommonLog
=
207 /* TRANSLATORS: This is the name of the log format displayed when this format is detected in an input log file. */
208 N_("common log format"),