]> git.ipfire.org Git - thirdparty/sarg.git/blob - readlog_common.c
Optimize away a useless strcpy.
[thirdparty/sarg.git] / readlog_common.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2015
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
10 *
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.
15 *
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.
20 *
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.
24 *
25 */
26
27 #include "include/conf.h"
28 #include "include/defs.h"
29 #include "include/readlog.h"
30
31 /*!
32 A new file is being read. The name of the file is \a FileName.
33 */
34 static void Common_NewFile(const char *FileName)
35 {
36 }
37
38 /*!
39 Extract a column containing a long long int from \a Line.
40
41 The extracted value is stored in \a Value.
42
43 The pointer to the next byte just after the number is returned
44 by the function.
45 */
46 static char *Common_GetLongLongInt(char *Line,long long int *Value)
47 {
48 *Value=0LL;
49 if (*Line=='-') {
50 ++Line;
51 } else {
52 while (isdigit(*Line)) *Value=*Value*10+(*Line++-'0');
53 }
54 return(Line);
55 }
56
57 /*!
58 Read one entry from a standard squid log format.
59
60 \param Line One line from the input log file.
61 \param Entry Where to store the information parsed from the line.
62
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.
66 */
67 static enum ReadLogReturnCodeEnum Common_ReadEntry(char *Line,struct ReadLogStruct *Entry)
68 {
69 const char *Begin;
70 int IpLen;
71 int HttpCodeLen;
72 int UrlLen;
73 int UserLen;
74 int Day;
75 char MonthName[4];
76 int MonthNameLen;
77 int Month;
78 int Year;
79 int Hour;
80 int Minute;
81 int Second;
82 char *Ip;
83 char *User;
84
85 // get IP address
86 Entry->Ip=Ip=Line;
87 for (IpLen=0 ; *Line && *Line!=' ' ; IpLen++) Line++;
88 if (*Line!=' ' || IpLen==0) return(RLRC_Unknown);
89
90 if (!squid24) {
91 // squid version <= 2.4 store the user ID in the second column: skip the first column here
92 Begin=++Line;
93 while (*Line && *Line!=' ') Line++;
94 if (*Line!=' '|| Line==Begin) return(RLRC_Unknown);
95 }
96
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);
101
102 if (squid24) {
103 // squid version > 2.4 store the user ID in the first column: skip the second column here
104 Begin=++Line;
105 while (*Line && *Line!=' ') Line++;
106 if (*Line!=' '|| Line==Begin) return(RLRC_Unknown);
107 }
108
109 // get the date enclosed within square brackets
110 ++Line;
111 if (*Line!='[') return(RLRC_Unknown);
112 ++Line;
113 Day=0;
114 while (isdigit(*Line)) Day=Day*10+(*Line++-'0');
115 if (*Line!='/' || Day<1 || Day>31) return(RLRC_Unknown);
116
117 ++Line;
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);
123
124 ++Line;
125 Year=0;
126 while (isdigit(*Line)) Year=Year*10+(*Line++-'0');
127 if (*Line!=':' || Year<1900 || Year>2200) return(RLRC_Unknown);
128
129 // get the time
130 ++Line;
131 Hour=0;
132 while (isdigit(*Line)) Hour=Hour*10+(*Line++-'0');
133 if (*Line!=':' || Hour>=24) return(RLRC_Unknown);
134 ++Line;
135 Minute=0;
136 while (isdigit(*Line)) Minute=Minute*10+(*Line++-'0');
137 if (*Line!=':' || Minute>=60) return(RLRC_Unknown);
138 ++Line;
139 Second=0;
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
142
143 // skip the timezone up to the closing ]
144 while (*Line && *Line!=']') Line++;
145 if (*Line!=']') return(RLRC_Unknown);
146
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;
154
155 // the URL is enclosed between double qhotes
156 ++Line;
157 if (*Line!=' ') return(RLRC_Unknown);
158 ++Line;
159 if (*Line!='\"') return(RLRC_Unknown);
160
161 // skip the HTTP function
162 Begin=++Line;
163 while (isalpha(*Line)) Line++;
164 if (*Line!=' ' || Line==Begin) return(RLRC_Unknown);
165
166 // get the URL
167 Entry->Url=++Line;
168 for (UrlLen=0 ; *Line && *Line!=' ' ; UrlLen++) Line++;
169 if (*Line!=' ' || UrlLen==0) return(RLRC_Unknown);
170
171 // skip the HTTP/...
172 ++Line;
173 while (*Line && *Line!='\"') Line++;
174 if (*Line!='\"') return(RLRC_Unknown);
175 ++Line;
176 if (*Line!=' ') return(RLRC_Unknown);
177
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);
182
183 // get the number of transfered bytes.
184 Begin=++Line;
185 Line=Common_GetLongLongInt(Line,&Entry->DataSize);
186 // some log contains more columns
187 if ((*Line && *Line!=' ') || Begin==Line) return(RLRC_Unknown);
188
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);
193 }
194
195 // it is safe to alter the line buffer now that we are returning a valid entry
196 Ip[IpLen]='\0';
197 Entry->HttpCode[HttpCodeLen]='\0';
198 Entry->Url[UrlLen]='\0';
199 User[UserLen]='\0';
200
201 return(RLRC_NoError);
202 }
203
204 //! \brief Object to read a standard common log format.
205 const struct ReadLogProcessStruct ReadCommonLog=
206 {
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"),
209 Common_NewFile,
210 Common_ReadEntry
211 };