Coverage Report

Created: 2026-08-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata/src/util-debug.c
Line
Count
Source
1
/* Copyright (C) 2007-2021 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22
 *
23
 * Debug utility functions
24
 */
25
26
#include "suricata-common.h"
27
#include "util-debug.h"
28
29
#include "output.h"
30
31
#include "suricata.h"
32
33
#include "util-conf.h"
34
#include "util-enum.h"
35
#include "util-path.h"
36
#include "util-syslog.h"
37
#include "util-time.h"
38
39
// clang-format off
40
/* holds the string-enum mapping for the enums held in the table SCLogLevel */
41
SCEnumCharMap sc_log_level_map[] = {
42
    { "Not set",        SC_LOG_NOTSET },
43
    { "None",           SC_LOG_NONE },
44
    { "Error",          SC_LOG_ERROR },
45
    { "Warning",        SC_LOG_WARNING },
46
    { "Notice",         SC_LOG_NOTICE },
47
    { "Info",           SC_LOG_INFO },
48
    { "Perf",           SC_LOG_PERF },
49
    { "Config",         SC_LOG_CONFIG },
50
    { "Debug",          SC_LOG_DEBUG },
51
    { NULL,             -1 }
52
};
53
54
SCEnumCharMap sc_log_slevel_map[] = {
55
    { "Not set",        SC_LOG_NOTSET },
56
    { "None",           SC_LOG_NONE },
57
    { "E",              SC_LOG_ERROR },
58
    { "W",              SC_LOG_WARNING },
59
    { "i",              SC_LOG_NOTICE },
60
    { "i",              SC_LOG_INFO },
61
    { "i",              SC_LOG_PERF },
62
    { "i",              SC_LOG_CONFIG },
63
    { "d",              SC_LOG_DEBUG },
64
    { NULL,             -1 }
65
};
66
67
/* holds the string-enum mapping for the enums held in the table SCLogOPIface */
68
SCEnumCharMap sc_log_op_iface_map[ ] = {
69
    { "Console",        SC_LOG_OP_IFACE_CONSOLE },
70
    { "File",           SC_LOG_OP_IFACE_FILE },
71
    { "Syslog",         SC_LOG_OP_IFACE_SYSLOG },
72
    { NULL,             -1 }
73
};
74
// clang-format on
75
76
#if defined (OS_WIN32)
77
/**
78
 * \brief Used for synchronous output on WIN32
79
 */
80
static SCMutex sc_log_stream_lock;
81
#endif /* OS_WIN32 */
82
83
/**
84
 * \brief Transform the module name into display module name for logging
85
 */
86
static const char *SCTransformModule(const char *module_name, int *dn_len);
87
88
/**
89
 * \brief Holds the config state for the logging module
90
 */
91
static SCLogConfig *sc_log_config = NULL;
92
93
/**
94
 * \brief Returns the full path given a file and configured log dir
95
 */
96
static char *SCLogGetLogFilename(const char *);
97
98
/**
99
 * \brief Holds the global log level.  Is the same as sc_log_config->log_level
100
 */
101
SCLogLevel sc_log_global_log_level;
102
103
/**
104
 * \brief Used to indicate whether the logging module has been init or not
105
 */
106
int sc_log_module_initialized = 0;
107
108
/**
109
 * \brief Used to indicate whether the logging module has been cleaned or not
110
 */
111
int sc_log_module_cleaned = 0;
112
113
/**
114
 * \brief Maps the SC logging level to the syslog logging level
115
 *
116
 * \param The SC logging level that has to be mapped to the syslog_log_level
117
 *
118
 * \retval syslog_log_level The mapped syslog_api_log_level, for the logging
119
 *                          module api's internal log_level
120
 */
121
static inline int SCLogMapLogLevelToSyslogLevel(int log_level)
122
0
{
123
0
    int syslog_log_level = 0;
124
125
0
    switch (log_level) {
126
0
        case SC_LOG_ERROR:
127
0
            syslog_log_level = LOG_ERR;
128
0
            break;
129
0
        case SC_LOG_WARNING:
130
0
            syslog_log_level = LOG_WARNING;
131
0
            break;
132
0
        case SC_LOG_NOTICE:
133
0
            syslog_log_level = LOG_NOTICE;
134
0
            break;
135
0
        case SC_LOG_INFO:
136
0
            syslog_log_level = LOG_INFO;
137
0
            break;
138
0
        case SC_LOG_CONFIG:
139
0
        case SC_LOG_DEBUG:
140
0
        case SC_LOG_PERF:
141
0
            syslog_log_level = LOG_DEBUG;
142
0
            break;
143
0
        default:
144
0
            syslog_log_level = LOG_EMERG;
145
0
            break;
146
0
    }
147
148
0
    return syslog_log_level;
149
0
}
150
151
/**
152
 * \brief Output function that logs a character string out to a file descriptor
153
 *
154
 * \param fd  Pointer to the file descriptor
155
 * \param msg Pointer to the character string that should be logged
156
 */
157
static inline void SCLogPrintToStream(FILE *fd, char *msg)
158
8.12M
{
159
    /* Would only happen if the log file failed to re-open during rotation. */
160
8.12M
    if (fd == NULL) {
161
0
        return;
162
0
    }
163
164
#if defined (OS_WIN32)
165
  SCMutexLock(&sc_log_stream_lock);
166
#endif /* OS_WIN32 */
167
168
8.12M
    if (fprintf(fd, "%s\n", msg) < 0)
169
0
        printf("Error writing to stream using fprintf\n");
170
171
8.12M
    fflush(fd);
172
173
#if defined (OS_WIN32)
174
  SCMutexUnlock(&sc_log_stream_lock);
175
#endif /* OS_WIN32 */
176
8.12M
}
177
178
/**
179
 * \brief Output function that logs a character string through the syslog iface
180
 *
181
 * \param syslog_log_level Holds the syslog_log_level that the message should be
182
 *                         logged as
183
 * \param msg              Pointer to the char string, that should be logged
184
 *
185
 * \todo syslog is thread-safe according to POSIX manual and glibc code, but we
186
 *       we will have to look into non POSIX compliant boxes like freeBSD
187
 */
188
static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg)
189
0
{
190
    //static struct syslog_data data = SYSLOG_DATA_INIT;
191
    //syslog_r(syslog_log_level, NULL, "%s", msg);
192
193
0
    syslog(syslog_log_level, "%s", msg);
194
0
}
195
196
/**
197
 */
198
static int SCLogMessageJSON(SCTime_t tval, char *buffer, size_t buffer_size, SCLogLevel log_level,
199
        const char *file, unsigned line, const char *function, const char *module,
200
        const char *message)
201
0
{
202
0
    SCJsonBuilder *js = SCJbNewObject();
203
0
    if (unlikely(js == NULL))
204
0
        goto error;
205
206
0
    char timebuf[64];
207
0
    CreateIsoTimeString(tval, timebuf, sizeof(timebuf));
208
0
    SCJbSetString(js, "timestamp", timebuf);
209
210
0
    const char *s = SCMapEnumValueToName(log_level, sc_log_level_map);
211
0
    if (s != NULL) {
212
0
        SCJbSetString(js, "log_level", s);
213
0
    } else {
214
0
        JB_SET_STRING(js, "log_level", "INVALID");
215
0
    }
216
217
0
    JB_SET_STRING(js, "event_type", "engine");
218
0
    SCJbOpenObject(js, "engine");
219
220
0
    if (message)
221
0
        SCJbSetString(js, "message", message);
222
223
0
    if (t_thread_name[0] != '\0') {
224
0
        SCJbSetString(js, "thread_name", t_thread_name);
225
0
    }
226
227
0
    if (module) {
228
        /* Determine how much of module name to display */
229
0
        int dn_len = 0;
230
0
        const char *dn_name;
231
0
        dn_name = SCTransformModule(module, &dn_len);
232
0
        SCJbSetString(js, "module", dn_name);
233
0
    }
234
235
0
    if (log_level >= SC_LOG_DEBUG) {
236
0
        if (function)
237
0
            SCJbSetString(js, "function", function);
238
239
0
        if (file)
240
0
            SCJbSetString(js, "file", file);
241
242
0
        if (line > 0)
243
0
            SCJbSetUint(js, "line", line);
244
0
    }
245
0
    SCJbClose(js); // engine
246
247
0
    SCJbClose(js);
248
0
    memcpy(buffer, SCJbPtr(js), MIN(buffer_size, SCJbLen(js)));
249
250
0
    SCJbFree(js);
251
252
0
    return 0;
253
254
0
error:
255
0
    return -1;
256
0
}
257
258
static const int transform_max_segs = 2; /* The maximum segment count to display */
259
/*
260
 * \brief Return a display name for the given module name for logging.
261
 *
262
 * The transformation is dependent upon the source code module names
263
 * that use the dash character to separate incremental refinements of
264
 * the subsystem.
265
 *
266
 * The transformation uses the local constant "transform_max_segs" to determine
267
 * how many segments to display; the transformed name will never consist
268
 * of more than this many segments.
269
 *
270
 * E.g., "detect-http-content-len" ==> "detect-http" when the max is 2
271
 *
272
 * \param module_name The source code module name to be transformed.
273
 * \param dn_len The number of characters in the display name to print.
274
 *
275
 * \retval Pointer to the display name
276
 */
277
static const char *SCTransformModule(const char *module_name, int *dn_len)
278
19.3M
{
279
    /*
280
     * special case for source code module names beginning with:
281
     *    Prefixes skipped
282
     *        tm-*
283
     *        util-*
284
     *        source-*
285
     *    No transformation
286
     *        app-layer-*
287
     */
288
19.3M
    if (strncmp("tm-", module_name, 3) == 0) {
289
0
        *dn_len = (int)strlen(module_name) - 3;
290
0
        return module_name + 3;
291
19.3M
    } else if (strncmp("util-", module_name, 5) == 0) {
292
857k
        *dn_len = (int)strlen(module_name) - 5;
293
857k
        return module_name + 5;
294
18.4M
    } else if (strncmp("source-pcap-file", module_name, 16) == 0) {
295
48.6k
        *dn_len = (int)strlen("pcap");
296
48.6k
        return "pcap";
297
18.4M
    } else if (strncmp("source-", module_name, 7) == 0) {
298
0
        *dn_len = (int)strlen(module_name) - 7;
299
0
        return module_name + 7;
300
18.4M
    } else if (strncmp("runmode-", module_name, 8) == 0) {
301
0
        *dn_len = (int)strlen(module_name) - 8;
302
0
        return module_name + 8;
303
18.4M
    } else if (strncmp("app-layer-", module_name, 10) == 0) {
304
423k
        *dn_len = (int)strlen(module_name);
305
423k
        return module_name;
306
18.0M
    } else if (strncmp("detect-engine", module_name, 13) == 0) {
307
8.40M
        *dn_len = (int)strlen("detect");
308
8.40M
        return "detect";
309
8.40M
    }
310
311
9.60M
    int seg_cnt = 0;
312
313
9.60M
    char *last;
314
9.60M
    char *w = (char *)module_name;
315
20.0M
    while (w && (w = strchr(w, '-')) != NULL && seg_cnt < transform_max_segs) {
316
10.4M
        seg_cnt++;
317
10.4M
        last = w;
318
10.4M
        w++; /* skip past '-' */
319
10.4M
    }
320
321
9.60M
    if (seg_cnt < transform_max_segs)
322
7.96M
        *dn_len = (int)strlen(module_name);
323
1.63M
    else
324
1.63M
        *dn_len = (int)(last - module_name);
325
326
9.60M
    return module_name;
327
19.3M
}
328
329
/**
330
 * \brief Adds the global log_format to the outgoing buffer
331
 *
332
 * \param log_level log_level of the message that has to be logged
333
 * \param msg       Buffer containing the outgoing message
334
 * \param file      File_name from where the message originated
335
 * \param function  Function_name from where the message originated
336
 * \param line      Line_no from where the messaged originated
337
 *
338
 * \retval 0 on success; else a negative value on error
339
 */
340
static SCError SCLogMessageGetBuffer(SCTime_t tval, bool color, SCLogOPType type, char *buffer,
341
        size_t buffer_size, const char *log_format, const SCLogLevel log_level, const char *file,
342
        const unsigned int line, const char *function, const char *module, const char *message)
343
8.12M
{
344
8.12M
    if (type == SC_LOG_OP_TYPE_JSON)
345
0
        return SCLogMessageJSON(
346
0
                tval, buffer, buffer_size, log_level, file, line, function, module, message);
347
348
8.12M
    char *temp = buffer;
349
8.12M
    const char *s = NULL;
350
8.12M
    struct tm *tms = NULL;
351
352
8.12M
    const char *redb = "";
353
8.12M
    const char *red = "";
354
8.12M
    const char *yellowb = "";
355
8.12M
    const char *yellow = "";
356
8.12M
    const char *green = "";
357
8.12M
    const char *blue = "";
358
8.12M
    const char *reset = "";
359
8.12M
    if (color) {
360
0
        redb = "\x1b[1;31m";
361
0
        red = "\x1b[31m";
362
0
        yellowb = "\x1b[1;33m";
363
0
        yellow = "\x1b[33m";
364
0
        green = "\x1b[32m";
365
0
        blue = "\x1b[34m";
366
0
        reset = "\x1b[0m";
367
0
    }
368
    /* no of characters_written(cw) by snprintf */
369
8.12M
    int cw = 0;
370
371
8.12M
    DEBUG_VALIDATE_BUG_ON(sc_log_module_initialized != 1);
372
373
    /* make a copy of the format string as it will be modified below */
374
8.12M
    const int add_M = strstr(log_format, "%M") == NULL;
375
8.12M
    DEBUG_VALIDATE_BUG_ON(strlen(log_format) > UINT16_MAX);
376
8.12M
    char local_format[strlen(log_format) + add_M * 2 + 1];
377
8.12M
    strlcpy(local_format, log_format, sizeof(local_format));
378
8.12M
    if (add_M)
379
0
        strlcat(local_format, "%M", sizeof(local_format));
380
8.12M
    char *temp_fmt = local_format;
381
8.12M
    char *substr = temp_fmt;
382
8.12M
    struct tm local_tm;
383
384
56.8M
    while ((temp_fmt = strchr(temp_fmt, SC_LOG_FMT_PREFIX))) {
385
48.7M
        if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
386
193
            return 0;
387
193
        }
388
48.7M
        switch(temp_fmt[1]) {
389
0
            case SC_LOG_FMT_TIME:
390
0
                temp_fmt[0] = '\0';
391
392
0
                tms = SCLocalTime(SCTIME_SECS(tval), &local_tm);
393
394
0
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
395
0
                        "%s%s%04d-%02d-%02d %02d:%02d:%02d%s", substr, green, tms->tm_year + 1900,
396
0
                        tms->tm_mon + 1, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec,
397
0
                        reset);
398
0
                if (cw < 0)
399
0
                    return -1;
400
0
                temp += cw;
401
0
                temp_fmt++;
402
0
                substr = temp_fmt;
403
0
                substr++;
404
0
                break;
405
406
0
            case SC_LOG_FMT_TIME_LEGACY:
407
0
                temp_fmt[0] = '\0';
408
409
0
                tms = SCLocalTime(SCTIME_SECS(tval), &local_tm);
410
411
0
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
412
0
                              "%s%s%d/%d/%04d -- %02d:%02d:%02d%s",
413
0
                              substr, green, tms->tm_mday, tms->tm_mon + 1,
414
0
                              tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
415
0
                              tms->tm_sec, reset);
416
0
                if (cw < 0)
417
0
                    return -1;
418
0
                temp += cw;
419
0
                temp_fmt++;
420
0
                substr = temp_fmt;
421
0
                substr++;
422
0
                break;
423
424
0
            case SC_LOG_FMT_PID:
425
0
                temp_fmt[0] = '\0';
426
0
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
427
0
                              "%s%s%u%s", substr, yellow, getpid(), reset);
428
0
                if (cw < 0)
429
0
                    return -1;
430
0
                temp += cw;
431
0
                temp_fmt++;
432
0
                substr = temp_fmt;
433
0
                substr++;
434
0
                break;
435
436
0
            case SC_LOG_FMT_TID:
437
0
                temp_fmt[0] = '\0';
438
0
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
439
0
                              "%s%s%lu%s", substr, yellow, SCGetThreadIdLong(), reset);
440
0
                if (cw < 0)
441
0
                    return -1;
442
0
                temp += cw;
443
0
                temp_fmt++;
444
0
                substr = temp_fmt;
445
0
                substr++;
446
0
                break;
447
448
0
            case SC_LOG_FMT_THREAD_NAME:
449
0
            case SC_LOG_FMT_TM:
450
0
                temp_fmt[0] = '\0';
451
0
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr,
452
0
                        yellow, t_thread_name, reset);
453
0
                if (cw < 0)
454
0
                    return -1;
455
0
                temp += cw;
456
0
                temp_fmt++;
457
0
                substr = temp_fmt;
458
0
                substr++;
459
0
                break;
460
461
8.12M
            case SC_LOG_FMT_LOG_LEVEL:
462
8.12M
                temp_fmt[0] = '\0';
463
8.12M
                s = SCMapEnumValueToName(log_level, sc_log_level_map);
464
8.12M
                if (s != NULL) {
465
8.12M
                    if (log_level <= SC_LOG_ERROR)
466
6.64M
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
467
6.64M
                                  "%s%s%s%s", substr, redb, s, reset);
468
1.48M
                    else if (log_level == SC_LOG_WARNING)
469
638k
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
470
638k
                                  "%s%s%s%s", substr, red, s, reset);
471
841k
                    else if (log_level == SC_LOG_NOTICE)
472
360k
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
473
360k
                                  "%s%s%s%s", substr, yellowb, s, reset);
474
481k
                    else
475
481k
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
476
481k
                                substr, yellow, s, reset);
477
8.12M
                } else {
478
0
                    cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr,
479
0
                            "INVALID");
480
0
                }
481
8.12M
                if (cw < 0)
482
0
                    return -1;
483
8.12M
                temp += cw;
484
8.12M
                temp_fmt++;
485
8.12M
                substr = temp_fmt;
486
8.12M
                substr++;
487
8.12M
                break;
488
489
0
            case SC_LOG_FMT_LOG_SLEVEL:
490
0
                temp_fmt[0] = '\0';
491
0
                s = SCMapEnumValueToName(log_level, sc_log_slevel_map);
492
0
                if (s != NULL) {
493
0
                    if (log_level <= SC_LOG_ERROR)
494
0
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
495
0
                                substr, redb, s, reset);
496
0
                    else if (log_level == SC_LOG_WARNING)
497
0
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
498
0
                                substr, red, s, reset);
499
0
                    else if (log_level == SC_LOG_NOTICE)
500
0
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
501
0
                                substr, yellowb, s, reset);
502
0
                    else
503
0
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
504
0
                                  "%s%s%s%s", substr, yellow, s, reset);
505
0
                } else {
506
0
                    cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
507
0
                                  "%s%s", substr, "INVALID");
508
0
                }
509
0
                if (cw < 0)
510
0
                    return -1;
511
0
                temp += cw;
512
0
                temp_fmt++;
513
0
                substr = temp_fmt;
514
0
                substr++;
515
0
                break;
516
517
8.12M
            case SC_LOG_FMT_FILE_NAME:
518
8.12M
                temp_fmt[0] = '\0';
519
8.12M
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
520
8.12M
                              "%s%s%s%s", substr, blue, file, reset);
521
8.12M
                if (cw < 0)
522
0
                    return -1;
523
8.12M
                temp += cw;
524
8.12M
                temp_fmt++;
525
8.12M
                substr = temp_fmt;
526
8.12M
                substr++;
527
8.12M
                break;
528
529
8.12M
            case SC_LOG_FMT_LINE:
530
8.12M
                temp_fmt[0] = '\0';
531
8.12M
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
532
8.12M
                              "%s%s%u%s", substr, green, line, reset);
533
8.12M
                if (cw < 0)
534
0
                    return -1;
535
8.12M
                temp += cw;
536
8.12M
                temp_fmt++;
537
8.12M
                substr = temp_fmt;
538
8.12M
                substr++;
539
8.12M
                break;
540
541
8.12M
            case SC_LOG_FMT_SUBSYSTEM:
542
8.12M
                temp_fmt[0] = '\0';
543
544
                /* Determine how much of module name to display */
545
8.12M
                int dn_len = 0;
546
8.12M
                const char *dn_name = "unknown";
547
8.12M
                if (module) {
548
8.12M
                    dn_name = SCTransformModule(module, &dn_len);
549
8.12M
                }
550
551
8.12M
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr,
552
8.12M
                        green, dn_name, reset);
553
8.12M
                if (cw < 0)
554
0
                    return -1;
555
8.12M
                temp += cw;
556
8.12M
                temp_fmt++;
557
8.12M
                substr = temp_fmt;
558
8.12M
                substr++;
559
8.12M
                break;
560
561
8.12M
            case SC_LOG_FMT_FUNCTION:
562
8.12M
                temp_fmt[0] = '\0';
563
8.12M
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
564
8.12M
                              "%s%s%s%s", substr, green, function, reset);
565
8.12M
                if (cw < 0)
566
0
                    return -1;
567
8.12M
                temp += cw;
568
8.12M
                temp_fmt++;
569
8.12M
                substr = temp_fmt;
570
8.12M
                substr++;
571
8.12M
                break;
572
573
8.12M
            case SC_LOG_FMT_MESSAGE: {
574
8.12M
                temp_fmt[0] = '\0';
575
8.12M
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr);
576
8.12M
                if (cw < 0) {
577
0
                    return -1;
578
0
                }
579
8.12M
                temp += cw;
580
8.12M
                if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
581
0
                    return 0;
582
0
                }
583
8.12M
                const char *hi = "";
584
8.12M
                if (log_level <= SC_LOG_ERROR)
585
6.64M
                    hi = red;
586
1.48M
                else if (log_level <= SC_LOG_NOTICE)
587
998k
                    hi = yellow;
588
8.12M
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", hi, message,
589
8.12M
                        reset);
590
8.12M
                if (cw < 0) {
591
0
                    return -1;
592
0
                }
593
8.12M
                temp += cw;
594
8.12M
                if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
595
181
                    return 0;
596
181
                }
597
8.12M
                temp_fmt++;
598
8.12M
                substr = temp_fmt;
599
8.12M
                substr++;
600
8.12M
                break;
601
8.12M
            }
602
48.7M
        }
603
48.7M
        temp_fmt++;
604
48.7M
    }
605
8.12M
    if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
606
184
        return 0;
607
184
    }
608
8.12M
    cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr);
609
8.12M
    if (cw < 0) {
610
0
        return -1;
611
0
    }
612
8.12M
    if (sc_log_config->op_filter_regex != NULL) {
613
0
        if (pcre2_match(sc_log_config->op_filter_regex, (PCRE2_SPTR8)buffer, strlen(buffer), 0, 0,
614
0
                    sc_log_config->op_filter_regex_match, NULL) < 0) {
615
0
            return -1; // bit hacky, but just return !0
616
0
        }
617
0
    }
618
619
8.12M
    return 0;
620
8.12M
}
621
622
/** \internal
623
 *  \brief try to reopen file
624
 *  \note no error reporting here, as we're called by SCLogMessage
625
 *  \retval status 0 ok, -1 error */
626
static int SCLogReopen(SCLogOPIfaceCtx *op_iface_ctx)
627
0
{
628
0
    if (op_iface_ctx->file == NULL) {
629
0
        return 0;
630
0
    }
631
632
0
    if (op_iface_ctx->file_d != NULL) {
633
0
        fclose(op_iface_ctx->file_d);
634
0
    }
635
0
    op_iface_ctx->file_d = fopen(op_iface_ctx->file, "a");
636
0
    if (op_iface_ctx->file_d == NULL) {
637
0
        return -1;
638
0
    }
639
0
    return 0;
640
0
}
641
642
/**
643
 * \brief Adds the global log_format to the outgoing buffer
644
 *
645
 * \param log_level log_level of the message that has to be logged
646
 * \param msg       Buffer containing the outgoing message
647
 * \param file      File_name from where the message originated
648
 * \param function  Function_name from where the message originated
649
 * \param line      Line_no from where the messaged originated
650
 *
651
 * \retval SC_OK on success; else an error code
652
 */
653
SCError SCLogMessage(const SCLogLevel log_level, const char *file, const unsigned int line,
654
        const char *function, const char *module, const char *message)
655
19.3M
{
656
19.3M
    char buffer[SC_LOG_MAX_LOG_MSG_LEN] = "";
657
19.3M
    SCLogOPIfaceCtx *op_iface_ctx = NULL;
658
659
19.3M
    if (sc_log_module_initialized != 1) {
660
0
        printf("Logging module not initialized.  Call SCLogInitLogModule() "
661
0
               "first before using the debug API\n");
662
0
        return SC_OK;
663
0
    }
664
665
    /* get ts here so we log the same ts to each output */
666
19.3M
    struct timeval tval;
667
19.3M
    gettimeofday(&tval, NULL);
668
19.3M
    SCTime_t ts = SCTIME_FROM_TIMEVAL(&tval);
669
670
19.3M
    op_iface_ctx = sc_log_config->op_ifaces;
671
38.6M
    while (op_iface_ctx != NULL) {
672
19.3M
        if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) {
673
0
            op_iface_ctx = op_iface_ctx->next;
674
0
            continue;
675
0
        }
676
677
19.3M
        switch (op_iface_ctx->iface) {
678
6
            case SC_LOG_OP_IFACE_CONSOLE:
679
6
                if (SCLogMessageGetBuffer(ts, op_iface_ctx->use_color, op_iface_ctx->type, buffer,
680
6
                            sizeof(buffer),
681
6
                            op_iface_ctx->log_format ? op_iface_ctx->log_format
682
6
                                                     : sc_log_config->log_format,
683
6
                            log_level, file, line, function, module, message) == 0) {
684
6
                    SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, buffer);
685
6
                }
686
6
                break;
687
19.3M
            case SC_LOG_OP_IFACE_FILE:
688
19.3M
                if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer),
689
19.3M
                            op_iface_ctx->log_format ? op_iface_ctx->log_format
690
19.3M
                                                     : sc_log_config->log_format,
691
19.3M
                            log_level, file, line, function, module, message) == 0) {
692
19.3M
                    int r = 0;
693
19.3M
                    SCMutexLock(&op_iface_ctx->fp_mutex);
694
19.3M
                    if (op_iface_ctx->rotation_flag) {
695
0
                        r = SCLogReopen(op_iface_ctx);
696
0
                        op_iface_ctx->rotation_flag = 0;
697
0
                    }
698
19.3M
                    SCLogPrintToStream(op_iface_ctx->file_d, buffer);
699
19.3M
                    SCMutexUnlock(&op_iface_ctx->fp_mutex);
700
701
                    /* report error outside of lock to avoid recursion */
702
19.3M
                    if (r == -1) {
703
0
                        SCLogError("re-opening file \"%s\" failed: %s", op_iface_ctx->file,
704
0
                                strerror(errno));
705
0
                    }
706
19.3M
                }
707
19.3M
                break;
708
0
            case SC_LOG_OP_IFACE_SYSLOG:
709
0
                if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer),
710
0
                            op_iface_ctx->log_format ? op_iface_ctx->log_format
711
0
                                                     : sc_log_config->log_format,
712
0
                            log_level, file, line, function, module, message) == 0) {
713
0
                    SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), buffer);
714
0
                }
715
0
                break;
716
0
            default:
717
0
                break;
718
19.3M
        }
719
19.3M
        op_iface_ctx = op_iface_ctx->next;
720
19.3M
    }
721
19.3M
    return SC_OK;
722
19.3M
}
723
724
void SCLog(int x, const char *file, const char *func, const int line, const char *module,
725
        const char *fmt, ...)
726
5.17M
{
727
5.17M
    if (sc_log_global_log_level >= x &&
728
1.82M
            (sc_log_fg_filters_present == 0 ||
729
0
             SCLogMatchFGFilterWL(file, func, line) == 1 ||
730
0
             SCLogMatchFGFilterBL(file, func, line) == 1) &&
731
1.82M
            (sc_log_fd_filters_present == 0 ||
732
0
             SCLogMatchFDFilter(func) == 1))
733
1.82M
    {
734
1.82M
        char msg[SC_LOG_MAX_LOG_MSG_LEN];
735
1.82M
        va_list ap;
736
1.82M
        va_start(ap, fmt);
737
1.82M
        vsnprintf(msg, sizeof(msg), fmt, ap);
738
1.82M
        va_end(ap);
739
1.82M
        SCLogMessage(x, file, line, func, module, msg);
740
1.82M
    }
741
5.17M
}
742
743
void SCLogErr(int x, const char *file, const char *func, const int line, const char *module,
744
        const char *fmt, ...)
745
17.0M
{
746
17.0M
    if (sc_log_global_log_level >= x &&
747
17.0M
            (sc_log_fg_filters_present == 0 ||
748
0
             SCLogMatchFGFilterWL(file, func, line) == 1 ||
749
0
             SCLogMatchFGFilterBL(file, func, line) == 1) &&
750
17.0M
            (sc_log_fd_filters_present == 0 ||
751
0
             SCLogMatchFDFilter(func) == 1))
752
17.0M
    {
753
17.0M
        char msg[SC_LOG_MAX_LOG_MSG_LEN];
754
17.0M
        va_list ap;
755
17.0M
        va_start(ap, fmt);
756
17.0M
        vsnprintf(msg, sizeof(msg), fmt, ap);
757
17.0M
        va_end(ap);
758
17.0M
        SCLogMessage(x, file, line, func, module, msg);
759
17.0M
    }
760
17.0M
}
761
762
/**
763
 * \brief Returns whether debug messages are enabled to be logged or not
764
 *
765
 * \retval 1 if debug messages are enabled to be logged
766
 * \retval 0 if debug messages are not enabled to be logged
767
 */
768
int SCLogDebugEnabled(void)
769
380k
{
770
#ifdef DEBUG
771
    if (sc_log_global_log_level == SC_LOG_DEBUG)
772
        return 1;
773
    else
774
        return 0;
775
#else
776
380k
    return 0;
777
380k
#endif
778
380k
}
779
780
/**
781
 * \brief Allocates an output buffer for an output interface.  Used when we
782
 *        want the op_interface log_format to override the global_log_format.
783
 *        Currently not used.
784
 *
785
 * \retval buffer Pointer to the newly created output_buffer
786
 */
787
SCLogOPBuffer *SCLogAllocLogOPBuffer(void)
788
0
{
789
0
    SCLogOPBuffer *buffer = NULL;
790
791
0
    if ( (buffer = SCMalloc(sc_log_config->op_ifaces_cnt *
792
0
                          sizeof(SCLogOPBuffer))) == NULL) {
793
0
        FatalError("Fatal error encountered in SCLogAllocLogOPBuffer. Exiting...");
794
0
    }
795
796
0
    SCLogOPIfaceCtx *op_iface_ctx = sc_log_config->op_ifaces;
797
0
    for (int i = 0; i < sc_log_config->op_ifaces_cnt; i++, op_iface_ctx = op_iface_ctx->next) {
798
0
        buffer[i].log_format = op_iface_ctx->log_format;
799
0
        buffer[i].temp = buffer[i].msg;
800
0
    }
801
802
0
    return buffer;
803
0
}
804
805
/*----------------------The logging module initialization code--------------- */
806
807
/**
808
 * \brief Returns a new output_interface_context
809
 *
810
 * \retval iface_ctx Pointer to a newly allocated output_interface_context
811
 * \initonly
812
 */
813
static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx(void)
814
81
{
815
81
    SCLogOPIfaceCtx *iface_ctx = NULL;
816
817
81
    if ((iface_ctx = SCCalloc(1, sizeof(SCLogOPIfaceCtx))) == NULL) {
818
0
        FatalError("Fatal error encountered in SCLogallocLogOPIfaceCtx. Exiting...");
819
0
    }
820
821
81
    return iface_ctx;
822
81
}
823
824
/**
825
 * \brief Initializes the file output interface
826
 *
827
 * \param file       Path to the file used for logging purposes
828
 * \param log_format Pointer to the log_format for this op interface, that
829
 *                   overrides the global_log_format
830
 * \param log_level  Override of the global_log_level by this interface
831
 *
832
 * \retval iface_ctx Pointer to the file output interface context created
833
 * \initonly
834
 */
835
static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, uint32_t userid,
836
        uint32_t groupid, const char *log_format, int log_level, SCLogOPType type)
837
79
{
838
79
    SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
839
79
    if (iface_ctx == NULL) {
840
0
        FatalError("Fatal error encountered in SCLogInitFileOPIface. Exiting...");
841
0
    }
842
843
79
    if (file == NULL) {
844
0
        goto error;
845
0
    }
846
847
79
    iface_ctx->iface = SC_LOG_OP_IFACE_FILE;
848
79
    iface_ctx->type = type;
849
850
79
    if ( (iface_ctx->file_d = fopen(file, "a")) == NULL) {
851
0
        SCLogWarning("error opening file %s: %s", file, strerror(errno));
852
0
        goto error;
853
0
    }
854
855
79
#ifndef OS_WIN32
856
79
    if (userid != 0 || groupid != 0) {
857
0
        if (fchown(fileno(iface_ctx->file_d), userid, groupid) == -1) {
858
0
            SCLogWarning("Failed to change ownership of file %s: %s", file, strerror(errno));
859
0
        }
860
0
    }
861
79
#endif
862
863
79
    if ((iface_ctx->file = SCStrdup(file)) == NULL) {
864
0
        goto error;
865
0
    }
866
867
79
    if (log_format != NULL && (iface_ctx->log_format = SCStrdup(log_format)) == NULL) {
868
0
        goto error;
869
0
    }
870
871
79
    SCMutexInit(&iface_ctx->fp_mutex, NULL);
872
79
    OutputRegisterFileRotationFlag(&iface_ctx->rotation_flag);
873
874
79
    iface_ctx->log_level = log_level;
875
876
79
    return iface_ctx;
877
878
0
error:
879
0
    if (iface_ctx->file != NULL) {
880
0
        SCFree((char *)iface_ctx->file);
881
0
        iface_ctx->file = NULL;
882
0
    }
883
0
    if (iface_ctx->log_format != NULL) {
884
0
        SCFree((char *)iface_ctx->log_format);
885
0
        iface_ctx->log_format = NULL;
886
0
    }
887
0
    if (iface_ctx->file_d != NULL) {
888
0
        fclose(iface_ctx->file_d);
889
0
        iface_ctx->file_d = NULL;
890
0
    }
891
0
    SCFree(iface_ctx);
892
0
    return NULL;
893
79
}
894
895
/**
896
 * \brief Initializes the console output interface and deals with possible
897
 *        env var overrides.
898
 *
899
 * \param log_format Pointer to the log_format for this op interface, that
900
 *                   overrides the global_log_format
901
 * \param log_level  Override of the global_log_level by this interface
902
 *
903
 * \retval iface_ctx Pointer to the console output interface context created
904
 * \initonly
905
 */
906
static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format,
907
                                                       SCLogLevel log_level, SCLogOPType type)
908
2
{
909
2
    SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
910
911
2
    if (iface_ctx == NULL) {
912
0
        FatalError("Fatal error encountered in SCLogInitConsoleOPIface. Exiting...");
913
0
    }
914
915
2
    iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE;
916
2
    iface_ctx->type = type;
917
918
    /* console log format is overridden by envvars */
919
2
    const char *tmp_log_format = log_format;
920
2
    const char *s = getenv(SC_LOG_ENV_LOG_FORMAT);
921
2
    if (s != NULL) {
922
#if 0
923
        printf("Overriding setting for \"console.format\" because of env "
924
                "var SC_LOG_FORMAT=\"%s\".\n", s);
925
#endif
926
0
        tmp_log_format = s;
927
0
    }
928
929
2
    if (tmp_log_format != NULL &&
930
0
        (iface_ctx->log_format = SCStrdup(tmp_log_format)) == NULL) {
931
0
        printf("Error allocating memory\n");
932
0
        exit(EXIT_FAILURE);
933
0
    }
934
935
    /* console log level is overridden by envvars */
936
2
    SCLogLevel tmp_log_level = log_level;
937
2
    s = getenv(SC_LOG_ENV_LOG_LEVEL);
938
2
    if (s != NULL) {
939
0
        SCLogLevel l = SCMapEnumNameToValue(s, sc_log_level_map);
940
0
        if (l > SC_LOG_NOTSET && l < SC_LOG_LEVEL_MAX) {
941
#if 0
942
            printf("Overriding setting for \"console.level\" because of env "
943
                    "var SC_LOG_LEVEL=\"%s\".\n", s);
944
#endif
945
0
            tmp_log_level = l;
946
0
        }
947
0
    }
948
2
    iface_ctx->log_level = tmp_log_level;
949
950
2
#ifndef OS_WIN32
951
2
    if (isatty(fileno(stdout)) && isatty(fileno(stderr))) {
952
0
        iface_ctx->use_color = true;
953
0
    }
954
2
#endif
955
956
2
    return iface_ctx;
957
2
}
958
959
/**
960
 * \brief Initializes the syslog output interface
961
 *
962
 * \param facility   The facility code for syslog
963
 * \param log_format Pointer to the log_format for this op interface, that
964
 *                   overrides the global_log_format
965
 * \param log_level  Override of the global_log_level by this interface
966
 *
967
 * \retval iface_ctx Pointer to the syslog output interface context created
968
 */
969
static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility,
970
                                                      const char *log_format,
971
                                                      SCLogLevel log_level,
972
                                                      SCLogOPType type)
973
0
{
974
0
    SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
975
976
0
    if ( iface_ctx == NULL) {
977
0
        FatalError("Fatal error encountered in SCLogInitSyslogOPIface. Exiting...");
978
0
    }
979
980
0
    iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG;
981
0
    iface_ctx->type = type;
982
983
0
    if (facility == -1)
984
0
        facility = SC_LOG_DEF_SYSLOG_FACILITY;
985
0
    iface_ctx->facility = facility;
986
987
0
    if (log_format != NULL &&
988
0
        (iface_ctx->log_format = SCStrdup(log_format)) == NULL) {
989
0
        printf("Error allocating memory\n");
990
0
        exit(EXIT_FAILURE);
991
0
    }
992
993
0
    iface_ctx->log_level = log_level;
994
995
0
    openlog(NULL, LOG_NDELAY, iface_ctx->facility);
996
997
0
    return iface_ctx;
998
0
}
999
1000
/**
1001
 * \brief Frees the output_interface context supplied as an argument
1002
 *
1003
 * \param iface_ctx Pointer to the op_interface_context to be freed
1004
 */
1005
static inline void SCLogFreeLogOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx)
1006
0
{
1007
0
    SCLogOPIfaceCtx *temp = NULL;
1008
1009
0
    while (iface_ctx != NULL) {
1010
0
        temp = iface_ctx;
1011
1012
0
        if (iface_ctx->file_d != NULL) {
1013
0
            fclose(iface_ctx->file_d);
1014
0
            SCMutexDestroy(&iface_ctx->fp_mutex);
1015
0
        }
1016
1017
0
        if (iface_ctx->file != NULL)
1018
0
            SCFree((void *)iface_ctx->file);
1019
1020
0
        if (iface_ctx->log_format != NULL)
1021
0
            SCFree((void *)iface_ctx->log_format);
1022
1023
0
        if (iface_ctx->iface == SC_LOG_OP_IFACE_SYSLOG) {
1024
0
            closelog();
1025
0
        }
1026
1027
0
        iface_ctx = iface_ctx->next;
1028
1029
0
        SCFree(temp);
1030
0
    }
1031
0
}
1032
1033
/**
1034
 * \brief Internal function used to set the logging module global_log_level
1035
 *        during the initialization phase
1036
 *
1037
 * \param sc_lid The initialization data supplied.
1038
 * \param sc_lc  The logging module context which has to be updated.
1039
 */
1040
static inline void SCLogSetLogLevel(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
1041
44
{
1042
44
    SCLogLevel log_level = SC_LOG_NOTSET;
1043
44
    const char *s = NULL;
1044
1045
    /* envvar overrides config */
1046
44
    s = getenv(SC_LOG_ENV_LOG_LEVEL);
1047
44
    if (s != NULL) {
1048
0
        log_level = SCMapEnumNameToValue(s, sc_log_level_map);
1049
44
    } else if (sc_lid != NULL) {
1050
0
        log_level = sc_lid->global_log_level;
1051
0
    }
1052
1053
    /* deal with the global_log_level to be used */
1054
44
    if (log_level > SC_LOG_NOTSET && log_level < SC_LOG_LEVEL_MAX)
1055
0
        sc_lc->log_level = log_level;
1056
44
    else {
1057
44
        sc_lc->log_level = SC_LOG_DEF_LOG_LEVEL;
1058
44
#ifndef UNITTESTS
1059
44
        if (sc_lid != NULL) {
1060
0
            printf("Warning: Invalid/No global_log_level assigned by user.  Falling "
1061
0
                   "back on the default_log_level \"%s\"\n",
1062
0
                   SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map));
1063
0
        }
1064
44
#endif
1065
44
    }
1066
1067
    /* we also set it to a global var, as it is easier to access it */
1068
44
    sc_log_global_log_level = sc_lc->log_level;
1069
44
}
1070
1071
const char *SCLogLevel2Name(const SCLogLevel lvl)
1072
0
{
1073
0
    return SCMapEnumValueToName(lvl, sc_log_level_map);
1074
0
}
1075
1076
SCLogLevel SCLogGetLogLevel(void)
1077
0
{
1078
0
    return sc_log_global_log_level;
1079
0
}
1080
1081
static inline const char *SCLogGetDefaultLogFormat(const SCLogLevel lvl)
1082
81
{
1083
81
    const char *prog_ver = GetProgramVersion();
1084
81
    if (strstr(prog_ver, "RELEASE") != NULL) {
1085
0
        if (lvl <= SC_LOG_NOTICE)
1086
0
            return SC_LOG_DEF_LOG_FORMAT_REL_NOTICE;
1087
0
        else if (lvl <= SC_LOG_INFO)
1088
0
            return SC_LOG_DEF_LOG_FORMAT_REL_INFO;
1089
0
        else if (lvl <= SC_LOG_CONFIG)
1090
0
            return SC_LOG_DEF_LOG_FORMAT_REL_CONFIG;
1091
0
    }
1092
81
    return SC_LOG_DEF_LOG_FORMAT_DEBUG;
1093
81
}
1094
1095
/**
1096
 * \brief Internal function used to set the logging module global_log_format
1097
 *        during the initialization phase
1098
 *
1099
 * \param sc_lid The initialization data supplied.
1100
 * \param sc_lc  The logging module context which has to be updated.
1101
 */
1102
static inline void SCLogSetLogFormat(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
1103
44
{
1104
44
    const char *format = NULL;
1105
1106
    /* envvar overrides config */
1107
44
    format = getenv(SC_LOG_ENV_LOG_FORMAT);
1108
44
    if (format == NULL) {
1109
44
        if (sc_lid != NULL) {
1110
0
            format = sc_lid->global_log_format;
1111
0
        }
1112
44
    }
1113
1114
    /* deal with the global log format to be used */
1115
44
    if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) {
1116
44
        format = SCLogGetDefaultLogFormat(sc_lc->log_level);
1117
44
#ifndef UNITTESTS
1118
44
        if (sc_lid != NULL) {
1119
0
            printf("Warning: Invalid/No global_log_format supplied by user or format "
1120
0
                   "length exceeded limit of \"%d\" characters.  Falling back on "
1121
0
                   "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN,
1122
0
                   format);
1123
0
        }
1124
44
#endif
1125
44
    }
1126
1127
44
    if (format != NULL && (sc_lc->log_format = SCStrdup(format)) == NULL) {
1128
0
        printf("Error allocating memory\n");
1129
0
        exit(EXIT_FAILURE);
1130
0
    }
1131
44
}
1132
1133
/**
1134
 * \brief Internal function used to set the logging module global_op_ifaces
1135
 *        during the initialization phase
1136
 *
1137
 * \param sc_lid The initialization data supplied.
1138
 * \param sc_lc  The logging module context which has to be updated.
1139
 */
1140
static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
1141
44
{
1142
44
    SCLogOPIfaceCtx *op_ifaces_ctx = NULL;
1143
44
    int op_iface = 0;
1144
44
    const char *s = NULL;
1145
1146
44
    if (sc_lid != NULL && sc_lid->op_ifaces != NULL) {
1147
0
        sc_lc->op_ifaces = sc_lid->op_ifaces;
1148
0
        sc_lid->op_ifaces = NULL;
1149
0
        sc_lc->op_ifaces_cnt = sc_lid->op_ifaces_cnt;
1150
44
    } else {
1151
44
        s = getenv(SC_LOG_ENV_LOG_OP_IFACE);
1152
44
        if (s != NULL) {
1153
43
            op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map);
1154
1155
43
            if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) {
1156
0
                op_iface = SC_LOG_DEF_LOG_OP_IFACE;
1157
0
#ifndef UNITTESTS
1158
0
                printf("Warning: Invalid output interface supplied by user.  "
1159
0
                       "Falling back on default_output_interface \"%s\"\n",
1160
0
                       SCMapEnumValueToName(op_iface, sc_log_op_iface_map));
1161
0
#endif
1162
0
            }
1163
43
        }
1164
1
        else {
1165
1
            op_iface = SC_LOG_DEF_LOG_OP_IFACE;
1166
1
#ifndef UNITTESTS
1167
1
            if (sc_lid != NULL) {
1168
0
                printf("Warning: Output_interface not supplied by user.  Falling "
1169
0
                       "back on default_output_interface \"%s\"\n",
1170
0
                       SCMapEnumValueToName(op_iface, sc_log_op_iface_map));
1171
0
            }
1172
1
#endif
1173
1
        }
1174
1175
44
        switch (op_iface) {
1176
1
            case SC_LOG_OP_IFACE_CONSOLE:
1177
1
                op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX,0);
1178
1
                break;
1179
43
            case SC_LOG_OP_IFACE_FILE:
1180
43
                s = getenv(SC_LOG_ENV_LOG_FILE);
1181
43
                if (s == NULL) {
1182
0
                    char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE);
1183
0
                    if (str != NULL) {
1184
0
                        op_ifaces_ctx = SCLogInitFileOPIface(str, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0);
1185
0
                        SCFree(str);
1186
0
                    }
1187
43
                } else {
1188
43
                    op_ifaces_ctx = SCLogInitFileOPIface(s, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0);
1189
43
                }
1190
43
                break;
1191
0
            case SC_LOG_OP_IFACE_SYSLOG:
1192
0
                s = getenv(SC_LOG_ENV_LOG_FACILITY);
1193
0
                if (s == NULL)
1194
0
                    s = SC_LOG_DEF_SYSLOG_FACILITY_STR;
1195
1196
0
                op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1,0);
1197
0
                break;
1198
44
        }
1199
44
        sc_lc->op_ifaces = op_ifaces_ctx;
1200
44
        sc_lc->op_ifaces_cnt++;
1201
44
    }
1202
44
}
1203
1204
/**
1205
 * \brief Internal function used to set the logging module op_filter
1206
 *        during the initialization phase
1207
 *
1208
 * \param sc_lid The initialization data supplied.
1209
 * \param sc_lc  The logging module context which has to be updated.
1210
 */
1211
static inline void SCLogSetOPFilter(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
1212
44
{
1213
44
    const char *filter = NULL;
1214
1215
44
    int opts = 0;
1216
44
    int en;
1217
44
    PCRE2_SIZE eo = 0;
1218
1219
    /* envvar overrides */
1220
44
    filter = getenv(SC_LOG_ENV_LOG_OP_FILTER);
1221
44
    if (filter == NULL) {
1222
44
        if (sc_lid != NULL) {
1223
0
            filter = sc_lid->op_filter;
1224
0
        }
1225
44
    }
1226
1227
44
    if (filter != NULL && strcmp(filter, "") != 0) {
1228
0
        sc_lc->op_filter = SCStrdup(filter);
1229
0
        if (sc_lc->op_filter == NULL) {
1230
0
            printf("pcre filter alloc failed\n");
1231
0
            return;
1232
0
        }
1233
0
        sc_lc->op_filter_regex =
1234
0
                pcre2_compile((PCRE2_SPTR8)filter, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
1235
0
        if (sc_lc->op_filter_regex == NULL) {
1236
0
            SCFree(sc_lc->op_filter);
1237
0
            PCRE2_UCHAR errbuffer[256];
1238
0
            pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
1239
0
            printf("pcre2 compile of \"%s\" failed at offset %d : %s\n", filter, (int)eo,
1240
0
                    errbuffer);
1241
0
            return;
1242
0
        }
1243
0
        sc_lc->op_filter_regex_match =
1244
0
                pcre2_match_data_create_from_pattern(sc_lc->op_filter_regex, NULL);
1245
0
    }
1246
44
}
1247
1248
/**
1249
 * \brief Returns a pointer to a new SCLogInitData.  This is a public interface
1250
 *        intended to be used after the logging parameters are read from the
1251
 *        conf file
1252
 *
1253
 * \retval sc_lid Pointer to the newly created SCLogInitData
1254
 * \initonly
1255
 */
1256
SCLogInitData *SCLogAllocLogInitData(void)
1257
0
{
1258
0
    SCLogInitData *sc_lid = NULL;
1259
1260
0
    if ((sc_lid = SCCalloc(1, sizeof(SCLogInitData))) == NULL)
1261
0
        return NULL;
1262
1263
0
    return sc_lid;
1264
0
}
1265
1266
#ifdef UNITTESTS
1267
#ifndef OS_WIN32
1268
/**
1269
 * \brief Frees a SCLogInitData
1270
 *
1271
 * \param sc_lid Pointer to the SCLogInitData to be freed
1272
 */
1273
static void SCLogFreeLogInitData(SCLogInitData *sc_lid)
1274
{
1275
    if (sc_lid != NULL) {
1276
        SCLogFreeLogOPIfaceCtx(sc_lid->op_ifaces);
1277
        SCFree(sc_lid);
1278
    }
1279
}
1280
#endif
1281
#endif
1282
1283
/**
1284
 * \brief Frees the logging module context
1285
 */
1286
static inline void SCLogFreeLogConfig(SCLogConfig *sc_lc)
1287
44
{
1288
44
    if (sc_lc != NULL) {
1289
0
        if (sc_lc->startup_message != NULL)
1290
0
            SCFree(sc_lc->startup_message);
1291
0
        if (sc_lc->log_format != NULL)
1292
0
            SCFree(sc_lc->log_format);
1293
0
        if (sc_lc->op_filter != NULL)
1294
0
            SCFree(sc_lc->op_filter);
1295
1296
0
        if (sc_lc->op_filter_regex != NULL)
1297
0
            pcre2_code_free(sc_lc->op_filter_regex);
1298
0
        if (sc_lc->op_filter_regex_match)
1299
0
            pcre2_match_data_free(sc_lc->op_filter_regex_match);
1300
1301
0
        SCLogFreeLogOPIfaceCtx(sc_lc->op_ifaces);
1302
0
        SCFree(sc_lc);
1303
0
    }
1304
44
}
1305
1306
/**
1307
 * \brief Appends an output_interface to the output_interface list sent in head
1308
 *
1309
 * \param iface_ctx Pointer to the output_interface that has to be added to head
1310
 * \param head      Pointer to the output_interface list
1311
 */
1312
void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx, SCLogInitData *sc_lid)
1313
0
{
1314
0
    SCLogOPIfaceCtx *temp = NULL, *prev = NULL;
1315
0
    SCLogOPIfaceCtx **head = &sc_lid->op_ifaces;
1316
1317
0
    if (iface_ctx == NULL) {
1318
#ifdef DEBUG
1319
        printf("Argument(s) to SCLogAppendOPIfaceCtx() NULL\n");
1320
#endif
1321
0
        return;
1322
0
    }
1323
1324
0
    temp = *head;
1325
0
    while (temp != NULL) {
1326
0
        prev = temp;
1327
0
        temp = temp->next;
1328
0
    }
1329
1330
0
    if (prev == NULL)
1331
0
        *head = iface_ctx;
1332
0
    else
1333
0
        prev->next = iface_ctx;
1334
1335
0
    sc_lid->op_ifaces_cnt++;
1336
0
}
1337
1338
#ifdef UNITTESTS
1339
#ifndef OS_WIN32
1340
/**
1341
 * \internal
1342
 * \brief Creates a new output interface based on the arguments sent.  The kind
1343
 *        of output interface to be created is decided by the iface_name arg.
1344
 *        If iface_name is "file", the arg argument will hold the filename to be
1345
 *        used for logging purposes.  If iface_name is "syslog", the arg
1346
 *        argument holds the facility code.  If iface_name is "console", arg is
1347
 *        NULL.
1348
 *
1349
 * \param iface_name Interface name.  Can be "console", "file" or "syslog"
1350
 * \param log_format Override for the global_log_format
1351
 * \param log_level  Override for the global_log_level
1352
 * \param log_level  Parameter required by a particular interface.  Explained in
1353
 *                   the function description
1354
 *
1355
 * \retval iface_ctx Pointer to the newly created output interface
1356
 */
1357
static SCLogOPIfaceCtx *SCLogInitOPIfaceCtx(
1358
        const char *iface_name, const char *log_format, int log_level, const char *arg)
1359
{
1360
    int iface = SCMapEnumNameToValue(iface_name, sc_log_op_iface_map);
1361
1362
    if (log_level < SC_LOG_NONE || log_level > SC_LOG_DEBUG) {
1363
        printf("Warning: Supplied log_level_override for op_interface \"%s\" "
1364
               "is invalid.  Defaulting to not specifying an override\n",
1365
                iface_name);
1366
        log_level = SC_LOG_NOTSET;
1367
    }
1368
1369
    switch (iface) {
1370
        case SC_LOG_OP_IFACE_CONSOLE:
1371
            return SCLogInitConsoleOPIface(log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1372
        case SC_LOG_OP_IFACE_FILE:
1373
            return SCLogInitFileOPIface(arg, 0, 0, log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1374
        case SC_LOG_OP_IFACE_SYSLOG:
1375
            return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()),
1376
                    log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1377
        default:
1378
#ifdef DEBUG
1379
            printf("Output Interface \"%s\" not supported by the logging module",
1380
                   iface_name);
1381
#endif
1382
            return NULL;
1383
    }
1384
}
1385
#endif
1386
#endif
1387
1388
/**
1389
 * \brief Initializes the logging module.
1390
 *
1391
 * \param sc_lid The initialization data for the logging module.  If sc_lid is
1392
 *               NULL, we would stick to the default configuration for the
1393
 *               logging subsystem.
1394
 * \initonly
1395
 */
1396
void SCLogInitLogModule(SCLogInitData *sc_lid)
1397
44
{
1398
    /* De-initialize the logging context, if it has already init by the
1399
     * environment variables at the start of the engine */
1400
44
    SCLogDeInitLogModule();
1401
1402
#if defined (OS_WIN32)
1403
    if (SCMutexInit(&sc_log_stream_lock, NULL) != 0) {
1404
        FatalError("Failed to initialize log mutex.");
1405
    }
1406
#endif /* OS_WIN32 */
1407
1408
    /* sc_log_config is a global variable */
1409
44
    if ((sc_log_config = SCCalloc(1, sizeof(SCLogConfig))) == NULL) {
1410
0
        FatalError("Fatal error encountered in SCLogInitLogModule. Exiting...");
1411
0
    }
1412
1413
44
    SCLogSetLogLevel(sc_lid, sc_log_config);
1414
44
    SCLogSetLogFormat(sc_lid, sc_log_config);
1415
44
    SCLogSetOPIface(sc_lid, sc_log_config);
1416
44
    SCLogSetOPFilter(sc_lid, sc_log_config);
1417
1418
44
    sc_log_module_initialized = 1;
1419
44
    sc_log_module_cleaned = 0;
1420
1421
    //SCOutputPrint(sc_did->startup_message);
1422
1423
44
    SCSetRustLogLevel(sc_log_global_log_level);
1424
44
}
1425
1426
void SCLogLoadConfig(int daemon, int verbose, uint32_t userid, uint32_t groupid)
1427
0
{
1428
0
    SCConfNode *outputs;
1429
0
    SCLogInitData *sc_lid;
1430
0
    int have_logging = 0;
1431
0
    int max_level = 0;
1432
0
    SCLogLevel min_level = 0;
1433
1434
    /* If verbose logging was requested, set the minimum as
1435
     * SC_LOG_NOTICE plus the extra verbosity. */
1436
0
    if (verbose) {
1437
0
        min_level = SC_LOG_NOTICE + verbose;
1438
0
    }
1439
1440
0
    outputs = SCConfGetNode("logging.outputs");
1441
0
    if (outputs == NULL) {
1442
0
        SCLogDebug("No logging.output configuration section found.");
1443
0
        return;
1444
0
    }
1445
1446
0
    sc_lid = SCLogAllocLogInitData();
1447
0
    if (sc_lid == NULL) {
1448
0
        SCLogDebug("Could not allocate memory for log init data");
1449
0
        return;
1450
0
    }
1451
1452
    /* Get default log level and format. */
1453
0
    const char *default_log_level_s = NULL;
1454
0
    if (SCConfGetNonNull("logging.default-log-level", &default_log_level_s) == 1) {
1455
0
        SCLogLevel default_log_level =
1456
0
            SCMapEnumNameToValue(default_log_level_s, sc_log_level_map);
1457
0
        if (default_log_level == -1) {
1458
0
            SCLogError("Invalid default log level: %s", default_log_level_s);
1459
0
            exit(EXIT_FAILURE);
1460
0
        }
1461
0
        sc_lid->global_log_level = MAX(min_level, default_log_level);
1462
0
    } else {
1463
0
        sc_lid->global_log_level = MAX(min_level, SC_LOG_NOTICE);
1464
0
    }
1465
1466
0
    if (SCConfGetNonNull("logging.default-log-format", &sc_lid->global_log_format) != 1)
1467
0
        sc_lid->global_log_format = SCLogGetDefaultLogFormat(sc_lid->global_log_level);
1468
1469
0
    (void)SCConfGet("logging.default-output-filter", &sc_lid->op_filter);
1470
1471
0
    SCConfNode *seq_node, *output;
1472
0
    TAILQ_FOREACH(seq_node, &outputs->head, next) {
1473
0
        SCLogLevel level = sc_lid->global_log_level;
1474
0
        SCLogOPIfaceCtx *op_iface_ctx = NULL;
1475
0
        const char *format;
1476
0
        const char *level_s;
1477
1478
0
        output = SCConfNodeLookupChild(seq_node, seq_node->val);
1479
0
        if (output == NULL)
1480
0
            continue;
1481
1482
        /* By default an output is enabled. */
1483
0
        const char *enabled = SCConfNodeLookupChildValue(output, "enabled");
1484
0
        if (enabled != NULL && SCConfValIsFalse(enabled))
1485
0
            continue;
1486
1487
0
        SCLogOPType type = SC_LOG_OP_TYPE_REGULAR;
1488
0
        const char *type_s = SCConfNodeLookupChildValue(output, "type");
1489
0
        if (type_s != NULL) {
1490
0
            if (strcmp(type_s, "regular") == 0)
1491
0
                type = SC_LOG_OP_TYPE_REGULAR;
1492
0
            else if (strcmp(type_s, "json") == 0) {
1493
0
                type = SC_LOG_OP_TYPE_JSON;
1494
0
            }
1495
0
        }
1496
1497
0
        format = SCConfNodeLookupChildValue(output, "format");
1498
1499
0
        level_s = SCConfNodeLookupChildValue(output, "level");
1500
0
        if (level_s != NULL) {
1501
0
            level = SCMapEnumNameToValue(level_s, sc_log_level_map);
1502
0
            if (level == -1) {
1503
0
                SCLogError("Invalid log level: %s", level_s);
1504
0
                exit(EXIT_FAILURE);
1505
0
            }
1506
0
            max_level = MAX(max_level, level);
1507
0
        }
1508
1509
        /* Increase the level of extra verbosity was requested. */
1510
0
        level = MAX(min_level, level);
1511
1512
0
        if (strcmp(output->name, "console") == 0) {
1513
0
            op_iface_ctx = SCLogInitConsoleOPIface(format, level, type);
1514
0
        }
1515
0
        else if (strcmp(output->name, "file") == 0) {
1516
0
            if (format == NULL) {
1517
0
                format = SC_LOG_DEF_FILE_FORMAT;
1518
0
            }
1519
1520
0
            const char *filename = SCConfNodeLookupChildValue(output, "filename");
1521
0
            if (filename == NULL) {
1522
0
                FatalError("Logging to file requires a filename");
1523
0
            }
1524
0
            char *path = NULL;
1525
0
            if (!(PathIsAbsolute(filename))) {
1526
0
                path = SCLogGetLogFilename(filename);
1527
0
            } else {
1528
0
                path = SCStrdup(filename);
1529
0
            }
1530
0
            if (path == NULL)
1531
0
                FatalError("failed to setup output to file");
1532
0
            have_logging = 1;
1533
0
            op_iface_ctx = SCLogInitFileOPIface(path, userid, groupid, format, level, type);
1534
0
            SCFree(path);
1535
0
        }
1536
0
        else if (strcmp(output->name, "syslog") == 0) {
1537
0
            int facility = SC_LOG_DEF_SYSLOG_FACILITY;
1538
0
            const char *facility_s = SCConfNodeLookupChildValue(output, "facility");
1539
0
            if (facility_s != NULL) {
1540
0
                facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap());
1541
0
                if (facility == -1) {
1542
0
                    SCLogWarning("Invalid syslog "
1543
0
                                 "facility: \"%s\", now using \"%s\" as syslog "
1544
0
                                 "facility",
1545
0
                            facility_s, SC_LOG_DEF_SYSLOG_FACILITY_STR);
1546
0
                    facility = SC_LOG_DEF_SYSLOG_FACILITY;
1547
0
                }
1548
0
            }
1549
0
            SCLogDebug("Initializing syslog logging with format \"%s\"", format);
1550
0
            have_logging = 1;
1551
0
            op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level, type);
1552
0
        }
1553
0
        else {
1554
0
            SCLogWarning("invalid logging method: %s, ignoring", output->name);
1555
0
        }
1556
0
        if (op_iface_ctx != NULL) {
1557
0
            SCLogAppendOPIfaceCtx(op_iface_ctx, sc_lid);
1558
0
        }
1559
0
    }
1560
1561
0
    if (daemon && (have_logging == 0)) {
1562
0
        SCLogWarning("no logging compatible with daemon mode selected,"
1563
0
                     " suricata won't be able to log. Please update "
1564
0
                     " 'logging.outputs' in the YAML.");
1565
0
    }
1566
1567
    /* Set the global log level to that of the max level used. */
1568
0
    sc_lid->global_log_level = MAX(sc_lid->global_log_level, max_level);
1569
0
    SCLogInitLogModule(sc_lid);
1570
1571
0
    SCLogDebug("sc_log_global_log_level: %d", sc_log_global_log_level);
1572
0
    SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format);
1573
0
    SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter);
1574
1575
0
    SCFree(sc_lid);
1576
0
}
1577
1578
/**
1579
 * \brief Returns a full file path given a filename uses log dir specified in
1580
 *        conf or DEFAULT_LOG_DIR
1581
 *
1582
 * \param filearg The relative filename for which we want a full path include
1583
 *                log directory
1584
 *
1585
 * \retval log_filename The fullpath of the logfile to open
1586
 */
1587
static char *SCLogGetLogFilename(const char *filearg)
1588
0
{
1589
0
    const char *log_dir = SCConfigGetLogDirectory();
1590
0
    char *log_filename = SCMalloc(PATH_MAX);
1591
0
    if (unlikely(log_filename == NULL))
1592
0
        return NULL;
1593
0
    snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, filearg);
1594
0
    return log_filename;
1595
0
}
1596
1597
/**
1598
 * \brief De-Initializes the logging module
1599
 */
1600
void SCLogDeInitLogModule(void)
1601
44
{
1602
44
    SCLogFreeLogConfig(sc_log_config);
1603
1604
    /* reset the global logging_module variables */
1605
44
    sc_log_global_log_level = 0;
1606
44
    sc_log_module_initialized = 0;
1607
44
    sc_log_module_cleaned = 1;
1608
44
    sc_log_config = NULL;
1609
1610
    /* de-init the FD filters */
1611
44
    SCLogReleaseFDFilters();
1612
    /* de-init the FG filters */
1613
44
    SCLogReleaseFGFilters();
1614
1615
#if defined (OS_WIN32)
1616
    SCMutexDestroy(&sc_log_stream_lock);
1617
#endif /* OS_WIN32 */
1618
44
}
1619
1620
void SCFatalErrorOnInitStatic(const char *arg)
1621
0
{
1622
0
    FatalErrorOnInit("%s", arg);
1623
0
}
1624
1625
//------------------------------------Unit_Tests--------------------------------
1626
1627
/* The logging engine should be tested to the maximum extent possible, since
1628
 * logging code would be used throughout the codebase, and hence we can't afford
1629
 * to have a single bug here(not that you can afford to have a bug
1630
 * elsewhere ;) ). Please report a bug, if you get a slightest hint of a bug
1631
 * from the logging module.
1632
 */
1633
1634
#ifdef UNITTESTS
1635
1636
static int SCLogTestInit01(void)
1637
{
1638
#ifndef OS_WIN32
1639
    /* unset any environment variables set for the logging module */
1640
    unsetenv(SC_LOG_ENV_LOG_LEVEL);
1641
    unsetenv(SC_LOG_ENV_LOG_OP_IFACE);
1642
    unsetenv(SC_LOG_ENV_LOG_FORMAT);
1643
1644
    SCLogInitLogModule(NULL);
1645
1646
    FAIL_IF_NULL(sc_log_config);
1647
1648
    FAIL_IF_NOT(SC_LOG_DEF_LOG_LEVEL == sc_log_config->log_level);
1649
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1650
               SC_LOG_DEF_LOG_OP_IFACE == sc_log_config->op_ifaces->iface);
1651
    FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1652
                strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level),
1653
                        sc_log_config->log_format) == 0);
1654
1655
    SCLogDeInitLogModule();
1656
1657
    setenv(SC_LOG_ENV_LOG_LEVEL, "Debug", 1);
1658
    setenv(SC_LOG_ENV_LOG_OP_IFACE, "Console", 1);
1659
    setenv(SC_LOG_ENV_LOG_FORMAT, "%n- %l", 1);
1660
1661
    SCLogInitLogModule(NULL);
1662
1663
    FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1664
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1665
               SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface);
1666
    FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1667
               !strcmp("%n- %l", sc_log_config->log_format));
1668
1669
    unsetenv(SC_LOG_ENV_LOG_LEVEL);
1670
    unsetenv(SC_LOG_ENV_LOG_OP_IFACE);
1671
    unsetenv(SC_LOG_ENV_LOG_FORMAT);
1672
1673
    SCLogDeInitLogModule();
1674
#endif
1675
    PASS;
1676
}
1677
1678
static int SCLogTestInit02(void)
1679
{
1680
#ifndef OS_WIN32
1681
    SCLogInitData *sc_lid = NULL;
1682
    SCLogOPIfaceCtx *sc_iface_ctx = NULL;
1683
    char *logfile = SCLogGetLogFilename("boo.txt");
1684
    sc_lid = SCLogAllocLogInitData();
1685
    FAIL_IF_NULL(sc_lid);
1686
    sc_lid->startup_message = "Test02";
1687
    sc_lid->global_log_level = SC_LOG_DEBUG;
1688
    sc_lid->op_filter = "boo";
1689
    sc_iface_ctx = SCLogInitOPIfaceCtx("file", "%m - %d", SC_LOG_WARNING, logfile);
1690
    SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid);
1691
    sc_iface_ctx = SCLogInitOPIfaceCtx("console", NULL, SC_LOG_ERROR,
1692
                                       NULL);
1693
    SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid);
1694
1695
    SCLogInitLogModule(sc_lid);
1696
1697
    FAIL_IF_NULL(sc_log_config);
1698
1699
    FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1700
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1701
               SC_LOG_OP_IFACE_FILE == sc_log_config->op_ifaces->iface);
1702
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1703
               sc_log_config->op_ifaces->next != NULL &&
1704
               SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->next->iface);
1705
    FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1706
                strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level),
1707
                        sc_log_config->log_format) == 0);
1708
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1709
               sc_log_config->op_ifaces->log_format != NULL &&
1710
               strcmp("%m - %d", sc_log_config->op_ifaces->log_format) == 0);
1711
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1712
               sc_log_config->op_ifaces->next != NULL &&
1713
               sc_log_config->op_ifaces->next->log_format == NULL);
1714
1715
    SCLogFreeLogInitData(sc_lid);
1716
    SCLogDeInitLogModule();
1717
1718
    sc_lid = SCLogAllocLogInitData();
1719
    FAIL_IF_NULL(sc_lid);
1720
    sc_lid->startup_message = "Test02";
1721
    sc_lid->global_log_level = SC_LOG_DEBUG;
1722
    sc_lid->op_filter = "boo";
1723
    sc_lid->global_log_format = "kaboo";
1724
1725
    SCLogInitLogModule(sc_lid);
1726
1727
    FAIL_IF_NULL(sc_log_config);
1728
1729
    FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1730
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1731
               SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface);
1732
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1733
               sc_log_config->op_ifaces->next == NULL);
1734
    FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1735
               strcmp("kaboo", sc_log_config->log_format) == 0);
1736
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1737
               sc_log_config->op_ifaces->log_format == NULL);
1738
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1739
               sc_log_config->op_ifaces->next == NULL);
1740
1741
    SCLogFreeLogInitData(sc_lid);
1742
    SCLogDeInitLogModule();
1743
    SCFree(logfile);
1744
#endif
1745
    PASS;
1746
}
1747
1748
static int SCLogTestInit03(void)
1749
{
1750
    SCLogInitLogModule(NULL);
1751
1752
    SCLogAddFGFilterBL(NULL, "bamboo", -1);
1753
    SCLogAddFGFilterBL(NULL, "soo", -1);
1754
    SCLogAddFGFilterBL(NULL, "dummy", -1);
1755
1756
    FAIL_IF_NOT(SCLogPrintFGFilters() == 3);
1757
1758
    SCLogAddFGFilterBL(NULL, "dummy1", -1);
1759
    SCLogAddFGFilterBL(NULL, "dummy2", -1);
1760
1761
    FAIL_IF_NOT(SCLogPrintFGFilters() == 5);
1762
1763
    SCLogDeInitLogModule();
1764
1765
    PASS;
1766
}
1767
1768
static int SCLogTestInit04(void)
1769
{
1770
    SCLogInitLogModule(NULL);
1771
1772
    SCLogAddFDFilter("bamboo");
1773
    SCLogAddFDFilter("soo");
1774
    SCLogAddFDFilter("foo");
1775
    SCLogAddFDFilter("roo");
1776
1777
    FAIL_IF_NOT(SCLogPrintFDFilters() == 4);
1778
1779
    SCLogAddFDFilter("loo");
1780
    SCLogAddFDFilter("soo");
1781
1782
    FAIL_IF_NOT(SCLogPrintFDFilters() == 5);
1783
1784
    SCLogRemoveFDFilter("bamboo");
1785
    SCLogRemoveFDFilter("soo");
1786
    SCLogRemoveFDFilter("foo");
1787
    SCLogRemoveFDFilter("noo");
1788
1789
    FAIL_IF_NOT(SCLogPrintFDFilters() == 2);
1790
1791
    SCLogDeInitLogModule();
1792
1793
    PASS;
1794
}
1795
1796
static int SCLogTestInit05(void)
1797
{
1798
    char str[4096];
1799
    memset(str, 'A', sizeof(str));
1800
    str[sizeof(str) - 1] = '\0';
1801
    SCLogInfo("%s", str);
1802
1803
    PASS;
1804
}
1805
1806
#endif /* UNITTESTS */
1807
1808
void SCLogRegisterTests(void)
1809
0
{
1810
1811
#ifdef UNITTESTS
1812
1813
    UtRegisterTest("SCLogTestInit01", SCLogTestInit01);
1814
    UtRegisterTest("SCLogTestInit02", SCLogTestInit02);
1815
    UtRegisterTest("SCLogTestInit03", SCLogTestInit03);
1816
    UtRegisterTest("SCLogTestInit04", SCLogTestInit04);
1817
    UtRegisterTest("SCLogTestInit05", SCLogTestInit05);
1818
1819
#endif /* UNITTESTS */
1820
1821
0
   return;
1822
0
}