Annotation of embedaddon/strongswan/src/libcharon/bus/listeners/file_logger.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012-2015 Tobias Brunner
3: * Copyright (C) 2006 Martin Willi
4: * HSR Hochschule fuer Technik Rapperswil
5: *
6: * This program is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2 of the License, or (at your
9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10: *
11: * This program is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14: * for more details.
15: */
16:
17: #include <stdio.h>
18: #include <string.h>
19: #include <time.h>
20: #include <errno.h>
21: #include <unistd.h>
22: #include <sys/types.h>
23:
24: #include "file_logger.h"
25:
26: #include <daemon.h>
27: #include <threading/mutex.h>
28: #include <threading/rwlock.h>
29:
30: typedef struct private_file_logger_t private_file_logger_t;
31:
32: /**
33: * Private data of a file_logger_t object
34: */
35: struct private_file_logger_t {
36:
37: /**
38: * Public data.
39: */
40: file_logger_t public;
41:
42: /**
43: * File name of the target
44: */
45: char *filename;
46:
47: /**
48: * Current output file
49: */
50: FILE *out;
51:
52: /**
53: * Flush after writing a line?
54: */
55: bool flush_line;
56:
57: /**
58: * Maximum level to log, for each group
59: */
60: level_t levels[DBG_MAX];
61:
62: /**
63: * strftime() format of time prefix, if any
64: */
65: char *time_format;
66:
67: /**
68: * Add milliseconds after the time string
69: */
70: bool add_ms;
71:
72: /**
73: * Print the name/# of the IKE_SA?
74: */
75: bool ike_name;
76:
77: /**
78: * Mutex to ensure multi-line log messages are not torn apart
79: */
80: mutex_t *mutex;
81:
82: /**
83: * Lock to read/write options (FD, levels, time_format, etc.)
84: */
85: rwlock_t *lock;
86: };
87:
88: METHOD(logger_t, log_, void,
89: private_file_logger_t *this, debug_t group, level_t level, int thread,
90: ike_sa_t* ike_sa, const char *message)
91: {
92: char timestr[128], namestr[128] = "";
93: const char *current = message, *next;
94: struct tm tm;
95: timeval_t tv;
96: time_t s;
97: u_int ms = 0;
98:
99: this->lock->read_lock(this->lock);
100: if (!this->out)
101: { /* file is not open */
102: this->lock->unlock(this->lock);
103: return;
104: }
105: if (this->time_format)
106: {
107: gettimeofday(&tv, NULL);
108: s = tv.tv_sec;
109: ms = tv.tv_usec / 1000;
110: localtime_r(&s, &tm);
111: strftime(timestr, sizeof(timestr), this->time_format, &tm);
112: }
113: if (this->ike_name && ike_sa)
114: {
115: if (ike_sa->get_peer_cfg(ike_sa))
116: {
117: snprintf(namestr, sizeof(namestr), " <%s|%d>",
118: ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
119: }
120: else
121: {
122: snprintf(namestr, sizeof(namestr), " <%d>",
123: ike_sa->get_unique_id(ike_sa));
124: }
125: }
126: else
127: {
128: namestr[0] = '\0';
129: }
130:
131: /* prepend a prefix in front of every line */
132: this->mutex->lock(this->mutex);
133: while (TRUE)
134: {
135: next = strchr(current, '\n');
136: if (this->time_format)
137: {
138: if (this->add_ms)
139: {
140: fprintf(this->out, "%s.%03u %.2d[%N]%s ",
141: timestr, ms, thread, debug_names, group, namestr);
142: }
143: else
144: {
145: fprintf(this->out, "%s %.2d[%N]%s ",
146: timestr, thread, debug_names, group, namestr);
147: }
148: }
149: else
150: {
151: fprintf(this->out, "%.2d[%N]%s ",
152: thread, debug_names, group, namestr);
153: }
154: if (next == NULL)
155: {
156: fprintf(this->out, "%s\n", current);
157: break;
158: }
159: fprintf(this->out, "%.*s\n", (int)(next - current), current);
160: current = next + 1;
161: }
162: #ifndef HAVE_SETLINEBUF
163: if (this->flush_line)
164: {
165: fflush(this->out);
166: }
167: #endif /* !HAVE_SETLINEBUF */
168: this->mutex->unlock(this->mutex);
169: this->lock->unlock(this->lock);
170: }
171:
172: METHOD(logger_t, get_level, level_t,
173: private_file_logger_t *this, debug_t group)
174: {
175: level_t level;
176:
177: this->lock->read_lock(this->lock);
178: level = this->levels[group];
179: this->lock->unlock(this->lock);
180: return level;
181: }
182:
183: METHOD(file_logger_t, set_level, void,
184: private_file_logger_t *this, debug_t group, level_t level)
185: {
186: this->lock->write_lock(this->lock);
187: if (group < DBG_ANY)
188: {
189: this->levels[group] = level;
190: }
191: else
192: {
193: for (group = 0; group < DBG_MAX; group++)
194: {
195: this->levels[group] = level;
196: }
197: }
198: this->lock->unlock(this->lock);
199: }
200:
201: METHOD(file_logger_t, set_options, void,
202: private_file_logger_t *this, char *time_format, bool add_ms, bool ike_name)
203: {
204: this->lock->write_lock(this->lock);
205: free(this->time_format);
206: this->time_format = strdupnull(time_format);
207: this->add_ms = add_ms;
208: this->ike_name = ike_name;
209: this->lock->unlock(this->lock);
210: }
211:
212: /**
213: * Close the current file, if any
214: */
215: static void close_file(private_file_logger_t *this)
216: {
217: if (this->out && this->out != stdout && this->out != stderr)
218: {
219: fclose(this->out);
220: this->out = NULL;
221: }
222: }
223:
224: METHOD(file_logger_t, open_, void,
225: private_file_logger_t *this, bool flush_line, bool append)
226: {
227: FILE *file;
228:
229: if (streq(this->filename, "stderr"))
230: {
231: file = stderr;
232: }
233: else if (streq(this->filename, "stdout"))
234: {
235: file = stdout;
236: }
237: else
238: {
239: file = fopen(this->filename, append ? "a" : "w");
240: if (file == NULL)
241: {
242: DBG1(DBG_DMN, "opening file %s for logging failed: %s",
243: this->filename, strerror(errno));
244: return;
245: }
246: #ifdef HAVE_SETLINEBUF
247: if (flush_line)
248: {
249: setlinebuf(file);
250: }
251: #endif /* HAVE_SETLINEBUF */
252: }
253: this->lock->write_lock(this->lock);
254: close_file(this);
255: this->out = file;
256: this->flush_line = flush_line;
257: this->lock->unlock(this->lock);
258: }
259:
260: METHOD(file_logger_t, destroy, void,
261: private_file_logger_t *this)
262: {
263: this->lock->write_lock(this->lock);
264: close_file(this);
265: this->lock->unlock(this->lock);
266: this->mutex->destroy(this->mutex);
267: this->lock->destroy(this->lock);
268: free(this->time_format);
269: free(this->filename);
270: free(this);
271: }
272:
273: /*
274: * Described in header.
275: */
276: file_logger_t *file_logger_create(char *filename)
277: {
278: private_file_logger_t *this;
279:
280: INIT(this,
281: .public = {
282: .logger = {
283: .log = _log_,
284: .get_level = _get_level,
285: },
286: .set_level = _set_level,
287: .set_options = _set_options,
288: .open = _open_,
289: .destroy = _destroy,
290: },
291: .filename = strdup(filename),
292: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
293: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
294: );
295:
296: set_level(this, DBG_ANY, LEVEL_SILENT);
297:
298: return &this->public;
299: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>