summaryrefslogtreecommitdiffstats
path: root/cfsysline.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfsysline.c')
-rw-r--r--cfsysline.c360
1 files changed, 273 insertions, 87 deletions
diff --git a/cfsysline.c b/cfsysline.c
index c4d81438..1fd03a46 100644
--- a/cfsysline.c
+++ b/cfsysline.c
@@ -3,21 +3,20 @@
*
* File begun on 2007-07-30 by RGerhards
*
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
+ * This file is part of rsyslog.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
+ * Rsyslog is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
*
* A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
@@ -35,10 +34,15 @@
#include "syslogd.h" /* TODO: when the module interface & library design is done, this should be able to go away */
#include "cfsysline.h"
+#include "obj.h"
+#include "errmsg.h"
#include "srUtils.h"
/* static data */
+DEFobjCurrIf(obj)
+DEFobjCurrIf(errmsg)
+
linkedList_t llCmdList; /* this is NOT a pointer - no typo here ;) */
/* --------------- START functions for handling canned syntaxes --------------- */
@@ -61,7 +65,7 @@ static rsRetVal doGetChar(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *
/* if we are not at a '\0', we have our new char - no validity checks here... */
if(**pp == '\0') {
- logerror("No character available");
+ errmsg.LogError(NO_ERRCODE, "No character available");
iRet = RS_RET_NOT_FOUND;
} else {
if(pSetHdlr == NULL) {
@@ -75,7 +79,7 @@ static rsRetVal doGetChar(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *
}
finalize_it:
- return iRet;
+ RETiRet;
}
@@ -93,47 +97,138 @@ static rsRetVal doCustomHdlr(uchar **pp, rsRetVal (*pSetHdlr)(uchar**, void*), v
CHKiRet(pSetHdlr(pp, pVal));
finalize_it:
- return iRet;
+ RETiRet;
}
-/* Parse a number from the configuration line.
- * rgerhards, 2007-07-31
+/* Parse a number from the configuration line. This functions just parses
+ * the number and does NOT call any handlers or set any values. It is just
+ * for INTERNAL USE by other parse functions!
+ * rgerhards, 2008-01-08
*/
-static rsRetVal doGetInt(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal)
+static rsRetVal parseIntVal(uchar **pp, int64 *pVal)
{
- uchar *p;
DEFiRet;
- int i;
+ uchar *p;
+ int64 i;
+ int bWasNegative;
assert(pp != NULL);
assert(*pp != NULL);
+ assert(pVal != NULL);
skipWhiteSpace(pp); /* skip over any whitespace */
p = *pp;
+ if(*p == '-') {
+ bWasNegative = 1;
+ ++p; /* eat it */
+ } else {
+ bWasNegative = 0;
+ }
+
if(!isdigit((int) *p)) {
errno = 0;
- logerror("invalid number");
+ errmsg.LogError(NO_ERRCODE, "invalid number");
ABORT_FINALIZE(RS_RET_INVALID_INT);
}
/* pull value */
- for(i = 0 ; *p && isdigit((int) *p) ; ++p)
- i = i * 10 + *p - '0';
+ for(i = 0 ; *p && (isdigit((int) *p) || *p == '.' || *p == ',') ; ++p) {
+ if(isdigit((int) *p)) {
+ i = i * 10 + *p - '0';
+ }
+ }
+
+ if(bWasNegative)
+ i *= -1;
+
+ *pVal = i;
+ *pp = p;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* Parse a number from the configuration line.
+ * rgerhards, 2007-07-31
+ */
+static rsRetVal doGetInt(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal)
+{
+ uchar *p;
+ DEFiRet;
+ int64 i;
+
+ assert(pp != NULL);
+ assert(*pp != NULL);
+
+ CHKiRet(parseIntVal(pp, &i));
+ p = *pp;
if(pSetHdlr == NULL) {
/* we should set value directly to var */
- *((int*)pVal) = i;
+ *((int*)pVal) = (int) i;
} else {
/* we set value via a set function */
- CHKiRet(pSetHdlr(pVal, i));
+ CHKiRet(pSetHdlr(pVal, (int) i));
}
*pp = p;
finalize_it:
- return iRet;
+ RETiRet;
+}
+
+
+/* Parse a size from the configuration line. This is basically an integer
+ * syntax, but modifiers may be added after the integer (e.g. 1k to mean
+ * 1024). The size must immediately follow the number. Note that the
+ * param value must be int64!
+ * rgerhards, 2008-01-09
+ */
+static rsRetVal doGetSize(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal)
+{
+ DEFiRet;
+ int64 i;
+
+ assert(pp != NULL);
+ assert(*pp != NULL);
+
+ CHKiRet(parseIntVal(pp, &i));
+
+ /* we now check if the next character is one of our known modifiers.
+ * If so, we accept it as such. If not, we leave it alone. tera and
+ * above does not make any sense as that is above a 32-bit int value.
+ */
+ switch(**pp) {
+ /* traditional binary-based definitions */
+ case 'k': i *= 1024; ++(*pp); break;
+ case 'm': i *= 1024 * 1024; ++(*pp); break;
+ case 'g': i *= 1024 * 1024 * 1024; ++(*pp); break;
+ case 't': i *= (int64) 1024 * 1024 * 1024 * 1024; ++(*pp); break; /* tera */
+ case 'p': i *= (int64) 1024 * 1024 * 1024 * 1024 * 1024; ++(*pp); break; /* peta */
+ case 'e': i *= (int64) 1024 * 1024 * 1024 * 1024 * 1024 * 1024; ++(*pp); break; /* exa */
+ /* and now the "new" 1000-based definitions */
+ case 'K': i *= 1000; ++(*pp); break;
+ case 'M': i *= 10000; ++(*pp); break;
+ case 'G': i *= 100000; ++(*pp); break;
+ case 'T': i *= 1000000; ++(*pp); break; /* tera */
+ case 'P': i *= 10000000; ++(*pp); break; /* peta */
+ case 'E': i *= 100000000; ++(*pp); break; /* exa */
+ }
+
+ /* done */
+ if(pSetHdlr == NULL) {
+ /* we should set value directly to var */
+ *((int64*)pVal) = i;
+ } else {
+ /* we set value via a set function */
+ CHKiRet(pSetHdlr(pVal, i));
+ }
+
+finalize_it:
+ RETiRet;
}
@@ -173,7 +268,7 @@ static rsRetVal doFileCreateMode(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t),
snprintf((char*) errMsg, sizeof(errMsg)/sizeof(uchar),
"value must be octal (e.g 0644).");
errno = 0;
- logerror((char*) errMsg);
+ errmsg.LogError(NO_ERRCODE, "%s", errMsg);
ABORT_FINALIZE(RS_RET_INVALID_VALUE);
}
@@ -194,7 +289,7 @@ static rsRetVal doFileCreateMode(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t),
*pp = p;
finalize_it:
- return iRet;
+ RETiRet;
}
@@ -218,7 +313,7 @@ static int doParseOnOffOption(uchar **pp)
skipWhiteSpace(pp); /* skip over any whitespace */
if(getSubString(pp, (char*) szOpt, sizeof(szOpt) / sizeof(uchar), ' ') != 0) {
- logerror("Invalid $-configline - could not extract on/off option");
+ errmsg.LogError(NO_ERRCODE, "Invalid $-configline - could not extract on/off option");
return -1;
}
@@ -227,7 +322,7 @@ static int doParseOnOffOption(uchar **pp)
} else if(!strcmp((char*)szOpt, "off")) {
return 0;
} else {
- logerrorSz("Option value must be on or off, but is '%s'", (char*)pOptStart);
+ errmsg.LogError(NO_ERRCODE, "Option value must be on or off, but is '%s'", (char*)pOptStart);
return -1;
}
}
@@ -248,14 +343,14 @@ static rsRetVal doGetGID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *p
assert(*pp != NULL);
if(getSubString(pp, (char*) szName, sizeof(szName) / sizeof(uchar), ' ') != 0) {
- logerror("could not extract group name");
+ errmsg.LogError(NO_ERRCODE, "could not extract group name");
ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
getgrnam_r((char*)szName, &gBuf, stringBuf, sizeof(stringBuf), &pgBuf);
if(pgBuf == NULL) {
- logerrorSz("ID for group '%s' could not be found or error", (char*)szName);
+ errmsg.LogError(NO_ERRCODE, "ID for group '%s' could not be found or error", (char*)szName);
iRet = RS_RET_NOT_FOUND;
} else {
if(pSetHdlr == NULL) {
@@ -271,7 +366,7 @@ static rsRetVal doGetGID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *p
skipWhiteSpace(pp); /* skip over any whitespace */
finalize_it:
- return iRet;
+ RETiRet;
}
@@ -290,14 +385,14 @@ static rsRetVal doGetUID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *p
assert(*pp != NULL);
if(getSubString(pp, (char*) szName, sizeof(szName) / sizeof(uchar), ' ') != 0) {
- logerror("could not extract user name");
+ errmsg.LogError(NO_ERRCODE, "could not extract user name");
ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
getpwnam_r((char*)szName, &pwBuf, stringBuf, sizeof(stringBuf), &ppwBuf);
if(ppwBuf == NULL) {
- logerrorSz("ID for user '%s' could not be found or error", (char*)szName);
+ errmsg.LogError(NO_ERRCODE, "ID for user '%s' could not be found or error", (char*)szName);
iRet = RS_RET_NOT_FOUND;
} else {
if(pSetHdlr == NULL) {
@@ -313,7 +408,7 @@ static rsRetVal doGetUID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *p
skipWhiteSpace(pp); /* skip over any whitespace */
finalize_it:
- return iRet;
+ RETiRet;
}
@@ -344,11 +439,43 @@ static rsRetVal doBinaryOptionLine(uchar **pp, rsRetVal (*pSetHdlr)(void*, int),
skipWhiteSpace(pp); /* skip over any whitespace */
finalize_it:
- return iRet;
+ RETiRet;
+}
+
+
+/* parse a whitespace-delimited word from the provided string. This is a
+ * helper function for a number of syntaxes. The parsed value is returned
+ * in ppStrB (which must be provided by caller).
+ * rgerhards, 2008-02-14
+ */
+static rsRetVal
+getWord(uchar **pp, cstr_t **ppStrB)
+{
+ DEFiRet;
+ uchar *p;
+
+ ASSERT(pp != NULL);
+ ASSERT(*pp != NULL);
+ ASSERT(ppStrB != NULL);
+
+ CHKiRet(rsCStrConstruct(ppStrB));
+
+ /* parse out the word */
+ p = *pp;
+
+ while(*p && !isspace((int) *p)) {
+ CHKiRet(rsCStrAppendChar(*ppStrB, *p++));
+ }
+ CHKiRet(rsCStrFinish(*ppStrB));
+
+ *pp = p;
+
+finalize_it:
+ RETiRet;
}
-/* Parse and a word config line option. A word is a consequitive
+/* Parse and a word config line option. A word is a consequtive
* sequence of non-whitespace characters. pVal must be
* a pointer to a string which is to receive the option
* value. The returned string must be freed by the caller.
@@ -360,28 +487,19 @@ finalize_it:
* no custom handler is defined. If it is, the customer handler
* must do the cleanup. I have checked and this was al also memory
* leak with some code. Obviously, not a large one. -- rgerhards, 2007-12-20
+ * Just to clarify: if pVal is parsed to a custom handler, this handler
+ * is responsible for freeing pVal. -- rgerhards, 2008-03-20
*/
static rsRetVal doGetWord(uchar **pp, rsRetVal (*pSetHdlr)(void*, uchar*), void *pVal)
{
DEFiRet;
- rsCStrObj *pStrB;
- uchar *p;
+ cstr_t *pStrB;
uchar *pNewVal;
- assert(pp != NULL);
- assert(*pp != NULL);
-
- if((pStrB = rsCStrConstruct()) == NULL)
- return RS_RET_OUT_OF_MEMORY;
-
- /* parse out the word */
- p = *pp;
-
- while(*p && !isspace((int) *p)) {
- CHKiRet(rsCStrAppendChar(pStrB, *p++));
- }
- CHKiRet(rsCStrFinish(pStrB));
+ ASSERT(pp != NULL);
+ ASSERT(*pp != NULL);
+ CHKiRet(getWord(pp, &pStrB));
CHKiRet(rsCStrConvSzStrAndDestruct(pStrB, &pNewVal, 0));
pStrB = NULL;
@@ -396,16 +514,75 @@ static rsRetVal doGetWord(uchar **pp, rsRetVal (*pSetHdlr)(void*, uchar*), void
CHKiRet(pSetHdlr(pVal, pNewVal));
}
- *pp = p;
skipWhiteSpace(pp); /* skip over any whitespace */
finalize_it:
if(iRet != RS_RET_OK) {
if(pStrB != NULL)
- rsCStrDestruct(pStrB);
+ rsCStrDestruct(&pStrB);
}
- return iRet;
+ RETiRet;
+}
+
+
+/* parse a syslog name from the string. This is the generic code that is
+ * called by the facility/severity functions. Note that we do not check the
+ * validity of numerical values, something that should probably change over
+ * time (TODO). -- rgerhards, 2008-02-14
+ */
+static rsRetVal
+doSyslogName(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal, syslogName_t *pNameTable)
+{
+ DEFiRet;
+ cstr_t *pStrB;
+ int iNewVal;
+
+ ASSERT(pp != NULL);
+ ASSERT(*pp != NULL);
+
+ CHKiRet(getWord(pp, &pStrB)); /* get word */
+ iNewVal = decodeSyslogName(rsCStrGetSzStr(pStrB), pNameTable);
+
+ if(pSetHdlr == NULL) {
+ /* we should set value directly to var */
+ *((int*)pVal) = iNewVal; /* set new one */
+ } else {
+ /* we set value via a set function */
+ CHKiRet(pSetHdlr(pVal, iNewVal));
+ }
+
+ skipWhiteSpace(pp); /* skip over any whitespace */
+
+finalize_it:
+ if(pStrB != NULL)
+ rsCStrDestruct(&pStrB);
+
+ RETiRet;
+}
+
+
+/* Implements the facility syntax.
+ * rgerhards, 2008-02-14
+ */
+static rsRetVal
+doFacility(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal)
+{
+ DEFiRet;
+ iRet = doSyslogName(pp, pSetHdlr, pVal, syslogFacNames);
+ RETiRet;
+}
+
+
+/* Implements the severity syntax.
+ * rgerhards, 2008-02-14
+ */
+static rsRetVal
+doSeverity(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal)
+{
+ DEFiRet;
+ iRet = doSyslogName(pp, pSetHdlr, pVal, syslogPriNames);
+ RETiRet;
}
@@ -417,7 +594,7 @@ finalize_it:
*/
static rsRetVal cslchDestruct(void *pThis)
{
- assert(pThis != NULL);
+ ASSERT(pThis != NULL);
free(pThis);
return RS_RET_OK;
@@ -438,7 +615,7 @@ static rsRetVal cslchConstruct(cslCmdHdlr_t **ppThis)
finalize_it:
*ppThis = pThis;
- return iRet;
+ RETiRet;
}
/* destructor for linked list keys. As we do not use any dynamic memory,
@@ -511,9 +688,18 @@ static rsRetVal cslchCallHdlr(cslCmdHdlr_t *pThis, uchar **ppConfLine)
case eCmdHdlrInt:
pHdlr = doGetInt;
break;
+ case eCmdHdlrSize:
+ pHdlr = doGetSize;
+ break;
case eCmdHdlrGetChar:
pHdlr = doGetChar;
break;
+ case eCmdHdlrFacility:
+ pHdlr = doFacility;
+ break;
+ case eCmdHdlrSeverity:
+ pHdlr = doSeverity;
+ break;
case eCmdHdlrGetWord:
pHdlr = doGetWord;
break;
@@ -527,7 +713,7 @@ static rsRetVal cslchCallHdlr(cslCmdHdlr_t *pThis, uchar **ppConfLine)
CHKiRet(pHdlr(ppConfLine, pThis->cslCmdHdlr, pThis->pData));
finalize_it:
- return iRet;
+ RETiRet;
}
@@ -576,7 +762,7 @@ static rsRetVal cslcConstruct(cslCmd_t **ppThis, int bChainingPermitted)
finalize_it:
*ppThis = pThis;
- return iRet;
+ RETiRet;
}
@@ -599,21 +785,7 @@ finalize_it:
cslchDestruct(pCmdHdlr);
}
- return iRet;
-}
-
-
-/* function that initializes this module here. This is primarily a hook
- * for syslogd.
- */
-rsRetVal cfsyslineInit(void)
-{
- DEFiRet;
-
- CHKiRet(llInit(&llCmdList, cslcDestruct, cslcKeyDestruct, strcasecmp));
-
-finalize_it:
- return iRet;
+ RETiRet;
}
@@ -626,9 +798,9 @@ finalize_it:
rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData,
void *pOwnerCookie)
{
+ DEFiRet;
cslCmd_t *pThis;
uchar *pMyCmdName;
- DEFiRet;
iRet = llFind(&llCmdList, (void *) pCmdName, (void*) &pThis);
if(iRet == RS_RET_NOT_FOUND) {
@@ -661,7 +833,7 @@ rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlTy
}
finalize_it:
- return iRet;
+ RETiRet;
}
@@ -695,7 +867,7 @@ DEFFUNC_llExecFunc(unregHdlrsHeadExec)
}
finalize_it:
- return iRet;
+ RETiRet;
}
/* unregister and destroy cfSysLineHandlers for a specific owner. This method is
* most importantly used before unloading a loadable module providing some handlers.
@@ -711,7 +883,7 @@ rsRetVal unregCfSysLineHdlrs4Owner(void *pOwnerCookie)
*/
iRet = llExecFunc(&llCmdList, unregHdlrsHeadExec, pOwnerCookie);
- return iRet;
+ RETiRet;
}
@@ -733,7 +905,7 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p)
iRet = llFind(&llCmdList, (void *) pCmdName, (void*) &pCmd);
if(iRet == RS_RET_NOT_FOUND) {
- logerror("invalid or yet-unknown config file command - have you forgotten to load a module?");
+ errmsg.LogError(NO_ERRCODE, "invalid or yet-unknown config file command - have you forgotten to load a module?");
}
if(iRet != RS_RET_OK)
@@ -765,7 +937,7 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p)
iRet = iRetLL;
finalize_it:
- return iRet;
+ RETiRet;
}
@@ -781,24 +953,38 @@ void dbgPrintCfSysLineHandlers(void)
linkedListCookie_t llCookieCmdHdlr;
uchar *pKey;
- printf("\nSytem Line Configuration Commands:\n");
+ dbgprintf("Sytem Line Configuration Commands:\n");
llCookieCmd = NULL;
while((iRet = llGetNextElt(&llCmdList, &llCookieCmd, (void*)&pCmd)) == RS_RET_OK) {
llGetKey(llCookieCmd, (void*) &pKey); /* TODO: using the cookie is NOT clean! */
- printf("\tCommand '%s':\n", pKey);
+ dbgprintf("\tCommand '%s':\n", pKey);
llCookieCmdHdlr = NULL;
while((iRet = llGetNextElt(&pCmd->llCmdHdlrs, &llCookieCmdHdlr, (void*)&pCmdHdlr)) == RS_RET_OK) {
- printf("\t\ttype : %d\n", pCmdHdlr->eType);
- printf("\t\tpData: 0x%lx\n", (unsigned long) pCmdHdlr->pData);
- printf("\t\tHdlr : 0x%lx\n", (unsigned long) pCmdHdlr->cslCmdHdlr);
- printf("\t\tOwner: 0x%lx\n", (unsigned long) llCookieCmdHdlr->pKey);
- printf("\n");
+ dbgprintf("\t\ttype : %d\n", pCmdHdlr->eType);
+ dbgprintf("\t\tpData: 0x%lx\n", (unsigned long) pCmdHdlr->pData);
+ dbgprintf("\t\tHdlr : 0x%lx\n", (unsigned long) pCmdHdlr->cslCmdHdlr);
+ dbgprintf("\t\tOwner: 0x%lx\n", (unsigned long) llCookieCmdHdlr->pKey);
+ dbgprintf("\n");
}
}
- printf("\n");
+ dbgprintf("\n");
+ ENDfunc
+}
+
+/* our init function. TODO: remove once converted to a class
+ */
+rsRetVal cfsyslineInit()
+{
+ DEFiRet;
+ CHKiRet(objGetObjInterface(&obj));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+
+ CHKiRet(llInit(&llCmdList, cslcDestruct, cslcKeyDestruct, strcasecmp));
+
+finalize_it:
+ RETiRet;
}
-/*
- * vi:set ai:
+/* vim:set ai:
*/