Go to the documentation of this file.
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>
44 #ifdef HAVE_LIBHIREDIS
48 #define LOGFILE_NAME_MAX 255
50 static bool LogFileNewThreadedCtx(
LogFileCtx *parent_ctx,
const char *log_path,
const char *append,
56 #ifdef BUILD_WITH_UNIXSOCKET
64 SCLogOpenUnixSocketFp(
const char *path,
int sock_type,
int log_err)
66 struct sockaddr_un saun;
70 memset(&saun, 0x00,
sizeof(saun));
72 s = socket(PF_UNIX, sock_type, 0);
75 saun.sun_family = AF_UNIX;
76 strlcpy(saun.sun_path, path,
sizeof(saun.sun_path));
78 if (connect(s, (
const struct sockaddr *)&saun,
sizeof(saun)) < 0)
90 "Error connecting to socket \"%s\": %s (will keep trying)", path, strerror(errno));
102 static int SCLogUnixSocketReconnect(
LogFileCtx *log_ctx)
104 int disconnected = 0;
116 gettimeofday(&
tv, NULL);
117 now = (uint64_t)
tv.tv_sec * 1000;
118 now +=
tv.tv_usec / 1000;
130 }
else if (disconnected) {
131 SCLogWarning(
"Reconnect failed: %s (will keep trying)", strerror(errno));
134 return log_ctx->
fp ? 1 : 0;
137 static int SCLogFileWriteSocket(
const char *buffer,
int buffer_len,
144 SCLogUnixSocketReconnect(ctx);
150 if (ctx->
fp != NULL) {
151 int fd = fileno(ctx->
fp);
152 ssize_t size = send(fd, buffer, buffer_len, ctx->
send_flags);
156 if (errno == EAGAIN || errno == EWOULDBLOCK) {
157 SCLogDebug(
"Socket would block, dropping event.");
158 }
else if (errno == EINTR) {
160 SCLogDebug(
"Interrupted system call, trying again.");
163 SCLogDebug(
"Too many interrupted system calls, "
167 SCLogDebug(
"Send failed: %s", strerror(errno));
173 if (reopen && tries++ == 0) {
174 if (SCLogUnixSocketReconnect(ctx)) {
186 static inline void OutputWriteLock(pthread_mutex_t *
m)
197 static int SCLogFileWriteNoLock(
const char *buffer,
int buffer_len,
LogFileCtx *log_ctx)
210 time_t now = time(NULL);
240 static int SCLogFileWrite(
const char *buffer,
int buffer_len,
LogFileCtx *log_ctx)
242 OutputWriteLock(&log_ctx->
fp_mutex);
245 #ifdef BUILD_WITH_UNIXSOCKET
247 ret = SCLogFileWriteSocket(buffer, buffer_len, log_ctx);
259 time_t now = time(NULL);
267 clearerr(log_ctx->
fp);
268 if (1 != fwrite(buffer, buffer_len, 1, log_ctx->
fp)) {
272 ferror(log_ctx->
fp) ? strerror(errno) :
"unknown error",
292 static char *SCLogFilenameFromPattern(
const char *pattern)
294 char *filename =
SCMalloc(PATH_MAX);
295 if (filename == NULL) {
308 static void SCLogFileCloseNoLock(
LogFileCtx *log_ctx)
320 static void SCLogFileClose(
LogFileCtx *log_ctx)
323 SCLogFileCloseNoLock(log_ctx);
327 static char ThreadLogFileHashCompareFunc(
328 void *data1, uint16_t datalen1,
void *data2, uint16_t datalen2)
333 if (p1 == NULL || p2 == NULL)
338 static uint32_t ThreadLogFileHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
345 static void ThreadLogFileHashFreeFunc(
void *data)
364 SCLogError(
"Unable to allocate threads container");
369 ThreadLogFileHashCompareFunc, ThreadLogFileHashFreeFunc);
371 FatalError(
"Unable to initialize thread/entry hash table");
376 SCLogError(
"Unable to allocate threads append setting");
404 SCLogOpenFileFp(
const char *path,
const char *append_setting, uint32_t mode)
408 char *filename = SCLogFilenameFromPattern(path);
409 if (filename == NULL) {
420 ret = fopen(filename,
"a");
422 ret = fopen(filename,
"w");
426 SCLogError(
"Error opening file: \"%s\": %s", filename, strerror(errno));
430 int r = _chmod(filename, (mode_t)mode);
432 int r = fchmod(fileno(ret), (mode_t)mode);
435 SCLogWarning(
"Could not chmod %s to %o: %s", filename, mode, strerror(errno));
455 const char *default_filename,
458 char log_path[PATH_MAX];
460 const char *filename, *filetype;
463 if (conf == NULL || log_ctx == NULL || default_filename == NULL) {
464 SCLogError(
"SCConfLogOpenGeneric(conf %p, ctx %p, default %p) "
465 "missing an argument",
466 conf, log_ctx, default_filename);
469 if (log_ctx->
fp != NULL) {
470 SCLogError(
"SCConfLogOpenGeneric: previously initialized Log CTX "
477 if (filename == NULL)
478 filename = default_filename;
483 snprintf(log_path, PATH_MAX,
"%s", filename);
485 snprintf(log_path, PATH_MAX,
"%s/%s", log_dir, filename);
490 if (rotate_int != NULL) {
491 time_t now = time(NULL);
495 if (strcmp(rotate_int,
"minute") == 0) {
498 }
else if (strcmp(rotate_int,
"hour") == 0) {
501 }
else if (strcmp(rotate_int,
"day") == 0) {
517 if (filetype == NULL)
522 if (filemode != NULL &&
StringParseUint32(&mode, 8, (uint16_t)strlen(filemode), filemode) > 0) {
531 log_ctx->
json_flags = JSON_PRESERVE_ORDER|JSON_COMPACT|
536 if (json_flags != 0) {
540 log_ctx->
json_flags &= ~(JSON_PRESERVE_ORDER);
557 #ifdef BUILD_WITH_UNIXSOCKET
559 if (strcasecmp(filetype,
"unix_stream") == 0 || strcasecmp(filetype,
"unix_dgram") == 0) {
560 FatalError(
"Socket file types do not support threaded output");
565 if (strcasecmp(filetype,
"unix_stream") == 0) {
566 #ifdef BUILD_WITH_UNIXSOCKET
570 log_ctx->
fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1);
574 }
else if (strcasecmp(filetype,
"unix_dgram") == 0) {
575 #ifdef BUILD_WITH_UNIXSOCKET
579 log_ctx->
fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1);
584 strcasecmp(filetype,
"file") == 0) {
587 log_ctx->
fp = SCLogOpenFileFp(log_path, append, log_ctx->
filemode);
588 if (log_ctx->
fp == NULL)
600 "%s.filetype. Expected \"regular\" (default), \"unix_stream\", "
606 SCLogError(
"Failed to allocate memory for filename");
610 #ifdef BUILD_WITH_UNIXSOCKET
613 SCLogInfo(
"Setting logging socket of non-blocking in live mode.");
617 SCLogInfo(
"%s output device (%s) initialized: %s", conf->
name, filetype,
638 SCLogWarning(
"Can't re-open LogFileCtx without a filename.");
642 if (log_ctx->
fp != NULL) {
650 if (log_ctx->
fp == NULL) {
668 lf_ctx->
Write = SCLogFileWrite;
669 lf_ctx->
Close = SCLogFileClose;
693 FatalError(
"Unable to allocate thread/entry entry");
698 FatalError(
"Unable to add thread/entry mapping");
725 if (LogFileNewThreadedCtx(
738 SCLogDebug(
"Existing file for thread/entry %p reference to file %s [ctx %p]", entry,
749 static bool LogFileThreadedName(
750 const char *original_name,
char *threaded_name,
size_t len, uint32_t unique_id)
754 if (strcmp(
"/dev/null", original_name) == 0) {
761 FatalError(
"Invalid filename for threaded mode \"%s\"; "
762 "no basename found.",
767 char *dot = strrchr(base,
'.');
769 char *tname =
SCStrdup(original_name);
778 dot = strrchr(original_name,
'.');
779 int dotpos = dot - original_name;
780 tname[dotpos] =
'\0';
781 char *ext = tname + dotpos + 1;
782 if (strlen(tname) && strlen(ext)) {
783 snprintf(threaded_name,
len,
"%s.%u.%s", tname, unique_id, ext);
785 FatalError(
"Invalid filename for threaded mode \"%s\"; "
786 "filenames must include an extension, e.g: \"name.ext\"",
791 snprintf(threaded_name,
len,
"%s.%u", original_name, unique_id);
802 static bool LogFileNewThreadedCtx(
LogFileCtx *parent_ctx,
const char *log_path,
const char *append,
807 SCLogError(
"Unable to allocate thread file context entry %p", entry);
811 *thread = *parent_ctx;
814 if (!LogFileThreadedName(log_path, fname,
sizeof(fname),
SC_ATOMIC_ADD(eve_file_id, 1))) {
815 SCLogError(
"Unable to create threaded filename for log");
818 SCLogDebug(
"Thread open -- using name %s [replaces %s]", fname, log_path);
819 thread->
fp = SCLogOpenFileFp(fname, append, thread->
filemode);
820 if (thread->
fp == NULL) {
825 SCLogError(
"Unable to duplicate filename for context entry %p", entry);
829 thread->
Write = SCLogFileWriteNoLock;
830 thread->
Close = SCLogFileCloseNoLock;
838 thread->
parent = parent_ctx;
839 thread->
entry = entry;
848 thread->
Close(thread);
864 if (lf_ctx == NULL) {
883 if (lf_ctx->
fp != NULL) {
884 lf_ctx->
Close(lf_ctx);
890 if (lf_ctx->
prefix != NULL) {
905 memset(lf_ctx, 0,
sizeof(*lf_ctx));
923 #ifdef HAVE_LIBHIREDIS
uint64_t SCParseTimeSizeString(const char *str)
Parse string containing time size (1m, 1h, etc).
int(* Write)(const char *buffer, int buffer_len, void *init_data, void *thread_data)
#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val)
wrapper for declaring an atomic variable and initializing it to a specific value
LogFileCtx * LogFileNewCtx(void)
LogFileNewCtx() Get a new LogFileCtx.
uint64_t SCGetSecondsUntil(const char *str, time_t epoch)
Get seconds until a time unit changes.
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
#define LOGFILE_RECONN_MIN_TIME
#define DEFAULT_LOG_MODE_APPEND
int(* Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp)
#define JSON_ESCAPE_SLASH
int SCConfLogReopen(LogFileCtx *log_ctx)
Reopen a regular log file with the side-affect of truncating it.
bool IsRunModeOffline(enum RunModes run_mode_to_check)
#define SCClearErrUnlocked
int ConfValIsTrue(const char *val)
Check if a value is true.
void HashTableFree(HashTable *ht)
int SCConfLogOpenGeneric(ConfNode *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
size_t strlcpy(char *dst, const char *src, size_t siz)
void OutputRegisterFileRotationFlag(int *flag)
Register a flag for file rotation notification.
int SCTimeToStringPattern(time_t epoch, const char *pattern, char *str, size_t size)
Convert epoch time to string pattern.
int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer)
#define DEFAULT_LOG_FILETYPE
#define SCMutexUnlock(mut)
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
LogFileCtx * LogFileEnsureExists(LogFileCtx *parent_ctx)
LogFileEnsureExists() Ensure a log file context for the thread exists.
int HashTableRemove(HashTable *ht, void *data, uint16_t datalen)
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
#define SCLogWarning(...)
Macro used to log WARNING messages.
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
LogThreadedFileCtx * threads
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
const char * SCBasename(const char *path)
@ LOGFILE_TYPE_UNIX_DGRAM
bool SCLogOpenThreadedFile(const char *log_path, const char *append, LogFileCtx *parent_ctx)
@ LOGFILE_TYPE_UNIX_STREAM
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
#define SCMutexInit(mut, mutattrs)
#define SCGetThreadIdLong(...)
ConfNode * ConfNodeLookupChild(const ConfNode *node, const char *name)
Lookup a child configuration node by name.
struct LogFileCtx_ * parent
#define MemBufferWriteString(dst,...)
Write a string buffer to the Membuffer dst.
int PathIsAbsolute(const char *path)
Check if a path is absolute.
ThreadLogFileHashEntry * entry
int LogFileFreeCtx(LogFileCtx *lf_ctx)
LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
void(* Deinit)(void *init_data)
int RunmodeGetCurrent(void)
const char * ConfigGetLogDirectory(void)
#define SCLogError(...)
Macro used to log ERROR messages.
#define LOGFILE_ROTATE_INTERVAL
int ConfValIsFalse(const char *val)
Check if a value is false.
thread_local SCError sc_errno
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
SCLogLevel sc_log_global_log_level
Holds the global log level. Is the same as sc_log_config->log_level.
void(* Close)(struct LogFileCtx_ *fp)
#define MEMBUFFER_BUFFER(mem_buffer)
Get the MemBuffers underlying buffer.
int(* ThreadInit)(void *init_data, int thread_id, void **thread_data)
#define SCLogNotice(...)
Macro used to log NOTICE messages.
void OutputUnregisterFileRotationFlag(int *flag)
Unregister a file rotation flag.
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
int SCCreateDirectoryTree(const char *path, const bool final)
Recursively create a directory.
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.