:pserver:anonymous@cvs.middle-man.sourceforge.net:/cvsroot/middle-man middleman
[middleman.git] / src / log.c
1 /*
2     MiddleMan filtering proxy server
3     Copyright (C) 2002  Jason McLaughlin
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <time.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <sys/file.h>
26 #include <fcntl.h>
27 #include "proto.h"
28
29 #ifdef USE_SYSLOG
30 #include <syslog.h>
31 #endif                          /* USE_SYSLOG */
32
33 int logfd = -1;
34 extern int loglevel;
35 extern char logfile[];
36 extern LOGBUFFER *logbuffer;
37 pthread_mutex_t logfile_lock = PTHREAD_MUTEX_INITIALIZER;
38
39 /*
40 write message to logfile
41 */
42 void putlog(int level, char *fmt, ...)
43 {
44 #ifndef USE_SYSLOG
45         time_t tt;
46         struct tm *tv;
47 #endif
48         va_list valist;
49         char buf[1024], *ptr;
50
51         pthread_mutex_lock(&logfile_lock);
52
53         ptr = buf;
54
55 #ifndef USE_SYSLOG
56         time(&tt);
57         tv = localtime(&tt);
58
59         ptr += strftime(ptr, 24, TIMEFORMAT, tv);
60
61         ptr += sprintf(ptr, " [%u] ", (unsigned int) getpid());
62 #endif
63
64         switch (level) {
65         case MMLOG_REQUEST:
66                 ptr += sprintf(ptr, "request: ");
67                 break;
68         case MMLOG_NETWORK:
69                 ptr += sprintf(ptr, "network: ");
70                 break;
71         case MMLOG_FILTER:
72                 ptr += sprintf(ptr, "url filter: ");
73                 break;
74         case MMLOG_HEADER:
75                 ptr += sprintf(ptr, "header: ");
76                 break;
77         case MMLOG_MIME:
78                 ptr += sprintf(ptr, "mime filter: ");
79                 break;
80         case MMLOG_COOKIE:
81                 ptr += sprintf(ptr, "cooke filter: ");
82                 break;
83         case MMLOG_REDIRECT:
84                 ptr += sprintf(ptr, "redirect: ");
85                 break;
86         case MMLOG_TEMPLATE:
87                 ptr += sprintf(ptr, "template: ");
88                 break;
89         case MMLOG_KEYWORDS:
90                 ptr += sprintf(ptr, "keyword filter: ");
91                 break;
92         case MMLOG_WARN:
93                 ptr += sprintf(ptr, "warning: ");
94                 break;
95         case MMLOG_ERROR:
96                 ptr += sprintf(ptr, "error: ");
97                 break;
98         case MMLOG_DEBUG:
99                 ptr += sprintf(ptr, "debug: ");
100                 break;
101         }
102
103         va_start(valist, fmt);
104         ptr += vsnprintf(ptr, sizeof(buf) - (ptr - buf - 1), fmt, valist);
105         va_end(valist);
106
107         if (level != MMLOG_DEBUG)
108                 logbuffer_add(logbuffer, buf);
109
110         if (!*logfile || !(loglevel & level))
111                 goto out;
112
113         if (*(ptr - 1) != '\n') {
114                 *(ptr++) = '\n';
115                 *ptr = '\0';
116         }
117 #ifdef USE_SYSLOG
118         syslog(LOG_INFO, "%s", buf);
119 #else
120         if (logfd == -1) {
121                 logfd = open(logfile, O_RDWR | O_CREAT, 0644);
122                 if (logfd == -1)
123                         goto out;
124
125                 lseek(logfd, 0, SEEK_END);
126         }
127
128         write(logfd, buf, strlen(buf));
129 #endif
130       out:
131         pthread_mutex_unlock(&logfile_lock);
132 }
133
134 void logbuffer_add(LOGBUFFER * logbuffer, char *msg)
135 {
136         struct LOGBUFFER_LIST *ll;
137
138         pthread_rwlock_wrlock(&logbuffer->lock);
139
140         if (logbuffer->size == 0) {
141                 pthread_rwlock_unlock(&logbuffer->lock);
142
143                 return;
144         }
145
146         ll = xmalloc(sizeof(struct LOGBUFFER_LIST));
147         ll->msg = xstrdup(msg);
148         ll->prev = NULL;
149
150         ll->next = logbuffer->head;
151         if (logbuffer->head != NULL)
152                 logbuffer->head->prev = ll;
153         if (logbuffer->tail == NULL)
154                 logbuffer->tail = ll;
155
156         logbuffer->head = ll;
157
158         if (logbuffer->entries == logbuffer->size) {
159                 /* remove last log entry if we're at the size limit */
160                 ll = logbuffer->tail;
161
162                 logbuffer->tail = ll->prev;
163                 ll->prev->next = NULL;
164
165                 xfree(ll->msg);
166                 xfree(ll);
167         } else
168                 logbuffer->entries++;
169
170         pthread_rwlock_unlock(&logbuffer->lock);
171 }
172
173 void logbuffer_clear(LOGBUFFER * logbuffer)
174 {
175         struct LOGBUFFER_LIST *ll, *tmp;
176
177         pthread_rwlock_wrlock(&logbuffer->lock);
178
179         ll = logbuffer->head;
180         logbuffer->head = NULL;
181         logbuffer->tail = NULL;
182         logbuffer->entries = 0;
183
184         while (ll != NULL) {
185                 tmp = ll->next;
186
187                 xfree(ll->msg);
188                 xfree(ll);
189
190                 ll = tmp;
191         }
192
193         pthread_rwlock_unlock(&logbuffer->lock);
194 }
195
196 /*
197 reduce number of entries to logbuffer->size
198 */
199 void logbuffer_resize(LOGBUFFER * logbuffer, int size)
200 {
201         int x;
202         struct LOGBUFFER_LIST *ll, *tmp;
203
204         if (size < 0)
205                 return;
206
207         pthread_rwlock_wrlock(&logbuffer->lock);
208
209         ll = logbuffer->head;
210
211         for (x = 0; x < size && ll != NULL; x++, ll = ll->next);
212         if (ll != NULL) {
213                 if (logbuffer->head == ll)
214                         logbuffer->head = NULL;
215                 logbuffer->tail = ll->prev;
216
217                 if (ll->prev != NULL)
218                         ll->prev->next = NULL;
219
220                 while (ll != NULL) {
221                         tmp = ll->next;
222
223                         xfree(ll->msg);
224                         xfree(ll);
225
226                         ll = tmp;
227                 }
228
229                 logbuffer->entries = size;
230         }
231
232         logbuffer->size = size;
233
234         pthread_rwlock_unlock(&logbuffer->lock);
235 }