Return to file_logger.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / bus / listeners |
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: }