]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/logger.c
ipsec-164.10.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / logger.c
1 /* $KAME: logger.c,v 1.9 2002/09/03 14:37:03 itojun Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/stat.h>
37
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <errno.h>
42 #ifdef HAVE_STDARG_H
43 #include <stdarg.h>
44 #else
45 #include <varargs.h>
46 #endif
47 #if TIME_WITH_SYS_TIME
48 # include <sys/time.h>
49 # include <time.h>
50 #else
51 # if HAVE_SYS_TIME_H
52 # include <sys/time.h>
53 # else
54 # include <time.h>
55 # endif
56 #endif
57
58 #include "logger.h"
59 #include "var.h"
60 #include "gcmalloc.h"
61
62 #define MAX_LOG_FILESIZE_BYTES 2097152 // 2MB
63 #define MAX_LOG_FILESIZE_KBYTES (MAX_LOG_FILESIZE_BYTES/1024)
64 #define MAX_LOG_FILESIZE_MBYTES (MAX_LOG_FILESIZE_BYTES/(1024 * 1024))
65 #define LOG_DISCARD_BYTES (MAX_LOG_FILESIZE_BYTES/3)
66
67 static int log_flush (struct log *p, int newbytes)
68 {
69 struct stat st;
70
71 if (!p || !p->fp) {
72 return -1;
73 }
74
75 if (!p->byteswritten) {
76 bzero(&st, sizeof(st));
77 if (fstat(fileno(p->fp), &st) < 0) {
78 return -1;
79 }
80 if (st.st_size < 0) {
81 return -1;
82 }
83 p->byteswritten = st.st_size;
84 }
85 if (newbytes > 0) {
86 p->byteswritten += newbytes;
87 }
88
89 if (p->byteswritten > MAX_LOG_FILESIZE_BYTES) {
90 // hack to delete the first 1/3 of the file: won't work on some devices because malloc(MAX_LOG_FILESIZE_BYTES) fails
91 char *buf = NULL;
92 size_t discard, saved = 0;
93 FILE *fp;
94
95 // calc how much to seek into the file
96 discard = p->byteswritten/3;
97 if (discard < LOG_DISCARD_BYTES) {
98 discard = LOG_DISCARD_BYTES;
99 }
100 fp = fopen(p->fname, "r");
101 // get a temp buffer to hold the last 2/3 of the file
102 buf = malloc(MAX_LOG_FILESIZE_BYTES);
103 // seek into the file (skipping the first 1/3 of the file)
104 if (fp && buf) {
105 if (fseeko(fp, discard, SEEK_SET) == 0) {
106 // try reading as much as possible.. shouldn't fill up buffer
107 saved = fread(buf, MAX_LOG_FILESIZE_BYTES, sizeof(*buf), fp);
108 // p->byteswritten may be inaccurate (e.g another stream is writing to the file)
109 if (saved == MAX_LOG_FILESIZE_BYTES) {
110 saved = 0;
111 }
112 }
113 }
114 if (fp) {
115 fclose(fp);
116 }
117
118 p->byteswritten = 0;
119 (void)fpurge(p->fp);
120 // delete file and start appending logs again
121 p->fp = freopen(p->fname, "wa", p->fp);
122 if (p->fp == NULL)
123 return -1;
124 fprintf(p->fp, "logfile turned over due to size>%d%s\n",
125 (MAX_LOG_FILESIZE_MBYTES > 0)? MAX_LOG_FILESIZE_MBYTES:MAX_LOG_FILESIZE_KBYTES,
126 (MAX_LOG_FILESIZE_MBYTES > 0)? "MB":"KB");
127 // append some of the previous logs (if successfully we buffered 2/3 of the file)
128 if (buf && saved) {
129 (void)fwrite(buf, saved, sizeof(*buf), p->fp);
130 }
131 if (buf) {
132 free(buf);
133 }
134 }
135 (void)fflush(p->fp);
136 return 0;
137 }
138
139 struct log *
140 log_open(siz, fname)
141 size_t siz;
142 char *fname;
143 {
144 struct log *p;
145
146 p = (struct log *)racoon_malloc(sizeof(*p));
147 if (p == NULL)
148 return NULL;
149 memset(p, 0, sizeof(*p));
150
151 p->buf = (char **)racoon_malloc(sizeof(char *) * siz);
152 if (p->buf == NULL) {
153 racoon_free(p);
154 return NULL;
155 }
156 memset(p->buf, 0, sizeof(char *) * siz);
157
158 p->tbuf = (time_t *)racoon_malloc(sizeof(time_t *) * siz);
159 if (p->tbuf == NULL) {
160 racoon_free(p->buf);
161 racoon_free(p);
162 return NULL;
163 }
164 memset(p->tbuf, 0, sizeof(time_t *) * siz);
165
166 p->siz = siz;
167 if (fname)
168 p->fname = racoon_strdup(fname);
169
170 return p;
171 }
172
173 /*
174 * append string to ring buffer.
175 * string must be \n-terminated (since we add timestamps).
176 * even if not, we'll add \n to avoid formatting mistake (see log_close()).
177 */
178 void
179 log_add(p, str)
180 struct log *p;
181 char *str;
182 {
183 /* syslog if p->fname == NULL? */
184 if (p->buf[p->head])
185 racoon_free(p->buf[p->head]);
186 p->buf[p->head] = racoon_strdup(str);
187 p->tbuf[p->head] = time(NULL);
188 p->head++;
189 p->head %= p->siz;
190 }
191
192 /*
193 * write out string to the log file, as is.
194 * \n-termination is up to the caller. if you don't add \n, the file
195 * format may be broken.
196 */
197 int
198 log_print(p, str)
199 struct log *p;
200 char *str;
201 {
202 int bytes;
203
204 if (p->fname == NULL)
205 return -1; /*XXX syslog?*/
206 if (p->fp == NULL) {
207 p->fp = fopen(p->fname, "a");
208 }
209 if (p->fp == NULL)
210 return -1;
211 bytes = fprintf(p->fp, "%s", str);
212 if (log_flush(p, bytes)) {
213 return -1;
214 }
215
216 return 0;
217 }
218
219 int
220 log_vprint(struct log *p, const char *fmt, ...)
221 {
222 va_list ap;
223 int bytes;
224
225 if (p->fname == NULL)
226 return -1; /*XXX syslog?*/
227 if (p->fp == NULL) {
228 p->fp = fopen(p->fname, "a");
229 }
230 if (p->fp == NULL)
231 return -1;
232 va_start(ap, fmt);
233 bytes = vfprintf(p->fp, fmt, ap);
234 va_end(ap);
235 if (log_flush(p, bytes)) {
236 return -1;
237 }
238
239 return 0;
240 }
241
242 int
243 log_vaprint(struct log *p, const char *fmt, va_list ap)
244 {
245 int bytes;
246
247 if (p->fname == NULL)
248 return -1; /*XXX syslog?*/
249 if (p->fp == NULL) {
250 p->fp = fopen(p->fname, "a");
251 }
252 if (p->fp == NULL)
253 return -1;
254 bytes = vfprintf(p->fp, fmt, ap);
255 if (log_flush(p, bytes)) {
256 return -1;
257 }
258
259 return 0;
260 }
261
262 /*
263 * write out content of ring buffer, and reclaim the log structure
264 */
265 int
266 log_close(p)
267 struct log *p;
268 {
269 int i, j;
270 char ts[256];
271 struct tm *tm;
272 int bytes;
273
274 if (p->fname == NULL)
275 goto nowrite;
276 if (p->fp == NULL) {
277 p->fp = fopen(p->fname, "a");
278 }
279 if (p->fp == NULL)
280 goto nowrite;
281
282 for (i = 0; i < p->siz; i++) {
283 j = (p->head + i) % p->siz;
284 if (p->buf[j]) {
285 tm = localtime(&p->tbuf[j]);
286 strftime(ts, sizeof(ts), "%B %d %T", tm);
287 bytes = fprintf(p->fp, "%s: %s\n", ts, p->buf[j]);
288 (void)log_flush(p, bytes);
289 if (*(p->buf[j] + strlen(p->buf[j]) - 1) != '\n') {
290 bytes = fprintf(p->fp, "\n");
291 (void)log_flush(p, bytes);
292 }
293 }
294 }
295
296 nowrite:
297 log_free(p);
298 return 0;
299 }
300
301 void
302 log_free(p)
303 struct log *p;
304 {
305 int i;
306
307 for (i = 0; i < p->siz; i++)
308 racoon_free(p->buf[i]);
309 racoon_free(p->buf);
310 racoon_free(p->tbuf);
311 if (p->fname)
312 racoon_free(p->fname);
313 if (p->fp) {
314 fclose(p->fp);
315 }
316 racoon_free(p);
317 }
318
319 #ifdef TEST
320 struct log *l;
321
322 void
323 vatest(const char *fmt, ...)
324 {
325 va_list ap;
326 va_start(ap, fmt);
327 log_vaprint(l, fmt, ap);
328 va_end(ap);
329 }
330
331 int
332 main(argc, argv)
333 int argc;
334 char **argv;
335 {
336 int i;
337
338 l = log_open(30, "/tmp/hoge");
339 if (l == NULL)
340 errx(1, "hoge");
341
342 for (i = 0; i < 50; i++) {
343 log_add(l, "foo");
344 log_add(l, "baa");
345 log_add(l, "baz");
346 }
347 log_print(l, "hoge\n");
348 log_vprint(l, "hoge %s\n", "this is test");
349 vatest("%s %s\n", "this is", "vprint test");
350 abort();
351 log_free(l);
352 }
353
354 #endif
355