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>