From 127d61fea78c967d2cdc536f898da425ffdd8a11 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Jul 2011 09:31:17 +0200 Subject: milestone: first steps at global() conf obj implementation also, the foundation for accessing conf file params has been laid. Still more work to do... --- grammar/Makefile.am | 2 + grammar/rainerscript.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 43 +++++++++++++++ runtime/glbl.c | 40 +++++++++++++- runtime/rsconf.c | 5 ++ runtime/typedefs.h | 1 + 6 files changed, 228 insertions(+), 2 deletions(-) diff --git a/grammar/Makefile.am b/grammar/Makefile.am index 9767c12f..4746a9de 100644 --- a/grammar/Makefile.am +++ b/grammar/Makefile.am @@ -11,7 +11,9 @@ libgrammar_la_SOURCES = \ rainerscript.h \ parserif.h \ grammar.h +libgrammar_la_CPPFLAGS = $(RSRT_CFLAGS) testdriver_SOURCES = testdriver.c libgrammar.la +testdriver_CPPFLAGS = $(RSRT_CFLAGS) testdriver_LDADD = libgrammar.la testdriver_LDFLAGS = -lestr diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 16140a3f..754910da 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -97,6 +97,7 @@ nvlstNew(es_str_t *name, es_str_t *value) lst->name = name; lst->val.datatype = 'S'; lst->val.d.estr = value; + lst->bUsed = 0; } return lst; @@ -145,6 +146,18 @@ nvlstFindName(struct nvlst *lst, es_str_t *name) } +/* find a name starting at node lst. SAme as nvlstFindName, but + * for classical C strings. This is useful because the config system + * uses C string constants. + */ +static inline struct nvlst* +nvlstFindNameCStr(struct nvlst *lst, char *name) +{ + while(lst != NULL && es_strbufcmp(lst->name, (uchar*)name, strlen(name))) + lst = lst->next; + return lst; +} + /* check if there are duplicate names inside a nvlst and emit * an error message, if so. */ @@ -167,6 +180,113 @@ nvlstChkDupes(struct nvlst *lst) } +/* check for unused params and emit error message is found. This must + * be called after all config params have been pulled from the object + * (otherwise the flags are not correctly set). + */ +void +nvlstChkUnused(struct nvlst *lst) +{ + char *cstr; + + while(lst != NULL) { + if(!lst->bUsed) { + cstr = es_str2cstr(lst->name, NULL); + parser_errmsg("parameter '%s' not known -- " + "typo in config file?", + cstr); + free(cstr); + } + lst = lst->next; + } +} + + +/* get a single parameter according to its definition. Helper to + * nvlstGetParams. + */ +static inline void +nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *vals) +{ + dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", + param->name, (int) param->type); + switch(param->type) { + case eCmdHdlrUID: + break; + case eCmdHdlrGID: + break; + case eCmdHdlrBinary: + break; + case eCmdHdlrFileCreateMode: + break; + case eCmdHdlrInt: + break; + case eCmdHdlrSize: + break; + case eCmdHdlrGetChar: + break; + case eCmdHdlrFacility: + break; + case eCmdHdlrSeverity: + break; + case eCmdHdlrGetWord: + break; + case eCmdHdlrString: + break; + case eCmdHdlrGoneAway: + parser_errmsg("parameter '%s' is no longer supported", + param->name); + break; + default: + dbgprintf("error: invalid param type\n"); + break; + } +} + + +/* obtain conf params from an nvlst and emit error messages if + * necessary. If an already-existing param value is passed, that is + * used. If NULL is passed instead, a new one is allocated. In that case, + * it is the caller's duty to free it when no longer needed. + * NULL is returned on error, otherwise a pointer to the vals array. + */ +struct cnfparamvals* +nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, + struct cnfparamvals *vals) +{ + int i; + struct nvlst *valnode; + struct cnfparamdescr *param; + + if(params->version != CNFPARAMBLK_VERSION) { + dbgprintf("nvlstGetParams: invalid param block version " + "%d, expected %d\n", + params->version, CNFPARAMBLK_VERSION); + return NULL; + } + + if(vals == NULL) { + if((vals = malloc(params->nParams * + sizeof(struct cnfparamvals))) == NULL) + return NULL; + } + + for(i = 0 ; i < params->nParams ; ++i) { + param = params->descr + i; + if((valnode = nvlstFindNameCStr(lst, param->name)) == NULL) + continue; + if(vals[i].bUsed) { + parser_errmsg("parameter '%s' specified more than once - " + "one instance is ignored. Fix config", param->name); + continue; + } + nvlstGetParam(lst, param, vals + i); + } + return vals; +} + + struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst) { @@ -1140,6 +1260,25 @@ cnfDoInclude(char *name) return 0; } +/* find the index (or -1!) for a config param by name. This is used to + * address the parameter array. Of course, we could use with static + * indices, but that would create some extra bug potential. So we + * resort to names. As we do this only during the initial config parsing + * stage the (considerable!) extra overhead is OK. -- rgerhards, 2011-07-19 + */ +int +cnfparamGetIdx(struct cnfparamblk *params, char *name) +{ + int i; + for(i = 0 ; i < params->nParams ; ++i) + if(!strcmp(params->descr[i].name, name)) + break; + if(i == params->nParams) + i = -1; /* not found */ + return i; +} + + void cstrPrint(char *text, es_str_t *estr) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 2c4d764f..1dc5719d 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -2,6 +2,7 @@ #define INC_UTILS_H #include #include +#include #define CNFFUNC_MAX_ARGS 32 /**< maximum number of arguments that any function can have (among @@ -65,6 +66,11 @@ struct nvlst { struct nvlst *next; es_str_t *name; struct var val; + unsigned char *bUsed; + /**< was this node used during config processing? If not, this + * indicates an error. After all, the user specified a setting + * that the software does not know. + */ }; struct cnfcfsyslinelst { @@ -172,6 +178,40 @@ struct x { }; */ + +/* the following defines describe the parameter block for puling + * config parameters. Note that the focus is on ease and saveness of + * use, not performance. For example, we address parameters by name + * instead of index, because the former is less error-prone. The (severe) + * performance hit does not matter, as it is a one-time hit during config + * load but never during actual processing. So there is really no reason + * to care. + */ +struct cnfparamdescr { /* first the param description */ + char *name; /**< not a es_str_t to ease definition in code */ + ecslCmdHdrlType type; + unsigned flags; +}; +/* flags for cnfparamdescr: */ +#define CNFPARAM_REQUIRED 0x0001 + +struct cnfparamblk { /* now the actual param block use in API calls */ + unsigned short version; + unsigned short nParams; + struct cnfparamdescr *descr; +}; +#define CNFPARAMBLK_VERSION 1 + /**< caller must have same version as engine -- else things may + * be messed up. But note that we may support multiple versions + * inside the engine, if at some later stage we want to do + * that. -- rgerhards, 2011-07-15 + */ +struct cnfparamvals { /* the values we obtained for param descr. */ + struct var val; + unsigned char bUsed; +}; + + int cnfParseBuffer(char *buf, unsigned lenBuf); void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); @@ -198,6 +238,9 @@ struct cnfvar* cnfvarNew(char *name); struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); int cnfDoInclude(char *name); +int cnfparamGetIdx(struct cnfparamblk *params, char *name); +struct cnfparamvals* nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, + struct cnfparamvals *vals); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); diff --git a/runtime/glbl.c b/runtime/glbl.c index 2fd52a5a..f978e1b3 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -7,7 +7,7 @@ * * Module begun 2008-04-16 by Rainer Gerhards * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. + * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -44,6 +44,7 @@ #include "prop.h" #include "atomic.h" #include "errmsg.h" +#include "rainerscript.h" /* some defaults */ #ifndef DFLT_NETSTRM_DRVR @@ -88,6 +89,28 @@ static int iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); /* si #endif +/* tables for interfacing with the v6 config system */ +static struct cnfparamdescr cnfparamdescr[] = { + { "workdirectory", eCmdHdlrString, 0 }, + { "dropmsgswithmaliciousdnsptrrecords", eCmdHdlrBinary, 0 }, + { "localhostname", eCmdHdlrGetWord, 0 }, + { "preservefqdn", eCmdHdlrBinary, 0 }, + { "defaultnetstreamdrivercafile", eCmdHdlrString, 0 }, + { "defaultnetstreamdriverkeyfile", eCmdHdlrString, 0 }, + { "defaultnetstreamdriver", eCmdHdlrString, 0 }, +}; +static struct cnfparamblk paramblk = + { CNFPARAMBLK_VERSION, + sizeof(cnfparamdescr)/sizeof(struct cnfparamdescr), + cnfparamdescr + }; + +static struct cnfparamvals *cnfparamvals = NULL; +/* we need to support multiple calls into our param block, so we need + * to persist the current settings. Note that this must be re-set + * each time a new config load begins (TODO: create interface?) + */ + /* define a macro for the simple properties' set and get functions * (which are always the same). This is only suitable for pretty * simple cases which require neither checks nor memory allocation. @@ -143,7 +166,7 @@ static int GetGlobalInputTermState(void) } -/* set global termiantion state to "terminate". Note that this is a +/* set global termination state to "terminate". Note that this is a * "once in a lifetime" action which can not be undone. -- gerhards, 2009-07-20 */ static void SetGlobalInputTermination(void) @@ -407,6 +430,17 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a } +/* handle a global config object. Note that multiple global config statements + * are permitted (because of plugin support), so once we got a param block, + * we need to hold to it. + * rgerhards, 2011-07-19 + */ +void +glblProcessCnf(struct cnfobj *o) +{ + cnfparamvals = nvlstGetParams(o->nvlst, ¶mblk, cnfparamvals); +} + /* Initialize the glbl class. Must be called as the very first method * before anything else is called inside this class. @@ -456,5 +490,7 @@ BEGINObjClassExit(glbl, OBJ_IS_CORE_MODULE) /* class, version */ DESTROY_ATOMIC_HELPER_MUT(mutTerminateInputs); ENDObjClassExit(glbl) +void glblProcessCnf(struct cnfobj *o); + /* vi:set ai: */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index f369dadf..aa7a3e3b 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -356,6 +356,11 @@ void cnfDoObj(struct cnfobj *o) { dbgprintf("cnf:global:obj: "); cnfobjPrint(o); + switch(o->objType) { + case CNFOBJ_GLOBAL: + glblProcessCnf(o); + break; + } cnfobjDestruct(o); } diff --git a/runtime/typedefs.h b/runtime/typedefs.h index 11061e14..d46851f6 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -159,6 +159,7 @@ typedef enum cslCmdHdlrType { eCmdHdlrFacility, eCmdHdlrSeverity, eCmdHdlrGetWord, + eCmdHdlrString, eCmdHdlrGoneAway /* statment existed, but is no longer supported */ } ecslCmdHdrlType; -- cgit