summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/cfsysline.c28
-rw-r--r--runtime/debug.c30
-rw-r--r--runtime/debug.h3
-rw-r--r--runtime/glbl.c27
-rw-r--r--runtime/glbl.h6
-rw-r--r--runtime/msg.c8
-rw-r--r--runtime/msg.h1
-rw-r--r--runtime/queue.c2
-rw-r--r--runtime/rsyslog.h3
-rw-r--r--runtime/sd-daemon.c172
-rw-r--r--runtime/srUtils.h1
-rw-r--r--runtime/srutils.c22
-rw-r--r--runtime/stream.c103
-rw-r--r--runtime/stream.h5
-rw-r--r--runtime/wtp.c2
15 files changed, 334 insertions, 79 deletions
diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c
index 6b06d427..a437b7f8 100644
--- a/runtime/cfsysline.c
+++ b/runtime/cfsysline.c
@@ -350,8 +350,9 @@ static rsRetVal doGetGID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *p
struct group gBuf;
DEFiRet;
uchar szName[256];
- int bufSize = 2048;
+ int bufSize = 1024;
char * stringBuf = NULL;
+ int err;
assert(pp != NULL);
assert(*pp != NULL);
@@ -361,20 +362,21 @@ static rsRetVal doGetGID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *p
ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
-
- CHKmalloc(stringBuf = malloc(bufSize));
- while(pgBuf == NULL) {
- errno = 0;
- getgrnam_r((char*)szName, &gBuf, stringBuf, bufSize, &pgBuf);
- if((pgBuf == NULL) && (errno == ERANGE)) {
- /* Increase bufsize and try again.*/
- bufSize *= 2;
- CHKmalloc(stringBuf = realloc(stringBuf, bufSize));
- }
- }
+ do {
+ /* Increase bufsize and try again.*/
+ bufSize *= 2;
+ CHKmalloc(stringBuf = realloc(stringBuf, bufSize));
+ err = getgrnam_r((char*)szName, &gBuf, stringBuf, bufSize, &pgBuf);
+ } while((pgBuf == NULL) && (err == ERANGE));
if(pgBuf == NULL) {
- errmsg.LogError(0, RS_RET_NOT_FOUND, "ID for group '%s' could not be found or error", (char*)szName);
+ if (err != 0) {
+ rs_strerror_r(err, stringBuf, bufSize);
+ errmsg.LogError(0, RS_RET_NOT_FOUND, "Query for group '%s' resulted in an error: %s\n",
+ (char*)szName, stringBuf);
+ } else {
+ errmsg.LogError(0, RS_RET_NOT_FOUND, "ID for group '%s' could not be found", (char*)szName);
+ }
iRet = RS_RET_NOT_FOUND;
} else {
if(pSetHdlr == NULL) {
diff --git a/runtime/debug.c b/runtime/debug.c
index fa39e7fe..876f61d0 100644
--- a/runtime/debug.c
+++ b/runtime/debug.c
@@ -303,7 +303,7 @@ static inline void dbgFuncDBRemoveMutexLock(dbgFuncDB_t *pFuncDB, pthread_mutex_
void
dbgOutputTID(char* name)
{
-# ifdef HAVE_SYSCALL
+# if defined(HAVE_SYSCALL) && defined(HAVE_SYS_gettid)
if(bOutputTidToStderr)
fprintf(stderr, "thread tid %u, name '%s'\n",
(unsigned)syscall(SYS_gettid), name);
@@ -1315,6 +1315,15 @@ dbgmalloc(size_t size)
}
+/* report fd used for debug log. This is needed in case of
+ * auto-backgrounding, where the debug log shall not be closed.
+ */
+int
+dbgGetDbglogFd(void)
+{
+ return altdbg;
+}
+
/* read in the runtime options
* rgerhards, 2008-02-28
*/
@@ -1398,6 +1407,25 @@ dbgGetRuntimeOptions(void)
}
+void
+dbgSetDebugLevel(int level)
+{
+ Debug = level;
+ debugging_on = (level == DEBUG_FULL) ? 1 : 0;
+}
+
+void
+dbgSetDebugFile(uchar *fn)
+{
+ if(altdbg != -1) {
+ dbgprintf("switching to debug file %s\n", fn);
+ close(altdbg);
+ }
+ if((altdbg = open((char*)fn, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, S_IRUSR|S_IWUSR)) == -1) {
+ fprintf(stderr, "alternate debug file could not be opened, ignoring. Error: %s\n", strerror(errno));
+ }
+}
+
/* end support system to set debug options at runtime */
rsRetVal dbgClassInit(void)
diff --git a/runtime/debug.h b/runtime/debug.h
index f802e8c1..f3226098 100644
--- a/runtime/debug.h
+++ b/runtime/debug.h
@@ -89,6 +89,8 @@ typedef struct dbgCallStack_s {
/* prototypes */
rsRetVal dbgClassInit(void);
rsRetVal dbgClassExit(void);
+void dbgSetDebugFile(uchar *fn);
+void dbgSetDebugLevel(int level);
void sigsegvHdlr(int signum);
void dbgoprint(obj_t *pObj, char *fmt, ...) __attribute__((format(printf, 2, 3)));
void dbgprintf(char *fmt, ...) __attribute__((format(printf, 1, 2)));
@@ -105,6 +107,7 @@ void dbgSetThrdName(uchar *pszName);
void dbgPrintAllDebugInfo(void);
void *dbgmalloc(size_t size);
void dbgOutputTID(char* name);
+int dbgGetDbglogFd(void);
/* macros */
#ifdef DEBUGLESS
diff --git a/runtime/glbl.c b/runtime/glbl.c
index 0e5cac20..b3fe3a1d 100644
--- a/runtime/glbl.c
+++ b/runtime/glbl.c
@@ -7,7 +7,7 @@
*
* Module begun 2008-04-16 by Rainer Gerhards
*
- * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2008-2013 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -82,6 +82,7 @@ static uchar *pszDfltNetstrmDrvrCAF = NULL; /* default CA file for the netstrm d
static uchar *pszDfltNetstrmDrvrKeyFile = NULL; /* default key file for the netstrm driver (server) */
static uchar *pszDfltNetstrmDrvrCertFile = NULL; /* default cert file for the netstrm driver (server) */
static int bTerminateInputs = 0; /* global switch that inputs shall terminate ASAP (1=> terminate) */
+pid_t glbl_ourpid;
#ifndef HAVE_ATOMIC_BUILTINS
static DEF_ATOMIC_HELPER_MUT(mutTerminateInputs);
#endif
@@ -278,6 +279,28 @@ finalize_it:
RETiRet;
}
+
+static rsRetVal
+setDebugFile(void __attribute__((unused)) *pVal, uchar *pNewVal)
+{
+ DEFiRet;
+ dbgSetDebugFile(pNewVal);
+ free(pNewVal);
+ RETiRet;
+}
+
+
+static rsRetVal
+setDebugLevel(void __attribute__((unused)) *pVal, int level)
+{
+ DEFiRet;
+ dbgSetDebugLevel(level);
+ dbgprintf("debug level %d set via config file\n", level);
+ dbgprintf("This is rsyslog version " VERSION "\n");
+ RETiRet;
+}
+
+
/* return our local IP.
* If no local IP is set, "127.0.0.1" is selected *and* set. This
* is an intensional side effect that we do in order to keep things
@@ -610,6 +633,8 @@ BEGINAbstractObjClassInit(glbl, 1, OBJ_IS_CORE_MODULE) /* class, version */
CHKiRet(objUse(errmsg, CORE_COMPONENT));
/* config handlers are never unregistered and need not be - we are always loaded ;) */
+ CHKiRet(regCfSysLineHdlr((uchar *)"debugfile", 0, eCmdHdlrGetWord, setDebugFile, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"debuglevel", 0, eCmdHdlrInt, setDebugLevel, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, setWorkDir, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"dropmsgswithmaliciousdnsptrrecords", 0, eCmdHdlrBinary, NULL, &bDropMalPTRMsgs, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriver", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvr, NULL));
diff --git a/runtime/glbl.h b/runtime/glbl.h
index d2d1e66a..e95e48f7 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -30,11 +30,14 @@
#ifndef GLBL_H_INCLUDED
#define GLBL_H_INCLUDED
+#include <sys/types.h>
#include "rainerscript.h"
#include "prop.h"
#define glblGetIOBufSize() 4096 /* size of the IO buffer, e.g. for strm class */
+extern pid_t glbl_ourpid;
+
/* interfaces */
BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
uchar* (*GetWorkDir)(void);
@@ -86,6 +89,9 @@ ENDinterface(glbl)
/* the remaining prototypes */
PROTOTYPEObj(glbl);
+static inline pid_t glblGetOurPid(void) { return glbl_ourpid; }
+static inline void glblSetOurPid(pid_t pid) { glbl_ourpid = pid; }
+
void glblPrepCnf(void);
void glblProcessCnf(struct cnfobj *o);
void glblDoneLoadCnf(void);
diff --git a/runtime/msg.c b/runtime/msg.c
index 68577ad0..c302a050 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -1468,6 +1468,14 @@ getRawMsg(msg_t *pM, uchar **pBuf, int *piLen)
}
+/* note: setMSGLen() is only for friends who really know what they
+ * do. Setting an invalid length can be desasterous!
+ */
+void setMSGLen(msg_t *pM, int lenMsg)
+{
+ pM->iLenMSG = lenMsg;
+}
+
int getMSGLen(msg_t *pM)
{
return((pM == NULL) ? 0 : pM->iLenMSG);
diff --git a/runtime/msg.h b/runtime/msg.h
index 564441b6..edf5ed98 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -198,6 +198,7 @@ uchar *getMSG(msg_t *pM);
char *getHOSTNAME(msg_t *pM);
char *getPROCID(msg_t *pM, sbool bLockMutex);
char *getAPPNAME(msg_t *pM, sbool bLockMutex);
+void setMSGLen(msg_t *pM, int lenMsg);
int getMSGLen(msg_t *pM);
char *getHOSTNAME(msg_t *pM);
diff --git a/runtime/queue.c b/runtime/queue.c
index 6df1c95e..4c8d3ac5 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -1356,7 +1356,7 @@ qqueueSetDefaultsActionQueue(qqueue_t *pThis)
pThis->iDeqBatchSize = 128; /* default batch size */
pThis->iHighWtrMrk = 800; /* high water mark for disk-assisted queues */
pThis->iLowWtrMrk = 200; /* low water mark for disk-assisted queues */
- pThis->iDiscardMrk = 9800; /* begin to discard messages */
+ pThis->iDiscardMrk = 980; /* begin to discard messages */
pThis->iDiscardSeverity = 8; /* turn off */
pThis->iNumWorkerThreads = 1; /* number of worker threads for the mm queue above */
pThis->iMaxFileSize = 1024*1024;
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 42c61579..5ba6ede7 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -399,6 +399,9 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_DS_PROP_SEQ_ERR = -2308,/**< property sequence error deserializing object */
RS_RET_TPL_INVLD_PROP = -2309,/**< property name error in template (unknown name) */
RS_RET_NO_RULEBASE = -2310,/**< mmnormalize: rulebase can not be found or otherwise invalid */
+ RS_RET_INVLD_MODE = -2311,/**< invalid mode specified in configuration */
+ RS_RET_INVLD_ANON_BITS = -2312,/**< mmanon: invalid number of bits to anonymize specified */
+ RS_RET_REPLCHAR_IGNORED = -2313,/**< mmanon: replacementChar parameter is ignored */
RS_RET_SIGPROV_ERR = -2320,/**< error in signature provider */
/* RainerScript error messages (range 1000.. 1999) */
diff --git a/runtime/sd-daemon.c b/runtime/sd-daemon.c
index 9c23b917..79d8ca37 100644
--- a/runtime/sd-daemon.c
+++ b/runtime/sd-daemon.c
@@ -25,14 +25,18 @@
***/
#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
+# define _GNU_SOURCE
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/fcntl.h>
+#ifdef __BIONIC__
+# include <linux/fcntl.h>
+#else
+# include <sys/fcntl.h>
+#endif
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
@@ -40,10 +44,28 @@
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
+#include <stddef.h>
+#include <limits.h>
+
+#if defined(__linux__)
+# include <mqueue.h>
+#endif
#include "sd-daemon.h"
-int sd_listen_fds(int unset_environment) {
+#if (__GNUC__ >= 4)
+# ifdef SD_EXPORT_SYMBOLS
+/* Export symbols */
+# define _sd_export_ __attribute__ ((visibility("default")))
+# else
+/* Don't export the symbols */
+# define _sd_export_ __attribute__ ((visibility("hidden")))
+# endif
+#else
+# define _sd_export_
+#endif
+
+_sd_export_ int sd_listen_fds(int unset_environment) {
#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
return 0;
@@ -53,7 +75,8 @@ int sd_listen_fds(int unset_environment) {
char *p = NULL;
unsigned long l;
- if (!(e = getenv("LISTEN_PID"))) {
+ e = getenv("LISTEN_PID");
+ if (!e) {
r = 0;
goto finish;
}
@@ -66,7 +89,7 @@ int sd_listen_fds(int unset_environment) {
goto finish;
}
- if (!p || *p || l <= 0) {
+ if (!p || p == e || *p || l <= 0) {
r = -EINVAL;
goto finish;
}
@@ -77,7 +100,8 @@ int sd_listen_fds(int unset_environment) {
goto finish;
}
- if (!(e = getenv("LISTEN_FDS"))) {
+ e = getenv("LISTEN_FDS");
+ if (!e) {
r = 0;
goto finish;
}
@@ -90,7 +114,7 @@ int sd_listen_fds(int unset_environment) {
goto finish;
}
- if (!p || *p) {
+ if (!p || p == e || *p) {
r = -EINVAL;
goto finish;
}
@@ -98,7 +122,8 @@ int sd_listen_fds(int unset_environment) {
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
int flags;
- if ((flags = fcntl(fd, F_GETFD)) < 0) {
+ flags = fcntl(fd, F_GETFD);
+ if (flags < 0) {
r = -errno;
goto finish;
}
@@ -124,13 +149,12 @@ finish:
#endif
}
-int sd_is_fifo(int fd, const char *path) {
+_sd_export_ int sd_is_fifo(int fd, const char *path) {
struct stat st_fd;
if (fd < 0)
return -EINVAL;
- memset(&st_fd, 0, sizeof(st_fd));
if (fstat(fd, &st_fd) < 0)
return -errno;
@@ -140,7 +164,6 @@ int sd_is_fifo(int fd, const char *path) {
if (path) {
struct stat st_path;
- memset(&st_path, 0, sizeof(st_path));
if (stat(path, &st_path) < 0) {
if (errno == ENOENT || errno == ENOTDIR)
@@ -157,6 +180,42 @@ int sd_is_fifo(int fd, const char *path) {
return 1;
}
+_sd_export_ int sd_is_special(int fd, const char *path) {
+ struct stat st_fd;
+
+ if (fd < 0)
+ return -EINVAL;
+
+ if (fstat(fd, &st_fd) < 0)
+ return -errno;
+
+ if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
+ return 0;
+
+ if (path) {
+ struct stat st_path;
+
+ if (stat(path, &st_path) < 0) {
+
+ if (errno == ENOENT || errno == ENOTDIR)
+ return 0;
+
+ return -errno;
+ }
+
+ if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
+ return
+ st_path.st_dev == st_fd.st_dev &&
+ st_path.st_ino == st_fd.st_ino;
+ else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
+ return st_path.st_rdev == st_fd.st_rdev;
+ else
+ return 0;
+ }
+
+ return 1;
+}
+
static int sd_is_socket_internal(int fd, int type, int listening) {
struct stat st_fd;
@@ -208,13 +267,14 @@ union sockaddr_union {
struct sockaddr_storage storage;
};
-int sd_is_socket(int fd, int family, int type, int listening) {
+_sd_export_ int sd_is_socket(int fd, int family, int type, int listening) {
int r;
if (family < 0)
return -EINVAL;
- if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
+ r = sd_is_socket_internal(fd, type, listening);
+ if (r <= 0)
return r;
if (family > 0) {
@@ -236,7 +296,7 @@ int sd_is_socket(int fd, int family, int type, int listening) {
return 1;
}
-int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
+_sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
union sockaddr_union sockaddr;
socklen_t l;
int r;
@@ -244,7 +304,8 @@ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port
if (family != 0 && family != AF_INET && family != AF_INET6)
return -EINVAL;
- if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
+ r = sd_is_socket_internal(fd, type, listening);
+ if (r <= 0)
return r;
memset(&sockaddr, 0, sizeof(sockaddr));
@@ -281,12 +342,13 @@ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port
return 1;
}
-int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
+_sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
union sockaddr_union sockaddr;
socklen_t l;
int r;
- if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
+ r = sd_is_socket_internal(fd, type, listening);
+ if (r <= 0)
return r;
memset(&sockaddr, 0, sizeof(sockaddr));
@@ -302,29 +364,66 @@ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t
return 0;
if (path) {
- if (length <= 0)
+ if (length == 0)
length = strlen(path);
- if (length <= 0)
+ if (length == 0)
/* Unnamed socket */
- return l == sizeof(sa_family_t);
+ return l == offsetof(struct sockaddr_un, sun_path);
if (path[0])
/* Normal path socket */
return
- (l >= sizeof(sa_family_t) + length + 1) &&
+ (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
memcmp(path, sockaddr.un.sun_path, length+1) == 0;
else
/* Abstract namespace socket */
return
- (l == sizeof(sa_family_t) + length) &&
+ (l == offsetof(struct sockaddr_un, sun_path) + length) &&
memcmp(path, sockaddr.un.sun_path, length) == 0;
}
return 1;
}
-int sd_notify(int unset_environment, const char *state) {
+_sd_export_ int sd_is_mq(int fd, const char *path) {
+#if !defined(__linux__)
+ return 0;
+#else
+ struct mq_attr attr;
+
+ if (fd < 0)
+ return -EINVAL;
+
+ if (mq_getattr(fd, &attr) < 0)
+ return -errno;
+
+ if (path) {
+ char fpath[PATH_MAX];
+ struct stat a, b;
+
+ if (path[0] != '/')
+ return -EINVAL;
+
+ if (fstat(fd, &a) < 0)
+ return -errno;
+
+ strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
+ fpath[sizeof(fpath)-1] = 0;
+
+ if (stat(fpath, &b) < 0)
+ return -errno;
+
+ if (a.st_dev != b.st_dev ||
+ a.st_ino != b.st_ino)
+ return 0;
+ }
+
+ return 1;
+#endif
+}
+
+_sd_export_ int sd_notify(int unset_environment, const char *state) {
#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
return 0;
#else
@@ -339,7 +438,8 @@ int sd_notify(int unset_environment, const char *state) {
goto finish;
}
- if (!(e = getenv("NOTIFY_SOCKET")))
+ e = getenv("NOTIFY_SOCKET");
+ if (!e)
return 0;
/* Must be an abstract socket, or an absolute path */
@@ -348,7 +448,8 @@ int sd_notify(int unset_environment, const char *state) {
goto finish;
}
- if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+ if (fd < 0) {
r = -errno;
goto finish;
}
@@ -366,7 +467,7 @@ int sd_notify(int unset_environment, const char *state) {
memset(&msghdr, 0, sizeof(msghdr));
msghdr.msg_name = &sockaddr;
- msghdr.msg_namelen = sizeof(sa_family_t) + strlen(e);
+ msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
msghdr.msg_namelen = sizeof(struct sockaddr_un);
@@ -392,7 +493,7 @@ finish:
#endif
}
-int sd_notifyf(int unset_environment, const char *format, ...) {
+_sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) {
#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
return 0;
#else
@@ -414,22 +515,19 @@ int sd_notifyf(int unset_environment, const char *format, ...) {
#endif
}
-int sd_booted(void) {
+_sd_export_ int sd_booted(void) {
#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
return 0;
#else
+ struct stat st;
- struct stat a, b;
-
- /* We simply test whether the systemd cgroup hierarchy is
- * mounted */
-
- if (lstat("/sys/fs/cgroup", &a) < 0)
- return 0;
+ /* We test whether the runtime unit file directory has been
+ * created. This takes place in mount-setup.c, so is
+ * guaranteed to happen very early during boot. */
- if (lstat("/sys/fs/cgroup/systemd", &b) < 0)
+ if (lstat("/run/systemd/system/", &st) < 0)
return 0;
- return a.st_dev != b.st_dev;
+ return !!S_ISDIR(st.st_mode);
#endif
}
diff --git a/runtime/srUtils.h b/runtime/srUtils.h
index 3169fd94..8626a4bb 100644
--- a/runtime/srUtils.h
+++ b/runtime/srUtils.h
@@ -91,6 +91,7 @@ char *rs_strerror_r(int errnum, char *buf, size_t buflen);
int decodeSyslogName(uchar *name, syslogName_t *codetab);
int getSubString(uchar **ppSrc, char *pDst, size_t DstSize, char cSep);
rsRetVal getFileSize(uchar *pszName, off_t *pSize);
+int containsGlobWildcard(char *str);
/* mutex operations */
/* some useful constants */
diff --git a/runtime/srutils.c b/runtime/srutils.c
index 7b485b23..6a509b4a 100644
--- a/runtime/srutils.c
+++ b/runtime/srutils.c
@@ -630,6 +630,28 @@ finalize_it:
RETiRet;
}
+/* Returns 1 if the given string contains a non-escaped glob(3)
+ * wildcard character and 0 otherwise (or if the string is empty).
+ */
+int
+containsGlobWildcard(char *str)
+{
+ char *p;
+ if(!str) {
+ return 0;
+ }
+ /* From Linux Programmer's Guide:
+ * "A string is a wildcard pattern if it contains one of the characters '?', '*' or '['"
+ * "One can remove the special meaning of '?', '*' and '[' by preceding them by a backslash"
+ */
+ for(p = str; *p != '\0'; p++) {
+ if((*p == '?' || *p == '*' || *p == '[') &&
+ (p == str || *(p-1) != '\\')) {
+ return 1;
+ }
+ }
+ return 0;
+}
/* vim:set ai:
*/
diff --git a/runtime/stream.c b/runtime/stream.c
index 3e890c71..00afcdaa 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -81,6 +81,7 @@ static void *asyncWriterThread(void *pPtr);
static rsRetVal doZipWrite(strm_t *pThis, uchar *pBuf, size_t lenBuf, int bFlush);
static rsRetVal doZipFinish(strm_t *pThis);
static rsRetVal strmPhysWrite(strm_t *pThis, uchar *pBuf, size_t lenBuf);
+static rsRetVal strmSeekCurrOffs(strm_t *pThis);
/* methods */
@@ -197,6 +198,7 @@ static rsRetVal
doPhysOpen(strm_t *pThis)
{
int iFlags = 0;
+ struct stat statOpen;
DEFiRet;
ISOBJ_TYPE_assert(pThis, strm);
@@ -234,15 +236,71 @@ doPhysOpen(strm_t *pThis)
ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
else
ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ if(pThis->tOperationsMode == STREAMMODE_READ) {
+ if(fstat(pThis->fd, &statOpen) == -1) {
+ DBGPRINTF("Error: cannot obtain inode# for file %s\n", pThis->pszCurrFName);
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+ pThis->inode = statOpen.st_ino;
+ }
+
+ if(!ustrcmp(pThis->pszCurrFName, UCHAR_CONSTANT(_PATH_CONSOLE)) || isatty(pThis->fd)) {
+ DBGPRINTF("file %d is a tty-type file\n", pThis->fd);
+ pThis->bIsTTY = 1;
} else {
- if(!ustrcmp(pThis->pszCurrFName, UCHAR_CONSTANT(_PATH_CONSOLE)) || isatty(pThis->fd)) {
- DBGPRINTF("file %d is a tty-type file\n", pThis->fd);
- pThis->bIsTTY = 1;
+ pThis->bIsTTY = 0;
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+static rsRetVal
+strmSetCurrFName(strm_t *pThis)
+{
+ DEFiRet;
+
+ if(pThis->sType == STREAMTYPE_FILE_CIRCULAR) {
+ CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
+ pThis->pszFName, pThis->lenFName, pThis->iCurrFNum, pThis->iFileNumDigits));
+ } else {
+ if(pThis->pszDir == NULL) {
+ if((pThis->pszCurrFName = ustrdup(pThis->pszFName)) == NULL)
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
} else {
- pThis->bIsTTY = 0;
+ CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
+ pThis->pszFName, pThis->lenFName, -1, 0));
}
}
+finalize_it:
+ RETiRet;
+}
+
+/* This function checks if the actual file has changed and, if so, resets the
+ * offset. This is support for monitoring files. It should be called after
+ * deserializing the strm object and before doing any other operation on it
+ * (most importantly not an open or seek!).
+ */
+static rsRetVal
+CheckFileChange(strm_t *pThis)
+{
+ struct stat statName;
+ DEFiRet;
+ CHKiRet(strmSetCurrFName(pThis));
+ if(stat((char*) pThis->pszCurrFName, &statName) == -1)
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ DBGPRINTF("stream/after deserialize checking for file change on '%s', "
+ "inode %u/%u, size/currOffs %llu/%llu\n",
+ pThis->pszCurrFName, (unsigned) pThis->inode,
+ (unsigned) statName.st_ino, statName.st_size, pThis->iCurrOffs);
+ if(pThis->inode != statName.st_ino || statName.st_size < pThis->iCurrOffs) {
+ DBGPRINTF("stream: file %s has changed\n", pThis->pszCurrFName);
+ pThis->iCurrOffs = 0;
+ }
finalize_it:
RETiRet;
}
@@ -265,19 +323,8 @@ static rsRetVal strmOpenFile(strm_t *pThis)
if(pThis->pszFName == NULL)
ABORT_FINALIZE(RS_RET_FILE_PREFIX_MISSING);
- if(pThis->sType == STREAMTYPE_FILE_CIRCULAR) {
- CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
- pThis->pszFName, pThis->lenFName, pThis->iCurrFNum, pThis->iFileNumDigits));
- } else {
- if(pThis->pszDir == NULL) {
- if((pThis->pszCurrFName = ustrdup(pThis->pszFName)) == NULL)
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
- } else {
- CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
- pThis->pszFName, pThis->lenFName, -1, 0));
- }
- }
-
+ CHKiRet(strmSetCurrFName(pThis));
+
CHKiRet(doPhysOpen(pThis));
pThis->iCurrOffs = 0;
@@ -357,6 +404,7 @@ static rsRetVal strmCloseFile(strm_t *pThis)
if(pThis->fd != -1) {
close(pThis->fd);
pThis->fd = -1;
+ pThis->inode = 0;
}
if(pThis->fdDir != -1) {
@@ -432,18 +480,15 @@ static rsRetVal
strmHandleEOFMonitor(strm_t *pThis)
{
DEFiRet;
- struct stat statOpen;
struct stat statName;
ISOBJ_TYPE_assert(pThis, strm);
- if(fstat(pThis->fd, &statOpen) == -1)
- ABORT_FINALIZE(RS_RET_IO_ERROR);
if(stat((char*) pThis->pszCurrFName, &statName) == -1)
ABORT_FINALIZE(RS_RET_IO_ERROR);
- DBGPRINTF("stream checking for file change on '%s', inode %u/%u",
- pThis->pszCurrFName, (unsigned) statOpen.st_ino,
+ DBGPRINTF("stream checking for file change on '%s', inode %u/%u\n",
+ pThis->pszCurrFName, (unsigned) pThis->inode,
(unsigned) statName.st_ino);
- if(statOpen.st_ino == statName.st_ino) {
+ if(pThis->inode == statName.st_ino) {
ABORT_FINALIZE(RS_RET_EOF);
} else {
/* we had a file change! */
@@ -1343,7 +1388,11 @@ static rsRetVal strmSeek(strm_t *pThis, off64_t offs)
}
long long i;
DBGOPRINT((obj_t*) pThis, "file %d seek, pos %llu\n", pThis->fd, (long long unsigned) offs);
- i = lseek64(pThis->fd, offs, SEEK_SET); // TODO: check error!
+ i = lseek64(pThis->fd, offs, SEEK_SET);
+ if(i != offs) {
+ DBGPRINTF("strmSeek: error %lld seeking to offset %lld\n", i, offs);
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
pThis->iCurrOffs = offs; /* we are now at *this* offset */
pThis->iBufPtr = 0; /* buffer invalidated */
@@ -1697,6 +1746,9 @@ static rsRetVal strmSerialize(strm_t *pThis, strm_t *pStrm)
l = pThis->iCurrOffs;
objSerializeSCALAR_VAR(pStrm, iCurrOffs, INT64, l);
+ l = pThis->inode;
+ objSerializeSCALAR_VAR(pStrm, inode, INT64, l);
+
objSerializePTR(pStrm, prevLineSegment, PSZ);
CHKiRet(obj.EndSerialize(pStrm));
@@ -1796,6 +1848,8 @@ static rsRetVal strmSetProperty(strm_t *pThis, var_t *pProp)
CHKiRet(strmSettOpenMode(pThis, pProp->val.num));
} else if(isProp("iCurrOffs")) {
pThis->iCurrOffs = pProp->val.num;
+ } else if(isProp("inode")) {
+ pThis->inode = (ino_t) pProp->val.num;
} else if(isProp("iMaxFileSize")) {
CHKiRet(strmSetiMaxFileSize(pThis, pProp->val.num));
} else if(isProp("iMaxFiles")) {
@@ -1865,6 +1919,7 @@ CODESTARTobjQueryInterface(strm)
pIf->GetCurrOffset = strmGetCurrOffset;
pIf->Dup = strmDup;
pIf->SetWCntr = strmSetWCntr;
+ pIf->CheckFileChange = CheckFileChange;
/* set methods */
pIf->SetbDeleteOnClose = strmSetbDeleteOnClose;
pIf->SetiMaxFileSize = strmSetiMaxFileSize;
diff --git a/runtime/stream.h b/runtime/stream.h
index b7e74074..b7cc6d36 100644
--- a/runtime/stream.h
+++ b/runtime/stream.h
@@ -112,6 +112,7 @@ typedef struct strm_s {
int lenDir;
int fd; /* the file descriptor, -1 if closed */
int fdDir; /* the directory's descriptor, in case bSync is requested (-1 if closed) */
+ ino_t inode; /* current inode for files being monitored (undefined else) */
uchar *pszCurrFName; /* name of current file (if open) */
uchar *pIOBuf; /* the iobuffer currently in use to gather data */
size_t iBufPtrMax; /* current max Ptr in Buffer (if partial read!) */
@@ -187,8 +188,10 @@ BEGINinterface(strm) /* name must also be changed in ENDinterface macro! */
rsRetVal (*ReadLine)(strm_t *pThis, cstr_t **ppCStr, int mode);
/* v7 added 2012-09-14 */
INTERFACEpropSetMeth(strm, bVeryReliableZip, int);
+ /* v8 added 2013-03-21 */
+ rsRetVal (*CheckFileChange)(strm_t *pThis);
ENDinterface(strm)
-#define strmCURR_IF_VERSION 7 /* increment whenever you change the interface structure! */
+#define strmCURR_IF_VERSION 8 /* increment whenever you change the interface structure! */
static inline int
strmGetCurrFileNum(strm_t *pStrm) {
diff --git a/runtime/wtp.c b/runtime/wtp.c
index f8d3588b..19151e7c 100644
--- a/runtime/wtp.c
+++ b/runtime/wtp.c
@@ -381,9 +381,9 @@ wtpWorker(void *arg) /* the arg is actually a wti object, even though we are in
if(prctl(PR_SET_NAME, thrdName, 0, 0, 0) != 0) {
DBGPRINTF("prctl failed, not setting thread name for '%s'\n", wtpGetDbgHdr(pThis));
}
+ dbgOutputTID((char*)thrdName);
# endif
- dbgOutputTID((char*)thrdName);
pthread_cleanup_push(wtpWrkrExecCancelCleanup, pWti);
wtiWorker(pWti);
pthread_cleanup_pop(0);