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>