Annotation of embedaddon/strongswan/src/libcharon/bus/listeners/file_logger.c, revision 1.1.1.2
1.1 misho 1: /*
1.1.1.2 ! misho 2: * Copyright (C) 2012-2020 Tobias Brunner
1.1 misho 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: /**
1.1.1.2 ! misho 78: * Print the log level
! 79: */
! 80: bool log_level;
! 81:
! 82: /**
1.1 misho 83: * Mutex to ensure multi-line log messages are not torn apart
84: */
85: mutex_t *mutex;
86:
87: /**
88: * Lock to read/write options (FD, levels, time_format, etc.)
89: */
90: rwlock_t *lock;
91: };
92:
93: METHOD(logger_t, log_, void,
94: private_file_logger_t *this, debug_t group, level_t level, int thread,
95: ike_sa_t* ike_sa, const char *message)
96: {
1.1.1.2 ! misho 97: char groupstr[5], timestr[128], namestr[128] = "";
1.1 misho 98: const char *current = message, *next;
99: struct tm tm;
100: timeval_t tv;
101: time_t s;
102: u_int ms = 0;
103:
104: this->lock->read_lock(this->lock);
105: if (!this->out)
106: { /* file is not open */
107: this->lock->unlock(this->lock);
108: return;
109: }
1.1.1.2 ! misho 110:
1.1 misho 111: if (this->time_format)
112: {
113: gettimeofday(&tv, NULL);
114: s = tv.tv_sec;
115: ms = tv.tv_usec / 1000;
116: localtime_r(&s, &tm);
117: strftime(timestr, sizeof(timestr), this->time_format, &tm);
118: }
1.1.1.2 ! misho 119:
! 120: if (this->log_level)
! 121: {
! 122: snprintf(groupstr, sizeof(groupstr), "%N%d", debug_names, group,
! 123: level);
! 124: }
! 125: else
! 126: {
! 127: snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group);
! 128: }
! 129:
1.1 misho 130: if (this->ike_name && ike_sa)
131: {
132: if (ike_sa->get_peer_cfg(ike_sa))
133: {
134: snprintf(namestr, sizeof(namestr), " <%s|%d>",
135: ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
136: }
137: else
138: {
139: snprintf(namestr, sizeof(namestr), " <%d>",
140: ike_sa->get_unique_id(ike_sa));
141: }
142: }
143: else
144: {
145: namestr[0] = '\0';
146: }
147:
148: /* prepend a prefix in front of every line */
149: this->mutex->lock(this->mutex);
150: while (TRUE)
151: {
152: next = strchr(current, '\n');
153: if (this->time_format)
154: {
155: if (this->add_ms)
156: {
1.1.1.2 ! misho 157: fprintf(this->out, "%s.%03u %.2d[%s]%s ",
! 158: timestr, ms, thread, groupstr, namestr);
1.1 misho 159: }
160: else
161: {
1.1.1.2 ! misho 162: fprintf(this->out, "%s %.2d[%s]%s ",
! 163: timestr, thread, groupstr, namestr);
1.1 misho 164: }
165: }
166: else
167: {
1.1.1.2 ! misho 168: fprintf(this->out, "%.2d[%s]%s ",
! 169: thread, groupstr, namestr);
1.1 misho 170: }
171: if (next == NULL)
172: {
173: fprintf(this->out, "%s\n", current);
174: break;
175: }
176: fprintf(this->out, "%.*s\n", (int)(next - current), current);
177: current = next + 1;
178: }
179: #ifndef HAVE_SETLINEBUF
180: if (this->flush_line)
181: {
182: fflush(this->out);
183: }
184: #endif /* !HAVE_SETLINEBUF */
185: this->mutex->unlock(this->mutex);
186: this->lock->unlock(this->lock);
187: }
188:
189: METHOD(logger_t, get_level, level_t,
190: private_file_logger_t *this, debug_t group)
191: {
192: level_t level;
193:
194: this->lock->read_lock(this->lock);
195: level = this->levels[group];
196: this->lock->unlock(this->lock);
197: return level;
198: }
199:
200: METHOD(file_logger_t, set_level, void,
201: private_file_logger_t *this, debug_t group, level_t level)
202: {
203: this->lock->write_lock(this->lock);
204: if (group < DBG_ANY)
205: {
206: this->levels[group] = level;
207: }
208: else
209: {
210: for (group = 0; group < DBG_MAX; group++)
211: {
212: this->levels[group] = level;
213: }
214: }
215: this->lock->unlock(this->lock);
216: }
217:
218: METHOD(file_logger_t, set_options, void,
1.1.1.2 ! misho 219: private_file_logger_t *this, char *time_format, bool add_ms, bool ike_name,
! 220: bool log_level)
1.1 misho 221: {
222: this->lock->write_lock(this->lock);
223: free(this->time_format);
224: this->time_format = strdupnull(time_format);
225: this->add_ms = add_ms;
226: this->ike_name = ike_name;
1.1.1.2 ! misho 227: this->log_level = log_level;
1.1 misho 228: this->lock->unlock(this->lock);
229: }
230:
231: /**
232: * Close the current file, if any
233: */
234: static void close_file(private_file_logger_t *this)
235: {
236: if (this->out && this->out != stdout && this->out != stderr)
237: {
238: fclose(this->out);
239: this->out = NULL;
240: }
241: }
242:
243: METHOD(file_logger_t, open_, void,
244: private_file_logger_t *this, bool flush_line, bool append)
245: {
246: FILE *file;
247:
248: if (streq(this->filename, "stderr"))
249: {
250: file = stderr;
251: }
252: else if (streq(this->filename, "stdout"))
253: {
254: file = stdout;
255: }
256: else
257: {
258: file = fopen(this->filename, append ? "a" : "w");
259: if (file == NULL)
260: {
261: DBG1(DBG_DMN, "opening file %s for logging failed: %s",
262: this->filename, strerror(errno));
263: return;
264: }
1.1.1.2 ! misho 265: #ifdef HAVE_CHOWN
! 266: if (lib->caps->check(lib->caps, CAP_CHOWN))
! 267: {
! 268: if (chown(this->filename, lib->caps->get_uid(lib->caps),
! 269: lib->caps->get_gid(lib->caps)) != 0)
! 270: {
! 271: DBG1(DBG_NET, "changing owner/group for '%s' failed: %s",
! 272: this->filename, strerror(errno));
! 273: }
! 274: }
! 275: else
! 276: {
! 277: if (chown(this->filename, -1, lib->caps->get_gid(lib->caps)) != 0)
! 278: {
! 279: DBG1(DBG_NET, "changing group for '%s' failed: %s",
! 280: this->filename, strerror(errno));
! 281: }
! 282: }
! 283: #endif /* HAVE_CHOWN */
1.1 misho 284: #ifdef HAVE_SETLINEBUF
285: if (flush_line)
286: {
287: setlinebuf(file);
288: }
289: #endif /* HAVE_SETLINEBUF */
290: }
291: this->lock->write_lock(this->lock);
292: close_file(this);
293: this->out = file;
294: this->flush_line = flush_line;
295: this->lock->unlock(this->lock);
296: }
297:
298: METHOD(file_logger_t, destroy, void,
299: private_file_logger_t *this)
300: {
301: this->lock->write_lock(this->lock);
302: close_file(this);
303: this->lock->unlock(this->lock);
304: this->mutex->destroy(this->mutex);
305: this->lock->destroy(this->lock);
306: free(this->time_format);
307: free(this->filename);
308: free(this);
309: }
310:
311: /*
312: * Described in header.
313: */
314: file_logger_t *file_logger_create(char *filename)
315: {
316: private_file_logger_t *this;
317:
318: INIT(this,
319: .public = {
320: .logger = {
321: .log = _log_,
322: .get_level = _get_level,
323: },
324: .set_level = _set_level,
325: .set_options = _set_options,
326: .open = _open_,
327: .destroy = _destroy,
328: },
329: .filename = strdup(filename),
330: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
331: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
332: );
333:
334: set_level(this, DBG_ANY, LEVEL_SILENT);
335:
336: return &this->public;
337: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>