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