• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22550934724

01 Mar 2026 07:34PM UTC coverage: 75.853% (+2.2%) from 73.687%
22550934724

Pull #14923

github

web-flow
github-actions: bump github/codeql-action from 4.32.3 to 4.32.4

Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.32.3 to 4.32.4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Commits](https://github.com/github/codeql-action/compare/v4.32.3...v4.32.4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.32.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #14923: github-actions: bump github/codeql-action from 4.32.3 to 4.32.4

240804 of 317461 relevant lines covered (75.85%)

2441195.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.39
/src/util-debug.c
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
{
×
123
    int syslog_log_level = 0;
×
124

125
    switch (log_level) {
×
126
        case SC_LOG_ERROR:
×
127
            syslog_log_level = LOG_ERR;
×
128
            break;
×
129
        case SC_LOG_WARNING:
×
130
            syslog_log_level = LOG_WARNING;
×
131
            break;
×
132
        case SC_LOG_NOTICE:
×
133
            syslog_log_level = LOG_NOTICE;
×
134
            break;
×
135
        case SC_LOG_INFO:
×
136
            syslog_log_level = LOG_INFO;
×
137
            break;
×
138
        case SC_LOG_CONFIG:
×
139
        case SC_LOG_DEBUG:
×
140
        case SC_LOG_PERF:
×
141
            syslog_log_level = LOG_DEBUG;
×
142
            break;
×
143
        default:
×
144
            syslog_log_level = LOG_EMERG;
×
145
            break;
×
146
    }
×
147

148
    return syslog_log_level;
×
149
}
×
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
{
10,789,695✔
159
    /* Would only happen if the log file failed to re-open during rotation. */
160
    if (fd == NULL) {
10,789,695✔
161
        return;
×
162
    }
×
163

164
#if defined (OS_WIN32)
165
        SCMutexLock(&sc_log_stream_lock);
166
#endif /* OS_WIN32 */
167

168
    if (fprintf(fd, "%s\n", msg) < 0)
10,789,695✔
169
        printf("Error writing to stream using fprintf\n");
×
170

171
    fflush(fd);
10,789,695✔
172

173
#if defined (OS_WIN32)
174
        SCMutexUnlock(&sc_log_stream_lock);
175
#endif /* OS_WIN32 */
176
}
10,789,695✔
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
{
×
190
    //static struct syslog_data data = SYSLOG_DATA_INIT;
191
    //syslog_r(syslog_log_level, NULL, "%s", msg);
192

193
    syslog(syslog_log_level, "%s", msg);
×
194
}
×
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
{
×
202
    SCJsonBuilder *js = SCJbNewObject();
×
203
    if (unlikely(js == NULL))
×
204
        goto error;
×
205

206
    char timebuf[64];
×
207
    CreateIsoTimeString(tval, timebuf, sizeof(timebuf));
×
208
    SCJbSetString(js, "timestamp", timebuf);
×
209

210
    const char *s = SCMapEnumValueToName(log_level, sc_log_level_map);
×
211
    if (s != NULL) {
×
212
        SCJbSetString(js, "log_level", s);
×
213
    } else {
×
214
        JB_SET_STRING(js, "log_level", "INVALID");
×
215
    }
×
216

217
    JB_SET_STRING(js, "event_type", "engine");
×
218
    SCJbOpenObject(js, "engine");
×
219

220
    if (message)
×
221
        SCJbSetString(js, "message", message);
×
222

223
    if (t_thread_name[0] != '\0') {
×
224
        SCJbSetString(js, "thread_name", t_thread_name);
×
225
    }
×
226

227
    if (module) {
×
228
        /* Determine how much of module name to display */
229
        int dn_len = 0;
×
230
        const char *dn_name;
×
231
        dn_name = SCTransformModule(module, &dn_len);
×
232
        SCJbSetString(js, "module", dn_name);
×
233
    }
×
234

235
    if (log_level >= SC_LOG_DEBUG) {
×
236
        if (function)
×
237
            SCJbSetString(js, "function", function);
×
238

239
        if (file)
×
240
            SCJbSetString(js, "file", file);
×
241

242
        if (line > 0)
×
243
            SCJbSetUint(js, "line", line);
×
244
    }
×
245
    SCJbClose(js); // engine
×
246

247
    SCJbClose(js);
×
248
    memcpy(buffer, SCJbPtr(js), MIN(buffer_size, SCJbLen(js)));
×
249

250
    SCJbFree(js);
×
251

252
    return 0;
×
253

254
error:
×
255
    return -1;
×
256
}
×
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
{
10,789,695✔
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
    if (strncmp("tm-", module_name, 3) == 0) {
10,789,695✔
289
        *dn_len = (int)strlen(module_name) - 3;
8✔
290
        return module_name + 3;
8✔
291
    } else if (strncmp("util-", module_name, 5) == 0) {
10,789,687✔
292
        *dn_len = (int)strlen(module_name) - 5;
230,764✔
293
        return module_name + 5;
230,764✔
294
    } else if (strncmp("source-pcap-file", module_name, 16) == 0) {
10,558,925✔
295
        *dn_len = (int)strlen("pcap");
28,282✔
296
        return "pcap";
28,282✔
297
    } else if (strncmp("source-", module_name, 7) == 0) {
10,530,641✔
298
        *dn_len = (int)strlen(module_name) - 7;
12✔
299
        return module_name + 7;
12✔
300
    } else if (strncmp("runmode-", module_name, 8) == 0) {
10,530,629✔
301
        *dn_len = (int)strlen(module_name) - 8;
6,960✔
302
        return module_name + 8;
6,960✔
303
    } else if (strncmp("app-layer-", module_name, 10) == 0) {
10,529,118✔
304
        *dn_len = (int)strlen(module_name);
2,712✔
305
        return module_name;
2,712✔
306
    } else if (strncmp("detect-engine", module_name, 13) == 0) {
10,520,957✔
307
        *dn_len = (int)strlen("detect");
5,265,239✔
308
        return "detect";
5,265,239✔
309
    }
5,265,239✔
310

311
    int seg_cnt = 0;
5,255,718✔
312

313
    char *last;
5,255,718✔
314
    char *w = (char *)module_name;
5,255,718✔
315
    while (w && (w = strchr(w, '-')) != NULL && seg_cnt < transform_max_segs) {
10,946,282✔
316
        seg_cnt++;
5,690,564✔
317
        last = w;
5,690,564✔
318
        w++; /* skip past '-' */
5,690,564✔
319
    }
5,690,564✔
320

321
    if (seg_cnt < transform_max_segs)
5,255,718✔
322
        *dn_len = (int)strlen(module_name);
4,685,871✔
323
    else
569,847✔
324
        *dn_len = (int)(last - module_name);
569,847✔
325

326
    return module_name;
5,255,718✔
327
}
10,789,695✔
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
{
10,789,695✔
344
    if (type == SC_LOG_OP_TYPE_JSON)
10,789,695✔
345
        return SCLogMessageJSON(
×
346
                tval, buffer, buffer_size, log_level, file, line, function, module, message);
×
347

348
    char *temp = buffer;
10,789,695✔
349
    const char *s = NULL;
10,789,695✔
350
    struct tm *tms = NULL;
10,789,695✔
351

352
    const char *redb = "";
10,789,695✔
353
    const char *red = "";
10,789,695✔
354
    const char *yellowb = "";
10,789,695✔
355
    const char *yellow = "";
10,789,695✔
356
    const char *green = "";
10,789,695✔
357
    const char *blue = "";
10,789,695✔
358
    const char *reset = "";
10,789,695✔
359
    if (color) {
10,789,695✔
360
        redb = "\x1b[1;31m";
×
361
        red = "\x1b[31m";
×
362
        yellowb = "\x1b[1;33m";
×
363
        yellow = "\x1b[33m";
×
364
        green = "\x1b[32m";
×
365
        blue = "\x1b[34m";
×
366
        reset = "\x1b[0m";
×
367
    }
×
368
    /* no of characters_written(cw) by snprintf */
369
    int cw = 0;
10,789,695✔
370

371
    DEBUG_VALIDATE_BUG_ON(sc_log_module_initialized != 1);
10,789,695✔
372

373
    /* make a copy of the format string as it will be modified below */
374
    const int add_M = strstr(log_format, "%M") == NULL;
10,789,695✔
375
    DEBUG_VALIDATE_BUG_ON(strlen(log_format) > UINT16_MAX);
10,789,695✔
376
    char local_format[strlen(log_format) + add_M * 2 + 1];
10,789,695✔
377
    strlcpy(local_format, log_format, sizeof(local_format));
10,789,695✔
378
    if (add_M)
10,789,695✔
379
        strlcat(local_format, "%M", sizeof(local_format));
×
380
    char *temp_fmt = local_format;
10,789,695✔
381
    char *substr = temp_fmt;
10,789,695✔
382
    struct tm local_tm;
10,789,695✔
383

384
    while ((temp_fmt = strchr(temp_fmt, SC_LOG_FMT_PREFIX))) {
75,527,047✔
385
        if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
64,737,627✔
386
            return 0;
108✔
387
        }
108✔
388
        switch(temp_fmt[1]) {
64,737,519✔
389
            case SC_LOG_FMT_TIME:
16,787✔
390
                temp_fmt[0] = '\0';
16,787✔
391

392
                tms = SCLocalTime(SCTIME_SECS(tval), &local_tm);
16,787✔
393

394
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
16,787✔
395
                        "%s%s%04d-%02d-%02d %02d:%02d:%02d%s", substr, green, tms->tm_year + 1900,
16,787✔
396
                        tms->tm_mon + 1, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec,
16,787✔
397
                        reset);
16,787✔
398
                if (cw < 0)
16,787✔
399
                    return -1;
×
400
                temp += cw;
16,787✔
401
                temp_fmt++;
16,787✔
402
                substr = temp_fmt;
16,787✔
403
                substr++;
16,787✔
404
                break;
16,787✔
405

406
            case SC_LOG_FMT_TIME_LEGACY:
×
407
                temp_fmt[0] = '\0';
×
408

409
                tms = SCLocalTime(SCTIME_SECS(tval), &local_tm);
×
410

411
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
×
412
                              "%s%s%d/%d/%04d -- %02d:%02d:%02d%s",
×
413
                              substr, green, tms->tm_mday, tms->tm_mon + 1,
×
414
                              tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
×
415
                              tms->tm_sec, reset);
×
416
                if (cw < 0)
×
417
                    return -1;
×
418
                temp += cw;
×
419
                temp_fmt++;
×
420
                substr = temp_fmt;
×
421
                substr++;
×
422
                break;
×
423

424
            case SC_LOG_FMT_PID:
×
425
                temp_fmt[0] = '\0';
×
426
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
×
427
                              "%s%s%u%s", substr, yellow, getpid(), reset);
×
428
                if (cw < 0)
×
429
                    return -1;
×
430
                temp += cw;
×
431
                temp_fmt++;
×
432
                substr = temp_fmt;
×
433
                substr++;
×
434
                break;
×
435

436
            case SC_LOG_FMT_TID:
16,787✔
437
                temp_fmt[0] = '\0';
16,787✔
438
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
16,787✔
439
                              "%s%s%lu%s", substr, yellow, SCGetThreadIdLong(), reset);
16,787✔
440
                if (cw < 0)
16,787✔
441
                    return -1;
×
442
                temp += cw;
16,787✔
443
                temp_fmt++;
16,787✔
444
                substr = temp_fmt;
16,787✔
445
                substr++;
16,787✔
446
                break;
16,787✔
447

448
            case SC_LOG_FMT_THREAD_NAME:
×
449
            case SC_LOG_FMT_TM:
16,787✔
450
                temp_fmt[0] = '\0';
16,787✔
451
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr,
16,787✔
452
                        yellow, t_thread_name, reset);
16,787✔
453
                if (cw < 0)
16,787✔
454
                    return -1;
×
455
                temp += cw;
16,787✔
456
                temp_fmt++;
16,787✔
457
                substr = temp_fmt;
16,787✔
458
                substr++;
16,787✔
459
                break;
16,787✔
460

461
            case SC_LOG_FMT_LOG_LEVEL:
10,789,693✔
462
                temp_fmt[0] = '\0';
10,789,693✔
463
                s = SCMapEnumValueToName(log_level, sc_log_level_map);
10,789,693✔
464
                if (s != NULL) {
10,789,694✔
465
                    if (log_level <= SC_LOG_ERROR)
10,789,694✔
466
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
9,925,434✔
467
                                  "%s%s%s%s", substr, redb, s, reset);
9,925,434✔
468
                    else if (log_level == SC_LOG_WARNING)
864,260✔
469
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
199,712✔
470
                                  "%s%s%s%s", substr, red, s, reset);
199,712✔
471
                    else if (log_level == SC_LOG_NOTICE)
664,548✔
472
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
74,148✔
473
                                  "%s%s%s%s", substr, yellowb, s, reset);
74,148✔
474
                    else
590,400✔
475
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
590,400✔
476
                                substr, yellow, s, reset);
590,400✔
477
                } else {
2,158,255,115✔
478
                    cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr,
2,147,483,647✔
479
                            "INVALID");
2,147,483,647✔
480
                }
2,147,483,647✔
481
                if (cw < 0)
10,789,693✔
482
                    return -1;
×
483
                temp += cw;
10,789,693✔
484
                temp_fmt++;
10,789,693✔
485
                substr = temp_fmt;
10,789,693✔
486
                substr++;
10,789,693✔
487
                break;
10,789,693✔
488

489
            case SC_LOG_FMT_LOG_SLEVEL:
×
490
                temp_fmt[0] = '\0';
×
491
                s = SCMapEnumValueToName(log_level, sc_log_slevel_map);
×
492
                if (s != NULL) {
×
493
                    if (log_level <= SC_LOG_ERROR)
×
494
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
×
495
                                substr, redb, s, reset);
×
496
                    else if (log_level == SC_LOG_WARNING)
×
497
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
×
498
                                substr, red, s, reset);
×
499
                    else if (log_level == SC_LOG_NOTICE)
×
500
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s",
×
501
                                substr, yellowb, s, reset);
×
502
                    else
×
503
                        cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
×
504
                                  "%s%s%s%s", substr, yellow, s, reset);
×
505
                } else {
×
506
                    cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
×
507
                                  "%s%s", substr, "INVALID");
×
508
                }
×
509
                if (cw < 0)
×
510
                    return -1;
×
511
                temp += cw;
×
512
                temp_fmt++;
×
513
                substr = temp_fmt;
×
514
                substr++;
×
515
                break;
×
516

517
            case SC_LOG_FMT_FILE_NAME:
10,772,704✔
518
                temp_fmt[0] = '\0';
10,772,704✔
519
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
10,772,704✔
520
                              "%s%s%s%s", substr, blue, file, reset);
10,772,704✔
521
                if (cw < 0)
10,772,704✔
522
                    return -1;
×
523
                temp += cw;
10,772,704✔
524
                temp_fmt++;
10,772,704✔
525
                substr = temp_fmt;
10,772,704✔
526
                substr++;
10,772,704✔
527
                break;
10,772,704✔
528

529
            case SC_LOG_FMT_LINE:
10,772,631✔
530
                temp_fmt[0] = '\0';
10,772,631✔
531
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
10,772,631✔
532
                              "%s%s%u%s", substr, green, line, reset);
10,772,631✔
533
                if (cw < 0)
10,772,631✔
534
                    return -1;
×
535
                temp += cw;
10,772,631✔
536
                temp_fmt++;
10,772,631✔
537
                substr = temp_fmt;
10,772,631✔
538
                substr++;
10,772,631✔
539
                break;
10,772,631✔
540

541
            case SC_LOG_FMT_SUBSYSTEM:
10,789,693✔
542
                temp_fmt[0] = '\0';
10,789,693✔
543

544
                /* Determine how much of module name to display */
545
                int dn_len = 0;
10,789,693✔
546
                const char *dn_name = "unknown";
10,789,693✔
547
                if (module) {
10,789,693✔
548
                    dn_name = SCTransformModule(module, &dn_len);
10,789,692✔
549
                }
10,789,692✔
550

551
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s%s", substr,
10,789,693✔
552
                        green, dn_name, reset);
10,789,693✔
553
                if (cw < 0)
10,789,693✔
554
                    return -1;
×
555
                temp += cw;
10,789,693✔
556
                temp_fmt++;
10,789,693✔
557
                substr = temp_fmt;
10,789,693✔
558
                substr++;
10,789,693✔
559
                break;
10,789,693✔
560

561
            case SC_LOG_FMT_FUNCTION:
10,772,739✔
562
                temp_fmt[0] = '\0';
10,772,739✔
563
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
10,772,739✔
564
                              "%s%s%s%s", substr, green, function, reset);
10,772,739✔
565
                if (cw < 0)
10,772,739✔
566
                    return -1;
×
567
                temp += cw;
10,772,739✔
568
                temp_fmt++;
10,772,739✔
569
                substr = temp_fmt;
10,772,739✔
570
                substr++;
10,772,739✔
571
                break;
10,772,739✔
572

573
            case SC_LOG_FMT_MESSAGE: {
10,789,695✔
574
                temp_fmt[0] = '\0';
10,789,695✔
575
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr);
10,789,695✔
576
                if (cw < 0) {
10,789,695✔
577
                    return -1;
×
578
                }
×
579
                temp += cw;
10,789,695✔
580
                if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
10,789,695✔
581
                    return 0;
×
582
                }
×
583
                const char *hi = "";
10,789,695✔
584
                if (log_level <= SC_LOG_ERROR)
10,789,695✔
585
                    hi = red;
9,925,434✔
586
                else if (log_level <= SC_LOG_NOTICE)
864,261✔
587
                    hi = yellow;
273,860✔
588
                cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", hi, message,
10,789,695✔
589
                        reset);
10,789,695✔
590
                if (cw < 0) {
10,789,695✔
591
                    return -1;
×
592
                }
×
593
                temp += cw;
10,789,695✔
594
                if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
10,789,695✔
595
                    return 0;
168✔
596
                }
168✔
597
                temp_fmt++;
10,789,527✔
598
                substr = temp_fmt;
10,789,527✔
599
                substr++;
10,789,527✔
600
                break;
10,789,527✔
601
            }
10,789,695✔
602
        }
64,737,519✔
603
        temp_fmt++;
64,737,352✔
604
    }
64,737,352✔
605
    if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
10,789,420✔
606
        return 0;
85✔
607
    }
85✔
608
    cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr);
10,789,335✔
609
    if (cw < 0) {
10,789,335✔
610
        return -1;
×
611
    }
×
612
    if (sc_log_config->op_filter_regex != NULL) {
10,789,335✔
613
        if (pcre2_match(sc_log_config->op_filter_regex, (PCRE2_SPTR8)buffer, strlen(buffer), 0, 0,
×
614
                    sc_log_config->op_filter_regex_match, NULL) < 0) {
×
615
            return -1; // bit hacky, but just return !0
×
616
        }
×
617
    }
×
618

619
    return 0;
10,789,335✔
620
}
10,789,335✔
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
{
×
628
    if (op_iface_ctx->file == NULL) {
×
629
        return 0;
×
630
    }
×
631

632
    if (op_iface_ctx->file_d != NULL) {
×
633
        fclose(op_iface_ctx->file_d);
×
634
    }
×
635
    op_iface_ctx->file_d = fopen(op_iface_ctx->file, "a");
×
636
    if (op_iface_ctx->file_d == NULL) {
×
637
        return -1;
×
638
    }
×
639
    return 0;
×
640
}
×
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
{
10,788,231✔
656
    char buffer[SC_LOG_MAX_LOG_MSG_LEN] = "";
10,788,231✔
657
    SCLogOPIfaceCtx *op_iface_ctx = NULL;
10,788,231✔
658

659
    if (sc_log_module_initialized != 1) {
10,788,231✔
660
        printf("Logging module not initialized.  Call SCLogInitLogModule() "
×
661
               "first before using the debug API\n");
×
662
        return SC_OK;
×
663
    }
×
664

665
    /* get ts here so we log the same ts to each output */
666
    struct timeval tval;
10,788,231✔
667
    gettimeofday(&tval, NULL);
10,788,231✔
668
    SCTime_t ts = SCTIME_FROM_TIMEVAL(&tval);
10,788,231✔
669

670
    op_iface_ctx = sc_log_config->op_ifaces;
10,788,231✔
671
    while (op_iface_ctx != NULL) {
21,593,250✔
672
        if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) {
10,805,019✔
673
            op_iface_ctx = op_iface_ctx->next;
15,324✔
674
            continue;
15,324✔
675
        }
15,324✔
676

677
        switch (op_iface_ctx->iface) {
10,789,695✔
678
            case SC_LOG_OP_IFACE_CONSOLE:
4,117✔
679
                if (SCLogMessageGetBuffer(ts, op_iface_ctx->use_color, op_iface_ctx->type, buffer,
4,117✔
680
                            sizeof(buffer),
4,117✔
681
                            op_iface_ctx->log_format ? op_iface_ctx->log_format
4,117✔
682
                                                     : sc_log_config->log_format,
4,117✔
683
                            log_level, file, line, function, module, message) == 0) {
4,117✔
684
                    SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, buffer);
4,117✔
685
                }
4,117✔
686
                break;
4,117✔
687
            case SC_LOG_OP_IFACE_FILE:
10,785,576✔
688
                if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer),
10,785,576✔
689
                            op_iface_ctx->log_format ? op_iface_ctx->log_format
10,785,576✔
690
                                                     : sc_log_config->log_format,
10,785,576✔
691
                            log_level, file, line, function, module, message) == 0) {
10,785,578✔
692
                    int r = 0;
10,785,578✔
693
                    SCMutexLock(&op_iface_ctx->fp_mutex);
10,785,578✔
694
                    if (op_iface_ctx->rotation_flag) {
10,785,578✔
695
                        r = SCLogReopen(op_iface_ctx);
×
696
                        op_iface_ctx->rotation_flag = 0;
×
697
                    }
×
698
                    SCLogPrintToStream(op_iface_ctx->file_d, buffer);
10,785,578✔
699
                    SCMutexUnlock(&op_iface_ctx->fp_mutex);
10,785,578✔
700

701
                    /* report error outside of lock to avoid recursion */
702
                    if (r == -1) {
10,785,578✔
703
                        SCLogError("re-opening file \"%s\" failed: %s", op_iface_ctx->file,
×
704
                                strerror(errno));
×
705
                    }
×
706
                }
10,785,578✔
707
                break;
10,785,576✔
708
            case SC_LOG_OP_IFACE_SYSLOG:
×
709
                if (SCLogMessageGetBuffer(ts, 0, op_iface_ctx->type, buffer, sizeof(buffer),
×
710
                            op_iface_ctx->log_format ? op_iface_ctx->log_format
×
711
                                                     : sc_log_config->log_format,
×
712
                            log_level, file, line, function, module, message) == 0) {
×
713
                    SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), buffer);
×
714
                }
×
715
                break;
×
716
            default:
×
717
                break;
×
718
        }
10,789,695✔
719
        op_iface_ctx = op_iface_ctx->next;
10,789,695✔
720
    }
10,789,695✔
721
    return SC_OK;
10,788,231✔
722
}
10,788,231✔
723

724
void SCLog(int x, const char *file, const char *func, const int line, const char *module,
725
        const char *fmt, ...)
726
{
1,683,180✔
727
    if (sc_log_global_log_level >= x &&
1,683,180✔
728
            (sc_log_fg_filters_present == 0 ||
1,683,180✔
729
             SCLogMatchFGFilterWL(file, func, line) == 1 ||
662,860✔
730
             SCLogMatchFGFilterBL(file, func, line) == 1) &&
662,860✔
731
            (sc_log_fd_filters_present == 0 ||
1,683,180✔
732
             SCLogMatchFDFilter(func) == 1))
662,860✔
733
    {
662,860✔
734
        char msg[SC_LOG_MAX_LOG_MSG_LEN];
662,860✔
735
        va_list ap;
662,860✔
736
        va_start(ap, fmt);
662,860✔
737
        vsnprintf(msg, sizeof(msg), fmt, ap);
662,860✔
738
        va_end(ap);
662,860✔
739
        SCLogMessage(x, file, line, func, module, msg);
662,860✔
740
    }
662,860✔
741
}
1,683,180✔
742

743
void SCLogErr(int x, const char *file, const char *func, const int line, const char *module,
744
        const char *fmt, ...)
745
{
10,057,437✔
746
    if (sc_log_global_log_level >= x &&
10,057,437✔
747
            (sc_log_fg_filters_present == 0 ||
10,057,437✔
748
             SCLogMatchFGFilterWL(file, func, line) == 1 ||
10,057,396✔
749
             SCLogMatchFGFilterBL(file, func, line) == 1) &&
10,057,396✔
750
            (sc_log_fd_filters_present == 0 ||
10,057,437✔
751
             SCLogMatchFDFilter(func) == 1))
10,057,396✔
752
    {
10,057,396✔
753
        char msg[SC_LOG_MAX_LOG_MSG_LEN];
10,057,396✔
754
        va_list ap;
10,057,396✔
755
        va_start(ap, fmt);
10,057,396✔
756
        vsnprintf(msg, sizeof(msg), fmt, ap);
10,057,396✔
757
        va_end(ap);
10,057,396✔
758
        SCLogMessage(x, file, line, func, module, msg);
10,057,396✔
759
    }
10,057,396✔
760
}
10,057,437✔
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
{
176,671✔
770
#ifdef DEBUG
771
    if (sc_log_global_log_level == SC_LOG_DEBUG)
772
        return 1;
773
    else
774
        return 0;
775
#else
776
    return 0;
176,671✔
777
#endif
176,671✔
778
}
176,671✔
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
{
×
789
    SCLogOPBuffer *buffer = NULL;
×
790

791
    if ( (buffer = SCMalloc(sc_log_config->op_ifaces_cnt *
×
792
                          sizeof(SCLogOPBuffer))) == NULL) {
×
793
        FatalError("Fatal error encountered in SCLogAllocLogOPBuffer. Exiting...");
×
794
    }
×
795

796
    SCLogOPIfaceCtx *op_iface_ctx = sc_log_config->op_ifaces;
×
797
    for (int i = 0; i < sc_log_config->op_ifaces_cnt; i++, op_iface_ctx = op_iface_ctx->next) {
×
798
        buffer[i].log_format = op_iface_ctx->log_format;
×
799
        buffer[i].temp = buffer[i].msg;
×
800
    }
×
801

802
    return buffer;
×
803
}
×
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
{
34✔
815
    SCLogOPIfaceCtx *iface_ctx = NULL;
34✔
816

817
    if ((iface_ctx = SCCalloc(1, sizeof(SCLogOPIfaceCtx))) == NULL) {
34✔
818
        FatalError("Fatal error encountered in SCLogallocLogOPIfaceCtx. Exiting...");
×
819
    }
×
820

821
    return iface_ctx;
34✔
822
}
34✔
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
{
9✔
838
    SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
9✔
839
    if (iface_ctx == NULL) {
9✔
840
        FatalError("Fatal error encountered in SCLogInitFileOPIface. Exiting...");
×
841
    }
×
842

843
    if (file == NULL) {
9✔
844
        goto error;
×
845
    }
×
846

847
    iface_ctx->iface = SC_LOG_OP_IFACE_FILE;
9✔
848
    iface_ctx->type = type;
9✔
849

850
    if ( (iface_ctx->file_d = fopen(file, "a")) == NULL) {
9✔
851
        SCLogWarning("error opening file %s: %s", file, strerror(errno));
×
852
        goto error;
×
853
    }
×
854

855
#ifndef OS_WIN32
9✔
856
    if (userid != 0 || groupid != 0) {
9✔
857
        if (fchown(fileno(iface_ctx->file_d), userid, groupid) == -1) {
×
858
            SCLogWarning("Failed to change ownership of file %s: %s", file, strerror(errno));
×
859
        }
×
860
    }
×
861
#endif
9✔
862

863
    if ((iface_ctx->file = SCStrdup(file)) == NULL) {
9✔
864
        goto error;
×
865
    }
×
866

867
    if (log_format != NULL && (iface_ctx->log_format = SCStrdup(log_format)) == NULL) {
9✔
868
        goto error;
×
869
    }
×
870

871
    SCMutexInit(&iface_ctx->fp_mutex, NULL);
9✔
872
    OutputRegisterFileRotationFlag(&iface_ctx->rotation_flag);
9✔
873

874
    iface_ctx->log_level = log_level;
9✔
875

876
    return iface_ctx;
9✔
877

878
error:
×
879
    if (iface_ctx->file != NULL) {
×
880
        SCFree((char *)iface_ctx->file);
×
881
        iface_ctx->file = NULL;
×
882
    }
×
883
    if (iface_ctx->log_format != NULL) {
×
884
        SCFree((char *)iface_ctx->log_format);
×
885
        iface_ctx->log_format = NULL;
×
886
    }
×
887
    if (iface_ctx->file_d != NULL) {
×
888
        fclose(iface_ctx->file_d);
×
889
        iface_ctx->file_d = NULL;
×
890
    }
×
891
    SCFree(iface_ctx);
×
892
    return NULL;
×
893
}
9✔
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
{
25✔
909
    SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
25✔
910

911
    if (iface_ctx == NULL) {
25✔
912
        FatalError("Fatal error encountered in SCLogInitConsoleOPIface. Exiting...");
×
913
    }
×
914

915
    iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE;
25✔
916
    iface_ctx->type = type;
25✔
917

918
    /* console log format is overridden by envvars */
919
    const char *tmp_log_format = log_format;
25✔
920
    const char *s = getenv(SC_LOG_ENV_LOG_FORMAT);
25✔
921
    if (s != NULL) {
25✔
922
#if 0
923
        printf("Overriding setting for \"console.format\" because of env "
924
                "var SC_LOG_FORMAT=\"%s\".\n", s);
925
#endif
926
        tmp_log_format = s;
1✔
927
    }
1✔
928

929
    if (tmp_log_format != NULL &&
25✔
930
        (iface_ctx->log_format = SCStrdup(tmp_log_format)) == NULL) {
25✔
931
        printf("Error allocating memory\n");
×
932
        exit(EXIT_FAILURE);
×
933
    }
×
934

935
    /* console log level is overridden by envvars */
936
    SCLogLevel tmp_log_level = log_level;
25✔
937
    s = getenv(SC_LOG_ENV_LOG_LEVEL);
25✔
938
    if (s != NULL) {
25✔
939
        SCLogLevel l = SCMapEnumNameToValue(s, sc_log_level_map);
1✔
940
        if (l > SC_LOG_NOTSET && l < SC_LOG_LEVEL_MAX) {
1✔
941
#if 0
942
            printf("Overriding setting for \"console.level\" because of env "
943
                    "var SC_LOG_LEVEL=\"%s\".\n", s);
944
#endif
945
            tmp_log_level = l;
1✔
946
        }
1✔
947
    }
1✔
948
    iface_ctx->log_level = tmp_log_level;
25✔
949

950
#ifndef OS_WIN32
25✔
951
    if (isatty(fileno(stdout)) && isatty(fileno(stderr))) {
25✔
952
        iface_ctx->use_color = true;
×
953
    }
×
954
#endif
25✔
955

956
    return iface_ctx;
25✔
957
}
25✔
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
{
×
974
    SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
×
975

976
    if ( iface_ctx == NULL) {
×
977
        FatalError("Fatal error encountered in SCLogInitSyslogOPIface. Exiting...");
×
978
    }
×
979

980
    iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG;
×
981
    iface_ctx->type = type;
×
982

983
    if (facility == -1)
×
984
        facility = SC_LOG_DEF_SYSLOG_FACILITY;
×
985
    iface_ctx->facility = facility;
×
986

987
    if (log_format != NULL &&
×
988
        (iface_ctx->log_format = SCStrdup(log_format)) == NULL) {
×
989
        printf("Error allocating memory\n");
×
990
        exit(EXIT_FAILURE);
×
991
    }
×
992

993
    iface_ctx->log_level = log_level;
×
994

995
    openlog(NULL, LOG_NDELAY, iface_ctx->facility);
×
996

997
    return iface_ctx;
×
998
}
×
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
{
19✔
1007
    SCLogOPIfaceCtx *temp = NULL;
19✔
1008

1009
    while (iface_ctx != NULL) {
39✔
1010
        temp = iface_ctx;
20✔
1011

1012
        if (iface_ctx->file_d != NULL) {
20✔
1013
            fclose(iface_ctx->file_d);
3✔
1014
            SCMutexDestroy(&iface_ctx->fp_mutex);
3✔
1015
        }
3✔
1016

1017
        if (iface_ctx->file != NULL)
20✔
1018
            SCFree((void *)iface_ctx->file);
3✔
1019

1020
        if (iface_ctx->log_format != NULL)
20✔
1021
            SCFree((void *)iface_ctx->log_format);
4✔
1022

1023
        if (iface_ctx->iface == SC_LOG_OP_IFACE_SYSLOG) {
20✔
1024
            closelog();
×
1025
        }
×
1026

1027
        iface_ctx = iface_ctx->next;
20✔
1028

1029
        SCFree(temp);
20✔
1030
    }
20✔
1031
}
19✔
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
{
31✔
1042
    SCLogLevel log_level = SC_LOG_NOTSET;
31✔
1043
    const char *s = NULL;
31✔
1044

1045
    /* envvar overrides config */
1046
    s = getenv(SC_LOG_ENV_LOG_LEVEL);
31✔
1047
    if (s != NULL) {
31✔
1048
        log_level = SCMapEnumNameToValue(s, sc_log_level_map);
1✔
1049
    } else if (sc_lid != NULL) {
30✔
1050
        log_level = sc_lid->global_log_level;
4✔
1051
    }
4✔
1052

1053
    /* deal with the global_log_level to be used */
1054
    if (log_level > SC_LOG_NOTSET && log_level < SC_LOG_LEVEL_MAX)
31✔
1055
        sc_lc->log_level = log_level;
5✔
1056
    else {
26✔
1057
        sc_lc->log_level = SC_LOG_DEF_LOG_LEVEL;
26✔
1058
#ifndef UNITTESTS
14✔
1059
        if (sc_lid != NULL) {
14✔
1060
            printf("Warning: Invalid/No global_log_level assigned by user.  Falling "
1061
                   "back on the default_log_level \"%s\"\n",
1062
                   SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map));
1063
        }
1064
#endif
14✔
1065
    }
26✔
1066

1067
    /* we also set it to a global var, as it is easier to access it */
1068
    sc_log_global_log_level = sc_lc->log_level;
31✔
1069
}
31✔
1070

1071
const char *SCLogLevel2Name(const SCLogLevel lvl)
1072
{
6✔
1073
    return SCMapEnumValueToName(lvl, sc_log_level_map);
6✔
1074
}
6✔
1075

1076
SCLogLevel SCLogGetLogLevel(void)
1077
{
×
1078
    return sc_log_global_log_level;
×
1079
}
×
1080

1081
static inline const char *SCLogGetDefaultLogFormat(const SCLogLevel lvl)
1082
{
31✔
1083
    const char *prog_ver = GetProgramVersion();
31✔
1084
    if (strstr(prog_ver, "RELEASE") != NULL) {
31✔
1085
        if (lvl <= SC_LOG_NOTICE)
×
1086
            return SC_LOG_DEF_LOG_FORMAT_REL_NOTICE;
×
1087
        else if (lvl <= SC_LOG_INFO)
×
1088
            return SC_LOG_DEF_LOG_FORMAT_REL_INFO;
×
1089
        else if (lvl <= SC_LOG_CONFIG)
×
1090
            return SC_LOG_DEF_LOG_FORMAT_REL_CONFIG;
×
1091
    }
×
1092
    return SC_LOG_DEF_LOG_FORMAT_DEBUG;
31✔
1093
}
31✔
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
{
31✔
1104
    const char *format = NULL;
31✔
1105

1106
    /* envvar overrides config */
1107
    format = getenv(SC_LOG_ENV_LOG_FORMAT);
31✔
1108
    if (format == NULL) {
31✔
1109
        if (sc_lid != NULL) {
30✔
1110
            format = sc_lid->global_log_format;
4✔
1111
        }
4✔
1112
    }
30✔
1113

1114
    /* deal with the global log format to be used */
1115
    if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) {
31✔
1116
        format = SCLogGetDefaultLogFormat(sc_lc->log_level);
27✔
1117
#ifndef UNITTESTS
14✔
1118
        if (sc_lid != NULL) {
14✔
1119
            printf("Warning: Invalid/No global_log_format supplied by user or format "
1120
                   "length exceeded limit of \"%d\" characters.  Falling back on "
1121
                   "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN,
1122
                   format);
1123
        }
1124
#endif
14✔
1125
    }
27✔
1126

1127
    if (format != NULL && (sc_lc->log_format = SCStrdup(format)) == NULL) {
31✔
1128
        printf("Error allocating memory\n");
×
1129
        exit(EXIT_FAILURE);
×
1130
    }
×
1131
}
31✔
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
{
31✔
1142
    SCLogOPIfaceCtx *op_ifaces_ctx = NULL;
31✔
1143
    int op_iface = 0;
31✔
1144
    const char *s = NULL;
31✔
1145

1146
    if (sc_lid != NULL && sc_lid->op_ifaces != NULL) {
31✔
1147
        sc_lc->op_ifaces = sc_lid->op_ifaces;
3✔
1148
        sc_lid->op_ifaces = NULL;
3✔
1149
        sc_lc->op_ifaces_cnt = sc_lid->op_ifaces_cnt;
3✔
1150
    } else {
28✔
1151
        s = getenv(SC_LOG_ENV_LOG_OP_IFACE);
28✔
1152
        if (s != NULL) {
28✔
1153
            op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map);
7✔
1154

1155
            if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) {
7✔
1156
                op_iface = SC_LOG_DEF_LOG_OP_IFACE;
×
1157
#ifndef UNITTESTS
1158
                printf("Warning: Invalid output interface supplied by user.  "
1159
                       "Falling back on default_output_interface \"%s\"\n",
1160
                       SCMapEnumValueToName(op_iface, sc_log_op_iface_map));
1161
#endif
1162
            }
×
1163
        }
7✔
1164
        else {
21✔
1165
            op_iface = SC_LOG_DEF_LOG_OP_IFACE;
21✔
1166
#ifndef UNITTESTS
8✔
1167
            if (sc_lid != NULL) {
8✔
1168
                printf("Warning: Output_interface not supplied by user.  Falling "
1169
                       "back on default_output_interface \"%s\"\n",
1170
                       SCMapEnumValueToName(op_iface, sc_log_op_iface_map));
1171
            }
1172
#endif
8✔
1173
        }
21✔
1174

1175
        switch (op_iface) {
28✔
1176
            case SC_LOG_OP_IFACE_CONSOLE:
22✔
1177
                op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX,0);
22✔
1178
                break;
22✔
1179
            case SC_LOG_OP_IFACE_FILE:
6✔
1180
                s = getenv(SC_LOG_ENV_LOG_FILE);
6✔
1181
                if (s == NULL) {
6✔
1182
                    char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE);
×
1183
                    if (str != NULL) {
×
1184
                        op_ifaces_ctx = SCLogInitFileOPIface(str, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0);
×
1185
                        SCFree(str);
×
1186
                    }
×
1187
                } else {
6✔
1188
                    op_ifaces_ctx = SCLogInitFileOPIface(s, 0, 0, NULL, SC_LOG_LEVEL_MAX, 0);
6✔
1189
                }
6✔
1190
                break;
6✔
1191
            case SC_LOG_OP_IFACE_SYSLOG:
×
1192
                s = getenv(SC_LOG_ENV_LOG_FACILITY);
×
1193
                if (s == NULL)
×
1194
                    s = SC_LOG_DEF_SYSLOG_FACILITY_STR;
×
1195

1196
                op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1,0);
×
1197
                break;
×
1198
        }
28✔
1199
        sc_lc->op_ifaces = op_ifaces_ctx;
28✔
1200
        sc_lc->op_ifaces_cnt++;
28✔
1201
    }
28✔
1202
}
31✔
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
{
31✔
1213
    const char *filter = NULL;
31✔
1214

1215
    int opts = 0;
31✔
1216
    int en;
31✔
1217
    PCRE2_SIZE eo = 0;
31✔
1218

1219
    /* envvar overrides */
1220
    filter = getenv(SC_LOG_ENV_LOG_OP_FILTER);
31✔
1221
    if (filter == NULL) {
31✔
1222
        if (sc_lid != NULL) {
31✔
1223
            filter = sc_lid->op_filter;
4✔
1224
        }
4✔
1225
    }
31✔
1226

1227
    if (filter != NULL && strcmp(filter, "") != 0) {
31✔
1228
        sc_lc->op_filter = SCStrdup(filter);
2✔
1229
        if (sc_lc->op_filter == NULL) {
2✔
1230
            printf("pcre filter alloc failed\n");
×
1231
            return;
×
1232
        }
×
1233
        sc_lc->op_filter_regex =
2✔
1234
                pcre2_compile((PCRE2_SPTR8)filter, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
2✔
1235
        if (sc_lc->op_filter_regex == NULL) {
2✔
1236
            SCFree(sc_lc->op_filter);
×
1237
            PCRE2_UCHAR errbuffer[256];
×
1238
            pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
×
1239
            printf("pcre2 compile of \"%s\" failed at offset %d : %s\n", filter, (int)eo,
×
1240
                    errbuffer);
×
1241
            return;
×
1242
        }
×
1243
        sc_lc->op_filter_regex_match =
2✔
1244
                pcre2_match_data_create_from_pattern(sc_lc->op_filter_regex, NULL);
2✔
1245
    }
2✔
1246
}
31✔
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
{
4✔
1258
    SCLogInitData *sc_lid = NULL;
4✔
1259

1260
    if ((sc_lid = SCCalloc(1, sizeof(SCLogInitData))) == NULL)
4✔
1261
        return NULL;
×
1262

1263
    return sc_lid;
4✔
1264
}
4✔
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
{
2✔
1275
    if (sc_lid != NULL) {
2✔
1276
        SCLogFreeLogOPIfaceCtx(sc_lid->op_ifaces);
2✔
1277
        SCFree(sc_lid);
2✔
1278
    }
2✔
1279
}
2✔
1280
#endif
1281
#endif
1282

1283
/**
1284
 * \brief Frees the logging module context
1285
 */
1286
static inline void SCLogFreeLogConfig(SCLogConfig *sc_lc)
1287
{
45✔
1288
    if (sc_lc != NULL) {
45✔
1289
        if (sc_lc->startup_message != NULL)
17✔
1290
            SCFree(sc_lc->startup_message);
×
1291
        if (sc_lc->log_format != NULL)
17✔
1292
            SCFree(sc_lc->log_format);
17✔
1293
        if (sc_lc->op_filter != NULL)
17✔
1294
            SCFree(sc_lc->op_filter);
2✔
1295

1296
        if (sc_lc->op_filter_regex != NULL)
17✔
1297
            pcre2_code_free(sc_lc->op_filter_regex);
17✔
1298
        if (sc_lc->op_filter_regex_match)
17✔
1299
            pcre2_match_data_free(sc_lc->op_filter_regex_match);
17✔
1300

1301
        SCLogFreeLogOPIfaceCtx(sc_lc->op_ifaces);
17✔
1302
        SCFree(sc_lc);
17✔
1303
    }
17✔
1304
}
45✔
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
{
6✔
1314
    SCLogOPIfaceCtx *temp = NULL, *prev = NULL;
6✔
1315
    SCLogOPIfaceCtx **head = &sc_lid->op_ifaces;
6✔
1316

1317
    if (iface_ctx == NULL) {
6✔
1318
#ifdef DEBUG
1319
        printf("Argument(s) to SCLogAppendOPIfaceCtx() NULL\n");
1320
#endif
1321
        return;
×
1322
    }
×
1323

1324
    temp = *head;
6✔
1325
    while (temp != NULL) {
9✔
1326
        prev = temp;
3✔
1327
        temp = temp->next;
3✔
1328
    }
3✔
1329

1330
    if (prev == NULL)
6✔
1331
        *head = iface_ctx;
3✔
1332
    else
3✔
1333
        prev->next = iface_ctx;
3✔
1334

1335
    sc_lid->op_ifaces_cnt++;
6✔
1336
}
6✔
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
{
2✔
1360
    int iface = SCMapEnumNameToValue(iface_name, sc_log_op_iface_map);
2✔
1361

1362
    if (log_level < SC_LOG_NONE || log_level > SC_LOG_DEBUG) {
2✔
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) {
2✔
1370
        case SC_LOG_OP_IFACE_CONSOLE:
1✔
1371
            return SCLogInitConsoleOPIface(log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1✔
1372
        case SC_LOG_OP_IFACE_FILE:
1✔
1373
            return SCLogInitFileOPIface(arg, 0, 0, log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1✔
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
    }
2✔
1384
}
2✔
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
{
31✔
1398
    /* De-initialize the logging context, if it has already init by the
1399
     * environment variables at the start of the engine */
1400
    SCLogDeInitLogModule();
31✔
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
    if ((sc_log_config = SCCalloc(1, sizeof(SCLogConfig))) == NULL) {
31✔
1410
        FatalError("Fatal error encountered in SCLogInitLogModule. Exiting...");
×
1411
    }
×
1412

1413
    SCLogSetLogLevel(sc_lid, sc_log_config);
31✔
1414
    SCLogSetLogFormat(sc_lid, sc_log_config);
31✔
1415
    SCLogSetOPIface(sc_lid, sc_log_config);
31✔
1416
    SCLogSetOPFilter(sc_lid, sc_log_config);
31✔
1417

1418
    sc_log_module_initialized = 1;
31✔
1419
    sc_log_module_cleaned = 0;
31✔
1420

1421
    //SCOutputPrint(sc_did->startup_message);
1422

1423
    SCSetRustLogLevel(sc_log_global_log_level);
31✔
1424
}
31✔
1425

1426
void SCLogLoadConfig(int daemon, int verbose, uint32_t userid, uint32_t groupid)
1427
{
9✔
1428
    SCConfNode *outputs;
9✔
1429
    SCLogInitData *sc_lid;
9✔
1430
    int have_logging = 0;
9✔
1431
    int max_level = 0;
9✔
1432
    SCLogLevel min_level = 0;
9✔
1433

1434
    /* If verbose logging was requested, set the minimum as
1435
     * SC_LOG_NOTICE plus the extra verbosity. */
1436
    if (verbose) {
9✔
1437
        min_level = SC_LOG_NOTICE + verbose;
6✔
1438
    }
6✔
1439

1440
    outputs = SCConfGetNode("logging.outputs");
9✔
1441
    if (outputs == NULL) {
9✔
1442
        SCLogDebug("No logging.output configuration section found.");
7✔
1443
        return;
7✔
1444
    }
7✔
1445

1446
    sc_lid = SCLogAllocLogInitData();
2✔
1447
    if (sc_lid == NULL) {
2✔
1448
        SCLogDebug("Could not allocate memory for log init data");
×
1449
        return;
×
1450
    }
×
1451

1452
    /* Get default log level and format. */
1453
    const char *default_log_level_s = NULL;
2✔
1454
    if (SCConfGet("logging.default-log-level", &default_log_level_s) == 1) {
2✔
1455
        SCLogLevel default_log_level =
2✔
1456
            SCMapEnumNameToValue(default_log_level_s, sc_log_level_map);
2✔
1457
        if (default_log_level == -1) {
2✔
1458
            SCLogError("Invalid default log level: %s", default_log_level_s);
×
1459
            exit(EXIT_FAILURE);
×
1460
        }
×
1461
        sc_lid->global_log_level = MAX(min_level, default_log_level);
2✔
1462
    } else {
2✔
1463
        sc_lid->global_log_level = MAX(min_level, SC_LOG_NOTICE);
×
1464
    }
×
1465

1466
    if (SCConfGet("logging.default-log-format", &sc_lid->global_log_format) != 1)
2✔
1467
        sc_lid->global_log_format = SCLogGetDefaultLogFormat(sc_lid->global_log_level);
2✔
1468

1469
    (void)SCConfGet("logging.default-output-filter", &sc_lid->op_filter);
2✔
1470

1471
    SCConfNode *seq_node, *output;
2✔
1472
    TAILQ_FOREACH(seq_node, &outputs->head, next) {
6✔
1473
        SCLogLevel level = sc_lid->global_log_level;
6✔
1474
        SCLogOPIfaceCtx *op_iface_ctx = NULL;
6✔
1475
        const char *format;
6✔
1476
        const char *level_s;
6✔
1477

1478
        output = SCConfNodeLookupChild(seq_node, seq_node->val);
6✔
1479
        if (output == NULL)
6✔
1480
            continue;
×
1481

1482
        /* By default an output is enabled. */
1483
        const char *enabled = SCConfNodeLookupChildValue(output, "enabled");
6✔
1484
        if (enabled != NULL && SCConfValIsFalse(enabled))
6✔
1485
            continue;
2✔
1486

1487
        SCLogOPType type = SC_LOG_OP_TYPE_REGULAR;
4✔
1488
        const char *type_s = SCConfNodeLookupChildValue(output, "type");
4✔
1489
        if (type_s != NULL) {
4✔
1490
            if (strcmp(type_s, "regular") == 0)
×
1491
                type = SC_LOG_OP_TYPE_REGULAR;
×
1492
            else if (strcmp(type_s, "json") == 0) {
×
1493
                type = SC_LOG_OP_TYPE_JSON;
×
1494
            }
×
1495
        }
×
1496

1497
        format = SCConfNodeLookupChildValue(output, "format");
4✔
1498

1499
        level_s = SCConfNodeLookupChildValue(output, "level");
4✔
1500
        if (level_s != NULL) {
4✔
1501
            level = SCMapEnumNameToValue(level_s, sc_log_level_map);
2✔
1502
            if (level == -1) {
2✔
1503
                SCLogError("Invalid log level: %s", level_s);
×
1504
                exit(EXIT_FAILURE);
×
1505
            }
×
1506
            max_level = MAX(max_level, level);
2✔
1507
        }
2✔
1508

1509
        /* Increase the level of extra verbosity was requested. */
1510
        level = MAX(min_level, level);
4✔
1511

1512
        if (strcmp(output->name, "console") == 0) {
4✔
1513
            op_iface_ctx = SCLogInitConsoleOPIface(format, level, type);
2✔
1514
        }
2✔
1515
        else if (strcmp(output->name, "file") == 0) {
2✔
1516
            if (format == NULL) {
2✔
1517
                format = SC_LOG_DEF_FILE_FORMAT;
2✔
1518
            }
2✔
1519

1520
            const char *filename = SCConfNodeLookupChildValue(output, "filename");
2✔
1521
            if (filename == NULL) {
2✔
1522
                FatalError("Logging to file requires a filename");
×
1523
            }
×
1524
            char *path = NULL;
2✔
1525
            if (!(PathIsAbsolute(filename))) {
2✔
1526
                path = SCLogGetLogFilename(filename);
2✔
1527
            } else {
2✔
1528
                path = SCStrdup(filename);
×
1529
            }
×
1530
            if (path == NULL)
2✔
1531
                FatalError("failed to setup output to file");
×
1532
            have_logging = 1;
2✔
1533
            op_iface_ctx = SCLogInitFileOPIface(path, userid, groupid, format, level, type);
2✔
1534
            SCFree(path);
2✔
1535
        }
2✔
1536
        else if (strcmp(output->name, "syslog") == 0) {
×
1537
            int facility = SC_LOG_DEF_SYSLOG_FACILITY;
×
1538
            const char *facility_s = SCConfNodeLookupChildValue(output, "facility");
×
1539
            if (facility_s != NULL) {
×
1540
                facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap());
×
1541
                if (facility == -1) {
×
1542
                    SCLogWarning("Invalid syslog "
×
1543
                                 "facility: \"%s\", now using \"%s\" as syslog "
×
1544
                                 "facility",
×
1545
                            facility_s, SC_LOG_DEF_SYSLOG_FACILITY_STR);
×
1546
                    facility = SC_LOG_DEF_SYSLOG_FACILITY;
×
1547
                }
×
1548
            }
×
1549
            SCLogDebug("Initializing syslog logging with format \"%s\"", format);
×
1550
            have_logging = 1;
×
1551
            op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level, type);
×
1552
        }
×
1553
        else {
×
1554
            SCLogWarning("invalid logging method: %s, ignoring", output->name);
×
1555
        }
×
1556
        if (op_iface_ctx != NULL) {
4✔
1557
            SCLogAppendOPIfaceCtx(op_iface_ctx, sc_lid);
4✔
1558
        }
4✔
1559
    }
4✔
1560

1561
    if (daemon && (have_logging == 0)) {
2✔
1562
        SCLogWarning("no logging compatible with daemon mode selected,"
×
1563
                     " suricata won't be able to log. Please update "
×
1564
                     " 'logging.outputs' in the YAML.");
×
1565
    }
×
1566

1567
    /* Set the global log level to that of the max level used. */
1568
    sc_lid->global_log_level = MAX(sc_lid->global_log_level, max_level);
2✔
1569
    SCLogInitLogModule(sc_lid);
2✔
1570

1571
    SCLogDebug("sc_log_global_log_level: %d", sc_log_global_log_level);
2✔
1572
    SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format);
2✔
1573
    SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter);
2✔
1574

1575
    SCFree(sc_lid);
2✔
1576
}
2✔
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
{
3✔
1589
    const char *log_dir = SCConfigGetLogDirectory();
3✔
1590
    char *log_filename = SCMalloc(PATH_MAX);
3✔
1591
    if (unlikely(log_filename == NULL))
3✔
1592
        return NULL;
×
1593
    snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, filearg);
3✔
1594
    return log_filename;
3✔
1595
}
3✔
1596

1597
/**
1598
 * \brief De-Initializes the logging module
1599
 */
1600
void SCLogDeInitLogModule(void)
1601
{
45✔
1602
    SCLogFreeLogConfig(sc_log_config);
45✔
1603

1604
    /* reset the global logging_module variables */
1605
    sc_log_global_log_level = 0;
45✔
1606
    sc_log_module_initialized = 0;
45✔
1607
    sc_log_module_cleaned = 1;
45✔
1608
    sc_log_config = NULL;
45✔
1609

1610
    /* de-init the FD filters */
1611
    SCLogReleaseFDFilters();
45✔
1612
    /* de-init the FG filters */
1613
    SCLogReleaseFGFilters();
45✔
1614

1615
#if defined (OS_WIN32)
1616
    SCMutexDestroy(&sc_log_stream_lock);
1617
#endif /* OS_WIN32 */
1618
}
45✔
1619

1620
void SCFatalErrorOnInitStatic(const char *arg)
1621
{
×
1622
    FatalErrorOnInit("%s", arg);
×
1623
}
×
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
{
1✔
1638
#ifndef OS_WIN32
1✔
1639
    /* unset any environment variables set for the logging module */
1640
    unsetenv(SC_LOG_ENV_LOG_LEVEL);
1✔
1641
    unsetenv(SC_LOG_ENV_LOG_OP_IFACE);
1✔
1642
    unsetenv(SC_LOG_ENV_LOG_FORMAT);
1✔
1643

1644
    SCLogInitLogModule(NULL);
1✔
1645

1646
    FAIL_IF_NULL(sc_log_config);
1✔
1647

1648
    FAIL_IF_NOT(SC_LOG_DEF_LOG_LEVEL == sc_log_config->log_level);
1✔
1649
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1650
               SC_LOG_DEF_LOG_OP_IFACE == sc_log_config->op_ifaces->iface);
1✔
1651
    FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1✔
1652
                strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level),
1✔
1653
                        sc_log_config->log_format) == 0);
1✔
1654

1655
    SCLogDeInitLogModule();
1✔
1656

1657
    setenv(SC_LOG_ENV_LOG_LEVEL, "Debug", 1);
1✔
1658
    setenv(SC_LOG_ENV_LOG_OP_IFACE, "Console", 1);
1✔
1659
    setenv(SC_LOG_ENV_LOG_FORMAT, "%n- %l", 1);
1✔
1660

1661
    SCLogInitLogModule(NULL);
1✔
1662

1663
    FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1✔
1664
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1665
               SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface);
1✔
1666
    FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1✔
1667
               !strcmp("%n- %l", sc_log_config->log_format));
1✔
1668

1669
    unsetenv(SC_LOG_ENV_LOG_LEVEL);
1✔
1670
    unsetenv(SC_LOG_ENV_LOG_OP_IFACE);
1✔
1671
    unsetenv(SC_LOG_ENV_LOG_FORMAT);
1✔
1672

1673
    SCLogDeInitLogModule();
1✔
1674
#endif
1✔
1675
    PASS;
1✔
1676
}
1✔
1677

1678
static int SCLogTestInit02(void)
1679
{
1✔
1680
#ifndef OS_WIN32
1✔
1681
    SCLogInitData *sc_lid = NULL;
1✔
1682
    SCLogOPIfaceCtx *sc_iface_ctx = NULL;
1✔
1683
    char *logfile = SCLogGetLogFilename("boo.txt");
1✔
1684
    sc_lid = SCLogAllocLogInitData();
1✔
1685
    FAIL_IF_NULL(sc_lid);
1✔
1686
    sc_lid->startup_message = "Test02";
1✔
1687
    sc_lid->global_log_level = SC_LOG_DEBUG;
1✔
1688
    sc_lid->op_filter = "boo";
1✔
1689
    sc_iface_ctx = SCLogInitOPIfaceCtx("file", "%m - %d", SC_LOG_WARNING, logfile);
1✔
1690
    SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid);
1✔
1691
    sc_iface_ctx = SCLogInitOPIfaceCtx("console", NULL, SC_LOG_ERROR,
1✔
1692
                                       NULL);
1✔
1693
    SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid);
1✔
1694

1695
    SCLogInitLogModule(sc_lid);
1✔
1696

1697
    FAIL_IF_NULL(sc_log_config);
1✔
1698

1699
    FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1✔
1700
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1701
               SC_LOG_OP_IFACE_FILE == sc_log_config->op_ifaces->iface);
1✔
1702
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1703
               sc_log_config->op_ifaces->next != NULL &&
1✔
1704
               SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->next->iface);
1✔
1705
    FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1✔
1706
                strcmp(SCLogGetDefaultLogFormat(sc_log_config->log_level),
1✔
1707
                        sc_log_config->log_format) == 0);
1✔
1708
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1709
               sc_log_config->op_ifaces->log_format != NULL &&
1✔
1710
               strcmp("%m - %d", sc_log_config->op_ifaces->log_format) == 0);
1✔
1711
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1712
               sc_log_config->op_ifaces->next != NULL &&
1✔
1713
               sc_log_config->op_ifaces->next->log_format == NULL);
1✔
1714

1715
    SCLogFreeLogInitData(sc_lid);
1✔
1716
    SCLogDeInitLogModule();
1✔
1717

1718
    sc_lid = SCLogAllocLogInitData();
1✔
1719
    FAIL_IF_NULL(sc_lid);
1✔
1720
    sc_lid->startup_message = "Test02";
1✔
1721
    sc_lid->global_log_level = SC_LOG_DEBUG;
1✔
1722
    sc_lid->op_filter = "boo";
1✔
1723
    sc_lid->global_log_format = "kaboo";
1✔
1724

1725
    SCLogInitLogModule(sc_lid);
1✔
1726

1727
    FAIL_IF_NULL(sc_log_config);
1✔
1728

1729
    FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1✔
1730
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1731
               SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface);
1✔
1732
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1733
               sc_log_config->op_ifaces->next == NULL);
1✔
1734
    FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1✔
1735
               strcmp("kaboo", sc_log_config->log_format) == 0);
1✔
1736
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1737
               sc_log_config->op_ifaces->log_format == NULL);
1✔
1738
    FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1✔
1739
               sc_log_config->op_ifaces->next == NULL);
1✔
1740

1741
    SCLogFreeLogInitData(sc_lid);
1✔
1742
    SCLogDeInitLogModule();
1✔
1743
    SCFree(logfile);
1✔
1744
#endif
1✔
1745
    PASS;
1✔
1746
}
1✔
1747

1748
static int SCLogTestInit03(void)
1749
{
1✔
1750
    SCLogInitLogModule(NULL);
1✔
1751

1752
    SCLogAddFGFilterBL(NULL, "bamboo", -1);
1✔
1753
    SCLogAddFGFilterBL(NULL, "soo", -1);
1✔
1754
    SCLogAddFGFilterBL(NULL, "dummy", -1);
1✔
1755

1756
    FAIL_IF_NOT(SCLogPrintFGFilters() == 3);
1✔
1757

1758
    SCLogAddFGFilterBL(NULL, "dummy1", -1);
1✔
1759
    SCLogAddFGFilterBL(NULL, "dummy2", -1);
1✔
1760

1761
    FAIL_IF_NOT(SCLogPrintFGFilters() == 5);
1✔
1762

1763
    SCLogDeInitLogModule();
1✔
1764

1765
    PASS;
1✔
1766
}
1✔
1767

1768
static int SCLogTestInit04(void)
1769
{
1✔
1770
    SCLogInitLogModule(NULL);
1✔
1771

1772
    SCLogAddFDFilter("bamboo");
1✔
1773
    SCLogAddFDFilter("soo");
1✔
1774
    SCLogAddFDFilter("foo");
1✔
1775
    SCLogAddFDFilter("roo");
1✔
1776

1777
    FAIL_IF_NOT(SCLogPrintFDFilters() == 4);
1✔
1778

1779
    SCLogAddFDFilter("loo");
1✔
1780
    SCLogAddFDFilter("soo");
1✔
1781

1782
    FAIL_IF_NOT(SCLogPrintFDFilters() == 5);
1✔
1783

1784
    SCLogRemoveFDFilter("bamboo");
1✔
1785
    SCLogRemoveFDFilter("soo");
1✔
1786
    SCLogRemoveFDFilter("foo");
1✔
1787
    SCLogRemoveFDFilter("noo");
1✔
1788

1789
    FAIL_IF_NOT(SCLogPrintFDFilters() == 2);
1✔
1790

1791
    SCLogDeInitLogModule();
1✔
1792

1793
    PASS;
1✔
1794
}
1✔
1795

1796
static int SCLogTestInit05(void)
1797
{
1✔
1798
    char str[4096];
1✔
1799
    memset(str, 'A', sizeof(str));
1✔
1800
    str[sizeof(str) - 1] = '\0';
1✔
1801
    SCLogInfo("%s", str);
1✔
1802

1803
    PASS;
1✔
1804
}
1✔
1805

1806
#endif /* UNITTESTS */
1807

1808
void SCLogRegisterTests(void)
1809
{
1✔
1810

1811
#ifdef UNITTESTS
1✔
1812

1813
    UtRegisterTest("SCLogTestInit01", SCLogTestInit01);
1✔
1814
    UtRegisterTest("SCLogTestInit02", SCLogTestInit02);
1✔
1815
    UtRegisterTest("SCLogTestInit03", SCLogTestInit03);
1✔
1816
    UtRegisterTest("SCLogTestInit04", SCLogTestInit04);
1✔
1817
    UtRegisterTest("SCLogTestInit05", SCLogTestInit05);
1✔
1818

1819
#endif /* UNITTESTS */
1✔
1820

1821
   return;
1✔
1822
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc