suricata
util-logopenfile.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2026 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 Mike Pomraning <mpomraning@qualys.com>
22  *
23  * File-like output for logging: regular files and sockets.
24  */
25 
26 #include "suricata-common.h" /* errno.h, string.h, etc. */
27 #include "util-logopenfile.h"
28 #include "suricata.h"
29 #include "conf.h" /* ConfNode, etc. */
30 #include "output.h" /* DEFAULT_LOG_* */
31 #include "util-byte.h"
32 #include "util-conf.h"
33 #include "util-path.h"
34 #include "util-misc.h"
35 #include "util-time.h"
36 #include "log-flush.h"
37 
38 #if defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SYS_TYPES_H)
39 #define BUILD_WITH_UNIXSOCKET
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/un.h>
43 #endif
44 
45 #ifdef HAVE_LIBHIREDIS
46 #include "util-log-redis.h"
47 #endif /* HAVE_LIBHIREDIS */
48 
49 #define LOGFILE_NAME_MAX 255
50 
51 static bool LogFileNewThreadedCtx(LogFileCtx *parent_ctx, const char *log_path, const char *append,
52  ThreadLogFileHashEntry *entry);
53 
54 // Threaded eve.json identifier
55 static SC_ATOMIC_DECL_AND_INIT_WITH_VAL(uint16_t, eve_file_id, 1);
56 
57 /* Flush list for heartbeat-triggered flushing */
58 static SCMutex log_file_flush_mutex = SCMUTEX_INITIALIZER;
59 static TAILQ_HEAD(, LogFileFlushEntry_) log_file_flush_list = TAILQ_HEAD_INITIALIZER(
60  log_file_flush_list);
61 
62 #ifdef BUILD_WITH_UNIXSOCKET
63 /** \brief connect to the indicated local stream socket, logging any errors
64  * \param path filesystem path to connect to
65  * \param log_err, non-zero if connect failure should be logged.
66  * \retval FILE* on success (fdopen'd wrapper of underlying socket)
67  * \retval NULL on error
68  */
69 static FILE *
70 SCLogOpenUnixSocketFp(const char *path, int sock_type, int log_err)
71 {
72  struct sockaddr_un saun;
73  int s = -1;
74  FILE * ret = NULL;
75 
76  memset(&saun, 0x00, sizeof(saun));
77 
78  s = socket(PF_UNIX, sock_type, 0);
79  if (s < 0) goto err;
80 
81  saun.sun_family = AF_UNIX;
82  strlcpy(saun.sun_path, path, sizeof(saun.sun_path));
83 
84  if (connect(s, (const struct sockaddr *)&saun, sizeof(saun)) < 0)
85  goto err;
86 
87  ret = fdopen(s, "w");
88  if (ret == NULL)
89  goto err;
90 
91  return ret;
92 
93 err:
94  if (log_err)
96  "Error connecting to socket \"%s\": %s (will keep trying)", path, strerror(errno));
97 
98  if (s >= 0)
99  close(s);
100 
101  return NULL;
102 }
103 
104 /**
105  * \brief Attempt to reconnect a disconnected (or never-connected) Unix domain socket.
106  * \retval 1 if it is now connected; otherwise 0
107  */
108 static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx)
109 {
110  int disconnected = 0;
111  if (log_ctx->fp) {
112  SCLogWarning("Write error on Unix socket \"%s\": %s; reconnecting...", log_ctx->filename,
113  strerror(errno));
114  fclose(log_ctx->fp);
115  log_ctx->fp = NULL;
116  log_ctx->reconn_timer = 0;
117  disconnected = 1;
118  }
119 
120  struct timeval tv;
121  uint64_t now;
122  gettimeofday(&tv, NULL);
123  now = (uint64_t)tv.tv_sec * 1000;
124  now += tv.tv_usec / 1000; /* msec resolution */
125  if (log_ctx->reconn_timer != 0 &&
126  (now - log_ctx->reconn_timer) < LOGFILE_RECONN_MIN_TIME) {
127  /* Don't bother to try reconnecting too often. */
128  return 0;
129  }
130  log_ctx->reconn_timer = now;
131 
132  log_ctx->fp = SCLogOpenUnixSocketFp(log_ctx->filename, log_ctx->sock_type, 0);
133  if (log_ctx->fp) {
134  /* Connected at last (or reconnected) */
135  SCLogDebug("Reconnected socket \"%s\"", log_ctx->filename);
136  } else if (disconnected) {
137  SCLogWarning("Reconnect failed: %s (will keep trying)", strerror(errno));
138  }
139 
140  return log_ctx->fp ? 1 : 0;
141 }
142 
143 static int SCLogFileWriteSocket(const char *buffer, int buffer_len,
144  LogFileCtx *ctx)
145 {
146  int tries = 0;
147  int ret = 0;
148  bool reopen = false;
149  if (ctx->fp == NULL && ctx->is_sock) {
150  SCLogUnixSocketReconnect(ctx);
151  }
152 tryagain:
153  ret = -1;
154  reopen = 0;
155  errno = 0;
156  if (ctx->fp != NULL) {
157  int fd = fileno(ctx->fp);
158  ssize_t size = send(fd, buffer, buffer_len, ctx->send_flags);
159  if (size > -1) {
160  ret = 0;
161  } else {
162  if (errno == EAGAIN || errno == EWOULDBLOCK) {
163  SCLogDebug("Socket would block, dropping event.");
164  } else if (errno == EINTR) {
165  if (tries++ == 0) {
166  SCLogDebug("Interrupted system call, trying again.");
167  goto tryagain;
168  }
169  SCLogDebug("Too many interrupted system calls, "
170  "dropping event.");
171  } else {
172  /* Some other error. Assume badness and reopen. */
173  SCLogDebug("Send failed: %s", strerror(errno));
174  reopen = true;
175  }
176  }
177  }
178 
179  if (reopen && tries++ == 0) {
180  if (SCLogUnixSocketReconnect(ctx)) {
181  goto tryagain;
182  }
183  }
184 
185  if (ret == -1) {
186  ctx->dropped++;
187  }
188 
189  return ret;
190 }
191 #endif /* BUILD_WITH_UNIXSOCKET */
192 static inline void OutputWriteLock(pthread_mutex_t *m)
193 {
194  SCMutexLock(m);
195 
196 }
197 
198 /**
199  * \brief Flush a log file.
200  */
201 static void SCLogFileFlushNoLock(LogFileCtx *log_ctx)
202 {
203  log_ctx->bytes_since_last_flush = 0;
204  SCFflushUnlocked(log_ctx->fp);
205 }
206 
207 static void SCLogFileFlush(LogFileCtx *log_ctx)
208 {
209  OutputWriteLock(&log_ctx->fp_mutex);
210  SCLogFileFlushNoLock(log_ctx);
211  SCMutexUnlock(&log_ctx->fp_mutex);
212 }
213 
214 /**
215  * \brief Handle log file rotation checks and updates
216  * \param log_ctx Log file context
217  * \retval true if rotation occurred
218  */
219 static bool HandleLogRotation(LogFileCtx *log_ctx)
220 {
221  if (log_ctx->rotation_flag) {
222  log_ctx->rotation_flag = 0;
223  SCConfLogReopen(log_ctx);
224  if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) {
225  log_ctx->rotate_time = time(NULL) + log_ctx->rotate_interval;
226  }
227  return true;
228  } else if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) {
229  time_t now = time(NULL);
230  if (now >= log_ctx->rotate_time) {
231  SCConfLogReopen(log_ctx);
232  log_ctx->rotate_time = now + log_ctx->rotate_interval;
233  return true;
234  }
235  }
236 
237  return false;
238 }
239 
240 /**
241  * \brief Write buffer to log file.
242  * \retval 0 on failure; otherwise, the return value of fwrite_unlocked (number of
243  * characters successfully written).
244  */
245 static int SCLogFileWriteNoLock(const char *buffer, int buffer_len, LogFileCtx *log_ctx)
246 {
247  int ret = 0;
248 
249  DEBUG_VALIDATE_BUG_ON(log_ctx->is_sock);
250 
251  HandleLogRotation(log_ctx);
252 
253  if (log_ctx->fp) {
254  SCClearErrUnlocked(log_ctx->fp);
255  if (1 != SCFwriteUnlocked(buffer, buffer_len, 1, log_ctx->fp)) {
256  /* Only the first error is logged */
257  if (!log_ctx->output_errors) {
258  SCLogError("%s error while writing to %s",
259  SCFerrorUnlocked(log_ctx->fp) ? strerror(errno) : "unknown error",
260  log_ctx->filename);
261  }
262  log_ctx->output_errors++;
263  return ret;
264  }
265 
266  log_ctx->bytes_since_last_flush += buffer_len;
267 
268  if (log_ctx->buffer_size && log_ctx->bytes_since_last_flush >= log_ctx->buffer_size) {
269  SCLogDebug("%s: flushing %" PRIu64 " during write", log_ctx->filename,
270  log_ctx->bytes_since_last_flush);
271  SCLogFileFlushNoLock(log_ctx);
272  }
273  }
274 
275  return ret;
276 }
277 
278 /**
279  * \brief Write buffer to log file.
280  * \retval 0 on failure; otherwise, the return value of fwrite (number of
281  * characters successfully written).
282  */
283 static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx)
284 {
285  OutputWriteLock(&log_ctx->fp_mutex);
286  int ret = 0;
287 
288 #ifdef BUILD_WITH_UNIXSOCKET
289  if (log_ctx->is_sock) {
290  ret = SCLogFileWriteSocket(buffer, buffer_len, log_ctx);
291  } else
292 #endif
293  {
294  ret = SCLogFileWriteNoLock(buffer, buffer_len, log_ctx);
295  }
296 
297  SCMutexUnlock(&log_ctx->fp_mutex);
298 
299  return ret;
300 }
301 
302 /** \brief generate filename based on pattern
303  * \param pattern pattern to use
304  * \retval char* on success
305  * \retval NULL on error
306  */
307 static char *SCLogFilenameFromPattern(const char *pattern)
308 {
309  char *filename = SCMalloc(PATH_MAX);
310  if (filename == NULL) {
311  return NULL;
312  }
313 
314  int rc = SCTimeToStringPattern(time(NULL), pattern, filename, PATH_MAX);
315  if (rc != 0) {
316  SCFree(filename);
317  return NULL;
318  }
319 
320  return filename;
321 }
322 
323 static void SCLogFileCloseNoLock(LogFileCtx *log_ctx)
324 {
325  SCLogDebug("Closing %s", log_ctx->filename);
326  if (log_ctx->fp) {
327  if (log_ctx->buffer_size)
328  SCFflushUnlocked(log_ctx->fp);
329  fclose(log_ctx->fp);
330  }
331 
332  if (log_ctx->output_errors) {
333  SCLogError("There were %" PRIu64 " output errors to %s", log_ctx->output_errors,
334  log_ctx->filename);
335  }
336 }
337 
338 static void SCLogFileClose(LogFileCtx *log_ctx)
339 {
340  SCMutexLock(&log_ctx->fp_mutex);
341  SCLogFileCloseNoLock(log_ctx);
342  SCMutexUnlock(&log_ctx->fp_mutex);
343 }
344 
345 static char ThreadLogFileHashCompareFunc(
346  void *data1, uint16_t datalen1, void *data2, uint16_t datalen2)
347 {
350 
351  if (p1 == NULL || p2 == NULL)
352  return 0;
353 
354  return p1->thread_id == p2->thread_id;
355 }
356 static uint32_t ThreadLogFileHashFunc(HashTable *ht, void *data, uint16_t datalen)
357 {
358  const ThreadLogFileHashEntry *ent = (ThreadLogFileHashEntry *)data;
359 
360  return ent->thread_id % ht->array_size;
361 }
362 
363 static void ThreadLogFileHashFreeFunc(void *data)
364 {
365  BUG_ON(data == NULL);
366  ThreadLogFileHashEntry *thread_ent = (ThreadLogFileHashEntry *)data;
367 
368  if (!thread_ent)
369  return;
370 
371  if (thread_ent->isopen) {
372  LogFileCtx *lf_ctx = thread_ent->ctx;
373  /* Free the leaf log file entries */
374  if (!lf_ctx->threaded) {
375  LogFileFreeCtx(lf_ctx);
376  }
377  }
378  SCFree(thread_ent);
379 }
380 
381 bool SCLogOpenThreadedFile(const char *log_path, const char *append, LogFileCtx *parent_ctx)
382 {
383  parent_ctx->threads = SCCalloc(1, sizeof(LogThreadedFileCtx));
384  if (!parent_ctx->threads) {
385  SCLogError("Unable to allocate threads container");
386  return false;
387  }
388 
389  parent_ctx->threads->ht = HashTableInit(255, ThreadLogFileHashFunc,
390  ThreadLogFileHashCompareFunc, ThreadLogFileHashFreeFunc);
391  if (!parent_ctx->threads->ht) {
392  FatalError("Unable to initialize thread/entry hash table");
393  }
394 
395  parent_ctx->threads->append = SCStrdup(append == NULL ? DEFAULT_LOG_MODE_APPEND : append);
396  if (!parent_ctx->threads->append) {
397  SCLogError("Unable to allocate threads append setting");
398  goto error_exit;
399  }
400 
401  SCMutexInit(&parent_ctx->threads->mutex, NULL);
402  return true;
403 
404 error_exit:
405 
406  if (parent_ctx->threads->append) {
407  SCFree(parent_ctx->threads->append);
408  }
409  if (parent_ctx->threads->ht) {
410  HashTableFree(parent_ctx->threads->ht);
411  }
412  SCFree(parent_ctx->threads);
413  parent_ctx->threads = NULL;
414  return false;
415 }
416 
417 /** \brief open the indicated file, logging any errors
418  * \param path filesystem path to open
419  * \param append_setting open file with O_APPEND: "yes" or "no"
420  * \param mode permissions to set on file
421  * \retval FILE* on success
422  * \retval NULL on error
423  */
424 static FILE *SCLogOpenFileFp(
425  const char *path, const char *append_setting, uint32_t mode, const uint32_t buffer_size)
426 {
427  FILE *ret = NULL;
428 
429  char *filename = SCLogFilenameFromPattern(path);
430  if (filename == NULL) {
431  return NULL;
432  }
433 
434  int rc = SCCreateDirectoryTree(filename, false);
435  if (rc < 0) {
436  SCFree(filename);
437  return NULL;
438  }
439 
440  if (SCConfValIsTrue(append_setting)) {
441  ret = fopen(filename, "a");
442  } else {
443  ret = fopen(filename, "w");
444  }
445 
446  if (ret == NULL) {
447  SCLogError("Error opening file: \"%s\": %s", filename, strerror(errno));
448  goto error_exit;
449  } else {
450  if (mode != 0) {
451 #ifdef OS_WIN32
452  int r = _chmod(filename, (mode_t)mode);
453 #else
454  int r = fchmod(fileno(ret), (mode_t)mode);
455 #endif
456  if (r < 0) {
457  SCLogWarning("Could not chmod %s to %o: %s", filename, mode, strerror(errno));
458  }
459  }
460  }
461 
462  /* Set buffering behavior */
463  if (buffer_size == 0) {
464  setbuf(ret, NULL);
465  SCLogConfig("Setting output to %s non-buffered", filename);
466  } else {
467  if (setvbuf(ret, NULL, _IOFBF, buffer_size) < 0)
468  FatalError("unable to set %s to buffered: %d", filename, buffer_size);
469  SCLogConfig("Setting output to %s buffered [limit %d bytes]", filename, buffer_size);
470  }
471 
472 error_exit:
473  SCFree(filename);
474 
475  return ret;
476 }
477 
478 /** \brief open a generic output "log file", which may be a regular file or a socket
479  * \param conf ConfNode structure for the output section in question
480  * \param log_ctx Log file context allocated by caller
481  * \param default_filename Default name of file to open, if not specified in ConfNode
482  * \param rotate Register the file for rotation in HUP.
483  * \retval 0 on success
484  * \retval -1 on error
485  */
487  SCConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate)
488 {
489  char log_path[PATH_MAX];
490  const char *log_dir;
491  const char *filename, *filetype;
492 
493  // Arg check
494  if (conf == NULL || log_ctx == NULL || default_filename == NULL) {
495  SCLogError("SCConfLogOpenGeneric(conf %p, ctx %p, default %p) "
496  "missing an argument",
497  conf, log_ctx, default_filename);
498  return -1;
499  }
500  if (log_ctx->fp != NULL) {
501  SCLogError("SCConfLogOpenGeneric: previously initialized Log CTX "
502  "encountered");
503  return -1;
504  }
505 
506  // Resolve the given config
507  filename = SCConfNodeLookupChildValue(conf, "filename");
508  if (filename == NULL)
509  filename = default_filename;
510 
511  log_dir = SCConfigGetLogDirectory();
512 
513  if (PathIsAbsolute(filename)) {
514  snprintf(log_path, PATH_MAX, "%s", filename);
515  } else {
516  snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename);
517  }
518 
519  /* Compress IPv6 addresses */
520  const char *compress = SCConfNodeLookupChildValue(conf, "ipv6-compress");
521  log_ctx->compress_ipv6 = false;
522  if (compress != NULL && SCConfValIsTrue(compress))
523  log_ctx->compress_ipv6 = true;
524 
525  /* Rotate log file based on time */
526  const char *rotate_int = SCConfNodeLookupChildValue(conf, "rotate-interval");
527  if (rotate_int != NULL) {
528  time_t now = time(NULL);
529  log_ctx->flags |= LOGFILE_ROTATE_INTERVAL;
530 
531  /* Use a specific time */
532  if (strcmp(rotate_int, "minute") == 0) {
533  log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now);
534  log_ctx->rotate_interval = 60;
535  } else if (strcmp(rotate_int, "hour") == 0) {
536  log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now);
537  log_ctx->rotate_interval = 3600;
538  } else if (strcmp(rotate_int, "day") == 0) {
539  log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now);
540  log_ctx->rotate_interval = 86400;
541  }
542 
543  /* Use a timer */
544  else {
545  log_ctx->rotate_interval = SCParseTimeSizeString(rotate_int);
546  if (log_ctx->rotate_interval == 0) {
547  FatalError("invalid rotate-interval value");
548  }
549  log_ctx->rotate_time = now + log_ctx->rotate_interval;
550  }
551  }
552 
553  filetype = SCConfNodeLookupChildValue(conf, "filetype");
554  if (filetype == NULL)
555  filetype = DEFAULT_LOG_FILETYPE;
556 
557  /* Determine the buffering for this output device; a value of 0 means to not buffer;
558  * any other value must be a multiple of 4096
559  * The default value is 0 (no buffering)
560  */
561  uint32_t buffer_size = LOGFILE_EVE_BUFFER_SIZE;
562  const char *buffer_size_value = SCConfNodeLookupChildValue(conf, "buffer-size");
563  if (buffer_size_value != NULL) {
564  uint32_t value;
565  if (ParseSizeStringU32(buffer_size_value, &value) < 0) {
566  FatalError("Error parsing "
567  "buffer-size - %s. Killing engine",
568  buffer_size_value);
569  }
570  buffer_size = value;
571  }
572 
573  SCLogDebug("buffering: %s -> %d", buffer_size_value, buffer_size);
574  const char *filemode = SCConfNodeLookupChildValue(conf, "filemode");
575  uint32_t mode = 0;
576  if (filemode != NULL && StringParseUint32(&mode, 8, (uint16_t)strlen(filemode), filemode) > 0) {
577  log_ctx->filemode = mode;
578  }
579 
580  const char *append = SCConfNodeLookupChildValue(conf, "append");
581  if (append == NULL)
582  append = DEFAULT_LOG_MODE_APPEND;
583 
584  /* JSON flags */
585  log_ctx->json_flags = JSON_PRESERVE_ORDER|JSON_COMPACT|
586  JSON_ENSURE_ASCII|JSON_ESCAPE_SLASH;
587 
588  SCConfNode *json_flags = SCConfNodeLookupChild(conf, "json");
589 
590  if (json_flags != 0) {
591  const char *preserve_order = SCConfNodeLookupChildValue(json_flags, "preserve-order");
592  if (preserve_order != NULL && SCConfValIsFalse(preserve_order))
593  log_ctx->json_flags &= ~(JSON_PRESERVE_ORDER);
594 
595  const char *compact = SCConfNodeLookupChildValue(json_flags, "compact");
596  if (compact != NULL && SCConfValIsFalse(compact))
597  log_ctx->json_flags &= ~(JSON_COMPACT);
598 
599  const char *ensure_ascii = SCConfNodeLookupChildValue(json_flags, "ensure-ascii");
600  if (ensure_ascii != NULL && SCConfValIsFalse(ensure_ascii))
601  log_ctx->json_flags &= ~(JSON_ENSURE_ASCII);
602 
603  const char *escape_slash = SCConfNodeLookupChildValue(json_flags, "escape-slash");
604  if (escape_slash != NULL && SCConfValIsFalse(escape_slash))
605  log_ctx->json_flags &= ~(JSON_ESCAPE_SLASH);
606  }
607 
608 #ifdef BUILD_WITH_UNIXSOCKET
609  if (log_ctx->threaded) {
610  if (strcasecmp(filetype, "unix_stream") == 0 || strcasecmp(filetype, "unix_dgram") == 0) {
611  FatalError("Socket file types do not support threaded output");
612  }
613  }
614 #endif
615  if (!(strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 || strcasecmp(filetype, "file") == 0)) {
616  SCLogConfig("buffering setting ignored for %s output types", filetype);
617  }
618 
619  // Now, what have we been asked to open?
620  if (strcasecmp(filetype, "unix_stream") == 0) {
621 #ifdef BUILD_WITH_UNIXSOCKET
622  /* Don't bail. May be able to connect later. */
623  log_ctx->is_sock = 1;
624  log_ctx->sock_type = SOCK_STREAM;
625  log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1);
626 #else
627  return -1;
628 #endif
629  } else if (strcasecmp(filetype, "unix_dgram") == 0) {
630 #ifdef BUILD_WITH_UNIXSOCKET
631  /* Don't bail. May be able to connect later. */
632  log_ctx->is_sock = 1;
633  log_ctx->sock_type = SOCK_DGRAM;
634  log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1);
635 #else
636  return -1;
637 #endif
638  } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 ||
639  strcasecmp(filetype, "file") == 0) {
640  log_ctx->is_regular = 1;
641  log_ctx->buffer_size = buffer_size;
642  if (!log_ctx->threaded) {
643  log_ctx->fp =
644  SCLogOpenFileFp(log_path, append, log_ctx->filemode, log_ctx->buffer_size);
645  if (log_ctx->fp == NULL)
646  return -1; // Error already logged by Open...Fp routine
647  } else {
648  if (!SCLogOpenThreadedFile(log_path, append, log_ctx)) {
649  return -1;
650  }
651  }
652  if (rotate) {
654  }
655  /* Register non-threaded regular files for direct heartbeat flushing */
656  if (!log_ctx->threaded && log_ctx->is_regular) {
657  LogFileRegisterForFlush(log_ctx);
658  }
659  } else {
660  SCLogError("Invalid entry for "
661  "%s.filetype. Expected \"regular\" (default), \"unix_stream\", "
662  "or \"unix_dgram\"",
663  conf->name);
664  }
665  log_ctx->filename = SCStrdup(log_path);
666  if (unlikely(log_ctx->filename == NULL)) {
667  SCLogError("Failed to allocate memory for filename");
668  return -1;
669  }
670 
671 #ifdef BUILD_WITH_UNIXSOCKET
672  /* If a socket and running live, do non-blocking writes. */
673  if (log_ctx->is_sock && !IsRunModeOffline(SCRunmodeGet())) {
674  SCLogInfo("Setting logging socket of non-blocking in live mode.");
675  log_ctx->send_flags |= MSG_DONTWAIT;
676  }
677 #endif
678  SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype,
679  filename);
680 
681  return 0;
682 }
683 
684 /**
685  * \brief Reopen a regular log file with the side-affect of truncating it.
686  *
687  * This is useful to clear the log file and start a new one, or to
688  * re-open the file after its been moved by something external
689  * (eg. logrotate).
690  */
692 {
693  if (!log_ctx->is_regular) {
694  /* Not supported and not needed on non-regular files. */
695  return 0;
696  }
697 
698  if (log_ctx->filename == NULL) {
699  SCLogWarning("Can't re-open LogFileCtx without a filename.");
700  return -1;
701  }
702 
703  if (log_ctx->fp != NULL) {
704  fclose(log_ctx->fp);
705  }
706 
707  /* Reopen the file. Append is forced in case the file was not
708  * moved as part of a rotation process. */
709  SCLogDebug("Reopening log file %s.", log_ctx->filename);
710  log_ctx->fp =
711  SCLogOpenFileFp(log_ctx->filename, "yes", log_ctx->filemode, log_ctx->buffer_size);
712  if (log_ctx->fp == NULL) {
713  return -1; // Already logged by Open..Fp routine.
714  }
715 
716  return 0;
717 }
718 
719 /** \brief LogFileNewCtx() Get a new LogFileCtx
720  * \retval LogFileCtx * pointer if successful, NULL if error
721  * */
723 {
724  LogFileCtx* lf_ctx;
725  lf_ctx = (LogFileCtx*)SCCalloc(1, sizeof(LogFileCtx));
726 
727  if (lf_ctx == NULL)
728  return NULL;
729 
730  lf_ctx->Write = SCLogFileWrite;
731  lf_ctx->Close = SCLogFileClose;
732  lf_ctx->Flush = SCLogFileFlush;
733 
734  return lf_ctx;
735 }
736 
737 /** \brief LogFileThread2Slot() Return a file entry
738  * \retval ThreadLogFileHashEntry * file entry for caller
739  *
740  * This function returns the file entry for the calling thread.
741  * Each thread -- identified by its operating system thread-id -- has its
742  * own file entry that includes a file pointer.
743  */
744 static ThreadLogFileHashEntry *LogFileThread2Slot(LogThreadedFileCtx *parent, ThreadId thread_id)
745 {
746  ThreadLogFileHashEntry thread_hash_entry;
747 
748  /* Check hash table for thread id*/
749  thread_hash_entry.thread_id = SCGetThreadIdLong();
751  HashTableLookup(parent->ht, &thread_hash_entry, sizeof(thread_hash_entry));
752 
753  if (!ent) {
754  ent = SCCalloc(1, sizeof(*ent));
755  if (!ent) {
756  FatalError("Unable to allocate thread/hash-entry entry");
757  }
758  ent->thread_id = thread_hash_entry.thread_id;
759  ent->internal_thread_id = thread_id;
760  SCLogDebug(
761  "Trying to add thread %" PRIi64 " to entry %d", ent->thread_id, ent->slot_number);
762  if (0 != HashTableAdd(parent->ht, ent, 0)) {
763  FatalError("Unable to add thread/hash-entry mapping");
764  }
765  }
766  return ent;
767 }
768 
769 /** \brief LogFileEnsureExists() Ensure a log file context for the thread exists
770  * \param parent_ctx
771  * \retval LogFileCtx * pointer if successful; NULL otherwise
772  */
774 {
775  /* threaded output disabled */
776  if (!parent_ctx->threaded)
777  return parent_ctx;
778 
779  LogFileCtx *ret_ctx = NULL;
780  SCMutexLock(&parent_ctx->threads->mutex);
781  /* Find this thread's entry */
782  ThreadLogFileHashEntry *entry = LogFileThread2Slot(parent_ctx->threads, thread_id);
783  SCLogDebug("%s: Adding reference for thread %" PRIi64
784  " (local thread id %d) to file %s [ctx %p]",
785  t_thread_name, SCGetThreadIdLong(), thread_id, parent_ctx->filename, parent_ctx);
786 
787  bool new = entry->isopen;
788  /* has it been opened yet? */
789  if (!new) {
790  SCLogDebug("%s: Opening new file for thread/id %d to file %s [ctx %p]", t_thread_name,
791  thread_id, parent_ctx->filename, parent_ctx);
792  if (LogFileNewThreadedCtx(
793  parent_ctx, parent_ctx->filename, parent_ctx->threads->append, entry)) {
794  entry->isopen = true;
795  ret_ctx = entry->ctx;
796  } else {
797  SCLogDebug(
798  "Unable to open slot %d for file %s", entry->slot_number, parent_ctx->filename);
799  (void)HashTableRemove(parent_ctx->threads->ht, entry, 0);
800  }
801  } else {
802  ret_ctx = entry->ctx;
803  }
804  SCMutexUnlock(&parent_ctx->threads->mutex);
805 
807  if (new) {
808  SCLogDebug("Existing file for thread/entry %p reference to file %s [ctx %p]", entry,
809  parent_ctx->filename, parent_ctx);
810  }
811  }
812 
813  return ret_ctx;
814 }
815 
816 /** \brief LogFileThreadedName() Create file name for threaded EVE storage
817  *
818  */
819 static bool LogFileThreadedName(
820  const char *original_name, char *threaded_name, size_t len, uint32_t unique_id)
821 {
822  sc_errno = SC_OK;
823 
824  if (strcmp("/dev/null", original_name) == 0) {
825  strlcpy(threaded_name, original_name, len);
826  return true;
827  }
828 
829  const char *base = SCBasename(original_name);
830  if (!base) {
831  FatalError("Invalid filename for threaded mode \"%s\"; "
832  "no basename found.",
833  original_name);
834  }
835 
836  /* Check if basename has an extension */
837  char *dot = strrchr(base, '.');
838  if (dot) {
839  char *tname = SCStrdup(original_name);
840  if (!tname) {
842  return false;
843  }
844 
845  /* Fetch extension location from original, not base
846  * for update
847  */
848  dot = strrchr(original_name, '.');
849  ptrdiff_t dotpos = dot - original_name;
850  tname[dotpos] = '\0';
851  char *ext = tname + dotpos + 1;
852  if (strlen(tname) && strlen(ext)) {
853  snprintf(threaded_name, len, "%s.%u.%s", tname, unique_id, ext);
854  } else {
855  FatalError("Invalid filename for threaded mode \"%s\"; "
856  "filenames must include an extension, e.g: \"name.ext\"",
857  original_name);
858  }
859  SCFree(tname);
860  } else {
861  snprintf(threaded_name, len, "%s.%u", original_name, unique_id);
862  }
863  return true;
864 }
865 
866 /** \brief LogFileNewThreadedCtx() Create file context for threaded output
867  * \param parent_ctx
868  * \param log_path
869  * \param append
870  * \param entry
871  */
872 static bool LogFileNewThreadedCtx(LogFileCtx *parent_ctx, const char *log_path, const char *append,
873  ThreadLogFileHashEntry *entry)
874 {
875  LogFileCtx *thread = SCCalloc(1, sizeof(LogFileCtx));
876  if (!thread) {
877  SCLogError("Unable to allocate thread file context entry %p", entry);
878  return false;
879  }
880 
881  *thread = *parent_ctx;
882  if (parent_ctx->type == LOGFILE_TYPE_FILE) {
883  char fname[LOGFILE_NAME_MAX];
884  entry->slot_number = SC_ATOMIC_ADD(eve_file_id, 1);
885  if (!LogFileThreadedName(log_path, fname, sizeof(fname), entry->slot_number)) {
886  SCLogError("Unable to create threaded filename for log");
887  goto error;
888  }
889  SCLogDebug("%s: thread open -- using name %s [replaces %s] - thread %d [slot %d]",
890  t_thread_name, fname, log_path, entry->internal_thread_id, entry->slot_number);
891  thread->fp = SCLogOpenFileFp(fname, append, thread->filemode, parent_ctx->buffer_size);
892  if (thread->fp == NULL) {
893  goto error;
894  }
895  thread->filename = SCStrdup(fname);
896  if (!thread->filename) {
897  SCLogError("Unable to duplicate filename for context entry %p", entry);
898  goto error;
899  }
900  thread->is_regular = true;
901  if (OutputFlushInterval() > 0) {
902  thread->Write = SCLogFileWrite;
903  thread->Close = SCLogFileClose;
904  } else {
905  thread->Write = SCLogFileWriteNoLock;
906  thread->Close = SCLogFileCloseNoLock;
907  }
909  LogFileRegisterForFlush(thread);
910  } else if (parent_ctx->type == LOGFILE_TYPE_FILETYPE) {
911  entry->slot_number = SC_ATOMIC_ADD(eve_file_id, 1);
912  SCLogDebug("%s - thread %d [slot %d]", log_path, entry->internal_thread_id,
913  entry->slot_number);
915  &thread->filetype.thread_data);
916  }
917  thread->threaded = false;
918  thread->parent = parent_ctx;
919  thread->entry = entry;
920  entry->ctx = thread;
921 
922  return true;
923 
924 error:
925  if (parent_ctx->type == LOGFILE_TYPE_FILE) {
926  SC_ATOMIC_SUB(eve_file_id, 1);
927  if (thread->fp) {
928  thread->Close(thread);
929  }
930  }
931 
932  if (thread) {
933  SCFree(thread);
934  }
935  return false;
936 }
937 
938 /** \brief LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
939  * \param lf_ctx pointer to the OutputCtx
940  * \retval int 1 if successful, 0 if error
941  * */
943 {
944  if (lf_ctx == NULL) {
945  SCReturnInt(0);
946  }
947 
948  /* Unregister from flush list first, before closing files.
949  * This ensures the heartbeat thread won't try to flush a context
950  * that's being destroyed. */
952 
953  if (lf_ctx->type == LOGFILE_TYPE_FILETYPE && lf_ctx->filetype.filetype->ThreadDeinit) {
954  lf_ctx->filetype.filetype->ThreadDeinit(
955  lf_ctx->filetype.init_data, lf_ctx->filetype.thread_data);
956  }
957 
958  if (lf_ctx->threaded) {
959  BUG_ON(lf_ctx->threads == NULL);
960  SCMutexDestroy(&lf_ctx->threads->mutex);
961  if (lf_ctx->threads->append)
962  SCFree(lf_ctx->threads->append);
963  if (lf_ctx->threads->ht) {
964  HashTableFree(lf_ctx->threads->ht);
965  }
966  SCFree(lf_ctx->threads);
967  } else {
968  if (lf_ctx->type != LOGFILE_TYPE_FILETYPE) {
969  if (lf_ctx->fp != NULL) {
970  lf_ctx->Close(lf_ctx);
971  }
972  }
973  SCMutexDestroy(&lf_ctx->fp_mutex);
974  }
975 
976  if (lf_ctx->prefix != NULL) {
977  SCFree(lf_ctx->prefix);
978  lf_ctx->prefix_len = 0;
979  }
980 
981  if(lf_ctx->filename != NULL)
982  SCFree(lf_ctx->filename);
983 
984  if (lf_ctx->sensor_name)
985  SCFree(lf_ctx->sensor_name);
986 
987  if (!lf_ctx->threaded) {
989  }
990 
991  /* Deinitialize output filetypes. We only want to call this for
992  * the parent of threaded output, or always for non-threaded
993  * output. */
994  if (lf_ctx->type == LOGFILE_TYPE_FILETYPE && lf_ctx->parent == NULL) {
995  lf_ctx->filetype.filetype->Deinit(lf_ctx->filetype.init_data);
996  }
997 
998 #ifdef HAVE_LIBHIREDIS
999  if (lf_ctx->type == LOGFILE_TYPE_REDIS) {
1000  if (lf_ctx->redis_setup.stream_format != NULL) {
1001  SCFree(lf_ctx->redis_setup.stream_format);
1002  }
1003  }
1004 #endif
1005 
1006  memset(lf_ctx, 0, sizeof(*lf_ctx));
1007  SCFree(lf_ctx);
1008 
1009  SCReturnInt(1);
1010 }
1011 
1012 void LogFileFlush(LogFileCtx *file_ctx)
1013 {
1014  SCLogDebug("%s: bytes-to-flush %ld", file_ctx->filename, file_ctx->bytes_since_last_flush);
1015  file_ctx->Flush(file_ctx);
1016 }
1017 
1018 /**
1019  * \brief Register a LogFileCtx for flush operations
1020  *
1021  * Adds a LogFileCtx to the global flush list so the heartbeat thread
1022  * can flush it directly without using pseudo packets.
1023  *
1024  * \param ctx The LogFileCtx to register (must be LOGFILE_TYPE_FILE)
1025  */
1027 {
1028  if (!OutputFlushInterval()) {
1029  SCLogDebug("heartbeat disabled; skipping flush registration");
1030  return;
1031  }
1032 
1033  if (ctx == NULL || ctx->type != LOGFILE_TYPE_FILE) {
1034  return;
1035  }
1036 
1037  LogFileFlushEntry *entry = SCMalloc(sizeof(LogFileFlushEntry));
1038  if (entry == NULL) {
1039  SCLogError("Unable to allocate memory for flush entry");
1040  return;
1041  }
1042 
1043  entry->ctx = ctx;
1044 
1045  SCMutexLock(&log_file_flush_mutex);
1046  TAILQ_INSERT_TAIL(&log_file_flush_list, entry, entries);
1047  SCMutexUnlock(&log_file_flush_mutex);
1048 }
1049 
1050 /**
1051  * \brief Unregister a LogFileCtx from flush operations
1052  *
1053  * Removes a LogFileCtx from the global flush list.
1054  *
1055  * \param ctx The LogFileCtx to unregister
1056  */
1058 {
1059  if (!OutputFlushInterval()) {
1060  SCLogDebug("heartbeat disabled; skipping flush deregistration");
1061  return;
1062  }
1063 
1064  if (ctx == NULL) {
1065  return;
1066  }
1067 
1068  SCMutexLock(&log_file_flush_mutex);
1069  LogFileFlushEntry *entry, *safe;
1070  TAILQ_FOREACH_SAFE (entry, &log_file_flush_list, entries, safe) {
1071  if (entry->ctx == ctx) {
1072  TAILQ_REMOVE(&log_file_flush_list, entry, entries);
1073  SCFree(entry);
1074  break;
1075  }
1076  }
1077  SCMutexUnlock(&log_file_flush_mutex);
1078 }
1079 
1080 /**
1081  * \brief Flush all registered LogFileCtx instances
1082  *
1083  * Called by the heartbeat thread to flush all active file-based loggers.
1084  * Iterates through the flush list and calls LogFileFlush on each context.
1085  */
1087 {
1088  SCMutexLock(&log_file_flush_mutex);
1089  LogFileFlushEntry *entry;
1090  TAILQ_FOREACH (entry, &log_file_flush_list, entries) {
1091  if (entry->ctx != NULL) {
1092  LogFileFlush(entry->ctx);
1093  }
1094  }
1095  SCMutexUnlock(&log_file_flush_mutex);
1096 }
1097 
1098 int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer)
1099 {
1100  if (file_ctx->type == LOGFILE_TYPE_FILE || file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM ||
1101  file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) {
1102  /* append \n for files only */
1103  MemBufferWriteString(buffer, "\n");
1104  file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer),
1105  MEMBUFFER_OFFSET(buffer), file_ctx);
1106  } else if (file_ctx->type == LOGFILE_TYPE_FILETYPE) {
1107  file_ctx->filetype.filetype->Write((const char *)MEMBUFFER_BUFFER(buffer),
1108  MEMBUFFER_OFFSET(buffer), file_ctx->filetype.init_data,
1109  file_ctx->filetype.thread_data);
1110  }
1111 #ifdef HAVE_LIBHIREDIS
1112  else if (file_ctx->type == LOGFILE_TYPE_REDIS) {
1113  SCMutexLock(&file_ctx->fp_mutex);
1114  LogFileWriteRedis(file_ctx, (const char *)MEMBUFFER_BUFFER(buffer),
1115  MEMBUFFER_OFFSET(buffer));
1116  SCMutexUnlock(&file_ctx->fp_mutex);
1117  }
1118 #endif
1119 
1120  return 0;
1121 }
SCParseTimeSizeString
uint64_t SCParseTimeSizeString(const char *str)
Parse string containing time size (1m, 1h, etc).
Definition: util-time.c:576
LogFileCtx_::rotation_flag
int rotation_flag
Definition: util-logopenfile.h:158
util-byte.h
LogThreadedFileCtx_::append
char * append
Definition: util-logopenfile.h:62
SCFerrorUnlocked
#define SCFerrorUnlocked
Definition: suricata-common.h:551
log-flush.h
len
uint8_t len
Definition: app-layer-dnp3.h:2
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:552
LOGFILE_TYPE_REDIS
@ LOGFILE_TYPE_REDIS
Definition: util-logopenfile.h:42
LogFileCtx_::sensor_name
char * sensor_name
Definition: util-logopenfile.h:120
SCEveFileType_::Deinit
SCEveFileTypeDeinitFunc Deinit
Final call to deinitialize this filetype.
Definition: output-eve-bindgen.h:202
LogFileCtx_::reconn_timer
uint64_t reconn_timer
Definition: util-logopenfile.h:125
IsRunModeOffline
bool IsRunModeOffline(enum SCRunModes run_mode_to_check)
Definition: runmodes.c:557
SC_LOG_DEBUG
@ SC_LOG_DEBUG
Definition: util-debug.h:44
LogFileCtx_::fp_mutex
SCMutex fp_mutex
Definition: util-logopenfile.h:100
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SC_ATOMIC_DECL_AND_INIT_WITH_VAL
#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val)
wrapper for declaring an atomic variable and initializing it to a specific value
Definition: util-atomic.h:303
SCEveFileType_::Write
SCEveFileTypeWriteFunc Write
Called for each EVE log record.
Definition: output-eve-bindgen.h:180
LogFileNewCtx
LogFileCtx * LogFileNewCtx(void)
LogFileNewCtx() Get a new LogFileCtx.
Definition: util-logopenfile.c:722
SCGetSecondsUntil
uint64_t SCGetSecondsUntil(const char *str, time_t epoch)
Get seconds until a time unit changes.
Definition: util-time.c:627
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
LogFileFlush
void LogFileFlush(LogFileCtx *file_ctx)
Definition: util-logopenfile.c:1012
LogFileCtx_::json_flags
size_t json_flags
Definition: util-logopenfile.h:161
ctx
struct Thresholds ctx
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:332
LogFileCtx_
Definition: util-logopenfile.h:77
LOGFILE_RECONN_MIN_TIME
#define LOGFILE_RECONN_MIN_TIME
Definition: util-logopenfile.h:177
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
DEFAULT_LOG_MODE_APPEND
#define DEFAULT_LOG_MODE_APPEND
Definition: output.h:30
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
HashTable_
Definition: util-hash.h:35
util-log-redis.h
SCConfValIsFalse
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:577
LogFileCtx_::Write
int(* Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp)
Definition: util-logopenfile.h:92
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:122
LogFileCtx_::filename
char * filename
Definition: util-logopenfile.h:111
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:294
LOGFILE_NAME_MAX
#define LOGFILE_NAME_MAX
Definition: util-logopenfile.c:49
JSON_ESCAPE_SLASH
#define JSON_ESCAPE_SLASH
Definition: suricata-common.h:290
m
SCMutex m
Definition: flow-hash.h:6
SCConfNodeLookupChildValue
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:852
ThreadLogFileHashEntry::ctx
struct LogFileCtx_ * ctx
Definition: util-logopenfile.h:49
LogFileCtx_::send_flags
uint8_t send_flags
Definition: util-logopenfile.h:148
SCConfLogReopen
int SCConfLogReopen(LogFileCtx *log_ctx)
Reopen a regular log file with the side-affect of truncating it.
Definition: util-logopenfile.c:691
ThreadLogFileHashEntry::slot_number
uint16_t slot_number
Definition: util-logopenfile.h:54
ThreadLogFileHashEntry::isopen
bool isopen
Definition: util-logopenfile.h:55
SCClearErrUnlocked
#define SCClearErrUnlocked
Definition: suricata-common.h:550
SC_ENOMEM
@ SC_ENOMEM
Definition: util-error.h:29
HashTableFree
void HashTableFree(HashTable *ht)
Free a HashTable and all its contents.
Definition: util-hash.c:100
t_thread_name
thread_local char t_thread_name[THREAD_NAME_LEN+1]
Definition: threads.c:33
HashTable_::array_size
uint32_t array_size
Definition: util-hash.h:37
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
LogFileCtx_::sock_type
int sock_type
Definition: util-logopenfile.h:124
OutputRegisterFileRotationFlag
void OutputRegisterFileRotationFlag(int *flag)
Register a flag for file rotation notification.
Definition: output.c:688
LogFileCtx_::filetype
LogFileTypeCtx filetype
Definition: util-logopenfile.h:96
SCTimeToStringPattern
int SCTimeToStringPattern(time_t epoch, const char *pattern, char *str, size_t size)
Convert epoch time to string pattern.
Definition: util-time.c:547
TAILQ_HEAD_INITIALIZER
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:236
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:312
SCRunmodeGet
SCRunMode SCRunmodeGet(void)
Get the current run mode.
Definition: suricata.c:289
LogFileWrite
int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer)
Definition: util-logopenfile.c:1098
SCEveFileType_::ThreadDeinit
SCEveFileTypeThreadDeinitFunc ThreadDeinit
Called to deinitialize each thread.
Definition: output-eve-bindgen.h:192
LogFileCtx_::rotate_interval
uint64_t rotate_interval
Definition: util-logopenfile.h:132
DEFAULT_LOG_FILETYPE
#define DEFAULT_LOG_FILETYPE
Definition: output.h:31
LogFileCtx_::is_sock
int is_sock
Definition: util-logopenfile.h:123
SCFwriteUnlocked
#define SCFwriteUnlocked
Definition: suricata-common.h:548
LogFileCtx_::prefix_len
uint32_t prefix_len
Definition: util-logopenfile.h:137
SCEveFileType_::ThreadInit
SCEveFileTypeThreadInitFunc ThreadInit
Initialize thread specific data.
Definition: output-eve-bindgen.h:161
SCFflushUnlocked
#define SCFflushUnlocked
Definition: suricata-common.h:549
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:120
OutputFlushInterval
int OutputFlushInterval(void)
Definition: log-flush.c:34
HashTableLookup
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:182
HashTableRemove
int HashTableRemove(HashTable *ht, void *data, uint16_t datalen)
Remove an item from the hash table.
Definition: util-hash.c:166
ThreadLogFileHashEntry::internal_thread_id
ThreadId internal_thread_id
Definition: util-logopenfile.h:52
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:269
util-time.h
LogFileFlushEntry_::ctx
struct LogFileCtx_ * ctx
Definition: util-logopenfile.h:72
LOGFILE_EVE_BUFFER_SIZE
#define LOGFILE_EVE_BUFFER_SIZE
Definition: util-logopenfile.h:183
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:262
HashTableAdd
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:120
LogFileCtx_::type
enum LogFileType type
Definition: util-logopenfile.h:108
LogFileUnregisterForFlush
void LogFileUnregisterForFlush(LogFileCtx *ctx)
Unregister a LogFileCtx from flush operations.
Definition: util-logopenfile.c:1057
LOGFILE_TYPE_FILE
@ LOGFILE_TYPE_FILE
Definition: util-logopenfile.h:39
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
LogFileCtx_::threads
LogThreadedFileCtx * threads
Definition: util-logopenfile.h:84
LogFileFlushAll
void LogFileFlushAll(void)
Flush all registered LogFileCtx instances.
Definition: util-logopenfile.c:1086
SC_ATOMIC_SUB
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:341
ThreadLogFileHashEntry::thread_id
uint64_t thread_id
Definition: util-logopenfile.h:51
SCConfigGetLogDirectory
const char * SCConfigGetLogDirectory(void)
Definition: util-conf.c:38
conf.h
SC_OK
@ SC_OK
Definition: util-error.h:27
SCBasename
const char * SCBasename(const char *path)
Definition: util-path.c:246
LogFileFlushEntry_
Definition: util-logopenfile.h:71
LOGFILE_TYPE_UNIX_DGRAM
@ LOGFILE_TYPE_UNIX_DGRAM
Definition: util-logopenfile.h:40
LogFileTypeCtx_::thread_data
void * thread_data
Definition: util-logopenfile.h:68
SCLogOpenThreadedFile
bool SCLogOpenThreadedFile(const char *log_path, const char *append, LogFileCtx *parent_ctx)
Definition: util-logopenfile.c:381
LogFileCtx_::compress_ipv6
bool compress_ipv6
Definition: util-logopenfile.h:155
LOGFILE_TYPE_UNIX_STREAM
@ LOGFILE_TYPE_UNIX_STREAM
Definition: util-logopenfile.h:41
MemBuffer_
Definition: util-buffer.h:27
LogFileCtx_::is_regular
uint8_t is_regular
Definition: util-logopenfile.h:152
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
TAILQ_FOREACH_SAFE
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:329
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
LogFileCtx_::buffer_size
uint32_t buffer_size
Definition: util-logopenfile.h:117
LogFileCtx_::bytes_since_last_flush
uint64_t bytes_since_last_flush
Definition: util-logopenfile.h:173
SCGetThreadIdLong
#define SCGetThreadIdLong(...)
Definition: threads.h:256
SCConfNodeLookupChild
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:824
LogFileCtx_::parent
struct LogFileCtx_ * parent
Definition: util-logopenfile.h:104
util-conf.h
LogThreadedFileCtx_
Definition: util-logopenfile.h:59
LogFileEnsureExists
LogFileCtx * LogFileEnsureExists(ThreadId thread_id, LogFileCtx *parent_ctx)
LogFileEnsureExists() Ensure a log file context for the thread exists.
Definition: util-logopenfile.c:773
suricata-common.h
LogFileTypeCtx_::init_data
void * init_data
Definition: util-logopenfile.h:67
util-path.h
LogFileCtx_::output_errors
uint64_t output_errors
Definition: util-logopenfile.h:170
ThreadLogFileHashEntry
Definition: util-logopenfile.h:48
ThreadId
uint32_t ThreadId
Definition: output-eve-bindgen.h:31
LogFileCtx_::Flush
void(* Flush)(struct LogFileCtx_ *fp)
Definition: util-logopenfile.h:94
PathIsAbsolute
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:44
LogFileCtx_::entry
ThreadLogFileHashEntry * entry
Definition: util-logopenfile.h:105
LogFileFreeCtx
int LogFileFreeCtx(LogFileCtx *lf_ctx)
LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
Definition: util-logopenfile.c:942
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
LogFileCtx_::rotate_time
time_t rotate_time
Definition: util-logopenfile.h:129
FatalError
#define FatalError(...)
Definition: util-debug.h:517
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:33
ParseSizeStringU32
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition: util-misc.c:174
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
SCConfLogOpenGeneric
int SCConfLogOpenGeneric(SCConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate)
open a generic output "log file", which may be a regular file or a socket
Definition: util-logopenfile.c:486
SCFree
#define SCFree(p)
Definition: util-mem.h:61
util-logopenfile.h
LOGFILE_ROTATE_INTERVAL
#define LOGFILE_ROTATE_INTERVAL
Definition: util-logopenfile.h:180
LogThreadedFileCtx_::mutex
SCMutex mutex
Definition: util-logopenfile.h:60
sc_errno
thread_local SCError sc_errno
Definition: util-error.c:31
LogFileCtx_::prefix
char * prefix
Definition: util-logopenfile.h:136
TAILQ_HEAD
#define TAILQ_HEAD(name, type)
Definition: queue.h:230
HashTableInit
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hash.c:35
sc_log_global_log_level
SCLogLevel sc_log_global_log_level
Holds the global log level. Is the same as sc_log_config->log_level.
Definition: util-debug.c:101
suricata.h
MemBufferWriteString
void MemBufferWriteString(MemBuffer *dst, const char *fmt,...)
Definition: util-buffer.c:130
SCConfNode_::name
char * name
Definition: conf.h:38
LogFileCtx_::flags
uint8_t flags
Definition: util-logopenfile.h:145
LogFileCtx_::Close
void(* Close)(struct LogFileCtx_ *fp)
Definition: util-logopenfile.h:93
MEMBUFFER_BUFFER
#define MEMBUFFER_BUFFER(mem_buffer)
Get the MemBuffers underlying buffer.
Definition: util-buffer.h:51
LogFileRegisterForFlush
void LogFileRegisterForFlush(LogFileCtx *ctx)
Register a LogFileCtx for flush operations.
Definition: util-logopenfile.c:1026
LogFileTypeCtx_::filetype
SCEveFileType * filetype
Definition: util-logopenfile.h:66
util-misc.h
LogThreadedFileCtx_::ht
HashTable * ht
Definition: util-logopenfile.h:61
OutputUnregisterFileRotationFlag
void OutputUnregisterFileRotationFlag(int *flag)
Unregister a file rotation flag.
Definition: output.c:711
MEMBUFFER_OFFSET
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
Definition: util-buffer.h:56
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:121
SCConfNode_
Definition: conf.h:37
LogFileCtx_::fp
FILE * fp
Definition: util-logopenfile.h:79
SCMutex
#define SCMutex
Definition: threads-debug.h:114
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
LOGFILE_TYPE_FILETYPE
@ LOGFILE_TYPE_FILETYPE
Definition: util-logopenfile.h:44
output.h
LogFileCtx_::threaded
bool threaded
Definition: util-logopenfile.h:103
SCCreateDirectoryTree
int SCCreateDirectoryTree(const char *path, const bool final)
Recursively create a directory.
Definition: util-path.c:137
LogFileCtx_::filemode
uint32_t filemode
Definition: util-logopenfile.h:114