|
|
c17bfd |
From: Jiri Vymazal <jvymazal@redhat.com>
|
|
|
c17bfd |
Date: Mon, 28 Jun 2018 15:07:55 +0100
|
|
|
c17bfd |
Subject: Imfile rewrite with symlink support
|
|
|
c17bfd |
|
|
|
c17bfd |
This commit greatly refactors imfile internal workings. It changes the
|
|
|
c17bfd |
handling of inotify, FEN, and polling modes. Mostly unchanged is the
|
|
|
c17bfd |
processing of the way a file is read and state files are kept.
|
|
|
c17bfd |
|
|
|
c17bfd |
This is about a 50% rewrite of the module.
|
|
|
c17bfd |
|
|
|
c17bfd |
Polling, inotify, and FEN modes now use greatly unified code. Some
|
|
|
c17bfd |
differences still exists and may be changed with further commits. The
|
|
|
c17bfd |
internal handling of wildcards and file detection has been completely
|
|
|
c17bfd |
re-written from scratch. For example, previously when multi-level
|
|
|
c17bfd |
wildcards were used these were not reliably detected. The code also
|
|
|
c17bfd |
now provides much of the same functionality in all modes, most importantly
|
|
|
c17bfd |
wildcards are now also supported in polling mode.
|
|
|
c17bfd |
|
|
|
c17bfd |
The refactoring sets ground for further enhancements and smaller
|
|
|
c17bfd |
refactorings. This commit provides the same feature set that imfile
|
|
|
c17bfd |
had previously.
|
|
|
c17bfd |
|
|
|
c17bfd |
Some specific changes:
|
|
|
c17bfd |
bugfix: imfile did not pick up all files when not present
|
|
|
c17bfd |
at startup
|
|
|
c17bfd |
|
|
|
c17bfd |
bugfix: directories only support "*" wildcard, no others
|
|
|
c17bfd |
|
|
|
c17bfd |
bugfix: parameter "sortfiles" did only work in FEN mode
|
|
|
c17bfd |
|
|
|
c17bfd |
provides the ability to dynamically add and remove files via
|
|
|
c17bfd |
multi-level wildcards
|
|
|
c17bfd |
|
|
|
c17bfd |
the state file name currently has been changed to inode number
|
|
|
c17bfd |
|
|
|
c17bfd |
We change it to json and also change the way it is stored and loaded.
|
|
|
c17bfd |
This sets base to additional improvements in imfile.
|
|
|
c17bfd |
|
|
|
c17bfd |
When imfile rewrites state files, it does not truncate previous
|
|
|
c17bfd |
content. If the new content is smaller than the existing one, the
|
|
|
c17bfd |
existing part will not be overwritten, resulting in invalid json.
|
|
|
c17bfd |
That in turn can lead to some other failures.
|
|
|
c17bfd |
|
|
|
c17bfd |
This introduces symlink detection and following as well
|
|
|
c17bfd |
as monitoring changes on them.
|
|
|
c17bfd |
|
|
|
c17bfd |
stream/bugfix: memory leak on stream open if filename as already generated -
|
|
|
c17bfd |
this can happen if imfile reads a state file. On each open, memory for the
|
|
|
c17bfd |
file name can be lost.
|
|
|
c17bfd |
|
|
|
c17bfd |
(cherry picked from commit a03dccf8484d621fe06cb2d11816fbe921751e54 - https://gitlab.cee.redhat.com/rsyslog/rsyslog)
|
|
|
c17bfd |
---
|
|
|
c17bfd |
plugins/imfile/imfile.c | 2264 ++++++++++++++++++++++---------------------
|
|
|
c17bfd |
runtime/msg.c | 22 ++++++++++++++++++++++
|
|
|
c17bfd |
runtime/msg.h | 1 +
|
|
|
c17bfd |
runtime/stream.c | 136 ++++++++++++++++++++-------
|
|
|
c17bfd |
runtime/stream.h | 17 ++++++++++++++---
|
|
|
c17bfd |
5 files changed, 1303 insertions(+), 1137 deletitions(-)
|
|
|
c17bfd |
|
|
|
c17bfd |
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
|
|
|
c17bfd |
index b0bc860bcd16beaecd67ce1b7c61991356ea5471..f8225d7068d8fc98edde7bbed194be1105b1696b 100644
|
|
|
c17bfd |
--- a/plugins/imfile/imfile.c
|
|
|
c17bfd |
+++ b/plugins/imfile/imfile.c
|
|
|
c17bfd |
@@ -35,6 +35,7 @@
|
|
|
c17bfd |
#include <unistd.h>
|
|
|
c17bfd |
#include <glob.h>
|
|
|
c17bfd |
#include <poll.h>
|
|
|
c17bfd |
+#include <json.h>
|
|
|
c17bfd |
#include <fnmatch.h>
|
|
|
c17bfd |
#ifdef HAVE_SYS_INOTIFY_H
|
|
|
c17bfd |
#include <sys/inotify.h>
|
|
|
c17bfd |
@@ -56,6 +57,7 @@
|
|
|
c17bfd |
#include "stringbuf.h"
|
|
|
c17bfd |
#include "ruleset.h"
|
|
|
c17bfd |
#include "ratelimit.h"
|
|
|
c17bfd |
+#include "parserif.h"
|
|
|
c17bfd |
|
|
|
c17bfd |
#include <regex.h> // TODO: fix via own module
|
|
|
c17bfd |
|
|
|
c17bfd |
@@ -77,50 +81,19 @@ static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config para
|
|
|
c17bfd |
|
|
|
c17bfd |
#define NUM_MULTISUB 1024 /* default max number of submits */
|
|
|
c17bfd |
#define DFLT_PollInterval 10
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-#define INIT_FILE_TAB_SIZE 4 /* default file table size - is extended as needed, use 2^x value */
|
|
|
c17bfd |
-#define INIT_FILE_IN_DIR_TAB_SIZE 1 /* initial size for "associated files tab" in directory table */
|
|
|
c17bfd |
#define INIT_WDMAP_TAB_SIZE 1 /* default wdMap table size - is extended as needed, use 2^x value */
|
|
|
c17bfd |
-
|
|
|
c17bfd |
#define ADD_METADATA_UNSPECIFIED -1
|
|
|
c17bfd |
+#define CONST_LEN_CEE_COOKIE 5
|
|
|
c17bfd |
+#define CONST_CEE_COOKIE "@cee:"
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* If set to 1, fileTableDisplay will be compiled and used for debugging */
|
|
|
c17bfd |
+#define ULTRA_DEBUG 0
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* Setting GLOB_BRACE to ZERO which disables support for GLOB_BRACE if not available on current platform */
|
|
|
c17bfd |
+#ifndef GLOB_BRACE
|
|
|
c17bfd |
+ #define GLOB_BRACE 0
|
|
|
c17bfd |
+#endif
|
|
|
c17bfd |
|
|
|
c17bfd |
-/* this structure is used in pure polling mode as well one of the support
|
|
|
c17bfd |
- * structures for inotify.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-typedef struct lstn_s {
|
|
|
c17bfd |
- struct lstn_s *next, *prev;
|
|
|
c17bfd |
- struct lstn_s *masterLstn;/* if dynamic file (via wildcard), this points to the configured
|
|
|
c17bfd |
- * master entry. For master entries, it is always NULL. Only
|
|
|
c17bfd |
- * dynamic files can be deleted from the "files" list. */
|
|
|
c17bfd |
- uchar *pszFileName;
|
|
|
c17bfd |
- uchar *pszDirName;
|
|
|
c17bfd |
- uchar *pszBaseName;
|
|
|
c17bfd |
- uchar *pszTag;
|
|
|
c17bfd |
- size_t lenTag;
|
|
|
c17bfd |
- uchar *pszStateFile; /* file in which state between runs is to be stored (dynamic if NULL) */
|
|
|
c17bfd |
- int readTimeout;
|
|
|
c17bfd |
- int iFacility;
|
|
|
c17bfd |
- int iSeverity;
|
|
|
c17bfd |
- int maxLinesAtOnce;
|
|
|
c17bfd |
- uint32_t trimLineOverBytes;
|
|
|
c17bfd |
- int nRecords; /**< How many records did we process before persisting the stream? */
|
|
|
c17bfd |
- int iPersistStateInterval; /**< how often should state be persisted? (0=on close only) */
|
|
|
c17bfd |
- strm_t *pStrm; /* its stream (NULL if not assigned) */
|
|
|
c17bfd |
- sbool bRMStateOnDel;
|
|
|
c17bfd |
- sbool hasWildcard;
|
|
|
c17bfd |
- uint8_t readMode; /* which mode to use in ReadMulteLine call? */
|
|
|
c17bfd |
- uchar *startRegex; /* regex that signifies end of message (NULL if unset) */
|
|
|
c17bfd |
- regex_t end_preg; /* compiled version of startRegex */
|
|
|
c17bfd |
- uchar *prevLineSegment; /* previous line segment (in regex mode) */
|
|
|
c17bfd |
- sbool escapeLF; /* escape LF inside the MSG content? */
|
|
|
c17bfd |
- sbool reopenOnTruncate;
|
|
|
c17bfd |
- sbool addMetadata;
|
|
|
c17bfd |
- sbool addCeeTag;
|
|
|
c17bfd |
- sbool freshStartTail; /* read from tail of file on fresh start? */
|
|
|
c17bfd |
- ruleset_t *pRuleset; /* ruleset to bind listener to (use system default if unspecified) */
|
|
|
c17bfd |
- ratelimit_t *ratelimiter;
|
|
|
c17bfd |
- multi_submit_t multiSub;
|
|
|
c17bfd |
-} lstn_t;
|
|
|
c17bfd |
|
|
|
c17bfd |
static struct configSettings_s {
|
|
|
c17bfd |
uchar *pszFileName;
|
|
|
c17bfd |
@@ -138,9 +111,11 @@ static struct configSettings_s {
|
|
|
c17bfd |
|
|
|
c17bfd |
struct instanceConf_s {
|
|
|
c17bfd |
uchar *pszFileName;
|
|
|
c17bfd |
+ uchar *pszFileName_forOldStateFile; /* we unfortunately needs this to read old state files */
|
|
|
c17bfd |
uchar *pszDirName;
|
|
|
c17bfd |
uchar *pszFileBaseName;
|
|
|
c17bfd |
uchar *pszTag;
|
|
|
c17bfd |
+ size_t lenTag;
|
|
|
c17bfd |
uchar *pszStateFile;
|
|
|
c17bfd |
uchar *pszBindRuleset;
|
|
|
c17bfd |
int nMultiSub;
|
|
|
c17bfd |
@@ -151,11 +126,15 @@ struct instanceConf_s {
|
|
|
c17bfd |
sbool bRMStateOnDel;
|
|
|
c17bfd |
uint8_t readMode;
|
|
|
c17bfd |
uchar *startRegex;
|
|
|
c17bfd |
+ regex_t end_preg; /* compiled version of startRegex */
|
|
|
c17bfd |
+ sbool discardTruncatedMsg;
|
|
|
c17bfd |
+ sbool msgDiscardingError;
|
|
|
c17bfd |
sbool escapeLF;
|
|
|
c17bfd |
sbool reopenOnTruncate;
|
|
|
c17bfd |
sbool addCeeTag;
|
|
|
c17bfd |
sbool addMetadata;
|
|
|
c17bfd |
sbool freshStartTail;
|
|
|
c17bfd |
+ sbool fileNotFoundError;
|
|
|
c17bfd |
int maxLinesAtOnce;
|
|
|
c17bfd |
uint32_t trimLineOverBytes;
|
|
|
c17bfd |
ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */
|
|
|
c17bfd |
@@ -163,9 +142,54 @@ struct instanceConf_s {
|
|
|
c17bfd |
};
|
|
|
c17bfd |
|
|
|
c17bfd |
|
|
|
c17bfd |
+/* file system objects */
|
|
|
c17bfd |
+typedef struct fs_edge_s fs_edge_t;
|
|
|
c17bfd |
+typedef struct fs_node_s fs_node_t;
|
|
|
c17bfd |
+typedef struct act_obj_s act_obj_t;
|
|
|
c17bfd |
+struct act_obj_s {
|
|
|
c17bfd |
+ act_obj_t *prev;
|
|
|
c17bfd |
+ act_obj_t *next;
|
|
|
c17bfd |
+ fs_edge_t *edge; /* edge which this object belongs to */
|
|
|
c17bfd |
+ char *name; /* full path name of active object */
|
|
|
c17bfd |
+ char *basename; /* only basename */ //TODO: remove when refactoring rename support
|
|
|
c17bfd |
+ char *source_name; /* if this object is target of a symlink, source_name is its name (else NULL) */
|
|
|
c17bfd |
+ //char *statefile; /* base name of state file (for move operations) */
|
|
|
c17bfd |
+ int wd;
|
|
|
c17bfd |
+ time_t timeoutBase; /* what time to calculate the timeout against? */
|
|
|
c17bfd |
+ /* file dynamic data */
|
|
|
c17bfd |
+ int in_move; /* workaround for inotify move: if set, state file must not be deleted */
|
|
|
c17bfd |
+ ino_t ino; /* current inode nbr */
|
|
|
c17bfd |
+ strm_t *pStrm; /* its stream (NULL if not assigned) */
|
|
|
c17bfd |
+ int nRecords; /**< How many records did we process before persisting the stream? */
|
|
|
c17bfd |
+ ratelimit_t *ratelimiter;
|
|
|
c17bfd |
+ multi_submit_t multiSub;
|
|
|
c17bfd |
+ int is_symlink;
|
|
|
c17bfd |
+};
|
|
|
c17bfd |
+struct fs_edge_s {
|
|
|
c17bfd |
+ fs_node_t *parent;
|
|
|
c17bfd |
+ fs_node_t *node; /* node this edge points to */
|
|
|
c17bfd |
+ fs_edge_t *next;
|
|
|
c17bfd |
+ uchar *name;
|
|
|
c17bfd |
+ uchar *path;
|
|
|
c17bfd |
+ act_obj_t *active;
|
|
|
c17bfd |
+ int is_file;
|
|
|
c17bfd |
+ int ninst; /* nbr of instances in instarr */
|
|
|
c17bfd |
+ instanceConf_t **instarr;
|
|
|
c17bfd |
+};
|
|
|
c17bfd |
+struct fs_node_s {
|
|
|
c17bfd |
+ fs_edge_t *edges;
|
|
|
c17bfd |
+ fs_node_t *root;
|
|
|
c17bfd |
+};
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
/* forward definitions */
|
|
|
c17bfd |
-static rsRetVal persistStrmState(lstn_t *pInfo);
|
|
|
c17bfd |
+static rsRetVal persistStrmState(act_obj_t *);
|
|
|
c17bfd |
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
|
|
|
c17bfd |
+static rsRetVal pollFile(act_obj_t *act);
|
|
|
c17bfd |
+static int getBasename(uchar *const __restrict__ basen, uchar *const __restrict__ path);
|
|
|
c17bfd |
+static void act_obj_unlink(act_obj_t *act);
|
|
|
c17bfd |
+static uchar * getStateFileName(const act_obj_t *, uchar *, const size_t);
|
|
|
c17bfd |
+static int getFullStateFileName(const uchar *const, uchar *const pszout, const size_t ilenout);
|
|
|
c17bfd |
|
|
|
c17bfd |
|
|
|
c17bfd |
#define OPMODE_POLLING 0
|
|
|
c17bfd |
@@ -178,57 +200,23 @@ struct modConfData_s {
|
|
|
c17bfd |
int readTimeout;
|
|
|
c17bfd |
int timeoutGranularity; /* value in ms */
|
|
|
c17bfd |
instanceConf_t *root, *tail;
|
|
|
c17bfd |
- lstn_t *pRootLstn;
|
|
|
c17bfd |
- lstn_t *pTailLstn;
|
|
|
c17bfd |
+ fs_node_t *conf_tree;
|
|
|
c17bfd |
uint8_t opMode;
|
|
|
c17bfd |
sbool configSetViaV2Method;
|
|
|
c17bfd |
+ sbool sortFiles;
|
|
|
c17bfd |
+ sbool normalizePath; /* normalize file system pathes (all start with root dir) */
|
|
|
c17bfd |
sbool haveReadTimeouts; /* use special processing if read timeouts exist */
|
|
|
c17bfd |
+ sbool bHadFileData; /* actually a global variable:
|
|
|
c17bfd |
+ 1 - last call to pollFile() had data
|
|
|
c17bfd |
+ 0 - last call to pollFile() had NO data
|
|
|
c17bfd |
+ Must be manually reset to 0 if desired. Helper for
|
|
|
c17bfd |
+ polling mode.
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
};
|
|
|
c17bfd |
static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
|
|
|
c17bfd |
static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */
|
|
|
c17bfd |
|
|
|
c17bfd |
#ifdef HAVE_INOTIFY_INIT
|
|
|
c17bfd |
-/* support for inotify mode */
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* we need to track directories */
|
|
|
c17bfd |
-struct dirInfoFiles_s { /* associated files */
|
|
|
c17bfd |
- lstn_t *pLstn;
|
|
|
c17bfd |
- int refcnt; /* due to inotify's async nature, we may have multiple
|
|
|
c17bfd |
- * references to a single file inside our cache - e.g. when
|
|
|
c17bfd |
- * inodes are removed, and the file name is re-created BUT another
|
|
|
c17bfd |
- * process (like rsyslogd ;)) holds open the old inode.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-};
|
|
|
c17bfd |
-typedef struct dirInfoFiles_s dirInfoFiles_t;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* This structure is a dynamic table to track file entries */
|
|
|
c17bfd |
-struct fileTable_s {
|
|
|
c17bfd |
- dirInfoFiles_t *listeners;
|
|
|
c17bfd |
- int currMax;
|
|
|
c17bfd |
- int allocMax;
|
|
|
c17bfd |
-};
|
|
|
c17bfd |
-typedef struct fileTable_s fileTable_t;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* The dirs table (defined below) contains one entry for each directory that
|
|
|
c17bfd |
- * is to be monitored. For each directory, it contains array which point to
|
|
|
c17bfd |
- * the associated *active* files as well as *configured* files. Note that
|
|
|
c17bfd |
- * the configured files may currently not exist, but will be processed
|
|
|
c17bfd |
- * when they are created.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-struct dirInfo_s {
|
|
|
c17bfd |
- uchar *dirName;
|
|
|
c17bfd |
- fileTable_t active; /* associated active files */
|
|
|
c17bfd |
- fileTable_t configured; /* associated configured files */
|
|
|
c17bfd |
-};
|
|
|
c17bfd |
-typedef struct dirInfo_s dirInfo_t;
|
|
|
c17bfd |
-static dirInfo_t *dirs = NULL;
|
|
|
c17bfd |
-static int allocMaxDirs;
|
|
|
c17bfd |
-static int currMaxDirs;
|
|
|
c17bfd |
-/* the following two macros are used to select the correct file table */
|
|
|
c17bfd |
-#define ACTIVE_FILE 1
|
|
|
c17bfd |
-#define CONFIGURED_FILE 0
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-
|
|
|
c17bfd |
/* We need to map watch descriptors to our actual objects. Unfortunately, the
|
|
|
c17bfd |
* inotify API does not provide us with any cookie, so a simple O(1) algorithm
|
|
|
c17bfd |
* cannot be done (what a shame...). We assume that maintaining the array is much
|
|
|
c17bfd |
@@ -238,9 +226,7 @@ static int currMaxDirs;
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
struct wd_map_s {
|
|
|
c17bfd |
int wd; /* ascending sort key */
|
|
|
c17bfd |
- lstn_t *pLstn; /* NULL, if this is a dir entry, otherwise pointer into listener(file) table */
|
|
|
c17bfd |
- int dirIdx; /* index into dirs table, undefined if pLstn == NULL */
|
|
|
c17bfd |
- time_t timeoutBase; /* what time to calculate the timeout against? */
|
|
|
c17bfd |
+ act_obj_t *act; /* point to related active object */
|
|
|
c17bfd |
};
|
|
|
c17bfd |
typedef struct wd_map_s wd_map_t;
|
|
|
c17bfd |
static wd_map_t *wdmap = NULL;
|
|
|
c17bfd |
@@ -257,6 +243,8 @@ static struct cnfparamdescr modpdescr[] = {
|
|
|
c17bfd |
{ "pollinginterval", eCmdHdlrPositiveInt, 0 },
|
|
|
c17bfd |
{ "readtimeout", eCmdHdlrPositiveInt, 0 },
|
|
|
c17bfd |
{ "timeoutgranularity", eCmdHdlrPositiveInt, 0 },
|
|
|
c17bfd |
+ { "sortfiles", eCmdHdlrBinary, 0 },
|
|
|
c17bfd |
+ { "normalizepath", eCmdHdlrBinary, 0 },
|
|
|
c17bfd |
{ "mode", eCmdHdlrGetWord, 0 }
|
|
|
c17bfd |
};
|
|
|
c17bfd |
static struct cnfparamblk modpblk =
|
|
|
c17bfd |
@@ -286,7 +274,8 @@ static struct cnfparamdescr inppdescr[] = {
|
|
|
c17bfd |
{ "addceetag", eCmdHdlrBinary, 0 },
|
|
|
c17bfd |
{ "statefile", eCmdHdlrString, CNFPARAM_DEPRECATED },
|
|
|
c17bfd |
{ "readtimeout", eCmdHdlrPositiveInt, 0 },
|
|
|
c17bfd |
- { "freshstarttail", eCmdHdlrBinary, 0}
|
|
|
c17bfd |
+ { "freshstarttail", eCmdHdlrBinary, 0},
|
|
|
c17bfd |
+ { "filenotfounderror", eCmdHdlrBinary, 0}
|
|
|
c17bfd |
};
|
|
|
c17bfd |
static struct cnfparamblk inppblk =
|
|
|
c17bfd |
{ CNFPARAMBLK_VERSION,
|
|
|
c17bfd |
@@ -297,18 +286,106 @@ static struct cnfparamblk inppblk =
|
|
|
c17bfd |
#include "im-helper.h" /* must be included AFTER the type definitions! */
|
|
|
c17bfd |
|
|
|
c17bfd |
|
|
|
c17bfd |
-#ifdef HAVE_INOTIFY_INIT
|
|
|
c17bfd |
-/* support for inotify mode */
|
|
|
c17bfd |
+/* Support for "old cruft" state files will potentially become optional in the
|
|
|
c17bfd |
+ * future (hopefully). To prepare so, we use conditional compilation with a
|
|
|
c17bfd |
+ * fixed-true condition ;-) -- rgerhards, 2018-03-28
|
|
|
c17bfd |
+ * reason: https://github.com/rsyslog/rsyslog/issues/2231#issuecomment-376862280
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+#define ENABLE_V1_STATE_FILE_FORMAT_SUPPORT 1
|
|
|
c17bfd |
+#ifdef ENABLE_V1_STATE_FILE_FORMAT_SUPPORT
|
|
|
c17bfd |
+static uchar *
|
|
|
c17bfd |
+OLD_getStateFileName(const instanceConf_t *const inst,
|
|
|
c17bfd |
+ uchar *const __restrict__ buf,
|
|
|
c17bfd |
+ const size_t lenbuf)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ DBGPRINTF("OLD_getStateFileName trying '%s'\n", inst->pszFileName_forOldStateFile);
|
|
|
c17bfd |
+ snprintf((char*)buf, lenbuf - 1, "imfile-state:%s", inst->pszFileName_forOldStateFile);
|
|
|
c17bfd |
+ buf[lenbuf-1] = '\0'; /* be on the safe side... */
|
|
|
c17bfd |
+ uchar *p = buf;
|
|
|
c17bfd |
+ for( ; *p ; ++p) {
|
|
|
c17bfd |
+ if(*p == '/')
|
|
|
c17bfd |
+ *p = '-';
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ return buf;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
|
|
|
c17bfd |
-#if 0 /* enable if you need this for debugging */
|
|
|
c17bfd |
+/* try to open an old-style state file for given file. If the state file does not
|
|
|
c17bfd |
+ * exist or cannot be read, an error is returned.
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+static rsRetVal
|
|
|
c17bfd |
+OLD_openFileWithStateFile(act_obj_t *const act)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ DEFiRet;
|
|
|
c17bfd |
+ strm_t *psSF = NULL;
|
|
|
c17bfd |
+ uchar pszSFNam[MAXFNAME];
|
|
|
c17bfd |
+ size_t lenSFNam;
|
|
|
c17bfd |
+ struct stat stat_buf;
|
|
|
c17bfd |
+ uchar statefile[MAXFNAME];
|
|
|
c17bfd |
+ const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances?
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ uchar *const statefn = OLD_getStateFileName(inst, statefile, sizeof(statefile));
|
|
|
c17bfd |
+ DBGPRINTF("OLD_openFileWithStateFile: trying to open state for '%s', state file '%s'\n",
|
|
|
c17bfd |
+ act->name, statefn);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* Get full path and file name */
|
|
|
c17bfd |
+ lenSFNam = getFullStateFileName(statefn, pszSFNam, sizeof(pszSFNam));
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* check if the file exists */
|
|
|
c17bfd |
+ if(stat((char*) pszSFNam, &stat_buf) == -1) {
|
|
|
c17bfd |
+ if(errno == ENOENT) {
|
|
|
c17bfd |
+ DBGPRINTF("OLD_openFileWithStateFile: NO state file (%s) exists for '%s'\n",
|
|
|
c17bfd |
+ pszSFNam, act->name);
|
|
|
c17bfd |
+ ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ char errStr[1024];
|
|
|
c17bfd |
+ rs_strerror_r(errno, errStr, sizeof(errStr));
|
|
|
c17bfd |
+ DBGPRINTF("OLD_openFileWithStateFile: error trying to access state "
|
|
|
c17bfd |
+ "file for '%s':%s\n", act->name, errStr);
|
|
|
c17bfd |
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* If we reach this point, we have a state file */
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ DBGPRINTF("old state file found - instantiating from it\n");
|
|
|
c17bfd |
+ CHKiRet(strm.Construct(&psSF));
|
|
|
c17bfd |
+ CHKiRet(strm.SettOperationsMode(psSF, STREAMMODE_READ));
|
|
|
c17bfd |
+ CHKiRet(strm.SetsType(psSF, STREAMTYPE_FILE_SINGLE));
|
|
|
c17bfd |
+ CHKiRet(strm.SetFName(psSF, pszSFNam, lenSFNam));
|
|
|
c17bfd |
+ CHKiRet(strm.SetFileNotFoundError(psSF, inst->fileNotFoundError));
|
|
|
c17bfd |
+ CHKiRet(strm.ConstructFinalize(psSF));
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* read back in the object */
|
|
|
c17bfd |
+ CHKiRet(obj.Deserialize(&act->pStrm, (uchar*) "strm", psSF, NULL, act));
|
|
|
c17bfd |
+ free(act->pStrm->pszFName);
|
|
|
c17bfd |
+ CHKmalloc(act->pStrm->pszFName = ustrdup(act->name));
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ strm.CheckFileChange(act->pStrm);
|
|
|
c17bfd |
+ CHKiRet(strm.SeekCurrOffs(act->pStrm));
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* we now persist the new state file and delete the old one, so we will
|
|
|
c17bfd |
+ * never have to deal with the old one. */
|
|
|
c17bfd |
+ persistStrmState(act);
|
|
|
c17bfd |
+ unlink((char*)pszSFNam);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+finalize_it:
|
|
|
c17bfd |
+ if(psSF != NULL)
|
|
|
c17bfd |
+ strm.Destruct(&psSF);
|
|
|
c17bfd |
+ RETiRet;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+#endif /* #ifdef ENABLE_V1_STATE_FILE_FORMAT_SUPPORT */
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+#ifdef HAVE_INOTIFY_INIT
|
|
|
c17bfd |
+#if ULTRA_DEBUG == 1
|
|
|
c17bfd |
static void
|
|
|
c17bfd |
-dbg_wdmapPrint(char *msg)
|
|
|
c17bfd |
+dbg_wdmapPrint(const char *msg)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
int i;
|
|
|
c17bfd |
DBGPRINTF("%s\n", msg);
|
|
|
c17bfd |
for(i = 0 ; i < nWdmap ; ++i)
|
|
|
c17bfd |
- DBGPRINTF("wdmap[%d]: wd: %d, file %d, dir %d\n", i,
|
|
|
c17bfd |
- wdmap[i].wd, wdmap[i].fIdx, wdmap[i].dirIdx);
|
|
|
c17bfd |
+ DBGPRINTF("wdmap[%d]: wd: %d, act %p, name: %s\n",
|
|
|
c17bfd |
+ i, wdmap[i].wd, wdmap[i].act, wdmap[i].act->name);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
#endif
|
|
|
c17bfd |
|
|
|
c17bfd |
@@ -324,48 +401,10 @@ finalize_it:
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
-/* looks up a wdmap entry by dirIdx and returns it's index if found
|
|
|
c17bfd |
- * or -1 if not found.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static int
|
|
|
c17bfd |
-wdmapLookupListner(lstn_t* pLstn)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int i = 0;
|
|
|
c17bfd |
- int wd = -1;
|
|
|
c17bfd |
- /* Loop through */
|
|
|
c17bfd |
- for(i = 0 ; i < nWdmap; ++i) {
|
|
|
c17bfd |
- if (wdmap[i].pLstn == pLstn)
|
|
|
c17bfd |
- wd = wdmap[i].wd;
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- return wd;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* compare function for bsearch() */
|
|
|
c17bfd |
-static int
|
|
|
c17bfd |
-wdmap_cmp(const void *k, const void *a)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int key = *((int*) k);
|
|
|
c17bfd |
- wd_map_t *etry = (wd_map_t*) a;
|
|
|
c17bfd |
- if(key < etry->wd)
|
|
|
c17bfd |
- return -1;
|
|
|
c17bfd |
- else if(key > etry->wd)
|
|
|
c17bfd |
- return 1;
|
|
|
c17bfd |
- else
|
|
|
c17bfd |
- return 0;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-/* looks up a wdmap entry and returns it's index if found
|
|
|
c17bfd |
- * or -1 if not found.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static wd_map_t *
|
|
|
c17bfd |
-wdmapLookup(int wd)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- return bsearch(&wd, wdmap, nWdmap, sizeof(wd_map_t), wdmap_cmp);
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
|
|
|
c17bfd |
/* note: we search backwards, as inotify tends to return increasing wd's */
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
-wdmapAdd(int wd, const int dirIdx, lstn_t *const pLstn)
|
|
|
c17bfd |
+wdmapAdd(int wd, act_obj_t *const act)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
wd_map_t *newmap;
|
|
|
c17bfd |
int newmapsize;
|
|
|
c17bfd |
@@ -375,7 +414,7 @@ wdmapAdd(int wd, const int dirIdx, lstn_t *const pLstn)
|
|
|
c17bfd |
for(i = nWdmap-1 ; i >= 0 && wdmap[i].wd > wd ; --i)
|
|
|
c17bfd |
; /* just scan */
|
|
|
c17bfd |
if(i >= 0 && wdmap[i].wd == wd) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: wd %d already in wdmap!\n", wd);
|
|
|
c17bfd |
+ LogError(0, RS_RET_INTERNAL_ERROR, "imfile: wd %d already in wdmap!", wd);
|
|
|
c17bfd |
ABORT_FINALIZE(RS_RET_FILE_ALREADY_IN_TABLE);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
++i;
|
|
|
c17bfd |
@@ -392,17 +431,59 @@ wdmapAdd(int wd, const int dirIdx, lstn_t *const pLstn)
|
|
|
c17bfd |
memmove(wdmap + i + 1, wdmap + i, sizeof(wd_map_t) * (nWdmap - i));
|
|
|
c17bfd |
}
|
|
|
c17bfd |
wdmap[i].wd = wd;
|
|
|
c17bfd |
- wdmap[i].dirIdx = dirIdx;
|
|
|
c17bfd |
- wdmap[i].pLstn = pLstn;
|
|
|
c17bfd |
+ wdmap[i].act = act;
|
|
|
c17bfd |
++nWdmap;
|
|
|
c17bfd |
- DBGPRINTF("imfile: enter into wdmap[%d]: wd %d, dir %d, lstn %s:%s\n",i,wd,dirIdx,
|
|
|
c17bfd |
- (pLstn == NULL) ? "DIRECTORY" : "FILE",
|
|
|
c17bfd |
- (pLstn == NULL) ? dirs[dirIdx].dirName : pLstn->pszFileName);
|
|
|
c17bfd |
+ DBGPRINTF("add wdmap[%d]: wd %d, act obj %p, path %s\n", i, wd, act, act->name);
|
|
|
c17bfd |
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
+/* return wd or -1 on error */
|
|
|
c17bfd |
+static int
|
|
|
c17bfd |
+in_setupWatch(act_obj_t *const act, const int is_file)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ int wd = -1;
|
|
|
c17bfd |
+ if(runModConf->opMode != OPMODE_INOTIFY)
|
|
|
c17bfd |
+ goto done;
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ wd = inotify_add_watch(ino_fd, act->name,
|
|
|
c17bfd |
+ (is_file) ? IN_MODIFY|IN_DONT_FOLLOW : IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO);
|
|
|
c17bfd |
+ if(wd < 0) { /* There is high probability of selinux denial on top-level paths */
|
|
|
c17bfd |
+ if (errno != EACCES)
|
|
|
c17bfd |
+ LogError(errno, RS_RET_IO_ERROR, "imfile: cannot watch object '%s'", act->name);
|
|
|
c17bfd |
+ else
|
|
|
c17bfd |
+ DBGPRINTF("Access denied when creating watch on '%s'\n", act->name);
|
|
|
c17bfd |
+ goto done;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ wdmapAdd(wd, act);
|
|
|
c17bfd |
+ DBGPRINTF("in_setupWatch: watch %d added for %s(object %p)\n", wd, act->name, act);
|
|
|
c17bfd |
+done: return wd;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* compare function for bsearch() */
|
|
|
c17bfd |
+static int
|
|
|
c17bfd |
+wdmap_cmp(const void *k, const void *a)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ int key = *((int*) k);
|
|
|
c17bfd |
+ wd_map_t *etry = (wd_map_t*) a;
|
|
|
c17bfd |
+ if(key < etry->wd)
|
|
|
c17bfd |
+ return -1;
|
|
|
c17bfd |
+ else if(key > etry->wd)
|
|
|
c17bfd |
+ return 1;
|
|
|
c17bfd |
+ else
|
|
|
c17bfd |
+ return 0;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+/* looks up a wdmap entry and returns it's index if found
|
|
|
c17bfd |
+ * or -1 if not found.
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+static wd_map_t *
|
|
|
c17bfd |
+wdmapLookup(int wd)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ return bsearch(&wd, wdmap, nWdmap, sizeof(wd_map_t), wdmap_cmp);
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
wdmapDel(const int wd)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
@@ -427,46 +506,570 @@ finalize_it:
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
-#endif /* #if HAVE_INOTIFY_INIT */
|
|
|
c17bfd |
+#endif // #ifdef HAVE_INOTIFY_INIT
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+fen_setupWatch(act_obj_t *const __attribute__((unused)) act)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ DBGPRINTF("fen_setupWatch: DUMMY CALLED - not on Solaris?\n");
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+fs_node_print(const fs_node_t *const node, const int level)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ fs_edge_t *chld;
|
|
|
c17bfd |
+ act_obj_t *act;
|
|
|
c17bfd |
+ dbgprintf("node print[%2.2d]: %p edges:\n", level, node);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ for(chld = node->edges ; chld != NULL ; chld = chld->next) {
|
|
|
c17bfd |
+ dbgprintf("node print[%2.2d]: child %p '%s' isFile %d, path: '%s'\n",
|
|
|
c17bfd |
+ level, chld->node, chld->name, chld->is_file, chld->path);
|
|
|
c17bfd |
+ for(int i = 0 ; i < chld->ninst ; ++i) {
|
|
|
c17bfd |
+ dbgprintf("\tinst: %p\n", chld->instarr[i]);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ for(act = chld->active ; act != NULL ; act = act->next) {
|
|
|
c17bfd |
+ dbgprintf("\tact : %p\n", act);
|
|
|
c17bfd |
+ dbgprintf("\tact : %p: name '%s', wd: %d\n",
|
|
|
c17bfd |
+ act, act->name, act->wd);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ for(chld = node->edges ; chld != NULL ; chld = chld->next) {
|
|
|
c17bfd |
+ fs_node_print(chld->node, level+1);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* add a new file system object if it not yet exists, ignore call
|
|
|
c17bfd |
+ * if it already does.
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+static rsRetVal
|
|
|
c17bfd |
+act_obj_add(fs_edge_t *const edge, const char *const name, const int is_file,
|
|
|
c17bfd |
+ const ino_t ino, const int is_symlink, const char *const source)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ act_obj_t *act;
|
|
|
c17bfd |
+ char basename[MAXFNAME];
|
|
|
c17bfd |
+ DEFiRet;
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ DBGPRINTF("act_obj_add: edge %p, name '%s' (source '%s')\n", edge, name, source? source : "---");
|
|
|
c17bfd |
+ for(act = edge->active ; act != NULL ; act = act->next) {
|
|
|
c17bfd |
+ if(!strcmp(act->name, name)) {
|
|
|
c17bfd |
+ if (!source || !act->source_name || !strcmp(act->source_name, source)) {
|
|
|
c17bfd |
+ DBGPRINTF("active object '%s' already exists in '%s' - no need to add\n",
|
|
|
c17bfd |
+ name, edge->path);
|
|
|
c17bfd |
+ FINALIZE;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ DBGPRINTF("add new active object '%s' in '%s'\n", name, edge->path);
|
|
|
c17bfd |
+ CHKmalloc(act = calloc(sizeof(act_obj_t), 1));
|
|
|
c17bfd |
+ CHKmalloc(act->name = strdup(name));
|
|
|
c17bfd |
+ if (-1 == getBasename((uchar*)basename, (uchar*)name)) {
|
|
|
c17bfd |
+ CHKmalloc(act->basename = strdup(name)); /* assume basename is same as name */
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ CHKmalloc(act->basename = strdup(basename));
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ act->edge = edge;
|
|
|
c17bfd |
+ act->ino = ino;
|
|
|
c17bfd |
+ act->is_symlink = is_symlink;
|
|
|
c17bfd |
+ if (source) { /* we are target of symlink */
|
|
|
c17bfd |
+ CHKmalloc(act->source_name = strdup(source));
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ act->source_name = NULL;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ #ifdef HAVE_INOTIFY_INIT
|
|
|
c17bfd |
+ act->wd = in_setupWatch(act, is_file);
|
|
|
c17bfd |
+ #endif
|
|
|
c17bfd |
+ fen_setupWatch(act);
|
|
|
c17bfd |
+ if(is_file && !is_symlink) {
|
|
|
c17bfd |
+ const instanceConf_t *const inst = edge->instarr[0];// TODO: same file, multiple instances?
|
|
|
c17bfd |
+ CHKiRet(ratelimitNew(&act->ratelimiter, "imfile", name));
|
|
|
c17bfd |
+ CHKmalloc(act->multiSub.ppMsgs = MALLOC(inst->nMultiSub * sizeof(smsg_t *)));
|
|
|
c17bfd |
+ act->multiSub.maxElem = inst->nMultiSub;
|
|
|
c17bfd |
+ act->multiSub.nElem = 0;
|
|
|
c17bfd |
+ pollFile(act);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* all well, add to active list */
|
|
|
c17bfd |
+ if(edge->active != NULL) {
|
|
|
c17bfd |
+ edge->active->prev = act;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ act->next = edge->active;
|
|
|
c17bfd |
+ edge->active = act;
|
|
|
c17bfd |
+//dbgprintf("printout of fs tree after act_obj_add for '%s'\n", name);
|
|
|
c17bfd |
+//fs_node_print(runModConf->conf_tree, 0);
|
|
|
c17bfd |
+//dbg_wdmapPrint("wdmap after act_obj_add");
|
|
|
c17bfd |
+finalize_it:
|
|
|
c17bfd |
+ if(iRet != RS_RET_OK) {
|
|
|
c17bfd |
+ if(act != NULL) {
|
|
|
c17bfd |
+ free(act->name);
|
|
|
c17bfd |
+ free(act);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ RETiRet;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* this walks an edges active list and detects and acts on any changes
|
|
|
c17bfd |
+ * seen there. It does NOT detect newly appeared files, as they are not
|
|
|
c17bfd |
+ * inside the active list!
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+detect_updates(fs_edge_t *const edge)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ act_obj_t *act;
|
|
|
c17bfd |
+ struct stat fileInfo;
|
|
|
c17bfd |
+ int restart = 0;
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ for(act = edge->active ; act != NULL ; ) {
|
|
|
c17bfd |
+ DBGPRINTF("detect_updates checking active obj '%s'\n", act->name);
|
|
|
c17bfd |
+ const int r = lstat(act->name, &fileInfo);
|
|
|
c17bfd |
+ if(r == -1) { /* object gone away? */
|
|
|
c17bfd |
+ DBGPRINTF("object gone away, unlinking: '%s'\n", act->name);
|
|
|
c17bfd |
+ act_obj_unlink(act);
|
|
|
c17bfd |
+ restart = 1;
|
|
|
c17bfd |
+ break;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ // TODO: add inode check for change notification!
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* Note: active nodes may get deleted, so we need to do the
|
|
|
c17bfd |
+ * pointer advancement at the end of the for loop!
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+ act = act->next;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ if (restart)
|
|
|
c17bfd |
+ detect_updates(edge);
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* check if active files need to be processed. This is only needed in
|
|
|
c17bfd |
+ * polling mode.
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+poll_active_files(fs_edge_t *const edge)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ if( runModConf->opMode != OPMODE_POLLING
|
|
|
c17bfd |
+ || !edge->is_file
|
|
|
c17bfd |
+ || glbl.GetGlobalInputTermState() != 0) {
|
|
|
c17bfd |
+ return;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ act_obj_t *act;
|
|
|
c17bfd |
+ for(act = edge->active ; act != NULL ; act = act->next) {
|
|
|
c17bfd |
+ fen_setupWatch(act);
|
|
|
c17bfd |
+ DBGPRINTF("poll_active_files: polling '%s'\n", act->name);
|
|
|
c17bfd |
+ pollFile(act);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+static rsRetVal
|
|
|
c17bfd |
+process_symlink(fs_edge_t *const chld, const char *symlink)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ DEFiRet;
|
|
|
c17bfd |
+ char *target = NULL;
|
|
|
c17bfd |
+ CHKmalloc(target = realpath(symlink, target));
|
|
|
c17bfd |
+ struct stat fileInfo;
|
|
|
c17bfd |
+ if(lstat(target, &fileInfo) != 0) {
|
|
|
c17bfd |
+ LogError(errno, RS_RET_ERR, "imfile: process_symlink cannot stat file '%s' - ignored", target);
|
|
|
c17bfd |
+ FINALIZE;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ const int is_file = (S_ISREG(fileInfo.st_mode));
|
|
|
c17bfd |
+ DBGPRINTF("process_symlink: found '%s', File: %d (config file: %d), symlink: %d\n",
|
|
|
c17bfd |
+ target, is_file, chld->is_file, 0);
|
|
|
c17bfd |
+ if (act_obj_add(chld, target, is_file, fileInfo.st_ino, 0, symlink) == RS_RET_OK) {
|
|
|
c17bfd |
+ /* need to watch parent target as well for proper rotation support */
|
|
|
c17bfd |
+ uint idx = ustrlen(chld->active->name) - ustrlen(chld->active->basename);
|
|
|
c17bfd |
+ if (idx) { /* basename is different from name */
|
|
|
c17bfd |
+ char parent[MAXFNAME];
|
|
|
c17bfd |
+ memcpy(parent, chld->active->name, idx-1);
|
|
|
c17bfd |
+ parent[idx-1] = '\0';
|
|
|
c17bfd |
+ if(lstat(parent, &fileInfo) != 0) {
|
|
|
c17bfd |
+ LogError(errno, RS_RET_ERR,
|
|
|
c17bfd |
+ "imfile: process_symlink: cannot stat directory '%s' - ignored", parent);
|
|
|
c17bfd |
+ FINALIZE;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ DBGPRINTF("process_symlink: adding parent '%s' of target '%s'\n", parent, target);
|
|
|
c17bfd |
+ act_obj_add(chld->parent->root->edges, parent, 0, fileInfo.st_ino, 0, NULL);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+finalize_it:
|
|
|
c17bfd |
+ free(target);
|
|
|
c17bfd |
+ RETiRet;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+poll_tree(fs_edge_t *const chld)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ struct stat fileInfo;
|
|
|
c17bfd |
+ glob_t files;
|
|
|
c17bfd |
+ int issymlink;
|
|
|
c17bfd |
+ DBGPRINTF("poll_tree: chld %p, name '%s', path: %s\n", chld, chld->name, chld->path);
|
|
|
c17bfd |
+ detect_updates(chld);
|
|
|
c17bfd |
+ const int ret = glob((char*)chld->path, runModConf->sortFiles|GLOB_BRACE, NULL, &files);
|
|
|
c17bfd |
+ DBGPRINTF("poll_tree: glob returned %d\n", ret);
|
|
|
c17bfd |
+ if(ret == 0) {
|
|
|
c17bfd |
+ DBGPRINTF("poll_tree: processing %d files\n", (int) files.gl_pathc);
|
|
|
c17bfd |
+ for(unsigned i = 0 ; i < files.gl_pathc ; i++) {
|
|
|
c17bfd |
+ if(glbl.GetGlobalInputTermState() != 0) {
|
|
|
c17bfd |
+ goto done;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ char *const file = files.gl_pathv[i];
|
|
|
c17bfd |
+ if(lstat(file, &fileInfo) != 0) {
|
|
|
c17bfd |
+ LogError(errno, RS_RET_ERR,
|
|
|
c17bfd |
+ "imfile: poll_tree cannot stat file '%s' - ignored", file);
|
|
|
c17bfd |
+ continue;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ if (S_ISLNK(fileInfo.st_mode)) {
|
|
|
c17bfd |
+ rsRetVal slink_ret = process_symlink(chld, file);
|
|
|
c17bfd |
+ if (slink_ret != RS_RET_OK) {
|
|
|
c17bfd |
+ continue;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ issymlink = 1;
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ issymlink = 0;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ const int is_file = (S_ISREG(fileInfo.st_mode) || issymlink);
|
|
|
c17bfd |
+ DBGPRINTF("poll_tree: found '%s', File: %d (config file: %d), symlink: %d\n",
|
|
|
c17bfd |
+ file, is_file, chld->is_file, issymlink);
|
|
|
c17bfd |
+ if(!is_file && S_ISREG(fileInfo.st_mode)) {
|
|
|
c17bfd |
+ LogMsg(0, RS_RET_ERR, LOG_WARNING,
|
|
|
c17bfd |
+ "imfile: '%s' is neither a regular file, symlink, nor a "
|
|
|
c17bfd |
+ "directory - ignored", file);
|
|
|
c17bfd |
+ continue;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ if(chld->is_file != is_file) {
|
|
|
c17bfd |
+ LogMsg(0, RS_RET_ERR, LOG_WARNING,
|
|
|
c17bfd |
+ "imfile: '%s' is %s but %s expected - ignored",
|
|
|
c17bfd |
+ file, (is_file) ? "FILE" : "DIRECTORY",
|
|
|
c17bfd |
+ (chld->is_file) ? "FILE" : "DIRECTORY");
|
|
|
c17bfd |
+ continue;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ act_obj_add(chld, file, is_file, fileInfo.st_ino, issymlink, NULL);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ globfree(&files);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ poll_active_files(chld);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+done: return;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+#ifdef HAVE_INOTIFY_INIT // TODO: shouldn't we use that in polling as well?
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+poll_timeouts(fs_edge_t *const edge)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ if(edge->is_file) {
|
|
|
c17bfd |
+ act_obj_t *act;
|
|
|
c17bfd |
+ for(act = edge->active ; act != NULL ; act = act->next) {
|
|
|
c17bfd |
+ if(strmReadMultiLine_isTimedOut(act->pStrm)) {
|
|
|
c17bfd |
+ DBGPRINTF("timeout occured on %s\n", act->name);
|
|
|
c17bfd |
+ pollFile(act);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+#endif
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* destruct a single act_obj object */
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+act_obj_destroy(act_obj_t *const act, const int is_deleted)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ uchar *statefn;
|
|
|
c17bfd |
+ uchar statefile[MAXFNAME];
|
|
|
c17bfd |
+ uchar toDel[MAXFNAME];
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ if(act == NULL)
|
|
|
c17bfd |
+ return;
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ DBGPRINTF("act_obj_destroy: act %p '%s', (source '%s'), wd %d, pStrm %p, is_deleted %d, in_move %d\n",
|
|
|
c17bfd |
+ act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm, is_deleted, act->in_move);
|
|
|
c17bfd |
+ if(act->is_symlink && is_deleted) {
|
|
|
c17bfd |
+ act_obj_t *target_act;
|
|
|
c17bfd |
+ for(target_act = act->edge->active ; target_act != NULL ; target_act = target_act->next) {
|
|
|
c17bfd |
+ if(target_act->source_name && !strcmp(target_act->source_name, act->name)) {
|
|
|
c17bfd |
+ DBGPRINTF("act_obj_destroy: unlinking slink target %s of %s "
|
|
|
c17bfd |
+ "symlink\n", target_act->name, act->name);
|
|
|
c17bfd |
+ act_obj_unlink(target_act);
|
|
|
c17bfd |
+ break;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ if(act->ratelimiter != NULL) {
|
|
|
c17bfd |
+ ratelimitDestruct(act->ratelimiter);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ if(act->pStrm != NULL) {
|
|
|
c17bfd |
+ const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances?
|
|
|
c17bfd |
+ pollFile(act); /* get any left-over data */
|
|
|
c17bfd |
+ if(inst->bRMStateOnDel) {
|
|
|
c17bfd |
+ statefn = getStateFileName(act, statefile, sizeof(statefile));
|
|
|
c17bfd |
+ getFullStateFileName(statefn, toDel, sizeof(toDel));
|
|
|
c17bfd |
+ statefn = toDel;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ persistStrmState(act);
|
|
|
c17bfd |
+ strm.Destruct(&act->pStrm);
|
|
|
c17bfd |
+ /* we delete state file after destruct in case strm obj initiated a write */
|
|
|
c17bfd |
+ if(is_deleted && !act->in_move && inst->bRMStateOnDel) {
|
|
|
c17bfd |
+ DBGPRINTF("act_obj_destroy: deleting state file %s\n", statefn);
|
|
|
c17bfd |
+ unlink((char*)statefn);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ #ifdef HAVE_INOTIFY_INIT
|
|
|
c17bfd |
+ if(act->wd != -1) {
|
|
|
c17bfd |
+ wdmapDel(act->wd);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ #endif
|
|
|
c17bfd |
+ #if defined(OS_SOLARIS) && defined (HAVE_PORT_SOURCE_FILE)
|
|
|
c17bfd |
+ if(act->pfinf != NULL) {
|
|
|
c17bfd |
+ free(act->pfinf->fobj.fo_name);
|
|
|
c17bfd |
+ free(act->pfinf);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ #endif
|
|
|
c17bfd |
+ free(act->basename);
|
|
|
c17bfd |
+ free(act->source_name);
|
|
|
c17bfd |
+ //free(act->statefile);
|
|
|
c17bfd |
+ free(act->multiSub.ppMsgs);
|
|
|
c17bfd |
+ #if defined(OS_SOLARIS) && defined (HAVE_PORT_SOURCE_FILE)
|
|
|
c17bfd |
+ act->is_deleted = 1;
|
|
|
c17bfd |
+ #else
|
|
|
c17bfd |
+ free(act->name);
|
|
|
c17bfd |
+ free(act);
|
|
|
c17bfd |
+ #endif
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
|
|
|
c17bfd |
+/* destroy complete act list starting at given node */
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+act_obj_destroy_all(act_obj_t *act)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ if(act == NULL)
|
|
|
c17bfd |
+ return;
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ DBGPRINTF("act_obj_destroy_all: act %p '%s', wd %d, pStrm %p\n", act, act->name, act->wd, act->pStrm);
|
|
|
c17bfd |
+ while(act != NULL) {
|
|
|
c17bfd |
+ act_obj_t *const toDel = act;
|
|
|
c17bfd |
+ act = act->next;
|
|
|
c17bfd |
+ act_obj_destroy(toDel, 0);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+#if 0
|
|
|
c17bfd |
+/* debug: find if ptr is still present in list */
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+chk_active(const act_obj_t *act, const act_obj_t *const deleted)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ while(act != NULL) {
|
|
|
c17bfd |
+ DBGPRINTF("chk_active %p vs %p\n", act, deleted);
|
|
|
c17bfd |
+ if(act->prev == deleted)
|
|
|
c17bfd |
+ DBGPRINTF("chk_active %p prev points to %p\n", act, deleted);
|
|
|
c17bfd |
+ if(act->next == deleted)
|
|
|
c17bfd |
+ DBGPRINTF("chk_active %p next points to %p\n", act, deleted);
|
|
|
c17bfd |
+ act = act->next;
|
|
|
c17bfd |
+ DBGPRINTF("chk_active next %p\n", act);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+#endif
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* unlink act object from linked list and then
|
|
|
c17bfd |
+ * destruct it.
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+act_obj_unlink(act_obj_t *act)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ DBGPRINTF("act_obj_unlink %p: %s\n", act, act->name);
|
|
|
c17bfd |
+ if(act->prev == NULL) {
|
|
|
c17bfd |
+ act->edge->active = act->next;
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ act->prev->next = act->next;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ if(act->next != NULL) {
|
|
|
c17bfd |
+ act->next->prev = act->prev;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ act_obj_destroy(act, 1);
|
|
|
c17bfd |
+ act = NULL;
|
|
|
c17bfd |
+//dbgprintf("printout of fs tree post unlink\n");
|
|
|
c17bfd |
+//fs_node_print(runModConf->conf_tree, 0);
|
|
|
c17bfd |
+//dbg_wdmapPrint("wdmap after");
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+fs_node_destroy(fs_node_t *const node)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ fs_edge_t *edge;
|
|
|
c17bfd |
+ DBGPRINTF("node destroy: %p edges:\n", node);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ for(edge = node->edges ; edge != NULL ; ) {
|
|
|
c17bfd |
+ fs_node_destroy(edge->node);
|
|
|
c17bfd |
+ fs_edge_t *const toDel = edge;
|
|
|
c17bfd |
+ edge = edge->next;
|
|
|
c17bfd |
+ act_obj_destroy_all(toDel->active);
|
|
|
c17bfd |
+ free(toDel->name);
|
|
|
c17bfd |
+ free(toDel->path);
|
|
|
c17bfd |
+ free(toDel->instarr);
|
|
|
c17bfd |
+ free(toDel);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ free(node);
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+static void
|
|
|
c17bfd |
+fs_node_walk(fs_node_t *const node,
|
|
|
c17bfd |
+ void (*f_usr)(fs_edge_t*const))
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ DBGPRINTF("node walk: %p edges:\n", node);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ fs_edge_t *edge;
|
|
|
c17bfd |
+ for(edge = node->edges ; edge != NULL ; edge = edge->next) {
|
|
|
c17bfd |
+ DBGPRINTF("node walk: child %p '%s'\n", edge->node, edge->name);
|
|
|
c17bfd |
+ f_usr(edge);
|
|
|
c17bfd |
+ fs_node_walk(edge->node, f_usr);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* add a file system object to config tree (or update existing node with new monitor)
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+static rsRetVal
|
|
|
c17bfd |
+fs_node_add(fs_node_t *const node, fs_node_t *const source,
|
|
|
c17bfd |
+ const uchar *const toFind,
|
|
|
c17bfd |
+ const size_t pathIdx,
|
|
|
c17bfd |
+ instanceConf_t *const inst)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ DEFiRet;
|
|
|
c17bfd |
+ fs_edge_t *newchld = NULL;
|
|
|
c17bfd |
+ int i;
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ DBGPRINTF("fs_node_add(%p, '%s') enter, idx %zd\n",
|
|
|
c17bfd |
+ node, toFind+pathIdx, pathIdx);
|
|
|
c17bfd |
+ assert(toFind[0] != '\0');
|
|
|
c17bfd |
+ for(i = pathIdx ; (toFind[i] != '\0') && (toFind[i] != '/') ; ++i)
|
|
|
c17bfd |
+ /*JUST SKIP*/;
|
|
|
c17bfd |
+ const int isFile = (toFind[i] == '\0') ? 1 : 0;
|
|
|
c17bfd |
+ uchar ourPath[PATH_MAX];
|
|
|
c17bfd |
+ if(i == 0) {
|
|
|
c17bfd |
+ ourPath[0] = '/';
|
|
|
c17bfd |
+ ourPath[1] = '\0';
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ memcpy(ourPath, toFind, i);
|
|
|
c17bfd |
+ ourPath[i] = '\0';
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ const size_t nextPathIdx = i+1;
|
|
|
c17bfd |
+ const size_t len = i - pathIdx;
|
|
|
c17bfd |
+ uchar name[PATH_MAX];
|
|
|
c17bfd |
+ memcpy(name, toFind+pathIdx, len);
|
|
|
c17bfd |
+ name[len] = '\0';
|
|
|
c17bfd |
+ DBGPRINTF("fs_node_add: name '%s'\n", name); node->root = source;
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ fs_edge_t *chld;
|
|
|
c17bfd |
+ for(chld = node->edges ; chld != NULL ; chld = chld->next) {
|
|
|
c17bfd |
+ if(!ustrcmp(chld->name, name)) {
|
|
|
c17bfd |
+ DBGPRINTF("fs_node_add(%p, '%s') found '%s'\n", chld->node, toFind, name);
|
|
|
c17bfd |
+ /* add new instance */
|
|
|
c17bfd |
+ chld->ninst++;
|
|
|
c17bfd |
+ CHKmalloc(chld->instarr = realloc(chld->instarr, sizeof(instanceConf_t*) * chld->ninst));
|
|
|
c17bfd |
+ chld->instarr[chld->ninst-1] = inst;
|
|
|
c17bfd |
+ /* recurse */
|
|
|
c17bfd |
+ if(!isFile) {
|
|
|
c17bfd |
+ CHKiRet(fs_node_add(chld->node, node, toFind, nextPathIdx, inst));
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ FINALIZE;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* could not find node --> add it */
|
|
|
c17bfd |
+ DBGPRINTF("fs_node_add(%p, '%s') did not find '%s' - adding it\n",
|
|
|
c17bfd |
+ node, toFind, name);
|
|
|
c17bfd |
+ CHKmalloc(newchld = calloc(sizeof(fs_edge_t), 1));
|
|
|
c17bfd |
+ CHKmalloc(newchld->name = ustrdup(name));
|
|
|
c17bfd |
+ CHKmalloc(newchld->node = calloc(sizeof(fs_node_t), 1));
|
|
|
c17bfd |
+ CHKmalloc(newchld->path = ustrdup(ourPath));
|
|
|
c17bfd |
+ CHKmalloc(newchld->instarr = calloc(sizeof(instanceConf_t*), 1));
|
|
|
c17bfd |
+ newchld->instarr[0] = inst;
|
|
|
c17bfd |
+ newchld->is_file = isFile;
|
|
|
c17bfd |
+ newchld->ninst = 1;
|
|
|
c17bfd |
+ newchld->parent = node;
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ DBGPRINTF("fs_node_add(%p, '%s') returns %p\n", node, toFind, newchld->node);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ if(!isFile) {
|
|
|
c17bfd |
+ CHKiRet(fs_node_add(newchld->node, node, toFind, nextPathIdx, inst));
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* link to list */
|
|
|
c17bfd |
+ newchld->next = node->edges;
|
|
|
c17bfd |
+ node->edges = newchld;
|
|
|
c17bfd |
+finalize_it:
|
|
|
c17bfd |
+ if(iRet != RS_RET_OK) {
|
|
|
c17bfd |
+ if(newchld != NULL) {
|
|
|
c17bfd |
+ free(newchld->name);
|
|
|
c17bfd |
+ free(newchld->node);
|
|
|
c17bfd |
+ free(newchld->path);
|
|
|
c17bfd |
+ free(newchld->instarr);
|
|
|
c17bfd |
+ free(newchld);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ RETiRet;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* Helper function to combine statefile and workdir
|
|
|
c17bfd |
+ * This function is guranteed to work only on config data and DOES NOT
|
|
|
c17bfd |
+ * open or otherwise modify disk file state.
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+static int
|
|
|
c17bfd |
+getFullStateFileName(const uchar *const pszstatefile, uchar *const pszout, const size_t ilenout)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ int lenout;
|
|
|
c17bfd |
+ const uchar* pszworkdir;
|
|
|
c17bfd |
|
|
|
c17bfd |
-/* this generates a state file name suitable for the current file. To avoid
|
|
|
c17bfd |
+ /* Get Raw Workdir, if it is NULL we need to propper handle it */
|
|
|
c17bfd |
+ pszworkdir = glblGetWorkDirRaw();
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* Construct file name */
|
|
|
c17bfd |
+ lenout = snprintf((char*)pszout, ilenout, "%s/%s",
|
|
|
c17bfd |
+ (char*) (pszworkdir == NULL ? "." : (char*) pszworkdir), (char*)pszstatefile);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* return out length */
|
|
|
c17bfd |
+ return lenout;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* this generates a state file name suitable for the given file. To avoid
|
|
|
c17bfd |
* malloc calls, it must be passed a buffer which should be MAXFNAME large.
|
|
|
c17bfd |
* Note: the buffer is not necessarily populated ... always ONLY use the
|
|
|
c17bfd |
* RETURN VALUE!
|
|
|
c17bfd |
+ * This function is guranteed to work only on config data and DOES NOT
|
|
|
c17bfd |
+ * open or otherwise modify disk file state.
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
static uchar *
|
|
|
c17bfd |
-getStateFileName(lstn_t *const __restrict__ pLstn,
|
|
|
c17bfd |
+getStateFileName(const act_obj_t *const act,
|
|
|
c17bfd |
uchar *const __restrict__ buf,
|
|
|
c17bfd |
const size_t lenbuf)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
- uchar *ret;
|
|
|
c17bfd |
- if(pLstn->pszStateFile == NULL) {
|
|
|
c17bfd |
- snprintf((char*)buf, lenbuf - 1, "imfile-state:%s", pLstn->pszFileName);
|
|
|
c17bfd |
- buf[lenbuf-1] = '\0'; /* be on the safe side... */
|
|
|
c17bfd |
- uchar *p = buf;
|
|
|
c17bfd |
- for( ; *p ; ++p) {
|
|
|
c17bfd |
- if(*p == '/')
|
|
|
c17bfd |
- *p = '-';
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- ret = buf;
|
|
|
c17bfd |
- } else {
|
|
|
c17bfd |
- ret = pLstn->pszStateFile;
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- return ret;
|
|
|
c17bfd |
+ DBGPRINTF("getStateFileName for '%s'\n", act->name);
|
|
|
c17bfd |
+ snprintf((char*)buf, lenbuf - 1, "imfile-state:%lld", (long long) act->ino);
|
|
|
c17bfd |
+ DBGPRINTF("getStateFileName: stat file name now is %s\n", buf);
|
|
|
c17bfd |
+ return buf;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
|
|
|
c17bfd |
/* enqueue the read file line as a message. The provided string is
|
|
|
c17bfd |
- * not freed - thuis must be done by the caller.
|
|
|
c17bfd |
+ * not freed - this must be done by the caller.
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
-static rsRetVal enqLine(lstn_t *const __restrict__ pLstn,
|
|
|
c17bfd |
- cstr_t *const __restrict__ cstrLine)
|
|
|
c17bfd |
+#define MAX_OFFSET_REPRESENTATION_NUM_BYTES 20
|
|
|
c17bfd |
+static rsRetVal
|
|
|
c17bfd |
+enqLine(act_obj_t *const act,
|
|
|
c17bfd |
+ cstr_t *const __restrict__ cstrLine,
|
|
|
c17bfd |
+ const int64 strtOffs)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
+ const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances?
|
|
|
c17bfd |
smsg_t *pMsg;
|
|
|
c17bfd |
+ uchar file_offset[MAX_OFFSET_REPRESENTATION_NUM_BYTES+1];
|
|
|
c17bfd |
+ const uchar *metadata_names[2] = {(uchar *)"filename",(uchar *)"fileoffset"} ;
|
|
|
c17bfd |
+ const uchar *metadata_values[2] ;
|
|
|
c17bfd |
+ const size_t msgLen = cstrLen(cstrLine);
|
|
|
c17bfd |
|
|
|
c17bfd |
- if(rsCStrLen(cstrLine) == 0) {
|
|
|
c17bfd |
+ if(msgLen == 0) {
|
|
|
c17bfd |
/* we do not process empty lines */
|
|
|
c17bfd |
FINALIZE;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
@@ -474,27 +1180,34 @@ static rsRetVal enqLine(lstn_t *const __restrict__ pLstn,
|
|
|
c17bfd |
CHKiRet(msgConstruct(&pMsg));
|
|
|
c17bfd |
MsgSetFlowControlType(pMsg, eFLOWCTL_FULL_DELAY);
|
|
|
c17bfd |
MsgSetInputName(pMsg, pInputName);
|
|
|
c17bfd |
- if (pLstn->addCeeTag) {
|
|
|
c17bfd |
- size_t msgLen = cstrLen(cstrLine);
|
|
|
c17bfd |
- const char *const ceeToken = "@cee:";
|
|
|
c17bfd |
- size_t ceeMsgSize = msgLen + strlen(ceeToken) +1;
|
|
|
c17bfd |
+ if(inst->addCeeTag) {
|
|
|
c17bfd |
+ /* Make sure we account for terminating null byte */
|
|
|
c17bfd |
+ size_t ceeMsgSize = msgLen + CONST_LEN_CEE_COOKIE + 1;
|
|
|
c17bfd |
char *ceeMsg;
|
|
|
c17bfd |
CHKmalloc(ceeMsg = MALLOC(ceeMsgSize));
|
|
|
c17bfd |
- strcpy(ceeMsg, ceeToken);
|
|
|
c17bfd |
+ strcpy(ceeMsg, CONST_CEE_COOKIE);
|
|
|
c17bfd |
strcat(ceeMsg, (char*)rsCStrGetSzStrNoNULL(cstrLine));
|
|
|
c17bfd |
MsgSetRawMsg(pMsg, ceeMsg, ceeMsgSize);
|
|
|
c17bfd |
free(ceeMsg);
|
|
|
c17bfd |
} else {
|
|
|
c17bfd |
- MsgSetRawMsg(pMsg, (char*)rsCStrGetSzStrNoNULL(cstrLine), cstrLen(cstrLine));
|
|
|
c17bfd |
+ MsgSetRawMsg(pMsg, (char*)rsCStrGetSzStrNoNULL(cstrLine), msgLen);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
MsgSetMSGoffs(pMsg, 0); /* we do not have a header... */
|
|
|
c17bfd |
MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
|
|
|
c17bfd |
- MsgSetTAG(pMsg, pLstn->pszTag, pLstn->lenTag);
|
|
|
c17bfd |
- msgSetPRI(pMsg, pLstn->iFacility | pLstn->iSeverity);
|
|
|
c17bfd |
- MsgSetRuleset(pMsg, pLstn->pRuleset);
|
|
|
c17bfd |
- if(pLstn->addMetadata)
|
|
|
c17bfd |
- msgAddMetadata(pMsg, (uchar*)"filename", pLstn->pszFileName);
|
|
|
c17bfd |
- ratelimitAddMsg(pLstn->ratelimiter, &pLstn->multiSub, pMsg);
|
|
|
c17bfd |
+ MsgSetTAG(pMsg, inst->pszTag, inst->lenTag);
|
|
|
c17bfd |
+ msgSetPRI(pMsg, inst->iFacility | inst->iSeverity);
|
|
|
c17bfd |
+ MsgSetRuleset(pMsg, inst->pBindRuleset);
|
|
|
c17bfd |
+ if(inst->addMetadata) {
|
|
|
c17bfd |
+ if (act->source_name) {
|
|
|
c17bfd |
+ metadata_values[0] = (const uchar*)act->source_name;
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ metadata_values[0] = (const uchar*)act->name;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ snprintf((char *)file_offset, MAX_OFFSET_REPRESENTATION_NUM_BYTES+1, "%lld", strtOffs);
|
|
|
c17bfd |
+ metadata_values[1] = file_offset;
|
|
|
c17bfd |
+ msgAddMultiMetadata(pMsg, metadata_names, metadata_values, 2);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ ratelimitAddMsg(act->ratelimiter, &act->multiSub, pMsg);
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
@@ -504,70 +1213,89 @@ finalize_it:
|
|
|
c17bfd |
* exist or cannot be read, an error is returned.
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
-openFileWithStateFile(lstn_t *const __restrict__ pLstn)
|
|
|
c17bfd |
+openFileWithStateFile(act_obj_t *const act)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
- strm_t *psSF = NULL;
|
|
|
c17bfd |
uchar pszSFNam[MAXFNAME];
|
|
|
c17bfd |
- size_t lenSFNam;
|
|
|
c17bfd |
- struct stat stat_buf;
|
|
|
c17bfd |
uchar statefile[MAXFNAME];
|
|
|
c17bfd |
+ int fd = -1;
|
|
|
c17bfd |
+ const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances?
|
|
|
c17bfd |
|
|
|
c17bfd |
- uchar *const statefn = getStateFileName(pLstn, statefile, sizeof(statefile));
|
|
|
c17bfd |
- DBGPRINTF("imfile: trying to open state for '%s', state file '%s'\n",
|
|
|
c17bfd |
- pLstn->pszFileName, statefn);
|
|
|
c17bfd |
- /* Construct file name */
|
|
|
c17bfd |
- lenSFNam = snprintf((char*)pszSFNam, sizeof(pszSFNam), "%s/%s",
|
|
|
c17bfd |
- (char*) glbl.GetWorkDir(), (char*)statefn);
|
|
|
c17bfd |
+ uchar *const statefn = getStateFileName(act, statefile, sizeof(statefile));
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ getFullStateFileName(statefn, pszSFNam, sizeof(pszSFNam));
|
|
|
c17bfd |
+ DBGPRINTF("trying to open state for '%s', state file '%s'\n", act->name, pszSFNam);
|
|
|
c17bfd |
|
|
|
c17bfd |
/* check if the file exists */
|
|
|
c17bfd |
- if(stat((char*) pszSFNam, &stat_buf) == -1) {
|
|
|
c17bfd |
+ fd = open((char*)pszSFNam, O_CLOEXEC | O_NOCTTY | O_RDONLY, 0600);
|
|
|
c17bfd |
+ if(fd < 0) {
|
|
|
c17bfd |
if(errno == ENOENT) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: NO state file exists for '%s'\n", pLstn->pszFileName);
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
|
|
|
c17bfd |
+ DBGPRINTF("NO state file (%s) exists for '%s' - trying to see if "
|
|
|
c17bfd |
+ "old-style file exists\n", pszSFNam, act->name);
|
|
|
c17bfd |
+ CHKiRet(OLD_openFileWithStateFile(act));
|
|
|
c17bfd |
+ FINALIZE;
|
|
|
c17bfd |
} else {
|
|
|
c17bfd |
- char errStr[1024];
|
|
|
c17bfd |
- rs_strerror_r(errno, errStr, sizeof(errStr));
|
|
|
c17bfd |
- DBGPRINTF("imfile: error trying to access state file for '%s':%s\n",
|
|
|
c17bfd |
- pLstn->pszFileName, errStr);
|
|
|
c17bfd |
+ LogError(errno, RS_RET_IO_ERROR,
|
|
|
c17bfd |
+ "imfile error trying to access state file for '%s'",
|
|
|
c17bfd |
+ act->name);
|
|
|
c17bfd |
ABORT_FINALIZE(RS_RET_IO_ERROR);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
- /* If we reach this point, we have a state file */
|
|
|
c17bfd |
+ CHKiRet(strm.Construct(&act->pStrm));
|
|
|
c17bfd |
|
|
|
c17bfd |
- CHKiRet(strm.Construct(&psSF));
|
|
|
c17bfd |
- CHKiRet(strm.SettOperationsMode(psSF, STREAMMODE_READ));
|
|
|
c17bfd |
- CHKiRet(strm.SetsType(psSF, STREAMTYPE_FILE_SINGLE));
|
|
|
c17bfd |
- CHKiRet(strm.SetFName(psSF, pszSFNam, lenSFNam));
|
|
|
c17bfd |
- CHKiRet(strm.ConstructFinalize(psSF));
|
|
|
c17bfd |
+ struct json_object *jval;
|
|
|
c17bfd |
+ struct json_object *json = fjson_object_from_fd(fd);
|
|
|
c17bfd |
+ if(json == NULL) {
|
|
|
c17bfd |
+ LogError(0, RS_RET_ERR, "imfile: error reading state file for '%s'", act->name);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
|
|
|
c17bfd |
- /* read back in the object */
|
|
|
c17bfd |
- CHKiRet(obj.Deserialize(&pLstn->pStrm, (uchar*) "strm", psSF, NULL, pLstn));
|
|
|
c17bfd |
- DBGPRINTF("imfile: deserialized state file, state file base name '%s', "
|
|
|
c17bfd |
- "configured base name '%s'\n", pLstn->pStrm->pszFName,
|
|
|
c17bfd |
- pLstn->pszFileName);
|
|
|
c17bfd |
- if(ustrcmp(pLstn->pStrm->pszFName, pLstn->pszFileName)) {
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_STATEFILE_WRONG_FNAME, "imfile: state file '%s' "
|
|
|
c17bfd |
- "contains file name '%s', but is used for file '%s'. State "
|
|
|
c17bfd |
- "file deleted, starting from begin of file.",
|
|
|
c17bfd |
- pszSFNam, pLstn->pStrm->pszFName, pLstn->pszFileName);
|
|
|
c17bfd |
+ /* we access some data items a bit dirty, as we need to refactor the whole
|
|
|
c17bfd |
+ * thing in any case - TODO
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+ /* Note: we ignore filname property - it is just an aid to the user. Most
|
|
|
c17bfd |
+ * importantly it *is wrong* after a file move!
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+ fjson_object_object_get_ex(json, "prev_was_nl", &jval);
|
|
|
c17bfd |
+ act->pStrm->bPrevWasNL = fjson_object_get_int(jval);
|
|
|
c17bfd |
|
|
|
c17bfd |
- unlink((char*)pszSFNam);
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_STATEFILE_WRONG_FNAME);
|
|
|
c17bfd |
+ fjson_object_object_get_ex(json, "curr_offs", &jval);
|
|
|
c17bfd |
+ act->pStrm->iCurrOffs = fjson_object_get_int64(jval);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ fjson_object_object_get_ex(json, "strt_offs", &jval);
|
|
|
c17bfd |
+ act->pStrm->strtOffs = fjson_object_get_int64(jval);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ fjson_object_object_get_ex(json, "prev_line_segment", &jval);
|
|
|
c17bfd |
+ const uchar *const prev_line_segment = (const uchar*)fjson_object_get_string(jval);
|
|
|
c17bfd |
+ if(jval != NULL) {
|
|
|
c17bfd |
+ CHKiRet(rsCStrConstructFromszStr(&act->pStrm->prevLineSegment, prev_line_segment));
|
|
|
c17bfd |
+ cstrFinalize(act->pStrm->prevLineSegment);
|
|
|
c17bfd |
+ uchar *ret = rsCStrGetSzStrNoNULL(act->pStrm->prevLineSegment);
|
|
|
c17bfd |
+ DBGPRINTF("prev_line_segment present in state file 2, is: %s\n", ret);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
- strm.CheckFileChange(pLstn->pStrm);
|
|
|
c17bfd |
- CHKiRet(strm.SeekCurrOffs(pLstn->pStrm));
|
|
|
c17bfd |
+ fjson_object_object_get_ex(json, "prev_msg_segment", &jval);
|
|
|
c17bfd |
+ const uchar *const prev_msg_segment = (const uchar*)fjson_object_get_string(jval);
|
|
|
c17bfd |
+ if(jval != NULL) {
|
|
|
c17bfd |
+ CHKiRet(rsCStrConstructFromszStr(&act->pStrm->prevMsgSegment, prev_msg_segment));
|
|
|
c17bfd |
+ cstrFinalize(act->pStrm->prevMsgSegment);
|
|
|
c17bfd |
+ uchar *ret = rsCStrGetSzStrNoNULL(act->pStrm->prevMsgSegment);
|
|
|
c17bfd |
+ DBGPRINTF("prev_msg_segment present in state file 2, is: %s\n", ret);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ fjson_object_put(json);
|
|
|
c17bfd |
|
|
|
c17bfd |
- /* note: we do not delete the state file, so that the last position remains
|
|
|
c17bfd |
- * known even in the case that rsyslogd aborts for some reason (like powerfail)
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
+ CHKiRet(strm.SetFName(act->pStrm, (uchar*)act->name, strlen(act->name)));
|
|
|
c17bfd |
+ CHKiRet(strm.SettOperationsMode(act->pStrm, STREAMMODE_READ));
|
|
|
c17bfd |
+ CHKiRet(strm.SetsType(act->pStrm, STREAMTYPE_FILE_MONITOR));
|
|
|
c17bfd |
+ CHKiRet(strm.SetFileNotFoundError(act->pStrm, inst->fileNotFoundError));
|
|
|
c17bfd |
+ CHKiRet(strm.ConstructFinalize(act->pStrm));
|
|
|
c17bfd |
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- if(psSF != NULL)
|
|
|
c17bfd |
- strm.Destruct(&psSF);
|
|
|
c17bfd |
+ CHKiRet(strm.SeekCurrOffs(act->pStrm));
|
|
|
c17bfd |
|
|
|
c17bfd |
+finalize_it:
|
|
|
c17bfd |
+ if(fd >= 0) {
|
|
|
c17bfd |
+ close(fd);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
@@ -576,30 +1304,32 @@ finalize_it:
|
|
|
c17bfd |
* checked before calling it.
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
-openFileWithoutStateFile(lstn_t *const __restrict__ pLstn)
|
|
|
c17bfd |
+openFileWithoutStateFile(act_obj_t *const act)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
struct stat stat_buf;
|
|
|
c17bfd |
|
|
|
c17bfd |
- DBGPRINTF("imfile: clean startup withOUT state file for '%s'\n", pLstn->pszFileName);
|
|
|
c17bfd |
- if(pLstn->pStrm != NULL)
|
|
|
c17bfd |
- strm.Destruct(&pLstn->pStrm);
|
|
|
c17bfd |
- CHKiRet(strm.Construct(&pLstn->pStrm));
|
|
|
c17bfd |
- CHKiRet(strm.SettOperationsMode(pLstn->pStrm, STREAMMODE_READ));
|
|
|
c17bfd |
- CHKiRet(strm.SetsType(pLstn->pStrm, STREAMTYPE_FILE_MONITOR));
|
|
|
c17bfd |
- CHKiRet(strm.SetFName(pLstn->pStrm, pLstn->pszFileName, strlen((char*) pLstn->pszFileName)));
|
|
|
c17bfd |
- CHKiRet(strm.ConstructFinalize(pLstn->pStrm));
|
|
|
c17bfd |
+ const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances?
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ DBGPRINTF("clean startup withOUT state file for '%s'\n", act->name);
|
|
|
c17bfd |
+ if(act->pStrm != NULL)
|
|
|
c17bfd |
+ strm.Destruct(&act->pStrm);
|
|
|
c17bfd |
+ CHKiRet(strm.Construct(&act->pStrm));
|
|
|
c17bfd |
+ CHKiRet(strm.SettOperationsMode(act->pStrm, STREAMMODE_READ));
|
|
|
c17bfd |
+ CHKiRet(strm.SetsType(act->pStrm, STREAMTYPE_FILE_MONITOR));
|
|
|
c17bfd |
+ CHKiRet(strm.SetFName(act->pStrm, (uchar*)act->name, strlen(act->name)));
|
|
|
c17bfd |
+ CHKiRet(strm.SetFileNotFoundError(act->pStrm, inst->fileNotFoundError));
|
|
|
c17bfd |
+ CHKiRet(strm.ConstructFinalize(act->pStrm));
|
|
|
c17bfd |
|
|
|
c17bfd |
/* As a state file not exist, this is a fresh start. seek to file end
|
|
|
c17bfd |
* when freshStartTail is on.
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
- if(pLstn->freshStartTail){
|
|
|
c17bfd |
- if(stat((char*) pLstn->pszFileName, &stat_buf) != -1) {
|
|
|
c17bfd |
- pLstn->pStrm->iCurrOffs = stat_buf.st_size;
|
|
|
c17bfd |
- CHKiRet(strm.SeekCurrOffs(pLstn->pStrm));
|
|
|
c17bfd |
+ if(inst->freshStartTail){
|
|
|
c17bfd |
+ if(stat((char*) act->name, &stat_buf) != -1) {
|
|
|
c17bfd |
+ act->pStrm->iCurrOffs = stat_buf.st_size;
|
|
|
c17bfd |
+ CHKiRet(strm.SeekCurrOffs(act->pStrm));
|
|
|
c17bfd |
}
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- strmSetReadTimeout(pLstn->pStrm, pLstn->readTimeout);
|
|
|
c17bfd |
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
@@ -608,17 +1338,18 @@ finalize_it:
|
|
|
c17bfd |
* if so, reading it in. Processing continues from the last know location.
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
-openFile(lstn_t *const __restrict__ pLstn)
|
|
|
c17bfd |
+openFile(act_obj_t *const act)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
+ const instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances?
|
|
|
c17bfd |
|
|
|
c17bfd |
- CHKiRet_Hdlr(openFileWithStateFile(pLstn)) {
|
|
|
c17bfd |
- CHKiRet(openFileWithoutStateFile(pLstn));
|
|
|
c17bfd |
+ CHKiRet_Hdlr(openFileWithStateFile(act)) {
|
|
|
c17bfd |
+ CHKiRet(openFileWithoutStateFile(act));
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
- DBGPRINTF("imfile: breopenOnTruncate %d for '%s'\n",
|
|
|
c17bfd |
- pLstn->reopenOnTruncate, pLstn->pszFileName);
|
|
|
c17bfd |
- CHKiRet(strm.SetbReopenOnTruncate(pLstn->pStrm, pLstn->reopenOnTruncate));
|
|
|
c17bfd |
+ DBGPRINTF("breopenOnTruncate %d for '%s'\n", inst->reopenOnTruncate, act->name);
|
|
|
c17bfd |
+ CHKiRet(strm.SetbReopenOnTruncate(act->pStrm, inst->reopenOnTruncate));
|
|
|
c17bfd |
+ strmSetReadTimeout(act->pStrm, inst->readTimeout);
|
|
|
c17bfd |
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
@@ -638,58 +1369,72 @@ static void pollFileCancelCleanup(void *pArg)
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
|
|
|
c17bfd |
-/* poll a file, need to check file rollover etc. open file if not open */
|
|
|
c17bfd |
-#if !defined(_AIX)
|
|
|
c17bfd |
-#pragma GCC diagnostic ignored "-Wempty-body"
|
|
|
c17bfd |
-#endif
|
|
|
c17bfd |
+/* pollFile needs to be split due to the unfortunate pthread_cancel_push() macros. */
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
-pollFile(lstn_t *pLstn, int *pbHadFileData)
|
|
|
c17bfd |
+pollFileReal(act_obj_t *act, cstr_t **pCStr)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
- cstr_t *pCStr = NULL;
|
|
|
c17bfd |
+ int64 strtOffs;
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- /* Note: we must do pthread_cleanup_push() immediately, because the POXIS macros
|
|
|
c17bfd |
- * otherwise do not work if I include the _cleanup_pop() inside an if... -- rgerhards, 2008-08-14
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
- pthread_cleanup_push(pollFileCancelCleanup, &pCStr);
|
|
|
c17bfd |
int nProcessed = 0;
|
|
|
c17bfd |
- if(pLstn->pStrm == NULL) {
|
|
|
c17bfd |
- CHKiRet(openFile(pLstn)); /* open file */
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ DBGPRINTF("pollFileReal enter, pStrm %p, name '%s'\n", act->pStrm, act->name);
|
|
|
c17bfd |
+ DBGPRINTF("pollFileReal enter, edge %p\n", act->edge);
|
|
|
c17bfd |
+ DBGPRINTF("pollFileReal enter, edge->instarr %p\n", act->edge->instarr);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ instanceConf_t *const inst = act->edge->instarr[0];// TODO: same file, multiple instances?
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ if(act->pStrm == NULL) {
|
|
|
c17bfd |
+ CHKiRet(openFile(act)); /* open file */
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
/* loop below will be exited when strmReadLine() returns EOF */
|
|
|
c17bfd |
while(glbl.GetGlobalInputTermState() == 0) {
|
|
|
c17bfd |
- if(pLstn->maxLinesAtOnce != 0 && nProcessed >= pLstn->maxLinesAtOnce)
|
|
|
c17bfd |
+ if(inst->maxLinesAtOnce != 0 && nProcessed >= inst->maxLinesAtOnce)
|
|
|
c17bfd |
break;
|
|
|
c17bfd |
- if(pLstn->startRegex == NULL) {
|
|
|
c17bfd |
- CHKiRet(strm.ReadLine(pLstn->pStrm, &pCStr, pLstn->readMode, pLstn->escapeLF, pLstn->trimLineOverBytes));
|
|
|
c17bfd |
+ if(inst->startRegex == NULL) {
|
|
|
c17bfd |
+ CHKiRet(strm.ReadLine(act->pStrm, pCStr, inst->readMode, inst->escapeLF,
|
|
|
c17bfd |
+ inst->trimLineOverBytes, &strtOffs));
|
|
|
c17bfd |
} else {
|
|
|
c17bfd |
- CHKiRet(strmReadMultiLine(pLstn->pStrm, &pCStr, &pLstn->end_preg, pLstn->escapeLF));
|
|
|
c17bfd |
+ CHKiRet(strmReadMultiLine(act->pStrm, pCStr, &inst->end_preg,
|
|
|
c17bfd |
+ inst->escapeLF, &strtOffs));
|
|
|
c17bfd |
}
|
|
|
c17bfd |
++nProcessed;
|
|
|
c17bfd |
- if(pbHadFileData != NULL)
|
|
|
c17bfd |
- *pbHadFileData = 1; /* this is just a flag, so set it and forget it */
|
|
|
c17bfd |
- CHKiRet(enqLine(pLstn, pCStr)); /* process line */
|
|
|
c17bfd |
- rsCStrDestruct(&pCStr); /* discard string (must be done by us!) */
|
|
|
c17bfd |
- if(pLstn->iPersistStateInterval > 0 && pLstn->nRecords++ >= pLstn->iPersistStateInterval) {
|
|
|
c17bfd |
- persistStrmState(pLstn);
|
|
|
c17bfd |
- pLstn->nRecords = 0;
|
|
|
c17bfd |
+ runModConf->bHadFileData = 1; /* this is just a flag, so set it and forget it */
|
|
|
c17bfd |
+ CHKiRet(enqLine(act, *pCStr, strtOffs)); /* process line */
|
|
|
c17bfd |
+ rsCStrDestruct(pCStr); /* discard string (must be done by us!) */
|
|
|
c17bfd |
+ if(inst->iPersistStateInterval > 0 && ++act->nRecords >= inst->iPersistStateInterval) {
|
|
|
c17bfd |
+ persistStrmState(act);
|
|
|
c17bfd |
+ act->nRecords = 0;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
- multiSubmitFlush(&pLstn->multiSub);
|
|
|
c17bfd |
- pthread_cleanup_pop(0);
|
|
|
c17bfd |
+ multiSubmitFlush(&act->multiSub);
|
|
|
c17bfd |
|
|
|
c17bfd |
- if(pCStr != NULL) {
|
|
|
c17bfd |
- rsCStrDestruct(&pCStr);
|
|
|
c17bfd |
+ if(*pCStr != NULL) {
|
|
|
c17bfd |
+ rsCStrDestruct(pCStr);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-#if !defined(_AIX)
|
|
|
c17bfd |
-#pragma GCC diagnostic warning "-Wempty-body"
|
|
|
c17bfd |
-#endif
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+/* poll a file, need to check file rollover etc. open file if not open */
|
|
|
c17bfd |
+static rsRetVal
|
|
|
c17bfd |
+pollFile(act_obj_t *const act)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ cstr_t *pCStr = NULL;
|
|
|
c17bfd |
+ DEFiRet;
|
|
|
c17bfd |
+ if (act->is_symlink) {
|
|
|
c17bfd |
+ FINALIZE; /* no reason to poll symlink file */
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ /* Note: we must do pthread_cleanup_push() immediately, because the POSIX macros
|
|
|
c17bfd |
+ * otherwise do not work if I include the _cleanup_pop() inside an if... -- rgerhards, 2008-08-14
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+ pthread_cleanup_push(pollFileCancelCleanup, &pCStr);
|
|
|
c17bfd |
+ iRet = pollFileReal(act, &pCStr);
|
|
|
c17bfd |
+ pthread_cleanup_pop(0);
|
|
|
c17bfd |
+finalize_it: RETiRet;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
|
|
|
c17bfd |
|
|
|
c17bfd |
/* create input instance, set default parameters, and
|
|
|
c17bfd |
@@ -722,6 +1467,7 @@ createInstance(instanceConf_t **pinst)
|
|
|
c17bfd |
inst->addMetadata = ADD_METADATA_UNSPECIFIED;
|
|
|
c17bfd |
inst->addCeeTag = 0;
|
|
|
c17bfd |
inst->freshStartTail = 0;
|
|
|
c17bfd |
+ inst->fileNotFoundError = 1;
|
|
|
c17bfd |
inst->readTimeout = loadModConf->readTimeout;
|
|
|
c17bfd |
|
|
|
c17bfd |
/* node created, let's add to config */
|
|
|
c17bfd |
@@ -767,19 +1513,11 @@ getBasename(uchar *const __restrict__ basen, uchar *const __restrict__ path)
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
/* this function checks instance parameters and does some required pre-processing
|
|
|
c17bfd |
- * (e.g. split filename in path and actual name)
|
|
|
c17bfd |
- * Note: we do NOT use dirname()/basename() as they have portability problems.
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
-checkInstance(instanceConf_t *inst)
|
|
|
c17bfd |
+checkInstance(instanceConf_t *const inst)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
- char dirn[MAXFNAME];
|
|
|
c17bfd |
- uchar basen[MAXFNAME];
|
|
|
c17bfd |
- int i;
|
|
|
c17bfd |
- struct stat sb;
|
|
|
c17bfd |
- int r;
|
|
|
c17bfd |
- int eno;
|
|
|
c17bfd |
- char errStr[512];
|
|
|
c17bfd |
+ uchar curr_wd[MAXFNAME];
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
|
|
|
c17bfd |
/* this is primarily for the clang static analyzer, but also
|
|
|
c17bfd |
@@ -788,36 +1526,37 @@ checkInstance(instanceConf_t *inst)
|
|
|
c17bfd |
if(inst->pszFileName == NULL)
|
|
|
c17bfd |
ABORT_FINALIZE(RS_RET_INTERNAL_ERROR);
|
|
|
c17bfd |
|
|
|
c17bfd |
- i = getBasename(basen, inst->pszFileName);
|
|
|
c17bfd |
- if (i == -1) {
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_CONFIG_ERROR, "imfile: file path '%s' does not include a basename component",
|
|
|
c17bfd |
- inst->pszFileName);
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- memcpy(dirn, inst->pszFileName, i); /* do not copy slash */
|
|
|
c17bfd |
- dirn[i] = '\0';
|
|
|
c17bfd |
- CHKmalloc(inst->pszFileBaseName = (uchar*) strdup((char*)basen));
|
|
|
c17bfd |
- CHKmalloc(inst->pszDirName = (uchar*) strdup(dirn));
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- if(dirn[0] == '\0') {
|
|
|
c17bfd |
- dirn[0] = '/';
|
|
|
c17bfd |
- dirn[1] = '\0';
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- r = stat(dirn, &sb);
|
|
|
c17bfd |
- if(r != 0) {
|
|
|
c17bfd |
- eno = errno;
|
|
|
c17bfd |
- rs_strerror_r(eno, errStr, sizeof(errStr));
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_CONFIG_ERROR, "imfile warning: directory '%s': %s",
|
|
|
c17bfd |
- dirn, errStr);
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- if(!S_ISDIR(sb.st_mode)) {
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_CONFIG_ERROR, "imfile warning: configured directory "
|
|
|
c17bfd |
- "'%s' is NOT a directory", dirn);
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
|
|
|
c17bfd |
+ CHKmalloc(inst->pszFileName_forOldStateFile = ustrdup(inst->pszFileName));
|
|
|
c17bfd |
+ if(loadModConf->normalizePath) {
|
|
|
c17bfd |
+ if(inst->pszFileName[0] == '.' && inst->pszFileName[1] == '/') {
|
|
|
c17bfd |
+ DBGPRINTF("imfile: removing heading './' from name '%s'\n", inst->pszFileName);
|
|
|
c17bfd |
+ memmove(inst->pszFileName, inst->pszFileName+2, ustrlen(inst->pszFileName) - 1);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ if(inst->pszFileName[0] != '/') {
|
|
|
c17bfd |
+ if(getcwd((char*)curr_wd, MAXFNAME) == NULL || curr_wd[0] != '/') {
|
|
|
c17bfd |
+ LogError(errno, RS_RET_ERR, "imfile: error querying current working "
|
|
|
c17bfd |
+ "directory - can not continue with %s", inst->pszFileName);
|
|
|
c17bfd |
+ ABORT_FINALIZE(RS_RET_ERR);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ const size_t len_curr_wd = ustrlen(curr_wd);
|
|
|
c17bfd |
+ if(len_curr_wd + ustrlen(inst->pszFileName) + 1 >= MAXFNAME) {
|
|
|
c17bfd |
+ LogError(0, RS_RET_ERR, "imfile: length of configured file and current "
|
|
|
c17bfd |
+ "working directory exceeds permitted size - ignoring %s",
|
|
|
c17bfd |
+ inst->pszFileName);
|
|
|
c17bfd |
+ ABORT_FINALIZE(RS_RET_ERR);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ curr_wd[len_curr_wd] = '/';
|
|
|
c17bfd |
+ strcpy((char*)curr_wd+len_curr_wd+1, (char*)inst->pszFileName);
|
|
|
c17bfd |
+ free(inst->pszFileName);
|
|
|
c17bfd |
+ CHKmalloc(inst->pszFileName = ustrdup(curr_wd));
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
}
|
|
|
c17bfd |
+ dbgprintf("imfile: adding file monitor for '%s'\n", inst->pszFileName);
|
|
|
c17bfd |
|
|
|
c17bfd |
+ if(inst->pszTag != NULL) {
|
|
|
c17bfd |
+ inst->lenTag = ustrlen(inst->pszTag);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
@@ -869,140 +1608,14 @@ addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal)
|
|
|
c17bfd |
inst->bRMStateOnDel = 0;
|
|
|
c17bfd |
inst->readTimeout = loadModConf->readTimeout;
|
|
|
c17bfd |
|
|
|
c17bfd |
- CHKiRet(checkInstance(inst));
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- /* reset legacy system */
|
|
|
c17bfd |
- cs.iPersistStateInterval = 0;
|
|
|
c17bfd |
- resetConfigVariables(NULL, NULL); /* values are both dummies */
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- free(pNewVal); /* we do not need it, but we must free it! */
|
|
|
c17bfd |
- RETiRet;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* This adds a new listener object to the bottom of the list, but
|
|
|
c17bfd |
- * it does NOT initialize any data members except for the list
|
|
|
c17bfd |
- * pointers themselves.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static rsRetVal
|
|
|
c17bfd |
-lstnAdd(lstn_t **newLstn)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- lstn_t *pLstn;
|
|
|
c17bfd |
- DEFiRet;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- CHKmalloc(pLstn = (lstn_t*) MALLOC(sizeof(lstn_t)));
|
|
|
c17bfd |
- if(runModConf->pRootLstn == NULL) {
|
|
|
c17bfd |
- runModConf->pRootLstn = pLstn;
|
|
|
c17bfd |
- pLstn->prev = NULL;
|
|
|
c17bfd |
- } else {
|
|
|
c17bfd |
- runModConf->pTailLstn->next = pLstn;
|
|
|
c17bfd |
- pLstn->prev = runModConf->pTailLstn;
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- runModConf->pTailLstn = pLstn;
|
|
|
c17bfd |
- pLstn->next = NULL;
|
|
|
c17bfd |
- *newLstn = pLstn;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- RETiRet;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* delete a listener object */
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-lstnDel(lstn_t *pLstn)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- DBGPRINTF("imfile: lstnDel called for %s\n", pLstn->pszFileName);
|
|
|
c17bfd |
- if(pLstn->pStrm != NULL) { /* stream open? */
|
|
|
c17bfd |
- persistStrmState(pLstn);
|
|
|
c17bfd |
- strm.Destruct(&(pLstn->pStrm));
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- ratelimitDestruct(pLstn->ratelimiter);
|
|
|
c17bfd |
- free(pLstn->multiSub.ppMsgs);
|
|
|
c17bfd |
- free(pLstn->pszFileName);
|
|
|
c17bfd |
- free(pLstn->pszTag);
|
|
|
c17bfd |
- free(pLstn->pszStateFile);
|
|
|
c17bfd |
- free(pLstn->pszBaseName);
|
|
|
c17bfd |
- if(pLstn->startRegex != NULL)
|
|
|
c17bfd |
- regfree(&pLstn->end_preg);
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- if(pLstn == runModConf->pRootLstn)
|
|
|
c17bfd |
- runModConf->pRootLstn = pLstn->next;
|
|
|
c17bfd |
- if(pLstn == runModConf->pTailLstn)
|
|
|
c17bfd |
- runModConf->pTailLstn = pLstn->prev;
|
|
|
c17bfd |
- if(pLstn->next != NULL)
|
|
|
c17bfd |
- pLstn->next->prev = pLstn->prev;
|
|
|
c17bfd |
- if(pLstn->prev != NULL)
|
|
|
c17bfd |
- pLstn->prev->next = pLstn->next;
|
|
|
c17bfd |
- free(pLstn);
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* This function is called when a new listener shall be added.
|
|
|
c17bfd |
- * It also does some late stage error checking on the config
|
|
|
c17bfd |
- * and reports issues it finds.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static rsRetVal
|
|
|
c17bfd |
-addListner(instanceConf_t *inst)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- DEFiRet;
|
|
|
c17bfd |
- lstn_t *pThis;
|
|
|
c17bfd |
- sbool hasWildcard;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- hasWildcard = containsGlobWildcard((char*)inst->pszFileBaseName);
|
|
|
c17bfd |
- if(hasWildcard) {
|
|
|
c17bfd |
- if(runModConf->opMode == OPMODE_POLLING) {
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_IMFILE_WILDCARD,
|
|
|
c17bfd |
- "imfile: The to-be-monitored file \"%s\" contains "
|
|
|
c17bfd |
- "wildcards. This is not supported in "
|
|
|
c17bfd |
- "polling mode.", inst->pszFileName);
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_IMFILE_WILDCARD);
|
|
|
c17bfd |
- } else if(inst->pszStateFile != NULL) {
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_IMFILE_WILDCARD,
|
|
|
c17bfd |
- "imfile: warning: it looks like to-be-monitored "
|
|
|
c17bfd |
- "file \"%s\" contains wildcards. This usually "
|
|
|
c17bfd |
- "does not work well with specifying a state file.",
|
|
|
c17bfd |
- inst->pszFileName);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
+ CHKiRet(checkInstance(inst));
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* reset legacy system */
|
|
|
c17bfd |
+ cs.iPersistStateInterval = 0;
|
|
|
c17bfd |
+ resetConfigVariables(NULL, NULL); /* values are both dummies */
|
|
|
c17bfd |
|
|
|
c17bfd |
- CHKiRet(lstnAdd(&pThis));
|
|
|
c17bfd |
- pThis->hasWildcard = hasWildcard;
|
|
|
c17bfd |
- pThis->pszFileName = (uchar*) strdup((char*) inst->pszFileName);
|
|
|
c17bfd |
- pThis->pszDirName = inst->pszDirName; /* use memory from inst! */
|
|
|
c17bfd |
- pThis->pszBaseName = (uchar*)strdup((char*)inst->pszFileBaseName); /* be consistent with expanded wildcards! */
|
|
|
c17bfd |
- pThis->pszTag = (uchar*) strdup((char*) inst->pszTag);
|
|
|
c17bfd |
- pThis->lenTag = ustrlen(pThis->pszTag);
|
|
|
c17bfd |
- pThis->pszStateFile = inst->pszStateFile == NULL ? NULL : (uchar*) strdup((char*) inst->pszStateFile);
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- CHKiRet(ratelimitNew(&pThis->ratelimiter, "imfile", (char*)inst->pszFileName));
|
|
|
c17bfd |
- CHKmalloc(pThis->multiSub.ppMsgs = MALLOC(inst->nMultiSub * sizeof(smsg_t *)));
|
|
|
c17bfd |
- pThis->multiSub.maxElem = inst->nMultiSub;
|
|
|
c17bfd |
- pThis->multiSub.nElem = 0;
|
|
|
c17bfd |
- pThis->iSeverity = inst->iSeverity;
|
|
|
c17bfd |
- pThis->iFacility = inst->iFacility;
|
|
|
c17bfd |
- pThis->maxLinesAtOnce = inst->maxLinesAtOnce;
|
|
|
c17bfd |
- pThis->trimLineOverBytes = inst->trimLineOverBytes;
|
|
|
c17bfd |
- pThis->iPersistStateInterval = inst->iPersistStateInterval;
|
|
|
c17bfd |
- pThis->readMode = inst->readMode;
|
|
|
c17bfd |
- pThis->startRegex = inst->startRegex; /* no strdup, as it is read-only */
|
|
|
c17bfd |
- if(pThis->startRegex != NULL)
|
|
|
c17bfd |
- if(regcomp(&pThis->end_preg, (char*)pThis->startRegex, REG_EXTENDED)) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: error regex compile\n");
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_ERR);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- pThis->bRMStateOnDel = inst->bRMStateOnDel;
|
|
|
c17bfd |
- pThis->escapeLF = inst->escapeLF;
|
|
|
c17bfd |
- pThis->reopenOnTruncate = inst->reopenOnTruncate;
|
|
|
c17bfd |
- pThis->addMetadata = (inst->addMetadata == ADD_METADATA_UNSPECIFIED) ?
|
|
|
c17bfd |
- hasWildcard : inst->addMetadata;
|
|
|
c17bfd |
- pThis->addCeeTag = inst->addCeeTag;
|
|
|
c17bfd |
- pThis->readTimeout = inst->readTimeout;
|
|
|
c17bfd |
- pThis->freshStartTail = inst->freshStartTail;
|
|
|
c17bfd |
- pThis->pRuleset = inst->pBindRuleset;
|
|
|
c17bfd |
- pThis->nRecords = 0;
|
|
|
c17bfd |
- pThis->pStrm = NULL;
|
|
|
c17bfd |
- pThis->prevLineSegment = NULL;
|
|
|
c17bfd |
- pThis->masterLstn = NULL; /* we *are* a master! */
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
+ free(pNewVal); /* we do not need it, but we must free it! */
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
@@ -1055,6 +1668,8 @@ CODESTARTnewInpInst
|
|
|
c17bfd |
inst->addCeeTag = (sbool) pvals[i].val.d.n;
|
|
|
c17bfd |
} else if(!strcmp(inppblk.descr[i].name, "freshstarttail")) {
|
|
|
c17bfd |
inst->freshStartTail = (sbool) pvals[i].val.d.n;
|
|
|
c17bfd |
+ } else if(!strcmp(inppblk.descr[i].name, "filenotfounderror")) {
|
|
|
c17bfd |
+ inst->fileNotFoundError = (sbool) pvals[i].val.d.n;
|
|
|
c17bfd |
} else if(!strcmp(inppblk.descr[i].name, "escapelf")) {
|
|
|
c17bfd |
inst->escapeLF = (sbool) pvals[i].val.d.n;
|
|
|
c17bfd |
} else if(!strcmp(inppblk.descr[i].name, "reopenontruncate")) {
|
|
|
c17bfd |
@@ -1087,6 +1702,16 @@ CODESTARTnewInpInst
|
|
|
c17bfd |
"at the same time --- remove one of them");
|
|
|
c17bfd |
ABORT_FINALIZE(RS_RET_PARAM_NOT_PERMITTED);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ if(inst->startRegex != NULL) {
|
|
|
c17bfd |
+ const int errcode = regcomp(&inst->end_preg, (char*)inst->startRegex, REG_EXTENDED);
|
|
|
c17bfd |
+ if(errcode != 0) {
|
|
|
c17bfd |
+ char errbuff[512];
|
|
|
c17bfd |
+ regerror(errcode, &inst->end_preg, errbuff, sizeof(errbuff));
|
|
|
c17bfd |
+ parser_errmsg("imfile: error in regex expansion: %s", errbuff);
|
|
|
c17bfd |
+ ABORT_FINALIZE(RS_RET_ERR);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
if(inst->readTimeout != 0)
|
|
|
c17bfd |
loadModConf->haveReadTimeouts = 1;
|
|
|
c17bfd |
CHKiRet(checkInstance(inst));
|
|
|
c17bfd |
@@ -1106,6 +1731,10 @@ CODESTARTbeginCnfLoad
|
|
|
c17bfd |
loadModConf->readTimeout = 0; /* default: no timeout */
|
|
|
c17bfd |
loadModConf->timeoutGranularity = 1000; /* default: 1 second */
|
|
|
c17bfd |
loadModConf->haveReadTimeouts = 0; /* default: no timeout */
|
|
|
c17bfd |
+ loadModConf->normalizePath = 1;
|
|
|
c17bfd |
+ loadModConf->sortFiles = GLOB_NOSORT;
|
|
|
c17bfd |
+ loadModConf->conf_tree = calloc(sizeof(fs_node_t), 1);
|
|
|
c17bfd |
+ loadModConf->conf_tree->edges = NULL;
|
|
|
c17bfd |
bLegacyCnfModGlobalsPermitted = 1;
|
|
|
c17bfd |
/* init legacy config vars */
|
|
|
c17bfd |
cs.pszFileName = NULL;
|
|
|
c17bfd |
@@ -1148,6 +1777,10 @@ CODESTARTsetModCnf
|
|
|
c17bfd |
} else if(!strcmp(modpblk.descr[i].name, "timeoutgranularity")) {
|
|
|
c17bfd |
/* note: we need ms, thus "* 1000" */
|
|
|
c17bfd |
loadModConf->timeoutGranularity = (int) pvals[i].val.d.n * 1000;
|
|
|
c17bfd |
+ } else if(!strcmp(modpblk.descr[i].name, "sortfiles")) {
|
|
|
c17bfd |
+ loadModConf->sortFiles = ((sbool) pvals[i].val.d.n) ? 0 : GLOB_NOSORT;
|
|
|
c17bfd |
+ } else if(!strcmp(modpblk.descr[i].name, "normalizepath")) {
|
|
|
c17bfd |
+ loadModConf->normalizePath = (sbool) pvals[i].val.d.n;
|
|
|
c17bfd |
} else if(!strcmp(modpblk.descr[i].name, "mode")) {
|
|
|
c17bfd |
if(!es_strconstcmp(pvals[i].val.d.estr, "polling"))
|
|
|
c17bfd |
loadModConf->opMode = OPMODE_POLLING;
|
|
|
c17bfd |
@@ -1217,19 +1850,31 @@ BEGINactivateCnf
|
|
|
c17bfd |
instanceConf_t *inst;
|
|
|
c17bfd |
CODESTARTactivateCnf
|
|
|
c17bfd |
runModConf = pModConf;
|
|
|
c17bfd |
- runModConf->pRootLstn = NULL,
|
|
|
c17bfd |
- runModConf->pTailLstn = NULL;
|
|
|
c17bfd |
+ if(runModConf->root == NULL) {
|
|
|
c17bfd |
+ LogError(0, NO_ERRCODE, "imfile: no file monitors configured, "
|
|
|
c17bfd |
+ "input not activated.\n");
|
|
|
c17bfd |
+ ABORT_FINALIZE(RS_RET_NO_RUN);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
|
|
|
c17bfd |
for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
|
|
|
c17bfd |
- addListner(inst);
|
|
|
c17bfd |
+ // TODO: provide switch to turn off this warning?
|
|
|
c17bfd |
+ if(!containsGlobWildcard((char*)inst->pszFileName)) {
|
|
|
c17bfd |
+ if(access((char*)inst->pszFileName, R_OK) != 0) {
|
|
|
c17bfd |
+ LogError(errno, RS_RET_ERR,
|
|
|
c17bfd |
+ "imfile: on startup file '%s' does not exist "
|
|
|
c17bfd |
+ "but is configured in static file monitor - this "
|
|
|
c17bfd |
+ "may indicate a misconfiguration. If the file "
|
|
|
c17bfd |
+ "appears at a later time, it will automatically "
|
|
|
c17bfd |
+ "be processed. Reason", inst->pszFileName);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ fs_node_add(runModConf->conf_tree, NULL, inst->pszFileName, 0, inst);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
- /* if we could not set up any listeners, there is no point in running... */
|
|
|
c17bfd |
- if(runModConf->pRootLstn == 0) {
|
|
|
c17bfd |
- errmsg.LogError(0, NO_ERRCODE, "imfile: no file monitors could be started, "
|
|
|
c17bfd |
- "input not activated.\n");
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_NO_RUN);
|
|
|
c17bfd |
+ if(Debug) {
|
|
|
c17bfd |
+ fs_node_print(runModConf->conf_tree, 0);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
ENDactivateCnf
|
|
|
c17bfd |
|
|
|
c17bfd |
@@ -1237,14 +1882,20 @@ ENDactivateCnf
|
|
|
c17bfd |
BEGINfreeCnf
|
|
|
c17bfd |
instanceConf_t *inst, *del;
|
|
|
c17bfd |
CODESTARTfreeCnf
|
|
|
c17bfd |
+ fs_node_destroy(pModConf->conf_tree);
|
|
|
c17bfd |
+ //move_list_destruct(pModConf);
|
|
|
c17bfd |
for(inst = pModConf->root ; inst != NULL ; ) {
|
|
|
c17bfd |
+ if(inst->startRegex != NULL)
|
|
|
c17bfd |
+ regfree(&inst->end_preg);
|
|
|
c17bfd |
free(inst->pszBindRuleset);
|
|
|
c17bfd |
free(inst->pszFileName);
|
|
|
c17bfd |
- free(inst->pszDirName);
|
|
|
c17bfd |
- free(inst->pszFileBaseName);
|
|
|
c17bfd |
free(inst->pszTag);
|
|
|
c17bfd |
free(inst->pszStateFile);
|
|
|
c17bfd |
- free(inst->startRegex);
|
|
|
c17bfd |
+ free(inst->pszFileName_forOldStateFile);
|
|
|
c17bfd |
+ if(inst->startRegex != NULL) {
|
|
|
c17bfd |
+ regfree(&inst->end_preg);
|
|
|
c17bfd |
+ free(inst->startRegex);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
del = inst;
|
|
|
c17bfd |
inst = inst->next;
|
|
|
c17bfd |
free(del);
|
|
|
c17bfd |
@@ -1252,45 +1903,25 @@ CODESTARTfreeCnf
|
|
|
c17bfd |
ENDfreeCnf
|
|
|
c17bfd |
|
|
|
c17bfd |
|
|
|
c17bfd |
-/* Monitor files in traditional polling mode.
|
|
|
c17bfd |
- *
|
|
|
c17bfd |
- * We go through all files and remember if at least one had data. If so, we do
|
|
|
c17bfd |
- * another run (until no data was present in any file). Then we sleep for
|
|
|
c17bfd |
- * PollInterval seconds and restart the whole process. This ensures that as
|
|
|
c17bfd |
- * long as there is some data present, it will be processed at the fastest
|
|
|
c17bfd |
- * possible pace - probably important for busy systmes. If we monitor just a
|
|
|
c17bfd |
- * single file, the algorithm is slightly modified. In that case, the sleep
|
|
|
c17bfd |
- * hapens immediately. The idea here is that if we have just one file, we
|
|
|
c17bfd |
- * returned from the file processer because that file had no additional data.
|
|
|
c17bfd |
- * So even if we found some lines, it is highly unlikely to find a new one
|
|
|
c17bfd |
- * just now. Trying it would result in a performance-costly additional try
|
|
|
c17bfd |
- * which in the very, very vast majority of cases will never find any new
|
|
|
c17bfd |
- * lines.
|
|
|
c17bfd |
- * On spamming the main queue: keep in mind that it will automatically rate-limit
|
|
|
c17bfd |
- * ourselfes if we begin to overrun it. So we really do not need to care here.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
+/* Monitor files in polling mode. */
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
doPolling(void)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
- int bHadFileData; /* were there at least one file with data during this run? */
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
while(glbl.GetGlobalInputTermState() == 0) {
|
|
|
c17bfd |
+ DBGPRINTF("doPolling: new poll run\n");
|
|
|
c17bfd |
do {
|
|
|
c17bfd |
- lstn_t *pLstn;
|
|
|
c17bfd |
- bHadFileData = 0;
|
|
|
c17bfd |
- for(pLstn = runModConf->pRootLstn ; pLstn != NULL ; pLstn = pLstn->next) {
|
|
|
c17bfd |
- if(glbl.GetGlobalInputTermState() == 1)
|
|
|
c17bfd |
- break; /* terminate input! */
|
|
|
c17bfd |
- pollFile(pLstn, &bHadFileData);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- } while(bHadFileData == 1 && glbl.GetGlobalInputTermState() == 0);
|
|
|
c17bfd |
- /* warning: do...while()! */
|
|
|
c17bfd |
+ runModConf->bHadFileData = 0;
|
|
|
c17bfd |
+ fs_node_walk(runModConf->conf_tree, poll_tree);
|
|
|
c17bfd |
+ DBGPRINTF("doPolling: end poll walk, hadData %d\n", runModConf->bHadFileData);
|
|
|
c17bfd |
+ } while(runModConf->bHadFileData); /* warning: do...while()! */
|
|
|
c17bfd |
|
|
|
c17bfd |
/* Note: the additional 10ns wait is vitally important. It guards rsyslog
|
|
|
c17bfd |
* against totally hogging the CPU if the users selects a polling interval
|
|
|
c17bfd |
* of 0 seconds. It doesn't hurt any other valid scenario. So do not remove.
|
|
|
c17bfd |
* rgerhards, 2008-02-14
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
+ DBGPRINTF("doPolling: poll going to sleep\n");
|
|
|
c17bfd |
if(glbl.GetGlobalInputTermState() == 0)
|
|
|
c17bfd |
srSleep(runModConf->iPollInterval, 10);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
@@ -1298,631 +1929,122 @@ doPolling(void)
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
+#if defined(HAVE_INOTIFY_INIT)
|
|
|
c17bfd |
|
|
|
c17bfd |
-#ifdef HAVE_INOTIFY_INIT
|
|
|
c17bfd |
-static rsRetVal
|
|
|
c17bfd |
-fileTableInit(fileTable_t *const __restrict__ tab, const int nelem)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- DEFiRet;
|
|
|
c17bfd |
- CHKmalloc(tab->listeners = malloc(sizeof(dirInfoFiles_t) * nelem));
|
|
|
c17bfd |
- tab->allocMax = nelem;
|
|
|
c17bfd |
- tab->currMax = 0;
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- RETiRet;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-/* uncomment if needed
|
|
|
c17bfd |
static void
|
|
|
c17bfd |
-fileTableDisplay(fileTable_t *tab)
|
|
|
c17bfd |
+in_dbg_showEv(const struct inotify_event *ev)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
- int f;
|
|
|
c17bfd |
- uchar *baseName;
|
|
|
c17bfd |
- DBGPRINTF("imfile: dirs.currMaxfiles %d\n", tab->currMax);
|
|
|
c17bfd |
- for(f = 0 ; f < tab->currMax ; ++f) {
|
|
|
c17bfd |
- baseName = tab->listeners[f].pLstn->pszBaseName;
|
|
|
c17bfd |
- DBGPRINTF("imfile: TABLE %p CONTENTS, %d->%p:'%s'\n", tab, f, tab->listeners[f].pLstn, (char*)baseName);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-*/
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-static int
|
|
|
c17bfd |
-fileTableSearch(fileTable_t *const __restrict__ tab, uchar *const __restrict__ fn)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int f;
|
|
|
c17bfd |
- uchar *baseName = NULL;
|
|
|
c17bfd |
- /* UNCOMMENT FOR DEBUG fileTableDisplay(tab); */
|
|
|
c17bfd |
- for(f = 0 ; f < tab->currMax ; ++f) {
|
|
|
c17bfd |
- baseName = tab->listeners[f].pLstn->pszBaseName;
|
|
|
c17bfd |
- if(!fnmatch((char*)baseName, (char*)fn, FNM_PATHNAME | FNM_PERIOD))
|
|
|
c17bfd |
- break; /* found */
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- if(f == tab->currMax)
|
|
|
c17bfd |
- f = -1;
|
|
|
c17bfd |
- DBGPRINTF("imfile: fileTableSearch file '%s' - '%s', found:%d\n", fn, baseName, f);
|
|
|
c17bfd |
- return f;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-static int
|
|
|
c17bfd |
-fileTableSearchNoWildcard(fileTable_t *const __restrict__ tab, uchar *const __restrict__ fn)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int f;
|
|
|
c17bfd |
- uchar *baseName = NULL;
|
|
|
c17bfd |
- /* UNCOMMENT FOR DEBUG fileTableDisplay(tab); */
|
|
|
c17bfd |
- for(f = 0 ; f < tab->currMax ; ++f) {
|
|
|
c17bfd |
- baseName = tab->listeners[f].pLstn->pszBaseName;
|
|
|
c17bfd |
- if (strcmp((const char*)baseName, (const char*)fn) == 0)
|
|
|
c17bfd |
- break; /* found */
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- if(f == tab->currMax)
|
|
|
c17bfd |
- f = -1;
|
|
|
c17bfd |
- DBGPRINTF("imfile: fileTableSearchNoWildcard file '%s' - '%s', found:%d\n", fn, baseName, f);
|
|
|
c17bfd |
- return f;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* add file to file table */
|
|
|
c17bfd |
-static rsRetVal
|
|
|
c17bfd |
-fileTableAddFile(fileTable_t *const __restrict__ tab, lstn_t *const __restrict__ pLstn)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int j;
|
|
|
c17bfd |
- DEFiRet;
|
|
|
c17bfd |
- /* UNCOMMENT FOR DEBUG fileTableDisplay(tab); */
|
|
|
c17bfd |
- for(j = 0 ; j < tab->currMax && tab->listeners[j].pLstn != pLstn ; ++j)
|
|
|
c17bfd |
- ; /* just scan */
|
|
|
c17bfd |
- if(j < tab->currMax) {
|
|
|
c17bfd |
- ++tab->listeners[j].refcnt;
|
|
|
c17bfd |
- DBGPRINTF("imfile: file '%s' already registered, refcnt now %d\n",
|
|
|
c17bfd |
- pLstn->pszFileName, tab->listeners[j].refcnt);
|
|
|
c17bfd |
- FINALIZE;
|
|
|
c17bfd |
+ if(ev->mask & IN_IGNORED) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch was REMOVED\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- if(tab->currMax == tab->allocMax) {
|
|
|
c17bfd |
- const int newMax = 2 * tab->allocMax;
|
|
|
c17bfd |
- dirInfoFiles_t *newListenerTab = realloc(tab->listeners, newMax * sizeof(dirInfoFiles_t));
|
|
|
c17bfd |
- if(newListenerTab == NULL) {
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_OUT_OF_MEMORY,
|
|
|
c17bfd |
- "cannot alloc memory to map directory/file relationship "
|
|
|
c17bfd |
- "for '%s' - ignoring", pLstn->pszFileName);
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- tab->listeners = newListenerTab;
|
|
|
c17bfd |
- tab->allocMax = newMax;
|
|
|
c17bfd |
- DBGPRINTF("imfile: increased dir table to %d entries\n", allocMaxDirs);
|
|
|
c17bfd |
+ if(ev->mask & IN_MODIFY) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch was MODIFID\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- tab->listeners[tab->currMax].pLstn = pLstn;
|
|
|
c17bfd |
- tab->listeners[tab->currMax].refcnt = 1;
|
|
|
c17bfd |
- tab->currMax++;
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- RETiRet;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* delete a file from file table */
|
|
|
c17bfd |
-static rsRetVal
|
|
|
c17bfd |
-fileTableDelFile(fileTable_t *const __restrict__ tab, lstn_t *const __restrict__ pLstn)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int j;
|
|
|
c17bfd |
- DEFiRet;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- for(j = 0 ; j < tab->currMax && tab->listeners[j].pLstn != pLstn ; ++j)
|
|
|
c17bfd |
- ; /* just scan */
|
|
|
c17bfd |
- if(j == tab->currMax) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: no association for file '%s'\n", pLstn->pszFileName);
|
|
|
c17bfd |
- FINALIZE;
|
|
|
c17bfd |
+ if(ev->mask & IN_ACCESS) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_ACCESS\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- tab->listeners[j].refcnt--;
|
|
|
c17bfd |
- if(tab->listeners[j].refcnt == 0) {
|
|
|
c17bfd |
- /* we remove that entry (but we never shrink the table) */
|
|
|
c17bfd |
- if(j < tab->currMax - 1) {
|
|
|
c17bfd |
- /* entry in middle - need to move others */
|
|
|
c17bfd |
- memmove(tab->listeners+j, tab->listeners+j+1,
|
|
|
c17bfd |
- (tab->currMax -j-1) * sizeof(dirInfoFiles_t));
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- --tab->currMax;
|
|
|
c17bfd |
+ if(ev->mask & IN_ATTRIB) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_ATTRIB\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- RETiRet;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-/* add entry to dirs array */
|
|
|
c17bfd |
-static rsRetVal
|
|
|
c17bfd |
-dirsAdd(uchar *dirName)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int newMax;
|
|
|
c17bfd |
- dirInfo_t *newDirTab;
|
|
|
c17bfd |
- DEFiRet;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- if(currMaxDirs == allocMaxDirs) {
|
|
|
c17bfd |
- newMax = 2 * allocMaxDirs;
|
|
|
c17bfd |
- newDirTab = realloc(dirs, newMax * sizeof(dirInfo_t));
|
|
|
c17bfd |
- if(newDirTab == NULL) {
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_OUT_OF_MEMORY,
|
|
|
c17bfd |
- "cannot alloc memory to monitor directory '%s' - ignoring",
|
|
|
c17bfd |
- dirName);
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- dirs = newDirTab;
|
|
|
c17bfd |
- allocMaxDirs = newMax;
|
|
|
c17bfd |
- DBGPRINTF("imfile: increased dir table to %d entries\n", allocMaxDirs);
|
|
|
c17bfd |
+ if(ev->mask & IN_CLOSE_WRITE) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_CLOSE_WRITE\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- /* if we reach this point, there is space in the file table for the new entry */
|
|
|
c17bfd |
- dirs[currMaxDirs].dirName = dirName;
|
|
|
c17bfd |
- CHKiRet(fileTableInit(&dirs[currMaxDirs].active, INIT_FILE_IN_DIR_TAB_SIZE));
|
|
|
c17bfd |
- CHKiRet(fileTableInit(&dirs[currMaxDirs].configured, INIT_FILE_IN_DIR_TAB_SIZE));
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- ++currMaxDirs;
|
|
|
c17bfd |
- DBGPRINTF("imfile: added to dirs table: '%s'\n", dirName);
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- RETiRet;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* checks if a dir name is already inside the dirs array. If so, returns
|
|
|
c17bfd |
- * its index. If not present, -1 is returned.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static int
|
|
|
c17bfd |
-dirsFindDir(uchar *dir)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int i;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- for(i = 0 ; i < currMaxDirs && ustrcmp(dir, dirs[i].dirName) ; ++i)
|
|
|
c17bfd |
- ; /* just scan, all done in for() */
|
|
|
c17bfd |
- if(i == currMaxDirs)
|
|
|
c17bfd |
- i = -1;
|
|
|
c17bfd |
- return i;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-static rsRetVal
|
|
|
c17bfd |
-dirsInit(void)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- instanceConf_t *inst;
|
|
|
c17bfd |
- DEFiRet;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- free(dirs);
|
|
|
c17bfd |
- CHKmalloc(dirs = malloc(sizeof(dirInfo_t) * INIT_FILE_TAB_SIZE));
|
|
|
c17bfd |
- allocMaxDirs = INIT_FILE_TAB_SIZE;
|
|
|
c17bfd |
- currMaxDirs = 0;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
|
|
|
c17bfd |
- if(dirsFindDir(inst->pszDirName) == -1)
|
|
|
c17bfd |
- dirsAdd(inst->pszDirName);
|
|
|
c17bfd |
+ if(ev->mask & IN_CLOSE_NOWRITE) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_CLOSE_NOWRITE\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- RETiRet;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* add file to directory (create association)
|
|
|
c17bfd |
- * fIdx is index into file table, all other information is pulled from that table.
|
|
|
c17bfd |
- * bActive is 1 if the file is to be added to active set, else zero
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static rsRetVal
|
|
|
c17bfd |
-dirsAddFile(lstn_t *__restrict__ pLstn, const int bActive)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int dirIdx;
|
|
|
c17bfd |
- dirInfo_t *dir;
|
|
|
c17bfd |
- DEFiRet;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- dirIdx = dirsFindDir(pLstn->pszDirName);
|
|
|
c17bfd |
- if(dirIdx == -1) {
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_INTERNAL_ERROR, "imfile: could not find "
|
|
|
c17bfd |
- "directory '%s' in dirs array - ignoring",
|
|
|
c17bfd |
- pLstn->pszDirName);
|
|
|
c17bfd |
- FINALIZE;
|
|
|
c17bfd |
+ if(ev->mask & IN_CREATE) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: file was CREATED: %s\n", ev->name);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- dir = dirs + dirIdx;
|
|
|
c17bfd |
- CHKiRet(fileTableAddFile((bActive ? &dir->active : &dir->configured), pLstn));
|
|
|
c17bfd |
- DBGPRINTF("imfile: associated file [%s] to directory %d[%s], Active = %d\n",
|
|
|
c17bfd |
- pLstn->pszFileName, dirIdx, dir->dirName, bActive);
|
|
|
c17bfd |
- /* UNCOMMENT FOR DEBUG fileTableDisplay(bActive ? &dir->active : &dir->configured); */
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- RETiRet;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-in_setupDirWatch(const int dirIdx)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int wd;
|
|
|
c17bfd |
- wd = inotify_add_watch(ino_fd, (char*)dirs[dirIdx].dirName, IN_CREATE|IN_DELETE|IN_MOVED_FROM);
|
|
|
c17bfd |
- if(wd < 0) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: could not create dir watch for '%s'\n",
|
|
|
c17bfd |
- dirs[dirIdx].dirName);
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
+ if(ev->mask & IN_DELETE) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_DELETE\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- wdmapAdd(wd, dirIdx, NULL);
|
|
|
c17bfd |
- DBGPRINTF("imfile: watch %d added for dir %s\n", wd, dirs[dirIdx].dirName);
|
|
|
c17bfd |
-done: return;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* Setup a new file watch for a known active file. It must already have
|
|
|
c17bfd |
- * been entered into the correct tables.
|
|
|
c17bfd |
- * Note: we need to try to read this file, as it may already contain data this
|
|
|
c17bfd |
- * needs to be processed, and we won't get an event for that as notifications
|
|
|
c17bfd |
- * happen only for things after the watch has been activated.
|
|
|
c17bfd |
- * Note: newFileName is NULL for configured files, and non-NULL for dynamically
|
|
|
c17bfd |
- * detected files (e.g. wildcards!)
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-startLstnFile(lstn_t *const __restrict__ pLstn)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- rsRetVal localRet;
|
|
|
c17bfd |
- const int wd = inotify_add_watch(ino_fd, (char*)pLstn->pszFileName, IN_MODIFY);
|
|
|
c17bfd |
- if(wd < 0) {
|
|
|
c17bfd |
- char errStr[512];
|
|
|
c17bfd |
- rs_strerror_r(errno, errStr, sizeof(errStr));
|
|
|
c17bfd |
- DBGPRINTF("imfile: could not create file table entry for '%s' - "
|
|
|
c17bfd |
- "not processing it now: %s\n",
|
|
|
c17bfd |
- pLstn->pszFileName, errStr);
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
+ if(ev->mask & IN_DELETE_SELF) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_DELETE_SELF\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- if((localRet = wdmapAdd(wd, -1, pLstn)) != RS_RET_OK) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: error %d adding file to wdmap, ignoring\n", localRet);
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
+ if(ev->mask & IN_MOVE_SELF) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_MOVE_SELF\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- DBGPRINTF("imfile: watch %d added for file %s\n", wd, pLstn->pszFileName);
|
|
|
c17bfd |
- dirsAddFile(pLstn, ACTIVE_FILE);
|
|
|
c17bfd |
- pollFile(pLstn, NULL);
|
|
|
c17bfd |
-done: return;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* Duplicate an existing listener. This is called when a new file is to
|
|
|
c17bfd |
- * be monitored due to wildcard detection. Returns the new pLstn in
|
|
|
c17bfd |
- * the ppExisting parameter.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static rsRetVal
|
|
|
c17bfd |
-lstnDup(lstn_t **ppExisting, uchar *const __restrict__ newname)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- DEFiRet;
|
|
|
c17bfd |
- lstn_t *const existing = *ppExisting;
|
|
|
c17bfd |
- lstn_t *pThis;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- CHKiRet(lstnAdd(&pThis));
|
|
|
c17bfd |
- pThis->pszDirName = existing->pszDirName; /* read-only */
|
|
|
c17bfd |
- pThis->pszBaseName = (uchar*)strdup((char*)newname);
|
|
|
c17bfd |
- if(asprintf((char**)&pThis->pszFileName, "%s/%s", (char*)pThis->pszDirName, (char*)newname) == -1) {
|
|
|
c17bfd |
- DBGPRINTF("imfile/lstnDup: asprintf failed, malfunction can happen\n");
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- pThis->pszTag = (uchar*) strdup((char*) existing->pszTag);
|
|
|
c17bfd |
- pThis->lenTag = ustrlen(pThis->pszTag);
|
|
|
c17bfd |
- pThis->pszStateFile = existing->pszStateFile == NULL ? NULL : (uchar*) strdup((char*) existing->pszStateFile);
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- CHKiRet(ratelimitNew(&pThis->ratelimiter, "imfile", (char*)pThis->pszFileName));
|
|
|
c17bfd |
- pThis->multiSub.maxElem = existing->multiSub.maxElem;
|
|
|
c17bfd |
- pThis->multiSub.nElem = 0;
|
|
|
c17bfd |
- CHKmalloc(pThis->multiSub.ppMsgs = MALLOC(pThis->multiSub.maxElem * sizeof(smsg_t*)));
|
|
|
c17bfd |
- pThis->iSeverity = existing->iSeverity;
|
|
|
c17bfd |
- pThis->iFacility = existing->iFacility;
|
|
|
c17bfd |
- pThis->maxLinesAtOnce = existing->maxLinesAtOnce;
|
|
|
c17bfd |
- pThis->trimLineOverBytes = existing->trimLineOverBytes;
|
|
|
c17bfd |
- pThis->iPersistStateInterval = existing->iPersistStateInterval;
|
|
|
c17bfd |
- pThis->readMode = existing->readMode;
|
|
|
c17bfd |
- pThis->startRegex = existing->startRegex; /* no strdup, as it is read-only */
|
|
|
c17bfd |
- if(pThis->startRegex != NULL) // TODO: make this a single function with better error handling
|
|
|
c17bfd |
- if(regcomp(&pThis->end_preg, (char*)pThis->startRegex, REG_EXTENDED)) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: error regex compile\n");
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_ERR);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- pThis->bRMStateOnDel = existing->bRMStateOnDel;
|
|
|
c17bfd |
- pThis->hasWildcard = existing->hasWildcard;
|
|
|
c17bfd |
- pThis->escapeLF = existing->escapeLF;
|
|
|
c17bfd |
- pThis->reopenOnTruncate = existing->reopenOnTruncate;
|
|
|
c17bfd |
- pThis->addMetadata = existing->addMetadata;
|
|
|
c17bfd |
- pThis->addCeeTag = existing->addCeeTag;
|
|
|
c17bfd |
- pThis->readTimeout = existing->readTimeout;
|
|
|
c17bfd |
- pThis->freshStartTail = existing->freshStartTail;
|
|
|
c17bfd |
- pThis->pRuleset = existing->pRuleset;
|
|
|
c17bfd |
- pThis->nRecords = 0;
|
|
|
c17bfd |
- pThis->pStrm = NULL;
|
|
|
c17bfd |
- pThis->prevLineSegment = NULL;
|
|
|
c17bfd |
- pThis->masterLstn = existing;
|
|
|
c17bfd |
- *ppExisting = pThis;
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- RETiRet;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* Setup a new file watch for dynamically discovered files (via wildcards).
|
|
|
c17bfd |
- * Note: we need to try to read this file, as it may already contain data this
|
|
|
c17bfd |
- * needs to be processed, and we won't get an event for that as notifications
|
|
|
c17bfd |
- * happen only for things after the watch has been activated.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-in_setupFileWatchDynamic(lstn_t *pLstn, uchar *const __restrict__ newBaseName)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- char fullfn[MAXFNAME];
|
|
|
c17bfd |
- struct stat fileInfo;
|
|
|
c17bfd |
- snprintf(fullfn, MAXFNAME, "%s/%s", pLstn->pszDirName, newBaseName);
|
|
|
c17bfd |
- if(stat(fullfn, &fileInfo) != 0) {
|
|
|
c17bfd |
- char errStr[1024];
|
|
|
c17bfd |
- rs_strerror_r(errno, errStr, sizeof(errStr));
|
|
|
c17bfd |
- DBGPRINTF("imfile: ignoring file '%s' cannot stat(): %s\n",
|
|
|
c17bfd |
- fullfn, errStr);
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
+ if(ev->mask & IN_MOVED_FROM) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_MOVED_FROM, cookie %u, name '%s'\n", ev->cookie, ev->name);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- if(S_ISDIR(fileInfo.st_mode)) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: ignoring directory '%s'\n", fullfn);
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
+ if(ev->mask & IN_MOVED_TO) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_MOVED_TO, cookie %u, name '%s'\n", ev->cookie, ev->name);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- if(lstnDup(&pLstn, newBaseName) != RS_RET_OK)
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- startLstnFile(pLstn);
|
|
|
c17bfd |
-done: return;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* Setup a new file watch for static (configured) files.
|
|
|
c17bfd |
- * Note: we need to try to read this file, as it may already contain data this
|
|
|
c17bfd |
- * needs to be processed, and we won't get an event for that as notifications
|
|
|
c17bfd |
- * happen only for things after the watch has been activated.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-in_setupFileWatchStatic(lstn_t *pLstn)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- DBGPRINTF("imfile: adding file '%s' to configured table\n",
|
|
|
c17bfd |
- pLstn->pszFileName);
|
|
|
c17bfd |
- dirsAddFile(pLstn, CONFIGURED_FILE);
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- if(pLstn->hasWildcard) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: file '%s' has wildcard, doing initial "
|
|
|
c17bfd |
- "expansion\n", pLstn->pszFileName);
|
|
|
c17bfd |
- glob_t files;
|
|
|
c17bfd |
- const int ret = glob((char*)pLstn->pszFileName,
|
|
|
c17bfd |
- GLOB_MARK|GLOB_NOSORT|GLOB_BRACE, NULL, &files);
|
|
|
c17bfd |
- if(ret == 0) {
|
|
|
c17bfd |
- for(unsigned i = 0 ; i < files.gl_pathc ; i++) {
|
|
|
c17bfd |
- uchar basen[MAXFNAME];
|
|
|
c17bfd |
- uchar *const file = (uchar*)files.gl_pathv[i];
|
|
|
c17bfd |
- if(file[strlen((char*)file)-1] == '/')
|
|
|
c17bfd |
- continue;/* we cannot process subdirs! */
|
|
|
c17bfd |
- getBasename(basen, file);
|
|
|
c17bfd |
- in_setupFileWatchDynamic(pLstn, basen);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- globfree(&files);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- } else {
|
|
|
c17bfd |
- /* Duplicate static object as well, otherwise the configobject could be deleted later! */
|
|
|
c17bfd |
- if(lstnDup(&pLstn, pLstn->pszBaseName) != RS_RET_OK) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: in_setupFileWatchStatic failed to duplicate listener for '%s'\n", pLstn->pszFileName);
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- startLstnFile(pLstn);
|
|
|
c17bfd |
+ if(ev->mask & IN_OPEN) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_OPEN\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
-done: return;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-/* setup our initial set of watches, based on user config */
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-in_setupInitialWatches(void)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int i;
|
|
|
c17bfd |
- for(i = 0 ; i < currMaxDirs ; ++i) {
|
|
|
c17bfd |
- in_setupDirWatch(i);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- lstn_t *pLstn;
|
|
|
c17bfd |
- for(pLstn = runModConf->pRootLstn ; pLstn != NULL ; pLstn = pLstn->next) {
|
|
|
c17bfd |
- if(pLstn->masterLstn == NULL) {
|
|
|
c17bfd |
- /* we process only static (master) entries */
|
|
|
c17bfd |
- in_setupFileWatchStatic(pLstn);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
+ if(ev->mask & IN_ISDIR) {
|
|
|
c17bfd |
+ dbgprintf("INOTIFY event: watch IN_ISDIR\n");
|
|
|
c17bfd |
}
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-in_dbg_showEv(struct inotify_event *ev)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- if(ev->mask & IN_IGNORED) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch was REMOVED\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_MODIFY) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch was MODIFID\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_ACCESS) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_ACCESS\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_ATTRIB) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_ATTRIB\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_CLOSE_WRITE) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_CLOSE_WRITE\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_CLOSE_NOWRITE) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_CLOSE_NOWRITE\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_CREATE) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: file was CREATED: %s\n", ev->name);
|
|
|
c17bfd |
- } else if(ev->mask & IN_DELETE) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_DELETE\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_DELETE_SELF) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_DELETE_SELF\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_MOVE_SELF) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_MOVE_SELF\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_MOVED_FROM) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_MOVED_FROM\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_MOVED_TO) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_MOVED_TO\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_OPEN) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_OPEN\n");
|
|
|
c17bfd |
- } else if(ev->mask & IN_ISDIR) {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: watch IN_ISDIR\n");
|
|
|
c17bfd |
- } else {
|
|
|
c17bfd |
- DBGPRINTF("INOTIFY event: unknown mask code %8.8x\n", ev->mask);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
|
|
|
c17bfd |
-/* inotify told us that a file's wd was closed. We now need to remove
|
|
|
c17bfd |
- * the file from our internal structures. Remember that a different inode
|
|
|
c17bfd |
- * with the same name may already be in processing.
|
|
|
c17bfd |
- */
|
|
|
c17bfd |
static void
|
|
|
c17bfd |
-in_removeFile(const int dirIdx,
|
|
|
c17bfd |
- lstn_t *const __restrict__ pLstn)
|
|
|
c17bfd |
+in_handleFileEvent(struct inotify_event *ev, const wd_map_t *const etry)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
- uchar statefile[MAXFNAME];
|
|
|
c17bfd |
- uchar toDel[MAXFNAME];
|
|
|
c17bfd |
- int bDoRMState;
|
|
|
c17bfd |
- int wd;
|
|
|
c17bfd |
- uchar *statefn;
|
|
|
c17bfd |
- DBGPRINTF("imfile: remove listener '%s', dirIdx %d\n",
|
|
|
c17bfd |
- pLstn->pszFileName, dirIdx);
|
|
|
c17bfd |
- if(pLstn->bRMStateOnDel) {
|
|
|
c17bfd |
- statefn = getStateFileName(pLstn, statefile, sizeof(statefile));
|
|
|
c17bfd |
- snprintf((char*)toDel, sizeof(toDel), "%s/%s",
|
|
|
c17bfd |
- glbl.GetWorkDir(), (char*)statefn);
|
|
|
c17bfd |
- bDoRMState = 1;
|
|
|
c17bfd |
+ if(ev->mask & IN_MODIFY) {
|
|
|
c17bfd |
+ DBGPRINTF("fs_node_notify_file_update: act->name '%s'\n", etry->act->name);
|
|
|
c17bfd |
+ pollFile(etry->act);
|
|
|
c17bfd |
} else {
|
|
|
c17bfd |
- bDoRMState = 0;
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- pollFile(pLstn, NULL); /* one final try to gather data */
|
|
|
c17bfd |
- /* delete listener data */
|
|
|
c17bfd |
- DBGPRINTF("imfile: DELETING listener data for '%s' - '%s'\n", pLstn->pszBaseName, pLstn->pszFileName);
|
|
|
c17bfd |
- lstnDel(pLstn);
|
|
|
c17bfd |
- fileTableDelFile(&dirs[dirIdx].active, pLstn);
|
|
|
c17bfd |
- if(bDoRMState) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: unlinking '%s'\n", toDel);
|
|
|
c17bfd |
- if(unlink((char*)toDel) != 0) {
|
|
|
c17bfd |
- char errStr[1024];
|
|
|
c17bfd |
- rs_strerror_r(errno, errStr, sizeof(errStr));
|
|
|
c17bfd |
- errmsg.LogError(0, RS_RET_ERR, "imfile: could not remove state "
|
|
|
c17bfd |
- "file \"%s\": %s", toDel, errStr);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
+ DBGPRINTF("got non-expected inotify event:\n");
|
|
|
c17bfd |
+ in_dbg_showEv(ev);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- wd = wdmapLookupListner(pLstn);
|
|
|
c17bfd |
- wdmapDel(wd);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-in_handleDirEventCREATE(struct inotify_event *ev, const int dirIdx)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- lstn_t *pLstn;
|
|
|
c17bfd |
- int ftIdx;
|
|
|
c17bfd |
- ftIdx = fileTableSearch(&dirs[dirIdx].active, (uchar*)ev->name);
|
|
|
c17bfd |
- if(ftIdx >= 0) {
|
|
|
c17bfd |
- pLstn = dirs[dirIdx].active.listeners[ftIdx].pLstn;
|
|
|
c17bfd |
- } else {
|
|
|
c17bfd |
- DBGPRINTF("imfile: file '%s' not active in dir '%s'\n",
|
|
|
c17bfd |
- ev->name, dirs[dirIdx].dirName);
|
|
|
c17bfd |
- ftIdx = fileTableSearch(&dirs[dirIdx].configured, (uchar*)ev->name);
|
|
|
c17bfd |
- if(ftIdx == -1) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: file '%s' not associated with dir '%s'\n",
|
|
|
c17bfd |
- ev->name, dirs[dirIdx].dirName);
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- pLstn = dirs[dirIdx].configured.listeners[ftIdx].pLstn;
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- DBGPRINTF("imfile: file '%s' associated with dir '%s'\n", ev->name, dirs[dirIdx].dirName);
|
|
|
c17bfd |
- in_setupFileWatchDynamic(pLstn, (uchar*)ev->name);
|
|
|
c17bfd |
-done: return;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
|
|
|
c17bfd |
-/* note: we need to care only for active files in the DELETE case.
|
|
|
c17bfd |
- * Two reasons: a) if this is a configured file, it should be active
|
|
|
c17bfd |
- * b) if not for some reason, there still is nothing we can do against
|
|
|
c17bfd |
- * it, and trying to process a *deleted* file really makes no sense
|
|
|
c17bfd |
- * (remeber we don't have it open, so it actually *is gone*).
|
|
|
c17bfd |
+/* workaround for IN_MOVED: walk active list and prevent state file deletion of
|
|
|
c17bfd |
+ * IN_MOVED_IN active object
|
|
|
c17bfd |
+ * TODO: replace by a more generic solution.
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
static void
|
|
|
c17bfd |
-in_handleDirEventDELETE(struct inotify_event *const ev, const int dirIdx)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- const int ftIdx = fileTableSearch(&dirs[dirIdx].active, (uchar*)ev->name);
|
|
|
c17bfd |
- if(ftIdx == -1) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: deleted file '%s' not active in dir '%s'\n",
|
|
|
c17bfd |
- ev->name, dirs[dirIdx].dirName);
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- DBGPRINTF("imfile: imfile delete processing for '%s'\n",
|
|
|
c17bfd |
- dirs[dirIdx].active.listeners[ftIdx].pLstn->pszFileName);
|
|
|
c17bfd |
- in_removeFile(dirIdx, dirs[dirIdx].active.listeners[ftIdx].pLstn);
|
|
|
c17bfd |
-done: return;
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-in_handleDirEvent(struct inotify_event *const ev, const int dirIdx)
|
|
|
c17bfd |
+flag_in_move(fs_edge_t *const edge, const char *name_moved)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
- DBGPRINTF("imfile: handle dir event for %s\n", dirs[dirIdx].dirName);
|
|
|
c17bfd |
- if((ev->mask & IN_CREATE)) {
|
|
|
c17bfd |
- in_handleDirEventCREATE(ev, dirIdx);
|
|
|
c17bfd |
- } else if((ev->mask & IN_DELETE)) {
|
|
|
c17bfd |
- in_handleDirEventDELETE(ev, dirIdx);
|
|
|
c17bfd |
- } else {
|
|
|
c17bfd |
- DBGPRINTF("imfile: got non-expected inotify event:\n");
|
|
|
c17bfd |
- in_dbg_showEv(ev);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
+ act_obj_t *act;
|
|
|
c17bfd |
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-in_handleFileEvent(struct inotify_event *ev, const wd_map_t *const etry)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- if(ev->mask & IN_MODIFY) {
|
|
|
c17bfd |
- pollFile(etry->pLstn, NULL);
|
|
|
c17bfd |
- } else {
|
|
|
c17bfd |
- DBGPRINTF("imfile: got non-expected inotify event:\n");
|
|
|
c17bfd |
- in_dbg_showEv(ev);
|
|
|
c17bfd |
+ for(act = edge->active ; act != NULL ; act = act->next) {
|
|
|
c17bfd |
+ DBGPRINTF("checking active object %s\n", act->basename);
|
|
|
c17bfd |
+ if(!strcmp(act->basename, name_moved)){
|
|
|
c17bfd |
+ DBGPRINTF("found file\n");
|
|
|
c17bfd |
+ act->in_move = 1;
|
|
|
c17bfd |
+ break;
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ DBGPRINTF("name check fails, '%s' != '%s'\n", act->basename, name_moved);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
}
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
static void
|
|
|
c17bfd |
in_processEvent(struct inotify_event *ev)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
- wd_map_t *etry;
|
|
|
c17bfd |
- lstn_t *pLstn;
|
|
|
c17bfd |
- int iRet;
|
|
|
c17bfd |
- int ftIdx;
|
|
|
c17bfd |
- int wd;
|
|
|
c17bfd |
-
|
|
|
c17bfd |
if(ev->mask & IN_IGNORED) {
|
|
|
c17bfd |
- goto done;
|
|
|
c17bfd |
- } else if(ev->mask & IN_MOVED_FROM) {
|
|
|
c17bfd |
- /* Find wd entry and remove it */
|
|
|
c17bfd |
- etry = wdmapLookup(ev->wd);
|
|
|
c17bfd |
- if(etry != NULL) {
|
|
|
c17bfd |
- ftIdx = fileTableSearchNoWildcard(&dirs[etry->dirIdx].active, (uchar*)ev->name);
|
|
|
c17bfd |
- DBGPRINTF("imfile: IN_MOVED_FROM Event (ftIdx=%d, name=%s)\n", ftIdx, ev->name);
|
|
|
c17bfd |
- if(ftIdx >= 0) {
|
|
|
c17bfd |
- /* Find listener and wd table index*/
|
|
|
c17bfd |
- pLstn = dirs[etry->dirIdx].active.listeners[ftIdx].pLstn;
|
|
|
c17bfd |
- wd = wdmapLookupListner(pLstn);
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- /* Remove file from inotify watch */
|
|
|
c17bfd |
- iRet = inotify_rm_watch(ino_fd, wd); /* Note this will TRIGGER IN_IGNORED Event! */
|
|
|
c17bfd |
- if (iRet != 0) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: inotify_rm_watch error %d (ftIdx=%d, wd=%d, name=%s)\n", errno, ftIdx, wd, ev->name);
|
|
|
c17bfd |
- } else {
|
|
|
c17bfd |
- DBGPRINTF("imfile: inotify_rm_watch successfully removed file from watch (ftIdx=%d, wd=%d, name=%s)\n", ftIdx, wd, ev->name);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- in_removeFile(etry->dirIdx, pLstn);
|
|
|
c17bfd |
- DBGPRINTF("imfile: IN_MOVED_FROM Event file removed file (wd=%d, name=%s)\n", wd, ev->name);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
+ DBGPRINTF("imfile: got IN_IGNORED event\n");
|
|
|
c17bfd |
goto done;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- etry = wdmapLookup(ev->wd);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ DBGPRINTF("in_processEvent process Event %x for %s\n", ev->mask, ev->name);
|
|
|
c17bfd |
+ const wd_map_t *const etry = wdmapLookup(ev->wd);
|
|
|
c17bfd |
if(etry == NULL) {
|
|
|
c17bfd |
- DBGPRINTF("imfile: could not lookup wd %d\n", ev->wd);
|
|
|
c17bfd |
+ LogMsg(0, RS_RET_INTERNAL_ERROR, LOG_WARNING, "imfile: internal error? "
|
|
|
c17bfd |
+ "inotify provided watch descriptor %d which we could not find "
|
|
|
c17bfd |
+ "in our tables - ignored", ev->wd);
|
|
|
c17bfd |
goto done;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- if(etry->pLstn == NULL) { /* directory? */
|
|
|
c17bfd |
- in_handleDirEvent(ev, etry->dirIdx);
|
|
|
c17bfd |
+ DBGPRINTF("in_processEvent process Event %x is_file %d, act->name '%s'\n",
|
|
|
c17bfd |
+ ev->mask, etry->act->edge->is_file, etry->act->name);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ if((ev->mask & IN_MOVED_FROM)) {
|
|
|
c17bfd |
+ flag_in_move(etry->act->edge->node->edges, ev->name);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ if(ev->mask & (IN_MOVED_FROM | IN_MOVED_TO)) {
|
|
|
c17bfd |
+ fs_node_walk(etry->act->edge->node, poll_tree);
|
|
|
c17bfd |
+ } else if(etry->act->edge->is_file && !(etry->act->is_symlink)) {
|
|
|
c17bfd |
+ in_handleFileEvent(ev, etry); // esentially poll_file()!
|
|
|
c17bfd |
} else {
|
|
|
c17bfd |
- in_handleFileEvent(ev, etry);
|
|
|
c17bfd |
+ fs_node_walk(etry->act->edge->node, poll_tree);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
done: return;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
-static void
|
|
|
c17bfd |
-in_do_timeout_processing(void)
|
|
|
c17bfd |
-{
|
|
|
c17bfd |
- int i;
|
|
|
c17bfd |
- DBGPRINTF("imfile: readTimeouts are configured, checking if some apply\n");
|
|
|
c17bfd |
-
|
|
|
c17bfd |
- for(i = 0 ; i < nWdmap ; ++i) {
|
|
|
c17bfd |
- dbgprintf("imfile: wdmap %d, plstn %p\n", i, wdmap[i].pLstn);
|
|
|
c17bfd |
- lstn_t *const pLstn = wdmap[i].pLstn;
|
|
|
c17bfd |
- if(pLstn != NULL && strmReadMultiLine_isTimedOut(pLstn->pStrm)) {
|
|
|
c17bfd |
- dbgprintf("imfile: wdmap %d, timeout occured\n", i);
|
|
|
c17bfd |
- pollFile(pLstn, NULL);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
-
|
|
|
c17bfd |
-}
|
|
|
c17bfd |
-
|
|
|
c17bfd |
|
|
|
c17bfd |
/* Monitor files in inotify mode */
|
|
|
c17bfd |
#if !defined(_AIX)
|
|
|
c17bfd |
@@ -1940,14 +2062,16 @@ do_inotify(void)
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
|
|
|
c17bfd |
CHKiRet(wdmapInit());
|
|
|
c17bfd |
- CHKiRet(dirsInit());
|
|
|
c17bfd |
ino_fd = inotify_init();
|
|
|
c17bfd |
- if(ino_fd < 0) {
|
|
|
c17bfd |
- errmsg.LogError(1, RS_RET_INOTIFY_INIT_FAILED, "imfile: Init inotify instance failed ");
|
|
|
c17bfd |
- return RS_RET_INOTIFY_INIT_FAILED;
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- DBGPRINTF("imfile: inotify fd %d\n", ino_fd);
|
|
|
c17bfd |
- in_setupInitialWatches();
|
|
|
c17bfd |
+ if(ino_fd < 0) {
|
|
|
c17bfd |
+ LogError(errno, RS_RET_INOTIFY_INIT_FAILED, "imfile: Init inotify "
|
|
|
c17bfd |
+ "instance failed ");
|
|
|
c17bfd |
+ return RS_RET_INOTIFY_INIT_FAILED;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ DBGPRINTF("inotify fd %d\n", ino_fd);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* do watch initialization */
|
|
|
c17bfd |
+ fs_node_walk(runModConf->conf_tree, poll_tree);
|
|
|
c17bfd |
|
|
|
c17bfd |
while(glbl.GetGlobalInputTermState() == 0) {
|
|
|
c17bfd |
if(runModConf->haveReadTimeouts) {
|
|
|
c17bfd |
@@ -1959,7 +2083,8 @@ do_inotify(void)
|
|
|
c17bfd |
r = poll(&pollfd, 1, runModConf->timeoutGranularity);
|
|
|
c17bfd |
} while(r == -1 && errno == EINTR);
|
|
|
c17bfd |
if(r == 0) {
|
|
|
c17bfd |
- in_do_timeout_processing();
|
|
|
c17bfd |
+ DBGPRINTF("readTimeouts are configured, checking if some apply\n");
|
|
|
c17bfd |
+ fs_node_walk(runModConf->conf_tree, poll_timeouts);
|
|
|
c17bfd |
continue;
|
|
|
c17bfd |
} else if (r == -1) {
|
|
|
c17bfd |
char errStr[1024];
|
|
|
c17bfd |
@@ -2035,49 +2160,96 @@ CODESTARTwillRun
|
|
|
c17bfd |
CHKiRet(prop.Construct(&pInputName));
|
|
|
c17bfd |
CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imfile"), sizeof("imfile") - 1));
|
|
|
c17bfd |
CHKiRet(prop.ConstructFinalize(pInputName));
|
|
|
c17bfd |
-
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
ENDwillRun
|
|
|
c17bfd |
|
|
|
c17bfd |
+// TODO: refactor this into a generically-usable "atomic file creation" utility for
|
|
|
c17bfd |
+// all kinds of "state files"
|
|
|
c17bfd |
+static rsRetVal
|
|
|
c17bfd |
+atomicWriteStateFile(const char *fn, const char *content)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ DEFiRet;
|
|
|
c17bfd |
+ const int fd = open(fn, O_CLOEXEC | O_NOCTTY | O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
|
|
c17bfd |
+ if(fd < 0) {
|
|
|
c17bfd |
+ LogError(errno, RS_RET_IO_ERROR, "imfile: cannot open state file '%s' for "
|
|
|
c17bfd |
+ "persisting file state - some data will probably be duplicated "
|
|
|
c17bfd |
+ "on next startup", fn);
|
|
|
c17bfd |
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ const size_t toWrite = strlen(content);
|
|
|
c17bfd |
+ const ssize_t w = write(fd, content, toWrite);
|
|
|
c17bfd |
+ if(w != (ssize_t) toWrite) {
|
|
|
c17bfd |
+ LogError(errno, RS_RET_IO_ERROR, "imfile: partial write to state file '%s' "
|
|
|
c17bfd |
+ "this may cause trouble in the future. We will try to delete the "
|
|
|
c17bfd |
+ "state file, as this provides most consistent state", fn);
|
|
|
c17bfd |
+ unlink(fn);
|
|
|
c17bfd |
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+finalize_it:
|
|
|
c17bfd |
+ if(fd >= 0) {
|
|
|
c17bfd |
+ close(fd);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ RETiRet;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
/* This function persists information for a specific file being monitored.
|
|
|
c17bfd |
* To do so, it simply persists the stream object. We do NOT abort on error
|
|
|
c17bfd |
* iRet as that makes matters worse (at least we can try persisting the others...).
|
|
|
c17bfd |
* rgerhards, 2008-02-13
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
-persistStrmState(lstn_t *pLstn)
|
|
|
c17bfd |
+persistStrmState(act_obj_t *const act)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
- strm_t *psSF = NULL; /* state file (stream) */
|
|
|
c17bfd |
- size_t lenDir;
|
|
|
c17bfd |
uchar statefile[MAXFNAME];
|
|
|
c17bfd |
+ uchar statefname[MAXFNAME];
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ uchar *const statefn = getStateFileName(act, statefile, sizeof(statefile));
|
|
|
c17bfd |
+ getFullStateFileName(statefn, statefname, sizeof(statefname));
|
|
|
c17bfd |
+ DBGPRINTF("persisting state for '%s', state file '%s'\n", act->name, statefname);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ struct json_object *jval = NULL;
|
|
|
c17bfd |
+ struct json_object *json = NULL;
|
|
|
c17bfd |
+ CHKmalloc(json = json_object_new_object());
|
|
|
c17bfd |
+ jval = json_object_new_string((char*) act->name);
|
|
|
c17bfd |
+ json_object_object_add(json, "filename", jval);
|
|
|
c17bfd |
+ jval = json_object_new_int(strmGetPrevWasNL(act->pStrm));
|
|
|
c17bfd |
+ json_object_object_add(json, "prev_was_nl", jval);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ /* we access some data items a bit dirty, as we need to refactor the whole
|
|
|
c17bfd |
+ * thing in any case - TODO
|
|
|
c17bfd |
+ */
|
|
|
c17bfd |
+ jval = json_object_new_int64(act->pStrm->iCurrOffs);
|
|
|
c17bfd |
+ json_object_object_add(json, "curr_offs", jval);
|
|
|
c17bfd |
+ jval = json_object_new_int64(act->pStrm->strtOffs);
|
|
|
c17bfd |
+ json_object_object_add(json, "strt_offs", jval);
|
|
|
c17bfd |
|
|
|
c17bfd |
- uchar *const statefn = getStateFileName(pLstn, statefile, sizeof(statefile));
|
|
|
c17bfd |
- DBGPRINTF("imfile: persisting state for '%s' to file '%s'\n",
|
|
|
c17bfd |
- pLstn->pszFileName, statefn);
|
|
|
c17bfd |
- CHKiRet(strm.Construct(&psSF));
|
|
|
c17bfd |
- lenDir = ustrlen(glbl.GetWorkDir());
|
|
|
c17bfd |
- if(lenDir > 0)
|
|
|
c17bfd |
- CHKiRet(strm.SetDir(psSF, glbl.GetWorkDir(), lenDir));
|
|
|
c17bfd |
- CHKiRet(strm.SettOperationsMode(psSF, STREAMMODE_WRITE_TRUNC));
|
|
|
c17bfd |
- CHKiRet(strm.SetsType(psSF, STREAMTYPE_FILE_SINGLE));
|
|
|
c17bfd |
- CHKiRet(strm.SetFName(psSF, statefn, strlen((char*) statefn)));
|
|
|
c17bfd |
- CHKiRet(strm.ConstructFinalize(psSF));
|
|
|
c17bfd |
+ const uchar *const prevLineSegment = strmGetPrevLineSegment(act->pStrm);
|
|
|
c17bfd |
+ if(prevLineSegment != NULL) {
|
|
|
c17bfd |
+ jval = json_object_new_string((const char*) prevLineSegment);
|
|
|
c17bfd |
+ json_object_object_add(json, "prev_line_segment", jval);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
|
|
|
c17bfd |
- CHKiRet(strm.Serialize(pLstn->pStrm, psSF));
|
|
|
c17bfd |
- CHKiRet(strm.Flush(psSF));
|
|
|
c17bfd |
+ const uchar *const prevMsgSegment = strmGetPrevMsgSegment(act->pStrm);
|
|
|
c17bfd |
+ if(prevMsgSegment != NULL) {
|
|
|
c17bfd |
+ jval = json_object_new_string((const char*) prevMsgSegment);
|
|
|
c17bfd |
+ json_object_object_add(json, "prev_msg_segment", jval);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
|
|
|
c17bfd |
- CHKiRet(strm.Destruct(&psSF));
|
|
|
c17bfd |
+ const char *jstr = json_object_to_json_string_ext(json, JSON_C_TO_STRING_SPACED);
|
|
|
c17bfd |
|
|
|
c17bfd |
-finalize_it:
|
|
|
c17bfd |
- if(psSF != NULL)
|
|
|
c17bfd |
- strm.Destruct(&psSF);
|
|
|
c17bfd |
+ CHKiRet(atomicWriteStateFile((const char*)statefname, jstr));
|
|
|
c17bfd |
+ json_object_put(json);
|
|
|
c17bfd |
|
|
|
c17bfd |
+finalize_it:
|
|
|
c17bfd |
if(iRet != RS_RET_OK) {
|
|
|
c17bfd |
errmsg.LogError(0, iRet, "imfile: could not persist state "
|
|
|
c17bfd |
"file %s - data may be repeated on next "
|
|
|
c17bfd |
"startup. Is WorkDirectory set?",
|
|
|
c17bfd |
- statefn);
|
|
|
c17bfd |
+ statefname);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
@@ -2089,11 +2261,6 @@ finalize_it:
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
BEGINafterRun
|
|
|
c17bfd |
CODESTARTafterRun
|
|
|
c17bfd |
- while(runModConf->pRootLstn != NULL) {
|
|
|
c17bfd |
- /* Note: lstnDel() reasociates root! */
|
|
|
c17bfd |
- lstnDel(runModConf->pRootLstn);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
-
|
|
|
c17bfd |
if(pInputName != NULL)
|
|
|
c17bfd |
prop.Destruct(&pInputName);
|
|
|
c17bfd |
ENDafterRun
|
|
|
c17bfd |
@@ -2118,12 +2285,6 @@ CODESTARTmodExit
|
|
|
c17bfd |
objRelease(prop, CORE_COMPONENT);
|
|
|
c17bfd |
objRelease(ruleset, CORE_COMPONENT);
|
|
|
c17bfd |
#ifdef HAVE_INOTIFY_INIT
|
|
|
c17bfd |
- /* we use these vars only in inotify mode */
|
|
|
c17bfd |
- if(dirs != NULL) {
|
|
|
c17bfd |
- free(dirs->active.listeners);
|
|
|
c17bfd |
- free(dirs->configured.listeners);
|
|
|
c17bfd |
- free(dirs);
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
free(wdmap);
|
|
|
c17bfd |
#endif
|
|
|
c17bfd |
ENDmodExit
|
|
|
c17bfd |
diff --git a/runtime/msg.c b/runtime/msg.c
|
|
|
c17bfd |
index a885d2368bbaeea90a6e92dc0d569d169b1dd2e5..f45d6175283097974023905fc072508a18a8270a 100644
|
|
|
c17bfd |
--- a/runtime/msg.c
|
|
|
c17bfd |
+++ b/runtime/msg.c
|
|
|
c17bfd |
@@ -4890,6 +4890,28 @@ finalize_it:
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
+rsRetVal
|
|
|
c17bfd |
+msgAddMultiMetadata(smsg_t *const __restrict__ pMsg,
|
|
|
c17bfd |
+ const uchar ** __restrict__ metaname,
|
|
|
c17bfd |
+ const uchar ** __restrict__ metaval,
|
|
|
c17bfd |
+ const int count)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ DEFiRet;
|
|
|
c17bfd |
+ int i = 0 ;
|
|
|
c17bfd |
+ struct json_object *const json = json_object_new_object();
|
|
|
c17bfd |
+ CHKmalloc(json);
|
|
|
c17bfd |
+ for ( i = 0 ; i < count ; i++ ) {
|
|
|
c17bfd |
+ struct json_object *const jval = json_object_new_string((char*)metaval[i]);
|
|
|
c17bfd |
+ if(jval == NULL) {
|
|
|
c17bfd |
+ json_object_put(json);
|
|
|
c17bfd |
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ json_object_object_add(json, (const char *const)metaname[i], jval);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ iRet = msgAddJSON(pMsg, (uchar*)"!metadata", json, 0, 0);
|
|
|
c17bfd |
+finalize_it:
|
|
|
c17bfd |
+ RETiRet;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
|
|
|
c17bfd |
static struct json_object *
|
|
|
c17bfd |
jsonDeepCopy(struct json_object *src)
|
|
|
c17bfd |
diff --git a/runtime/msg.h b/runtime/msg.h
|
|
|
c17bfd |
index 6521e19b28b013f0d06e357bdb0f33a94dab638b..0e92da43398156f4871b2e567a242cb089f67a08 100644
|
|
|
c17bfd |
--- a/runtime/msg.h
|
|
|
c17bfd |
+++ b/runtime/msg.h
|
|
|
c17bfd |
@@ -195,6 +195,7 @@ int getPRIi(const smsg_t * const pM);
|
|
|
c17bfd |
void getRawMsg(smsg_t *pM, uchar **pBuf, int *piLen);
|
|
|
c17bfd |
rsRetVal msgAddJSON(smsg_t *pM, uchar *name, struct json_object *json, int force_reset, int sharedReference);
|
|
|
c17bfd |
rsRetVal msgAddMetadata(smsg_t *msg, uchar *metaname, uchar *metaval);
|
|
|
c17bfd |
+rsRetVal msgAddMultiMetadata(smsg_t *msg, const uchar **metaname, const uchar **metaval, const int count);
|
|
|
c17bfd |
rsRetVal MsgGetSeverity(smsg_t *pThis, int *piSeverity);
|
|
|
c17bfd |
rsRetVal MsgDeserialize(smsg_t *pMsg, strm_t *pStrm);
|
|
|
c17bfd |
rsRetVal MsgSetPropsViaJSON(smsg_t *__restrict__ const pMsg, const uchar *__restrict__ const json);
|
|
|
c17bfd |
diff --git a/runtime/stream.c b/runtime/stream.c
|
|
|
c17bfd |
index 701144c0e39d6fbcf9dd63fe60421e1dcd6f01c6..fb1ff11d1890bbaee107658dd3568c2bc67c223d 100644
|
|
|
c17bfd |
--- a/runtime/stream.c
|
|
|
c17bfd |
+++ b/runtime/stream.c
|
|
|
c17bfd |
@@ -91,6 +91,41 @@ static rsRetVal strmSeekCurrOffs(strm_t *pThis);
|
|
|
c17bfd |
|
|
|
c17bfd |
/* methods */
|
|
|
c17bfd |
|
|
|
c17bfd |
+/* note: this may return NULL if not line segment is currently set */
|
|
|
c17bfd |
+// TODO: due to the cstrFinalize() this is not totally clean, albeit for our
|
|
|
c17bfd |
+// current use case it does not hurt -- refactor! rgerhards, 2018-03-27
|
|
|
c17bfd |
+const uchar *
|
|
|
c17bfd |
+strmGetPrevLineSegment(strm_t *const pThis)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ const uchar *ret = NULL;
|
|
|
c17bfd |
+ if(pThis->prevLineSegment != NULL) {
|
|
|
c17bfd |
+ cstrFinalize(pThis->prevLineSegment);
|
|
|
c17bfd |
+ ret = rsCStrGetSzStrNoNULL(pThis->prevLineSegment);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ return ret;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+/* note: this may return NULL if not line segment is currently set */
|
|
|
c17bfd |
+// TODO: due to the cstrFinalize() this is not totally clean, albeit for our
|
|
|
c17bfd |
+// current use case it does not hurt -- refactor! rgerhards, 2018-03-27
|
|
|
c17bfd |
+const uchar *
|
|
|
c17bfd |
+strmGetPrevMsgSegment(strm_t *const pThis)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ const uchar *ret = NULL;
|
|
|
c17bfd |
+ if(pThis->prevMsgSegment != NULL) {
|
|
|
c17bfd |
+ cstrFinalize(pThis->prevMsgSegment);
|
|
|
c17bfd |
+ ret = rsCStrGetSzStrNoNULL(pThis->prevMsgSegment);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ return ret;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+int
|
|
|
c17bfd |
+strmGetPrevWasNL(const strm_t *const pThis)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ return pThis->bPrevWasNL;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+
|
|
|
c17bfd |
/* output (current) file name for debug log purposes. Falls back to various
|
|
|
c17bfd |
* levels of impreciseness if more precise name is not known.
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
@@ -242,17 +277,18 @@ doPhysOpen(strm_t *pThis)
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
pThis->fd = open((char*)pThis->pszCurrFName, iFlags | O_LARGEFILE, pThis->tOpenMode);
|
|
|
c17bfd |
+ const int errno_save = errno; /* dbgprintf can mangle it! */
|
|
|
c17bfd |
DBGPRINTF("file '%s' opened as #%d with mode %d\n", pThis->pszCurrFName,
|
|
|
c17bfd |
pThis->fd, (int) pThis->tOpenMode);
|
|
|
c17bfd |
if(pThis->fd == -1) {
|
|
|
c17bfd |
- char errStr[1024];
|
|
|
c17bfd |
- int err = errno;
|
|
|
c17bfd |
- rs_strerror_r(err, errStr, sizeof(errStr));
|
|
|
c17bfd |
- DBGOPRINT((obj_t*) pThis, "open error %d, file '%s': %s\n", errno, pThis->pszCurrFName, errStr);
|
|
|
c17bfd |
- if(err == ENOENT)
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
|
|
|
c17bfd |
- else
|
|
|
c17bfd |
- ABORT_FINALIZE(RS_RET_FILE_OPEN_ERROR);
|
|
|
c17bfd |
+ const rsRetVal errcode = (errno_save == ENOENT)
|
|
|
c17bfd |
+ ? RS_RET_FILE_NOT_FOUND : RS_RET_FILE_OPEN_ERROR;
|
|
|
c17bfd |
+ if(pThis->fileNotFoundError) {
|
|
|
c17bfd |
+ LogError(errno_save, errcode, "file '%s': open error", pThis->pszCurrFName);
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ DBGPRINTF("file '%s': open error", pThis->pszCurrFName);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ ABORT_FINALIZE(errcode);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
if(pThis->tOperationsMode == STREAMMODE_READ) {
|
|
|
c17bfd |
@@ -344,6 +380,8 @@ static rsRetVal strmOpenFile(strm_t *pThis)
|
|
|
c17bfd |
|
|
|
c17bfd |
if(pThis->fd != -1)
|
|
|
c17bfd |
ABORT_FINALIZE(RS_RET_OK);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
+ free(pThis->pszCurrFName);
|
|
|
c17bfd |
pThis->pszCurrFName = NULL; /* used to prevent mem leak in case of error */
|
|
|
c17bfd |
|
|
|
c17bfd |
if(pThis->pszFName == NULL)
|
|
|
c17bfd |
@@ -733,11 +771,11 @@ static rsRetVal strmUnreadChar(strm_t *pThis, uchar c)
|
|
|
c17bfd |
* a line, but following lines that are indented are part of the same log entry
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
static rsRetVal
|
|
|
c17bfd |
-strmReadLine(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF, uint32_t trimLineOverBytes)
|
|
|
c17bfd |
+strmReadLine(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF,
|
|
|
c17bfd |
+ uint32_t trimLineOverBytes, int64 *const strtOffs)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
uchar c;
|
|
|
c17bfd |
uchar finished;
|
|
|
c17bfd |
- rsRetVal readCharRet;
|
|
|
c17bfd |
DEFiRet;
|
|
|
c17bfd |
|
|
|
c17bfd |
ASSERT(pThis != NULL);
|
|
|
c17bfd |
@@ -756,12 +794,7 @@ strmReadLine(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF, uint
|
|
|
c17bfd |
if(mode == 0) {
|
|
|
c17bfd |
while(c != '\n') {
|
|
|
c17bfd |
CHKiRet(cstrAppendChar(*ppCStr, c));
|
|
|
c17bfd |
- readCharRet = strmReadChar(pThis, &c);
|
|
|
c17bfd |
- if((readCharRet == RS_RET_TIMED_OUT) ||
|
|
|
c17bfd |
- (readCharRet == RS_RET_EOF) ) { /* end reached without \n? */
|
|
|
c17bfd |
- CHKiRet(rsCStrConstructFromCStr(&pThis->prevLineSegment, *ppCStr));
|
|
|
c17bfd |
- }
|
|
|
c17bfd |
- CHKiRet(readCharRet);
|
|
|
c17bfd |
+ CHKiRet(strmReadChar(pThis, &c);;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
if (trimLineOverBytes > 0 && (uint32_t) cstrLen(*ppCStr) > trimLineOverBytes) {
|
|
|
c17bfd |
/* Truncate long line at trimLineOverBytes position */
|
|
|
c17bfd |
@@ -850,12 +883,19 @@ strmReadLine(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF, uint
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
- if(iRet != RS_RET_OK && *ppCStr != NULL) {
|
|
|
c17bfd |
- if(cstrLen(*ppCStr) > 0) {
|
|
|
c17bfd |
- /* we may have an empty string in an unsuccsfull poll or after restart! */
|
|
|
c17bfd |
- rsCStrConstructFromCStr(&pThis->prevLineSegment, *ppCStr);
|
|
|
c17bfd |
+ if(iRet == RS_RET_OK) {
|
|
|
c17bfd |
+ if(strtOffs != NULL) {
|
|
|
c17bfd |
+ *strtOffs = pThis->strtOffs;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ pThis->strtOffs = pThis->iCurrOffs; /* we are at begin of next line */
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ if(*ppCStr != NULL) {
|
|
|
c17bfd |
+ if(cstrLen(*ppCStr) > 0) {
|
|
|
c17bfd |
+ /* we may have an empty string in an unsuccesfull poll or after restart! */
|
|
|
c17bfd |
+ rsCStrConstructFromCStr(&pThis->prevLineSegment, *ppCStr);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ cstrDestruct(ppCStr);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- cstrDestruct(ppCStr);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
@@ -882,7 +922,8 @@ strmReadMultiLine_isTimedOut(const strm_t *const __restrict__ pThis)
|
|
|
c17bfd |
* added 2015-05-12 rgerhards
|
|
|
c17bfd |
*/
|
|
|
c17bfd |
rsRetVal
|
|
|
c17bfd |
-strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, const sbool bEscapeLF)
|
|
|
c17bfd |
+strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, const sbool bEscapeLF,
|
|
|
c17bfd |
+ int64 *const strtOffs)
|
|
|
c17bfd |
{
|
|
|
c17bfd |
uchar c;
|
|
|
c17bfd |
uchar finished = 0;
|
|
|
c17bfd |
@@ -946,16 +987,24 @@ strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, const sbool bEs
|
|
|
c17bfd |
} while(finished == 0);
|
|
|
c17bfd |
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
- if( pThis->readTimeout
|
|
|
c17bfd |
- && (iRet != RS_RET_OK)
|
|
|
c17bfd |
- && (pThis->prevMsgSegment != NULL)
|
|
|
c17bfd |
- && (tCurr > pThis->lastRead + pThis->readTimeout)) {
|
|
|
c17bfd |
- CHKiRet(rsCStrConstructFromCStr(ppCStr, pThis->prevMsgSegment));
|
|
|
c17bfd |
- cstrDestruct(&pThis->prevMsgSegment);
|
|
|
c17bfd |
- pThis->lastRead = tCurr;
|
|
|
c17bfd |
- dbgprintf("stream: generated msg based on timeout: %s\n", cstrGetSzStrNoNULL(*ppCStr));
|
|
|
c17bfd |
- FINALIZE;
|
|
|
c17bfd |
- iRet = RS_RET_OK;
|
|
|
c17bfd |
+ *strtOffs = pThis->strtOffs;
|
|
|
c17bfd |
+ if(thisLine != NULL) {
|
|
|
c17bfd |
+ cstrDestruct(&thisLine);
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
+ if(iRet == RS_RET_OK) {
|
|
|
c17bfd |
+ pThis->strtOffs = pThis->iCurrOffs; /* we are at begin of next line */
|
|
|
c17bfd |
+ } else {
|
|
|
c17bfd |
+ if( pThis->readTimeout
|
|
|
c17bfd |
+ && (pThis->prevMsgSegment != NULL)
|
|
|
c17bfd |
+ && (tCurr > pThis->lastRead + pThis->readTimeout)) {
|
|
|
c17bfd |
+ CHKiRet(rsCStrConstructFromCStr(ppCStr, pThis->prevMsgSegment));
|
|
|
c17bfd |
+ cstrDestruct(&pThis->prevMsgSegment);
|
|
|
c17bfd |
+ pThis->lastRead = tCurr;
|
|
|
c17bfd |
+ pThis->strtOffs = pThis->iCurrOffs; /* we are at begin of next line */
|
|
|
c17bfd |
+ dbgprintf("stream: generated msg based on timeout: %s\n", cstrGetSzStrNoNULL(*ppCStr));
|
|
|
c17bfd |
+ FINALIZE;
|
|
|
c17bfd |
+ iRet = RS_RET_OK;
|
|
|
c17bfd |
+ }
|
|
|
c17bfd |
}
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
@@ -974,7 +1023,10 @@ BEGINobjConstruct(strm) /* be sure to specify the object type also in END macro!
|
|
|
c17bfd |
pThis->pszSizeLimitCmd = NULL;
|
|
|
c17bfd |
pThis->prevLineSegment = NULL;
|
|
|
c17bfd |
pThis->prevMsgSegment = NULL;
|
|
|
c17bfd |
+ pThis->strtOffs = 0;
|
|
|
c17bfd |
+ pThis->ignoringMsg = 0;
|
|
|
c17bfd |
pThis->bPrevWasNL = 0;
|
|
|
c17bfd |
+ pThis->fileNotFoundError = 1;
|
|
|
c17bfd |
ENDobjConstruct(strm)
|
|
|
c17bfd |
|
|
|
c17bfd |
|
|
|
c17bfd |
@@ -1686,7 +1738,7 @@ static rsRetVal strmSeek(strm_t *pThis, off64_t offs)
|
|
|
c17bfd |
DBGPRINTF("strmSeek: error %lld seeking to offset %lld\n", i, (long long) offs);
|
|
|
c17bfd |
ABORT_FINALIZE(RS_RET_IO_ERROR);
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- pThis->iCurrOffs = offs; /* we are now at *this* offset */
|
|
|
c17bfd |
+ pThis->strtOffs = pThis->iCurrOffs = offs; /* we are now at *this* offset */
|
|
|
c17bfd |
pThis->iBufPtr = 0; /* buffer invalidated */
|
|
|
c17bfd |
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
@@ -1738,7 +1790,7 @@ strmMultiFileSeek(strm_t *pThis, unsigned int FNum, off64_t offs, off64_t *bytes
|
|
|
c17bfd |
} else {
|
|
|
c17bfd |
*bytesDel = 0;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
- pThis->iCurrOffs = offs;
|
|
|
c17bfd |
+ pThis->strtOffs = pThis->iCurrOffs = offs;
|
|
|
c17bfd |
|
|
|
c17bfd |
finalize_it:
|
|
|
c17bfd |
RETiRet;
|
|
|
c17bfd |
@@ -1763,7 +1815,7 @@ static rsRetVal strmSeekCurrOffs(strm_t *pThis)
|
|
|
c17bfd |
|
|
|
c17bfd |
/* As the cryprov may use CBC or similiar things, we need to read skip data */
|
|
|
c17bfd |
targetOffs = pThis->iCurrOffs;
|
|
|
c17bfd |
- pThis->iCurrOffs = 0;
|
|
|
c17bfd |
+ pThis->strtOffs = pThis->iCurrOffs = 0;
|
|
|
c17bfd |
DBGOPRINT((obj_t*) pThis, "encrypted, doing skip read of %lld bytes\n",
|
|
|
c17bfd |
(long long) targetOffs);
|
|
|
c17bfd |
while(targetOffs != pThis->iCurrOffs) {
|
|
|
c17bfd |
@@ -1935,6 +1987,12 @@ static rsRetVal strmSetiMaxFiles(strm_t *pThis, int iNewVal)
|
|
|
c17bfd |
return RS_RET_OK;
|
|
|
c17bfd |
}
|
|
|
c17bfd |
|
|
|
c17bfd |
+static rsRetVal strmSetFileNotFoundError(strm_t *pThis, int pFileNotFoundError)
|
|
|
c17bfd |
+{
|
|
|
c17bfd |
+ pThis->fileNotFoundError = pFileNotFoundError;
|
|
|
c17bfd |
+ return RS_RET_OK;
|
|
|
c17bfd |
+}
|
|
|
c17bfd |
+
|
|
|
c17bfd |
|
|
|
c17bfd |
/* set the stream's file prefix
|
|
|
c17bfd |
* The passed-in string is duplicated. So if the caller does not need
|
|
|
c17bfd |
@@ -2076,6 +2134,9 @@ static rsRetVal strmSerialize(strm_t *pThis, strm_t *pStrm)
|
|
|
c17bfd |
l = pThis->inode;
|
|
|
c17bfd |
objSerializeSCALAR_VAR(pStrm, inode, INT64, l);
|
|
|
c17bfd |
|
|
|
c17bfd |
+ l = pThis->strtOffs;
|
|
|
c17bfd |
+ objSerializeSCALAR_VAR(pStrm, strtOffs, INT64, l);
|
|
|
c17bfd |
+
|
|
|
c17bfd |
if(pThis->prevLineSegment != NULL) {
|
|
|
c17bfd |
cstrFinalize(pThis->prevLineSegment);
|
|
|
c17bfd |
objSerializePTR(pStrm, prevLineSegment, CSTR);
|
|
|
c17bfd |
@@ -2188,8 +2249,12 @@ static rsRetVal strmSetProperty(strm_t *pThis, var_t *pProp)
|
|
|
c17bfd |
pThis->iCurrOffs = pProp->val.num;
|
|
|
c17bfd |
} else if(isProp("inode")) {
|
|
|
c17bfd |
pThis->inode = (ino_t) pProp->val.num;
|
|
|
c17bfd |
+ } else if(isProp("strtOffs")) {
|
|
|
c17bfd |
+ pThis->strtOffs = pProp->val.num;
|
|
|
c17bfd |
} else if(isProp("iMaxFileSize")) {
|
|
|
c17bfd |
CHKiRet(strmSetiMaxFileSize(pThis, pProp->val.num));
|
|
|
c17bfd |
+ } else if(isProp("fileNotFoundError")) {
|
|
|
c17bfd |
+ CHKiRet(strmSetFileNotFoundError(pThis, pProp->val.num));
|
|
|
c17bfd |
} else if(isProp("iMaxFiles")) {
|
|
|
c17bfd |
CHKiRet(strmSetiMaxFiles(pThis, pProp->val.num));
|
|
|
c17bfd |
} else if(isProp("iFileNumDigits")) {
|
|
|
c17bfd |
@@ -2253,6 +2318,7 @@ CODESTARTobjQueryInterface(strm)
|
|
|
c17bfd |
pIf->WriteChar = strmWriteChar;
|
|
|
c17bfd |
pIf->WriteLong = strmWriteLong;
|
|
|
c17bfd |
pIf->SetFName = strmSetFName;
|
|
|
c17bfd |
+ pIf->SetFileNotFoundError = strmSetFileNotFoundError;
|
|
|
c17bfd |
pIf->SetDir = strmSetDir;
|
|
|
c17bfd |
pIf->Flush = strmFlush;
|
|
|
c17bfd |
pIf->RecordBegin = strmRecordBegin;
|
|
|
c17bfd |
diff --git a/runtime/stream.h b/runtime/stream.h
|
|
|
c17bfd |
index 1eee34979db34620b82e6351111864645187b035..bcb81a14f60f9effa52fffa42d18d66c484ae86d 100644
|
|
|
c17bfd |
--- a/runtime/stream.h
|
|
|
c17bfd |
+++ b/runtime/stream.h
|
|
|
c17bfd |
@@ -159,6 +159,10 @@ typedef struct strm_s {
|
|
|
c17bfd |
sbool bIsTTY; /* is this a tty file? */
|
|
|
c17bfd |
cstr_t *prevLineSegment; /* for ReadLine, previous, unprocessed part of file */
|
|
|
c17bfd |
cstr_t *prevMsgSegment; /* for ReadMultiLine, previous, yet unprocessed part of msg */
|
|
|
c17bfd |
+ int64 strtOffs; /* start offset in file for current line/msg */
|
|
|
c17bfd |
+ int fileNotFoundError;
|
|
|
c17bfd |
+ int noRepeatedErrorOutput; /* if a file is missing the Error is only given once */
|
|
|
c17bfd |
+ int ignoringMsg;
|
|
|
c17bfd |
} strm_t;
|
|
|
c17bfd |
|
|
|
c17bfd |
|
|
|
c17bfd |
@@ -174,6 +178,7 @@ BEGINinterface(strm) /* name must also be changed in ENDinterface macro! */
|
|
|
c17bfd |
rsRetVal (*Write)(strm_t *const pThis, const uchar *const pBuf, size_t lenBuf);
|
|
|
c17bfd |
rsRetVal (*WriteChar)(strm_t *pThis, uchar c);
|
|
|
c17bfd |
rsRetVal (*WriteLong)(strm_t *pThis, long i);
|
|
|
c17bfd |
+ rsRetVal (*SetFileNotFoundError)(strm_t *pThis, int pFileNotFoundError);
|
|
|
c17bfd |
rsRetVal (*SetFName)(strm_t *pThis, uchar *pszPrefix, size_t iLenPrefix);
|
|
|
c17bfd |
rsRetVal (*SetDir)(strm_t *pThis, uchar *pszDir, size_t iLenDir);
|
|
|
c17bfd |
rsRetVal (*Flush)(strm_t *pThis);
|
|
|
c17bfd |
@@ -198,7 +203,8 @@ BEGINinterface(strm) /* name must also be changed in ENDinterface macro! */
|
|
|
c17bfd |
INTERFACEpropSetMeth(strm, iFlushInterval, int);
|
|
|
c17bfd |
INTERFACEpropSetMeth(strm, pszSizeLimitCmd, uchar*);
|
|
|
c17bfd |
/* v6 added */
|
|
|
c17bfd |
- rsRetVal (*ReadLine)(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF, uint32_t trimLineOverBytes);
|
|
|
c17bfd |
+ rsRetVal (*ReadLine)(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF,
|
|
|
c17bfd |
+ uint32_t trimLineOverBytes, int64 *const strtOffs);
|
|
|
c17bfd |
/* v7 added 2012-09-14 */
|
|
|
c17bfd |
INTERFACEpropSetMeth(strm, bVeryReliableZip, int);
|
|
|
c17bfd |
/* v8 added 2013-03-21 */
|
|
|
c17bfd |
@@ -207,19 +213,24 @@ BEGINinterface(strm) /* name must also be changed in ENDinterface macro! */
|
|
|
c17bfd |
INTERFACEpropSetMeth(strm, cryprov, cryprov_if_t*);
|
|
|
c17bfd |
INTERFACEpropSetMeth(strm, cryprovData, void*);
|
|
|
c17bfd |
ENDinterface(strm)
|
|
|
c17bfd |
-#define strmCURR_IF_VERSION 12 /* increment whenever you change the interface structure! */
|
|
|
c17bfd |
+#define strmCURR_IF_VERSION 13 /* increment whenever you change the interface structure! */
|
|
|
c17bfd |
/* V10, 2013-09-10: added new parameter bEscapeLF, changed mode to uint8_t (rgerhards) */
|
|
|
c17bfd |
/* V11, 2015-12-03: added new parameter bReopenOnTruncate */
|
|
|
c17bfd |
/* V12, 2015-12-11: added new parameter trimLineOverBytes, changed mode to uint32_t */
|
|
|
c17bfd |
+/* V13, 2017-09-06: added new parameter strtoffs to ReadLine() */
|
|
|
c17bfd |
|
|
|
c17bfd |
#define strmGetCurrFileNum(pStrm) ((pStrm)->iCurrFNum)
|
|
|
c17bfd |
|
|
|
c17bfd |
/* prototypes */
|
|
|
c17bfd |
PROTOTYPEObjClassInit(strm);
|
|
|
c17bfd |
rsRetVal strmMultiFileSeek(strm_t *pThis, unsigned int fileNum, off64_t offs, off64_t *bytesDel);
|
|
|
c17bfd |
-rsRetVal strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, sbool bEscapeLF);
|
|
|
c17bfd |
+rsRetVal strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg,
|
|
|
c17bfd |
+ sbool bEscapeLF, int64 *const strtOffs);
|
|
|
c17bfd |
int strmReadMultiLine_isTimedOut(const strm_t *const __restrict__ pThis);
|
|
|
c17bfd |
void strmDebugOutBuf(const strm_t *const pThis);
|
|
|
c17bfd |
void strmSetReadTimeout(strm_t *const __restrict__ pThis, const int val);
|
|
|
c17bfd |
+const uchar * strmGetPrevLineSegment(strm_t *const pThis);
|
|
|
c17bfd |
+const uchar * strmGetPrevMsgSegment(strm_t *const pThis);
|
|
|
c17bfd |
+int strmGetPrevWasNL(const strm_t *const pThis);
|
|
|
c17bfd |
|
|
|
c17bfd |
#endif /* #ifndef STREAM_H_INCLUDED */
|
|
|
c17bfd |
|