summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS9
-rw-r--r--doc/manual.html7
-rw-r--r--doc/status.html6
-rwxr-xr-xstringbuf.c121
-rwxr-xr-xstringbuf.h3
-rw-r--r--syslogd.c72
-rw-r--r--version.h2
7 files changed, 172 insertions, 48 deletions
diff --git a/NEWS b/NEWS
index 7d558f74..7e0bd578 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,13 @@
---------------------------------------------------------------------------
+Version 1.10.2 (RGer), 2005-09-2?
+- added the "isequal" comparison operation in property-based filters
+- added ability to negate all property-based filter comparison oprations
+ by adding a !-sign right in front of the operation name
+- fixed a bug that caused rsyslogd to dump core when the compare value
+ was not quoted in property-based filters
+- fixed a bug in the new CStr compare function which lead to invalid
+ results (fortunately, this function was not yet used widely)
+---------------------------------------------------------------------------
Version 1.10.1 (RGer), 2005-09-23
- added the ability to execute a shell script as an action.
Thanks to Bjoern Kalkbrenner for providing the code!
diff --git a/doc/manual.html b/doc/manual.html
index d1bcfd57..5025c8e8 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -5,8 +5,9 @@
<body>
<h1>RSyslog - Documentation</h1>
<p><b><a href="http://www.rsyslog.com/">Rsyslog</a> is an enhanced syslogd
-supporting, among others, <a href="rsyslog_mysql.html">MySQL</a>, syslog/tcp
-and fine grain output format control.</b> It is quite compatible to stock
+supporting, among others, <a href="rsyslog_mysql.html">MySQL</a>, syslog/tcp,
+fine grain output format control, and the ability to filter on any message part.</b>
+It is quite compatible to stock
sysklogd and can be used as a drop-in replacement. Its <a href="features.html">
advanced features</a> make it suitable for enterprise-class,
<a href="rsyslog_stunnel.html">encryption protected syslog</a>
@@ -50,4 +51,4 @@ If you are interested in the &quot;backstage&quot;, you may find
<a href="http://www.adiscon.com/en/people/rainer-gerhards.php">Rainer</a>'s
<a href="http://rgerhards.blogspot.com/">syslog blog</a> an interesting read.</p>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/doc/status.html b/doc/status.html
index 9d12e4d1..245e1f5f 100644
--- a/doc/status.html
+++ b/doc/status.html
@@ -4,10 +4,10 @@
</head>
<body>
<h2>rsyslog status page</h2>
-<p>This page reflects the status as of 2005-09-20.</p>
+<p>This page reflects the status as of 2005-09-27.</p>
<h2>Current Releases</h2>
-<p><b>development:</b> 1.10.1 - <a href="http://www.rsyslog.com/Article36.phtml">change log</a> -
-<a href="http://www.rsyslog.com/Downloads-index-req-getit-lid-18.phtml">download</a></p>
+<p><b>development:</b> 1.10.2 - <a href="http://www.rsyslog.com/Article38.phtml">change log</a> -
+<a href="http://www.rsyslog.com/Downloads-index-req-getit-lid-19.phtml">download</a></p>
<p><b>stable:</b> 1.0.1 - <a href="http://www.rsyslog.com/Article34.phtml">change log</a> -
<a href="http://www.rsyslog.com/Downloads-index-req-getit-lid-17.phtml">download</a></p>
<p>&nbsp;(<a href="version_naming.html">How are versions named?</a>)</p>
diff --git a/stringbuf.c b/stringbuf.c
index 85763f27..1f6d6316 100755
--- a/stringbuf.c
+++ b/stringbuf.c
@@ -343,6 +343,9 @@ rsRetVal rsCStrTrimTrailingWhiteSpace(rsCStrObj *pThis)
* faster in the majority of cases, simply because it can
* rely on StrLen.
* rgerhards 2005-09-19
+ * fixed bug, in which only the last byte was actually compared
+ * in equal-size strings.
+ * rgerhards, 2005-09-26
*/
int rsCStrCStrCmp(rsCStrObj *pCS1, rsCStrObj *pCS2)
{
@@ -351,37 +354,113 @@ int rsCStrCStrCmp(rsCStrObj *pCS1, rsCStrObj *pCS2)
if(pCS1->iStrLen == pCS2->iStrLen)
if(pCS1->iStrLen == 0)
return 0; /* zero-sized string are equal ;) */
- else
- return pCS1->pBuf[pCS1->iStrLen - 1]
- - pCS2->pBuf[pCS2->iStrLen - 1];
+ else { /* we now have two non-empty strings of equal
+ * length, so we need to actually check if they
+ * are equal.
+ */
+ register int i;
+ for(i = 0 ; i < pCS1->iStrLen ; ++i) {
+ if(pCS1->pBuf[i] != pCS2->pBuf[i])
+ return pCS1->pBuf[i] - pCS2->pBuf[i];
+ }
+ /* if we arrive here, the strings are equal */
+ return 0;
+ }
else
return pCS1->iStrLen - pCS2->iStrLen;
}
-/* compare a string object with a classical zero-terminated C-string.
- * this function is primarily meant to support comparisons with constants.
- * It should not be used for variables (except with a very good reason).
- * rgerhards 2005-09-19
+
+/* compare a rsCStr object with a classical sz string. This function
+ * is almost identical to rsCStrZsStrCmp(), but it also takes an offset
+ * to the CStr object from where the comparison is to start.
+ * I have thought quite a while if it really makes sense to more or
+ * less duplicate the code. After all, if you call it with an offset of
+ * zero, the functionality is exactly the same. So it looks natural to
+ * just have a single function. However, supporting the offset requires
+ * some (few) additional integer operations. While they are few, they
+ * happen at places in the code that is run very frequently. All in all,
+ * I have opted for performance and thus duplicated the code. I hope
+ * this is a good, or at least acceptable, compromise.
+ * rgerhards, 2005-09-26
+ * This function also has an offset-pointer which allows to
+ * specify *where* the compare operation should begin in
+ * the CStr. If everything is to be compared, it must be set
+ * to 0. If some leading bytes are to be skipped, it must be set
+ * to the first index that is to be compared. It must not be
+ * set higher than the string length (this is considered a
+ * program bug and will lead to unpredictable results and program aborts).
+ * rgerhards 2005-09-26
*/
-int rsCStrSzCmp(rsCStrObj *pCStr, char *sz)
+int rsCStrOffsetSzStrCmp(rsCStrObj *pCS1, int iOffset, char *psz, int iLenSz)
{
- int iszLen;
-
- rsCHECKVALIDOBJECT(pCStr, OIDrsCStr);
- assert(sz != NULL);
+ rsCHECKVALIDOBJECT(pCS1, OIDrsCStr);
+ assert(iOffset >= 0);
+ assert(iOffset < pCS1->iStrLen);
+ assert(psz != NULL);
+ assert(iLenSz == strlen(psz)); /* just make sure during debugging! */
+ if((pCS1->iStrLen - iOffset) == iLenSz) {
+ /* we are using iLenSz below, because the lengths
+ * are equal and iLenSz is faster to access
+ */
+ if(iLenSz == 0)
+ return 0; /* zero-sized strings are equal ;) */
+ else { /* we now have two non-empty strings of equal
+ * length, so we need to actually check if they
+ * are equal.
+ */
+ register int i;
+ for(i = 0 ; i < iLenSz ; ++i) {
+ if(pCS1->pBuf[i+iOffset] != psz[i])
+ return pCS1->pBuf[i+iOffset] - psz[i];
+ }
+ /* if we arrive here, the strings are equal */
+ return 0;
+ }
+ }
+ else
+ return pCS1->iStrLen - iOffset - iLenSz;
+}
- iszLen = strlen(sz);
- if(pCStr->iStrLen == iszLen)
- /* note: we are using iszLen below, because it doesn't matter
- * and the simple integer is faster to derefence...
+/* compare a rsCStr object with a classical sz string.
+ * Just like rsCStrCStrCmp, just for a different data type.
+ * There must not only the sz string but also its length be
+ * provided. If the caller does not know the length he can
+ * call with
+ * rsCstrSzStrCmp(pCS, psz, strlen(psz));
+ * we are not doing the strlen() ourselfs as the caller might
+ * already know the length and in such cases we can save the
+ * overhead of doing it one more time (strelen() is costly!).
+ * The bottom line is that the provided length MUST be correct!
+ * The to sz string pointer must not be NULL!
+ * rgerhards 2005-09-26
+ */
+int rsCStrSzStrCmp(rsCStrObj *pCS1, char *psz, int iLenSz)
+{
+ rsCHECKVALIDOBJECT(pCS1, OIDrsCStr);
+ assert(psz != NULL);
+ assert(iLenSz == strlen(psz)); /* just make sure during debugging! */
+ if(pCS1->iStrLen == iLenSz)
+ /* we are using iLenSz below, because the lengths
+ * are equal and iLenSz is faster to access
*/
- if(iszLen == 0)
- return 0; /* zero-sized string are equal ;) */
- else
- return pCStr->pBuf[iszLen - 1] - sz[iszLen - 1];
+ if(iLenSz == 0)
+ return 0; /* zero-sized strings are equal ;) */
+ else { /* we now have two non-empty strings of equal
+ * length, so we need to actually check if they
+ * are equal.
+ */
+ register int i;
+ for(i = 0 ; i < iLenSz ; ++i) {
+ if(pCS1->pBuf[i] != psz[i])
+ return pCS1->pBuf[i] - psz[i];
+ }
+ /* if we arrive here, the strings are equal */
+ return 0;
+ }
else
- return pCStr->iStrLen - iszLen;
+ return pCS1->iStrLen - iLenSz;
}
diff --git a/stringbuf.h b/stringbuf.h
index 053f10c7..a5e99392 100755
--- a/stringbuf.h
+++ b/stringbuf.h
@@ -103,7 +103,8 @@ rsRetVal rsCStrAppendInt(rsCStrObj *pThis, int i);
char* rsCStrGetSzStr(rsCStrObj *pThis);
char* rsCStrConvSzStrAndDestruct(rsCStrObj *pThis);
int rsCStrCStrCmp(rsCStrObj *pCS1, rsCStrObj *pCS2);
-int rsCStrSzCmp(rsCStrObj *pCStr, char *sz);
+int rsCStrSzStrCmp(rsCStrObj *pCS1, char *psz, int iLenSz);
+int rsCStrOffsetSzStrCmp(rsCStrObj *pCS1, int iOffset, char *psz, int iLenSz);
int rsCStrLocateSzStr(rsCStrObj *pCStr, char *sz);
int rsCStrLocateInSzStr(rsCStrObj *pThis, char *sz);
diff --git a/syslogd.c b/syslogd.c
index cec310f4..02cd5b54 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -487,8 +487,10 @@ struct filed {
enum {
FIOP_NOP = 0, /* do not use - No Operation */
FIOP_CONTAINS = 1, /* contains string? */
+ FIOP_ISEQUAL = 2, /* is (exactly) equal? */
} operation;
rsCStrObj *pCSCompValue; /* value to "compare" against */
+ char isNegated; /* actually a boolean ;) */
} prop;
} f_filterData;
union {
@@ -2799,7 +2801,7 @@ int main(argc, argv)
logerror("recvfrom inet");
/* should be harmless now that we set
* BSDCOMPAT on the socket */
- sleep(10);
+ sleep(1);
}
}
@@ -3320,11 +3322,19 @@ int shouldProcessThisMessage(struct filed *f, struct msg *pMsg)
if(f->f_filterData.prop.operation == FIOP_CONTAINS) {
if(rsCStrLocateInSzStr(f->f_filterData.prop.pCSCompValue, pszPropVal) != -1)
iRet = 1;
+ } else if(f->f_filterData.prop.operation == FIOP_ISEQUAL) {
+ if(rsCStrSzStrCmp(f->f_filterData.prop.pCSCompValue,
+ pszPropVal, strlen(pszPropVal)) == 0)
+ iRet = 1; /* process message! */
} else { /* here, it handles NOP (for performance reasons) */
assert(f->f_filterData.prop.operation == FIOP_NOP);
iRet = 1; /* as good as any other default ;) */
}
+ /* now check if the value must be negated */
+ if(f->f_filterData.prop.isNegated)
+ iRet = (iRet == 1) ? 0 : 1;
+
/* cleanup */
if(pbMustBeFreed)
free(pszPropVal);
@@ -3524,6 +3534,14 @@ void logmsg(int pri, struct msg *pMsg, int flags)
}
for (f = Files; f; f = f->f_next) {
+ /* first, we need to check if this is a disabled (F_UNUSED)
+ * entry. If so, we must not further process it, as the data
+ * structure probably contains invalid pointers and other
+ * such mess.
+ * rgerhards 2005-09-26
+ */
+ if(f->f_type == F_UNUSED)
+ continue; /* on to next */
/* This is actually the "filter logic". Looks like we need
* to improve it a little for complex selector line conditions. We
@@ -3534,8 +3552,10 @@ void logmsg(int pri, struct msg *pMsg, int flags)
* of this, I am moving the actual decision code to outside this function.
* 2005-09-19 rgerhards
*/
- if(!shouldProcessThisMessage(f, pMsg))
+ if(!shouldProcessThisMessage(f, pMsg)) {
+ dprintf("message filter does not match - ignore this selector line\n");
continue;
+ }
/* We now need to check a special case - F_DISCARD. If that
* action is specified in the selector line, no futher processing
@@ -3854,20 +3874,6 @@ void iovCreate(struct filed *f)
}
}
#endif /* debug aid */
-#if 0
- /* almost done - just let's check how we need to terminate
- * the message.
- */
- dprintf(" %s\n", f->f_un.f_fname);
- if (f->f_type == F_TTY || f->f_type == F_CONSOLE) {
- v->iov_base = "\r\n";
- v->iov_len = 2;
- } else {
- v->iov_base = "\n";
- v->iov_len = 1;
- }
-
-#endif
return;
}
@@ -4148,7 +4154,7 @@ void fprintlog(register struct filed *f, int flags)
case F_TTY:
case F_FILE:
case F_PIPE:
- dprintf("\n");
+ dprintf("(%s)\n", f->f_un.f_fname);
/* TODO: check if we need f->f_time = now;*/
/* f->f_file == -1 is an indicator that the we couldn't
open the file at startup. */
@@ -4959,10 +4965,14 @@ void init()
printf("\tProperty.: '%s'\n",
rsCStrGetSzStr(f->f_filterData.prop.pCSPropName));
printf("\tOperation: ");
+ if(f->f_filterData.prop.isNegated)
+ printf("NOT ");
if(f->f_filterData.prop.operation == FIOP_NOP)
printf("'NOP'");
else if(f->f_filterData.prop.operation == FIOP_CONTAINS)
printf("'contains'");
+ else if(f->f_filterData.prop.operation == FIOP_ISEQUAL)
+ printf("'isequal'");
else
printf("'ERROR - invalid filter type!'");
printf("\n");
@@ -5410,6 +5420,7 @@ rsRetVal cflineProcessPropFilter(char **pline, register struct filed *f)
rsCStrObj *pCSLine;
rsCStrObj *pCSCompOp;
rsRetVal iRet;
+ int iOffset; /* for compare operations */
assert(pline != NULL);
assert(*pline != NULL);
@@ -5457,8 +5468,29 @@ rsRetVal cflineProcessPropFilter(char **pline, register struct filed *f)
RSFREEOBJ(pCSLine);
return(iRet);
}
- if(!rsCStrSzCmp(pCSCompOp, "contains")) {
+
+ /* we now first check if the condition is to be negated. To do so, we first
+ * must make sure we have at least one char in the param and then check the
+ * first one.
+ * rgerhards, 2005-09-26
+ */
+ if(rsCStrLen(pCSCompOp) > 0) {
+ if(*rsCStrGetBufBeg(pCSCompOp) == '!') {
+ f->f_filterData.prop.isNegated = 1;
+ iOffset = 1; /* ignore '!' */
+ } else {
+ f->f_filterData.prop.isNegated = 0;
+ iOffset = 0;
+ }
+ } else {
+ f->f_filterData.prop.isNegated = 0;
+ iOffset = 0;
+ }
+
+ if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, "contains", 8)) {
f->f_filterData.prop.operation = FIOP_CONTAINS;
+ } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, "isequal", 7)) {
+ f->f_filterData.prop.operation = FIOP_ISEQUAL;
} else {
logerrorSz("error: invalid compare operation '%s' - ignoring selector",
rsCStrGetSzStr(pCSCompOp));
@@ -5534,8 +5566,10 @@ rsRetVal cfline(char *line, register struct filed *f)
}
/* check if that went well... */
- if(iRet != RS_RET_OK)
+ if(iRet != RS_RET_OK) {
+ f->f_type = F_UNUSED;
return iRet;
+ }
if (*p == '-')
{
diff --git a/version.h b/version.h
index 2cbe0878..b7a684d7 100644
--- a/version.h
+++ b/version.h
@@ -1,2 +1,2 @@
#define VERSION "1.10"
-#define PATCHLEVEL "1"
+#define PATCHLEVEL "2"