suricata
output-filestore.c
Go to the documentation of this file.
1 /* Copyright (C) 2018 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 #include "suricata-common.h"
19 
20 #include "app-layer-parser.h"
21 #include "app-layer-htp.h"
22 #include "app-layer-htp-xff.h"
23 #include "app-layer-smtp.h"
24 
25 #include "output.h"
26 #include "output-filestore.h"
27 #include "output-json-file.h"
28 
29 #include "util-print.h"
30 #include "util-misc.h"
31 
32 #ifdef HAVE_NSS
33 
34 #define MODULE_NAME "OutputFilestore"
35 
36 /* Create a filestore specific PATH_MAX that is less than the system
37  * PATH_MAX to prevent newer gcc truncation warnings with snprint. */
38 #define SHA256_STRING_LEN (SHA256_LENGTH * 2)
39 #define LEAF_DIR_MAX_LEN 4
40 #define FILESTORE_PREFIX_MAX (PATH_MAX - SHA256_STRING_LEN - LEAF_DIR_MAX_LEN)
41 
42 /* The default log directory, relative to the default log
43  * directory. */
44 static const char *default_log_dir = "filestore";
45 
46 /* Atomic counter of simultaneously open files. */
47 static SC_ATOMIC_DECLARE(uint32_t, filestore_open_file_cnt);
48 
49 typedef struct OutputFilestoreCtx_ {
50  char prefix[FILESTORE_PREFIX_MAX];
51  char tmpdir[FILESTORE_PREFIX_MAX];
52  bool fileinfo;
53  HttpXFFCfg *xff_cfg;
54 } OutputFilestoreCtx;
55 
56 typedef struct OutputFilestoreLogThread_ {
57  OutputFilestoreCtx *ctx;
58  uint16_t counter_max_hits;
59  uint16_t fs_error_counter;
60 } OutputFilestoreLogThread;
61 
62 /* For WARN_ONCE, a record of warnings that have already been
63  * issued. */
64 static __thread bool once_errs[SC_ERR_MAX];
65 
66 #define WARN_ONCE(err_code, ...) do { \
67  if (!once_errs[err_code]) { \
68  once_errs[err_code] = true; \
69  SCLogWarning(err_code, __VA_ARGS__); \
70  } \
71  } while (0)
72 
73 static uint64_t OutputFilestoreOpenFilesCounter(void)
74 {
75  return SC_ATOMIC_GET(filestore_open_file_cnt);
76 }
77 
78 static uint32_t g_file_store_max_open_files = 0;
79 
80 static void FileSetMaxOpenFiles(uint32_t count)
81 {
82  g_file_store_max_open_files = count;
83 }
84 
85 static uint32_t FileGetMaxOpenFiles(void)
86 {
87  return g_file_store_max_open_files;
88 }
89 
90 static void PrintHexString(char *str, size_t size, uint8_t *buf, size_t buf_len)
91 {
92  int i = 0;
93  size_t x = 0;
94  for (i = 0, x = 0; x < buf_len; x++) {
95  i += snprintf(&str[i], size - i, "%02x", buf[x]);
96  }
97 }
98 
99 /**
100  * \brief Update the timestamps on a file to match those of another
101  * file.
102  *
103  * \param src_filename Filename to use as timestamp source.
104  * \param filename Filename to apply timestamps to.
105  */
106 static void OutputFilestoreUpdateFileTime(const char *src_filename,
107  const char *filename)
108 {
109  struct stat sb;
110  if (stat(src_filename, &sb) != 0) {
111  SCLogDebug("Failed to stat %s: %s", filename, strerror(errno));
112  return;
113  }
114  struct utimbuf utimbuf = {
115  .actime = sb.st_atime,
116  .modtime = sb.st_mtime,
117  };
118  if (utime(filename, &utimbuf) != 0) {
119  SCLogDebug("Failed to update file timestamps: %s: %s", filename,
120  strerror(errno));
121  }
122 }
123 
124 static void OutputFilestoreFinalizeFiles(ThreadVars *tv,
125  const OutputFilestoreLogThread *oft, const OutputFilestoreCtx *ctx,
126  const Packet *p, File *ff, uint8_t dir) {
127  /* Stringify the SHA256 which will be used in the final
128  * filename. */
129  char sha256string[(SHA256_LENGTH * 2) + 1];
130  PrintHexString(sha256string, sizeof(sha256string), ff->sha256,
131  sizeof(ff->sha256));
132 
133  char tmp_filename[PATH_MAX] = "";
134  snprintf(tmp_filename, sizeof(tmp_filename), "%s/file.%u", ctx->tmpdir,
135  ff->file_store_id);
136 
137  char final_filename[PATH_MAX] = "";
138  snprintf(final_filename, sizeof(final_filename), "%s/%c%c/%s",
139  ctx->prefix, sha256string[0], sha256string[1], sha256string);
140 
141  if (SCPathExists(final_filename)) {
142  OutputFilestoreUpdateFileTime(tmp_filename, final_filename);
143  if (unlink(tmp_filename) != 0) {
144  StatsIncr(tv, oft->fs_error_counter);
145  WARN_ONCE(SC_WARN_REMOVE_FILE,
146  "Failed to remove temporary file %s: %s", tmp_filename,
147  strerror(errno));
148  }
149  } else if (rename(tmp_filename, final_filename) != 0) {
150  StatsIncr(tv, oft->fs_error_counter);
151  WARN_ONCE(SC_WARN_RENAMING_FILE, "Failed to rename %s to %s: %s",
152  tmp_filename, final_filename, strerror(errno));
153  if (unlink(tmp_filename) != 0) {
154  /* Just increment, don't log as has_fs_errors would
155  * already be set above. */
156  StatsIncr(tv, oft->fs_error_counter);
157  }
158  return;
159  }
160 
161 #ifdef HAVE_LIBJANSSON
162  if (ctx->fileinfo) {
163  char js_metadata_filename[PATH_MAX];
164  if (snprintf(js_metadata_filename, sizeof(js_metadata_filename),
165  "%s.%"PRIuMAX".%u.json", final_filename,
166  (uintmax_t)p->ts.tv_sec, ff->file_store_id)
167  == (int)sizeof(js_metadata_filename)) {
168  WARN_ONCE(SC_ERR_SPRINTF,
169  "Failed to write file info record. Output filename truncated.");
170  } else {
171  json_t *js_fileinfo = JsonBuildFileInfoRecord(p, ff, true, dir,
172  ctx->xff_cfg);
173  if (likely(js_fileinfo != NULL)) {
174  json_dump_file(js_fileinfo, js_metadata_filename, 0);
175  json_decref(js_fileinfo);
176  }
177  }
178  }
179 #endif
180 }
181 
182 static int OutputFilestoreLogger(ThreadVars *tv, void *thread_data,
183  const Packet *p, File *ff, const uint8_t *data, uint32_t data_len,
184  uint8_t flags, uint8_t dir)
185 {
186  SCEnter();
187  OutputFilestoreLogThread *aft = (OutputFilestoreLogThread *)thread_data;
188  OutputFilestoreCtx *ctx = aft->ctx;
189  char filename[PATH_MAX] = "";
190  int file_fd = -1;
191 
192  /* no flow, no files */
193  if (p->flow == NULL) {
195  }
196 
197  if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) {
198  return 0;
199  }
200 
201  SCLogDebug("ff %p, data %p, data_len %u", ff, data, data_len);
202 
203  char base_filename[PATH_MAX] = "";
204  snprintf(base_filename, sizeof(base_filename), "%s/file.%u",
205  ctx->tmpdir, ff->file_store_id);
206  snprintf(filename, sizeof(filename), "%s", base_filename);
207 
208  if (flags & OUTPUT_FILEDATA_FLAG_OPEN) {
209  file_fd = open(filename, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY,
210  0644);
211  if (file_fd == -1) {
212  StatsIncr(tv, aft->fs_error_counter);
214  "Filestore (v2) failed to create %s: %s", filename,
215  strerror(errno));
216  return -1;
217  }
218 
219  if (SC_ATOMIC_GET(filestore_open_file_cnt) < FileGetMaxOpenFiles()) {
220  SC_ATOMIC_ADD(filestore_open_file_cnt, 1);
221  ff->fd = file_fd;
222  } else {
223  if (FileGetMaxOpenFiles() > 0) {
224  StatsIncr(tv, aft->counter_max_hits);
225  }
226  ff->fd = -1;
227  }
228  /* we can get called with a NULL ffd when we need to close */
229  } else if (data != NULL) {
230  if (ff->fd == -1) {
231  file_fd = open(filename, O_APPEND | O_NOFOLLOW | O_WRONLY);
232  if (file_fd == -1) {
233  StatsIncr(tv, aft->fs_error_counter);
234  WARN_ONCE(SC_ERR_OPENING_FILE,
235  "Filestore (v2) failed to open file %s: %s",
236  filename, strerror(errno));
237  return -1;
238  }
239  } else {
240  file_fd = ff->fd;
241  }
242  }
243 
244  if (file_fd != -1) {
245  ssize_t r = write(file_fd, (const void *)data, (size_t)data_len);
246  if (r == -1) {
247  StatsIncr(tv, aft->fs_error_counter);
248  WARN_ONCE(SC_ERR_FWRITE,
249  "Filestore (v2) failed to write to %s: %s",
250  filename, strerror(errno));
251  if (ff->fd != -1) {
252  SC_ATOMIC_SUB(filestore_open_file_cnt, 1);
253  }
254  ff->fd = -1;
255  }
256  if (ff->fd == -1) {
257  close(file_fd);
258  }
259  }
260 
261  if (flags & OUTPUT_FILEDATA_FLAG_CLOSE) {
262  if (ff->fd != -1) {
263  close(ff->fd);
264  ff->fd = -1;
265  SC_ATOMIC_SUB(filestore_open_file_cnt, 1);
266  }
267  OutputFilestoreFinalizeFiles(tv, aft, ctx, p, ff, dir);
268  }
269 
270  return 0;
271 }
272 
273 static TmEcode OutputFilestoreLogThreadInit(ThreadVars *t, const void *initdata,
274  void **data)
275 {
276  OutputFilestoreLogThread *aft = SCMalloc(sizeof(OutputFilestoreLogThread));
277  if (unlikely(aft == NULL))
278  return TM_ECODE_FAILED;
279  memset(aft, 0, sizeof(OutputFilestoreLogThread));
280 
281  if (initdata == NULL) {
282  SCLogDebug("Error getting context for LogFileStore. \"initdata\" argument NULL");
283  SCFree(aft);
284  return TM_ECODE_FAILED;
285  }
286 
287  OutputFilestoreCtx *ctx = ((OutputCtx *)initdata)->data;
288  aft->ctx = ctx;
289 
290  aft->counter_max_hits =
291  StatsRegisterCounter("file_store.open_files_max_hit", t);
292 
293  /* File system type errors (open, write, rename) will only be
294  * logged once. But this stat will be incremented for every
295  * occurence. */
296  aft->fs_error_counter = StatsRegisterCounter("file_store.fs_errors", t);
297 
298  *data = (void *)aft;
299  return TM_ECODE_OK;
300 }
301 
302 static TmEcode OutputFilestoreLogThreadDeinit(ThreadVars *t, void *data)
303 {
304  OutputFilestoreLogThread *aft = (OutputFilestoreLogThread *)data;
305  if (aft == NULL) {
306  return TM_ECODE_OK;
307  }
308 
309  /* clear memory */
310  memset(aft, 0, sizeof(OutputFilestoreLogThread));
311 
312  SCFree(aft);
313  return TM_ECODE_OK;
314 }
315 
316 static void OutputFilestoreLogDeInitCtx(OutputCtx *output_ctx)
317 {
318  OutputFilestoreCtx *ctx = (OutputFilestoreCtx *)output_ctx->data;
319  if (ctx->xff_cfg != NULL) {
320  SCFree(ctx->xff_cfg);
321  }
322  SCFree(ctx);
323  SCFree(output_ctx);
324 }
325 
326 static void GetLogDirectory(const ConfNode *conf, char *out, size_t out_size)
327 {
328  const char *log_base_dir = ConfNodeLookupChildValue(conf, "dir");
329  if (log_base_dir == NULL) {
330  SCLogConfig("Filestore (v2) default log directory %s", default_log_dir);
331  log_base_dir = default_log_dir;
332  }
333  if (PathIsAbsolute(log_base_dir)) {
334  strlcpy(out, log_base_dir, out_size);
335  } else {
336  const char *default_log_prefix = ConfigGetLogDirectory();
337  snprintf(out, out_size, "%s/%s", default_log_prefix, log_base_dir);
338  }
339 }
340 
341 static bool InitFilestoreDirectory(const char *dir)
342 {
343  const uint8_t dir_count = 0xff;
344 
345  if (!SCPathExists(dir)) {
346  SCLogInfo("Filestore (v2) creating directory %s", dir);
347  if (SCCreateDirectoryTree(dir, true) != 0) {
349  "Filestore (v2) failed to create directory %s: %s", dir,
350  strerror(errno));
351  return false;
352  }
353  }
354 
355  for (int i = 0; i <= dir_count; i++) {
356  char leaf[PATH_MAX];
357  int n = snprintf(leaf, sizeof(leaf), "%s/%02x", dir, i);
358  if (n < 0 || n >= PATH_MAX) {
360  "Filestore (v2) failed to create leaf directory: "
361  "path too long");
362  return false;
363  }
364  if (!SCPathExists(leaf)) {
365  SCLogInfo("Filestore (v2) creating directory %s", leaf);
366  if (SCDefaultMkDir(leaf) != 0) {
368  "Filestore (v2) failed to create directory %s: %s",
369  leaf, strerror(errno));
370  return false;
371  }
372  }
373  }
374 
375  /* Make sure the tmp directory exists. */
376  char tmpdir[PATH_MAX];
377  int n = snprintf(tmpdir, sizeof(tmpdir), "%s/tmp", dir);
378  if (n < 0 || n >= PATH_MAX) {
380  "Filestore (v2) failed to create tmp directory: path too long");
381  return false;
382  }
383  if (!SCPathExists(tmpdir)) {
384  SCLogInfo("Filestore (v2) creating directory %s", tmpdir);
385  if (SCDefaultMkDir(tmpdir) != 0) {
387  "Filestore (v2) failed to create directory %s: %s", tmpdir,
388  strerror(errno));
389  return false;
390  }
391  }
392 
393  return true;
394 }
395 
396 /** \brief Create a new http log OutputFilestoreCtx.
397  * \param conf Pointer to ConfNode containing this loggers configuration.
398  * \return NULL if failure, OutputFilestoreCtx* to the file_ctx if succesful
399  * */
400 static OutputInitResult OutputFilestoreLogInitCtx(ConfNode *conf)
401 {
402  OutputInitResult result = { NULL, false };
403 
404  intmax_t version = 0;
405  if (!ConfGetChildValueInt(conf, "version", &version) || version < 2) {
406  result.ok = true;
407  return result;
408  }
409 
412  "A file data logger is already enabled. Filestore (v2) "
413  "will not be enabled.");
414  return result;
415  }
416 
417  char log_directory[PATH_MAX] = "";
418  GetLogDirectory(conf, log_directory, sizeof(log_directory));
419  if (!InitFilestoreDirectory(log_directory)) {
420  return result;
421  }
422 
423  OutputFilestoreCtx *ctx = SCCalloc(1, sizeof(*ctx));
424  if (unlikely(ctx == NULL)) {
425  return result;
426  }
427 
428  strlcpy(ctx->prefix, log_directory, sizeof(ctx->prefix));
429  int written = snprintf(ctx->tmpdir, sizeof(ctx->tmpdir) - 1, "%s/tmp",
430  log_directory);
431  if (written == sizeof(ctx->tmpdir)) {
432  SCLogError(SC_ERR_SPRINTF, "File-store output directory overflow.");
433  SCFree(ctx);
434  return result;
435  }
436 
437  ctx->xff_cfg = SCCalloc(1, sizeof(HttpXFFCfg));
438  if (ctx->xff_cfg != NULL) {
439  HttpXFFGetCfg(conf, ctx->xff_cfg);
440  }
441 
442  OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
443  if (unlikely(output_ctx == NULL)) {
444  SCFree(ctx);
445  return result;
446  }
447 
448  output_ctx->data = ctx;
449  output_ctx->DeInit = OutputFilestoreLogDeInitCtx;
450 
451  const char *write_fileinfo = ConfNodeLookupChildValue(conf,
452  "write-fileinfo");
453  if (write_fileinfo != NULL && ConfValIsTrue(write_fileinfo)) {
454 #ifdef HAVE_LIBJANSSON
455  SCLogConfig("Filestore (v2) will output fileinfo records.");
456  ctx->fileinfo = true;
457 #else
459  "Filestore (v2) requires JSON support to log fileinfo records");
460 #endif
461  }
462 
463  const char *force_filestore = ConfNodeLookupChildValue(conf,
464  "force-filestore");
465  if (force_filestore != NULL && ConfValIsTrue(force_filestore)) {
467  SCLogInfo("forcing filestore of all files");
468  }
469 
470  const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic");
471  if (force_magic != NULL && ConfValIsTrue(force_magic)) {
473  SCLogConfig("Filestore (v2) forcing magic lookup for stored files");
474  }
475 
476  FileForceHashParseCfg(conf);
477 
478  /* The new filestore requires SHA256. */
480 
481  const char *stream_depth_str = ConfNodeLookupChildValue(conf,
482  "stream-depth");
483  if (stream_depth_str != NULL && strcmp(stream_depth_str, "no")) {
484  uint32_t stream_depth = 0;
485  if (ParseSizeStringU32(stream_depth_str,
486  &stream_depth) < 0) {
487  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
488  "file-store.stream-depth "
489  "from conf file - %s. Killing engine",
490  stream_depth_str);
491  exit(EXIT_FAILURE);
492  } else {
493  FileReassemblyDepthEnable(stream_depth);
494  }
495  }
496 
497  const char *file_count_str = ConfNodeLookupChildValue(conf,
498  "max-open-files");
499  if (file_count_str != NULL) {
500  uint32_t file_count = 0;
501  if (ParseSizeStringU32(file_count_str,
502  &file_count) < 0) {
503  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
504  "file-store.max-open-files "
505  "from conf file - %s. Killing engine",
506  stream_depth_str);
507  exit(EXIT_FAILURE);
508  } else {
509  if (file_count != 0) {
510  FileSetMaxOpenFiles(file_count);
511  SCLogConfig("Filestore (v2) will keep a max of %d "
512  "simultaneously open files", file_count);
513  }
514  }
515  }
516 
517  StatsRegisterGlobalCounter("file_store.open_files",
518  OutputFilestoreOpenFilesCounter);
519 
520  result.ctx = output_ctx;
521  result.ok = true;
522  SCReturnCT(result, "OutputInitResult");
523 }
524 
525 #endif /* HAVE_NSS */
526 
528 {
529 #ifdef HAVE_NSS
531  OutputFilestoreLogInitCtx, OutputFilestoreLogger,
532  OutputFilestoreLogThreadInit, OutputFilestoreLogThreadDeinit,
533  NULL);
534 
535  SC_ATOMIC_INIT(filestore_open_file_cnt);
536  SC_ATOMIC_SET(filestore_open_file_cnt, 0);
537 #endif
538 }
#define OUTPUT_FILEDATA_FLAG_CLOSE
uint16_t flags
#define SCLogDebug(...)
Definition: util-debug.h:335
struct Flow_ * flow
Definition: decode.h:444
#define SC_ATOMIC_DECLARE(type, name)
wrapper to declare an atomic variable including a (spin) lock to protect it.
Definition: util-atomic.h:57
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result)
Function to return XFF configuration from a configuration node.
#define unlikely(expr)
Definition: util-optimize.h:35
void OutputFilestoreRegister(void)
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:108
#define PKT_IS_IPV6(p)
Definition: decode.h:251
void(* DeInit)(struct OutputCtx_ *)
Definition: tm-modules.h:84
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:125
int fd
Definition: util-file.h:73
#define PKT_IS_IPV4(p)
Definition: decode.h:250
bool SCPathExists(const char *path)
Check if a path exists.
Definition: util-path.c:132
void FileReassemblyDepthEnable(uint32_t size)
Definition: util-file.c:116
#define SCReturnCT(x, type)
Definition: util-debug.h:351
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition: counters.c:939
#define O_NOFOLLOW
Definition: win32-misc.h:35
#define SC_ATOMIC_INIT(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:82
#define str(s)
#define SCCalloc(nm, a)
Definition: util-mem.h:205
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:843
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
void FileForceHashParseCfg(ConfNode *conf)
Function to parse forced file hashing configuration.
Definition: util-file.c:158
void FileForceMagicEnable(void)
Definition: util-file.c:91
#define SCEnter(...)
Definition: util-debug.h:337
#define MODULE_NAME
void FileForceFilestoreEnable(void)
Definition: util-file.c:86
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:163
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:39
uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
Definition: counters.c:1000
#define SCReturnInt(x)
Definition: util-debug.h:341
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:566
Definition: conf.h:32
OutputCtx * ctx
Definition: output.h:42
const char * ConfigGetLogDirectory()
Definition: util-conf.c:36
#define SCMalloc(a)
Definition: util-mem.h:174
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:208
void FileForceSha256Enable(void)
Definition: util-file.c:106
int RunModeOutputFiledataEnabled(void)
Definition: runmodes.c:495
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
uint8_t version
Definition: decode-gre.h:405
#define SCFree(a)
Definition: util-mem.h:236
void OutputRegisterFiledataModule(LoggerId id, const char *name, const char *conf_name, OutputInitFunc InitFunc, FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats)
Register a file data output module.
Definition: output.c:498
void * data
Definition: tm-modules.h:81
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:193
uint32_t file_store_id
Definition: util-file.h:72
int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val)
Definition: conf.c:469
int SCCreateDirectoryTree(const char *path, const bool final)
Recursively create a directory.
Definition: util-path.c:86
Per thread variable structure.
Definition: threadvars.h:57
struct timeval ts
Definition: decode.h:450
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition: util-misc.c:186
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
#define likely(expr)
Definition: util-optimize.h:32
int SCDefaultMkDir(const char *path)
Wrapper around SCMkDir with default mode arguments.
Definition: util-path.c:72
#define OUTPUT_FILEDATA_FLAG_OPEN