summaryrefslogtreecommitdiffstats
path: root/plugins/omlibdbi/omlibdbi.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/omlibdbi/omlibdbi.c')
-rw-r--r--plugins/omlibdbi/omlibdbi.c660
1 files changed, 660 insertions, 0 deletions
diff --git a/plugins/omlibdbi/omlibdbi.c b/plugins/omlibdbi/omlibdbi.c
new file mode 100644
index 0000000..5fd5df2
--- /dev/null
+++ b/plugins/omlibdbi/omlibdbi.c
@@ -0,0 +1,660 @@
+/* omlibdbi.c
+ * This is the implementation of the dbi output module.
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * This depends on libdbi being present with the proper settings. Older
+ * versions do not necessarily have them. Please visit this bug tracker
+ * for details: http://bugzilla.adiscon.com/show_bug.cgi?id=31
+ *
+ * File begun on 2008-02-14 by RGerhards (extracted from syslogd.c)
+ *
+ * Copyright 2008-2016 Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * -or-
+ * see COPYING.ASL20 in the source distribution
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <time.h>
+#include <libgen.h>
+#include <dbi/dbi.h>
+#include "dirty.h"
+#include "syslogd-types.h"
+#include "cfsysline.h"
+#include "conf.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "debug.h"
+#include "errmsg.h"
+#include "conf.h"
+
+#undef HAVE_DBI_TXSUPP
+/* transaction support disabled in v8 -- TODO: reenable */
+
+MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
+MODULE_CNFNAME("omlibdbi")
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+static int bDbiInitialized = 0; /* dbi_initialize() can only be called one - this keeps track of it */
+
+typedef struct _instanceData {
+ uchar *dbiDrvrDir; /* where do the dbi drivers reside? */
+ dbi_conn conn; /* handle to database */
+ uchar *drvrName; /* driver to use */
+ uchar *host; /* host to connect to */
+ uchar *usrName; /* user name for connect */
+ uchar *pwd; /* password for connect */
+ uchar *dbName; /* database to use */
+ unsigned uLastDBErrno; /* last errno returned by libdbi or 0 if all is well */
+ uchar *tplName; /* format template to use */
+ int txSupport; /* transaction support */
+} instanceData;
+
+typedef struct wrkrInstanceData {
+ instanceData *pData;
+} wrkrInstanceData_t;
+
+typedef struct configSettings_s {
+ uchar *dbiDrvrDir; /* global: where do the dbi drivers reside? */
+ uchar *drvrName; /* driver to use */
+ uchar *host; /* host to connect to */
+ uchar *usrName; /* user name for connect */
+ uchar *pwd; /* password for connect */
+ uchar *dbName; /* database to use */
+} configSettings_t;
+static configSettings_t cs;
+static uchar *pszFileDfltTplName; /* name of the default template to use */
+
+struct modConfData_s {
+ rsconf_t *pConf; /* our overall config object */
+ uchar *dbiDrvrDir; /* where do the dbi drivers reside? */
+ uchar *tplName; /* default template */
+};
+
+static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
+static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */
+static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */
+
+static pthread_mutex_t mutDoAct = PTHREAD_MUTEX_INITIALIZER;
+
+
+/* tables for interfacing with the v6 config system */
+/* module-global parameters */
+static struct cnfparamdescr modpdescr[] = {
+ { "template", eCmdHdlrGetWord, 0 },
+ { "driverdirectory", eCmdHdlrGetWord, 0 }
+};
+static struct cnfparamblk modpblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(modpdescr)/sizeof(struct cnfparamdescr),
+ modpdescr
+ };
+/* action (instance) parameters */
+static struct cnfparamdescr actpdescr[] = {
+ { "server", eCmdHdlrGetWord, 1 },
+ { "db", eCmdHdlrGetWord, 1 },
+ { "uid", eCmdHdlrGetWord, 1 },
+ { "pwd", eCmdHdlrGetWord, 1 },
+ { "driver", eCmdHdlrGetWord, 1 },
+ { "template", eCmdHdlrGetWord, 0 }
+};
+static struct cnfparamblk actpblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(actpdescr)/sizeof(struct cnfparamdescr),
+ actpdescr
+ };
+
+/* this function gets the default template. It coordinates action between
+ * old-style and new-style configuration parts.
+ */
+static uchar*
+getDfltTpl(void)
+{
+ if(loadModConf != NULL && loadModConf->tplName != NULL)
+ return loadModConf->tplName;
+ else if(pszFileDfltTplName == NULL)
+ return (uchar*)" StdDBFmt";
+ else
+ return pszFileDfltTplName;
+}
+
+
+BEGINinitConfVars /* (re)set config variables to default values */
+CODESTARTinitConfVars
+ cs.dbiDrvrDir = NULL;
+ cs.drvrName = NULL;
+ cs.host = NULL;
+ cs.usrName = NULL;
+ cs.pwd = NULL;
+ cs.dbName = NULL;
+ENDinitConfVars
+
+
+/* config settings */
+#ifdef HAVE_DBI_R
+static dbi_inst dbiInst;
+#endif
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+BEGINcreateWrkrInstance
+CODESTARTcreateWrkrInstance
+ENDcreateWrkrInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ /* we do not like repeated message reduction inside the database */
+ENDisCompatibleWithFeature
+
+
+/* The following function is responsible for closing a
+ * database connection.
+ */
+static void closeConn(instanceData *pData)
+{
+ assert(pData != NULL);
+ if(pData->conn != NULL) { /* just to be on the safe side... */
+ dbi_conn_close(pData->conn);
+ pData->conn = NULL;
+ }
+}
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ free(pData->drvrName);
+ free(pData->host);
+ free(pData->usrName);
+ free(pData->pwd);
+ free(pData->dbName);
+ENDfreeInstance
+
+BEGINfreeWrkrInstance
+CODESTARTfreeWrkrInstance
+ closeConn(pWrkrData->pData);
+ENDfreeWrkrInstance
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ /* nothing special here */
+ENDdbgPrintInstInfo
+
+
+/* log a database error with descriptive message.
+ * We check if we have a valid database handle. If not, we simply
+ * report an error, but can not be specific. RGerhards, 2007-01-30
+ */
+static void
+reportDBError(instanceData *pData, int bSilent)
+{
+ unsigned uDBErrno;
+ char errMsg[1024];
+ const char *pszDbiErr;
+
+ assert(pData != NULL);
+
+ /* output log message */
+ errno = 0;
+ if(pData->conn == NULL) {
+ LogError(0, NO_ERRCODE, "unknown DB error occurred - could not obtain connection handle");
+ } else { /* we can ask dbi for the error description... */
+ uDBErrno = dbi_conn_error(pData->conn, &pszDbiErr);
+ snprintf(errMsg, sizeof(errMsg), "db error (%d): %s\n", uDBErrno, pszDbiErr);
+ if(bSilent || uDBErrno == pData->uLastDBErrno)
+ dbgprintf("libdbi, DBError(silent): %s\n", errMsg);
+ else {
+ pData->uLastDBErrno = uDBErrno;
+ LogError(0, NO_ERRCODE, "%s", errMsg);
+ }
+ }
+
+}
+
+
+/* The following function is responsible for initializing a connection
+ */
+static rsRetVal initConn(instanceData *pData, int bSilent)
+{
+ DEFiRet;
+ int iDrvrsLoaded;
+
+ assert(pData != NULL);
+ assert(pData->conn == NULL);
+
+ if(bDbiInitialized == 0) {
+ /* we need to init libdbi first */
+# ifdef HAVE_DBI_R
+ iDrvrsLoaded = dbi_initialize_r((char*) pData->dbiDrvrDir, &dbiInst);
+# else
+ iDrvrsLoaded = dbi_initialize((char*) pData->dbiDrvrDir);
+# endif
+ if(iDrvrsLoaded == 0) {
+ LogError(0, RS_RET_SUSPENDED, "libdbi error: libdbi or libdbi drivers not "
+ "present on this system - suspending.");
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ } else if(iDrvrsLoaded < 0) {
+ LogError(0, RS_RET_SUSPENDED, "libdbi error: libdbi could not be "
+ "initialized (do you have any dbi drivers installed?) - suspending.");
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ }
+ bDbiInitialized = 1; /* we are done for the rest of our existence... */
+ }
+
+# ifdef HAVE_DBI_R
+ pData->conn = dbi_conn_new_r((char*)pData->drvrName, dbiInst);
+# else
+ pData->conn = dbi_conn_new((char*)pData->drvrName);
+# endif
+ if(pData->conn == NULL) {
+ LogError(0, RS_RET_SUSPENDED, "can not initialize libdbi connection");
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ } else { /* we could get the handle, now on with work... */
+ /* Connect to database */
+ dbi_conn_set_option(pData->conn, "host", (char*) pData->host);
+ dbi_conn_set_option(pData->conn, "username", (char*) pData->usrName);
+
+ /* libdbi-driver-sqlite(2/3) requires to provide sqlite3_db dir which is absolute
+ path, where database file lives,
+ * and dbname, which is database file name itself. So in order to keep the config API unchanged,
+ * we split the dbname to path and filename.
+ */
+ int is_sqlite2 = !strcmp((const char *)pData->drvrName, "sqlite");
+ int is_sqlite3 = !strcmp((const char *)pData->drvrName, "sqlite3");
+ if(is_sqlite2 || is_sqlite3) {
+ char *const dn_org = strdup((char*)pData->dbName);
+ char *const dn = dirname(dn_org);
+ dbi_conn_set_option(pData->conn, is_sqlite3 ? "sqlite3_dbdir" : "sqlite_dbdir",dn);
+ free(dn_org); /* Free original buffer - dirname may return different pointer */
+
+ char *tmp = strdup((char*)pData->dbName);
+ char *bn = basename(tmp);
+ dbi_conn_set_option(pData->conn, "dbname", bn);
+ free(tmp);
+ } else {
+ dbi_conn_set_option(pData->conn, "dbname", (char*) pData->dbName);
+ }
+ if(pData->pwd != NULL)
+ dbi_conn_set_option(pData->conn, "password", (char*) pData->pwd);
+ if(dbi_conn_connect(pData->conn) < 0) {
+ reportDBError(pData, bSilent);
+ closeConn(pData); /* ignore any error we may get */
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ }
+ pData->txSupport = dbi_conn_cap_get(pData->conn, "transaction_support");
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* The following function writes the current log entry
+ * to an established database connection.
+ */
+static rsRetVal
+writeDB(const uchar *psz, instanceData *const __restrict__ pData)
+{
+ DEFiRet;
+ dbi_result dbiRes = NULL;
+
+ assert(psz != NULL);
+ assert(pData != NULL);
+
+ /* see if we are ready to proceed */
+ if(pData->conn == NULL) {
+ CHKiRet(initConn(pData, 0));
+ }
+
+ /* try insert */
+ if((dbiRes = dbi_conn_query(pData->conn, (const char*)psz)) == NULL) {
+ /* error occurred, try to re-init connection and retry */
+ closeConn(pData); /* close the current handle */
+ CHKiRet(initConn(pData, 0)); /* try to re-open */
+ if((dbiRes = dbi_conn_query(pData->conn, (const char*)psz)) == NULL) { /* re-try insert */
+ /* we failed, giving up for now */
+ reportDBError(pData, 0);
+ closeConn(pData); /* free ressources */
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ }
+ }
+
+finalize_it:
+ if(iRet == RS_RET_OK) {
+ pData->uLastDBErrno = 0; /* reset error for error supression */
+ }
+
+ if(dbiRes != NULL)
+ dbi_result_free(dbiRes);
+
+ RETiRet;
+}
+
+
+BEGINtryResume
+CODESTARTtryResume
+ if(pWrkrData->pData->conn == NULL) {
+ iRet = initConn(pWrkrData->pData, 1);
+ }
+ENDtryResume
+
+/* transaction support 2013-03 */
+BEGINbeginTransaction
+CODESTARTbeginTransaction
+ if(pWrkrData->pData->conn == NULL) {
+ CHKiRet(initConn(pWrkrData->pData, 0));
+ }
+# ifdef HAVE_DBI_TXSUPP
+ if (pData->txSupport == 1) {
+ if (dbi_conn_transaction_begin(pData->conn) != 0) {
+ const char *emsg;
+ dbi_conn_error(pData->conn, &emsg);
+ dbgprintf("libdbi server error: begin transaction "
+ "not successful: %s\n", emsg);
+ closeConn(pData);
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ }
+ }
+# endif
+finalize_it:
+ENDbeginTransaction
+/* end transaction */
+
+BEGINdoAction
+CODESTARTdoAction
+ pthread_mutex_lock(&mutDoAct);
+ CHKiRet(writeDB(ppString[0], pWrkrData->pData));
+# ifdef HAVE_DBI_TXSUPP
+ if (pData->txSupport == 1) {
+ iRet = RS_RET_DEFER_COMMIT;
+ }
+# endif
+finalize_it:
+ pthread_mutex_unlock(&mutDoAct);
+ENDdoAction
+
+/* transaction support 2013-03 */
+BEGINendTransaction
+CODESTARTendTransaction
+# ifdef HAVE_DBI_TXSUPP
+ if (dbi_conn_transaction_commit(pData->conn) != 0) {
+ const char *emsg;
+ dbi_conn_error(pData->conn, &emsg);
+ dbgprintf("libdbi server error: transaction not committed: %s\n",
+ emsg);
+ closeConn(pData);
+ iRet = RS_RET_SUSPENDED;
+ }
+# endif
+ENDendTransaction
+/* end transaction */
+
+BEGINbeginCnfLoad
+CODESTARTbeginCnfLoad
+ loadModConf = pModConf;
+ pModConf->pConf = pConf;
+ pModConf->tplName = NULL;
+ bLegacyCnfModGlobalsPermitted = 1;
+ENDbeginCnfLoad
+
+BEGINsetModCnf
+ struct cnfparamvals *pvals = NULL;
+ int i;
+CODESTARTsetModCnf
+ pvals = nvlstGetParams(lst, &modpblk, NULL);
+ if(pvals == NULL) {
+ LogError(0, RS_RET_MISSING_CNFPARAMS, "omlibdbi: error processing "
+ "module config parameters [module(...)]");
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ if(Debug) {
+ dbgprintf("module (global) param blk for omlibdbi:\n");
+ cnfparamsPrint(&modpblk, pvals);
+ }
+
+ for(i = 0 ; i < modpblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(modpblk.descr[i].name, "template")) {
+ loadModConf->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ if(pszFileDfltTplName != NULL) {
+ LogError(0, RS_RET_DUP_PARAM, "omlibdbi: warning: default template "
+ "was already set via legacy directive - may lead to inconsistent "
+ "results.");
+ }
+ } else if(!strcmp(modpblk.descr[i].name, "driverdirectory")) {
+ loadModConf->dbiDrvrDir = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else {
+ dbgprintf("omlibdbi: program error, non-handled "
+ "param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
+ }
+ }
+ bLegacyCnfModGlobalsPermitted = 0;
+finalize_it:
+ if(pvals != NULL)
+ cnfparamvalsDestruct(pvals, &modpblk);
+ENDsetModCnf
+
+BEGINendCnfLoad
+CODESTARTendCnfLoad
+ loadModConf = NULL; /* done loading */
+ /* free legacy config vars */
+ free(cs.dbiDrvrDir);
+ free(cs.drvrName);
+ free(cs.host);
+ free(cs.usrName);
+ free(cs.pwd);
+ free(cs.dbName);
+ cs.dbiDrvrDir = NULL;
+ cs.drvrName = NULL;
+ cs.host = NULL;
+ cs.usrName = NULL;
+ cs.pwd = NULL;
+ cs.dbName = NULL;
+ free(pszFileDfltTplName);
+ pszFileDfltTplName = NULL;
+ENDendCnfLoad
+
+BEGINcheckCnf
+CODESTARTcheckCnf
+ENDcheckCnf
+
+BEGINactivateCnf
+CODESTARTactivateCnf
+ runModConf = pModConf;
+ENDactivateCnf
+
+BEGINfreeCnf
+CODESTARTfreeCnf
+ free(pModConf->tplName);
+ free(pModConf->dbiDrvrDir);
+ENDfreeCnf
+
+
+
+
+static inline void
+setInstParamDefaults(instanceData *pData)
+{
+ pData->tplName = NULL;
+}
+
+
+BEGINnewActInst
+ struct cnfparamvals *pvals;
+ uchar *tplToUse;
+ int i;
+CODESTARTnewActInst
+ if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) {
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ CHKiRet(createInstance(&pData));
+ setInstParamDefaults(pData);
+ CODE_STD_STRING_REQUESTnewActInst(1)
+ for(i = 0 ; i < actpblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(actpblk.descr[i].name, "server")) {
+ pData->host = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(actpblk.descr[i].name, "db")) {
+ pData->dbName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(actpblk.descr[i].name, "uid")) {
+ pData->usrName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(actpblk.descr[i].name, "pwd")) {
+ pData->pwd = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(actpblk.descr[i].name, "driver")) {
+ pData->drvrName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(actpblk.descr[i].name, "template")) {
+ pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else {
+ dbgprintf("omlibdbi: program error, non-handled "
+ "param '%s'\n", actpblk.descr[i].name);
+ }
+ }
+
+ tplToUse = (pData->tplName == NULL) ? (uchar*)strdup((char*)getDfltTpl()) : pData->tplName;
+ CHKiRet(OMSRsetEntry(*ppOMSR, 0, tplToUse, OMSR_RQD_TPL_OPT_SQL));
+CODE_STD_FINALIZERnewActInst
+ cnfparamvalsDestruct(pvals, &actpblk);
+ENDnewActInst
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ if(!strncmp((char*) p, ":omlibdbi:", sizeof(":omlibdbi:") - 1)) {
+ p += sizeof(":omlibdbi:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ } else {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ CHKiRet(createInstance(&pData));
+ /* no create the instance based on what we currently have */
+ if(cs.drvrName == NULL) {
+ LogError(0, RS_RET_NO_DRIVERNAME, "omlibdbi: no db driver name given - action can not "
+ "be created");
+ ABORT_FINALIZE(RS_RET_NO_DRIVERNAME);
+ }
+
+ if((pData->drvrName = (uchar*) strdup((char*)cs.drvrName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ /* NULL values are supported because drivers have different needs.
+ * They will err out on connect. -- rgerhards, 2008-02-15
+ */
+ if(cs.host != NULL)
+ CHKmalloc(pData->host = (uchar*) strdup((char*)cs.host));
+ if(cs.usrName != NULL)
+ CHKmalloc(pData->usrName = (uchar*) strdup((char*)cs.usrName));
+ if(cs.dbName != NULL)
+ CHKmalloc(pData->dbName = (uchar*) strdup((char*)cs.dbName));
+ if(cs.pwd != NULL)
+ CHKmalloc(pData->pwd = (uchar*) strdup((char*)cs.pwd));
+ if(cs.dbiDrvrDir != NULL)
+ CHKmalloc(loadModConf->dbiDrvrDir = (uchar*) strdup((char*)cs.dbiDrvrDir));
+ iRet = cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_RQD_TPL_OPT_SQL, getDfltTpl());
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ /* if we initialized libdbi, we now need to cleanup */
+ if(bDbiInitialized) {
+# ifdef HAVE_DBI_R
+ dbi_shutdown_r(dbiInst);
+# else
+ dbi_shutdown();
+# endif
+ }
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+CODEqueryEtryPt_STD_OMOD8_QUERIES
+CODEqueryEtryPt_STD_CONF2_QUERIES
+CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES
+CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES
+CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */
+ENDqueryEtryPt
+
+
+/* Reset config variables for this module to default values.
+ */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ DEFiRet;
+ free(cs.dbiDrvrDir);
+ cs.dbiDrvrDir = NULL;
+ free(cs.drvrName);
+ cs.drvrName = NULL;
+ free(cs.host);
+ cs.host = NULL;
+ free(cs.usrName);
+ cs.usrName = NULL;
+ free(cs.pwd);
+ cs.pwd = NULL;
+ free(cs.dbName);
+ cs.dbName = NULL;
+ RETiRet;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+INITLegCnfVars
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+# ifndef HAVE_DBI_TXSUPP
+ DBGPRINTF("omlibdbi: no transaction support in libdbi\n");
+# endif
+ CHKiRet(regCfSysLineHdlr2((uchar *)"actionlibdbidriverdirectory", 0, eCmdHdlrGetWord, NULL, &cs.dbiDrvrDir,
+ STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbidriver", 0, eCmdHdlrGetWord, NULL, &cs.drvrName,
+ STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbihost", 0, eCmdHdlrGetWord, NULL, &cs.host,
+ STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbiusername", 0, eCmdHdlrGetWord, NULL, &cs.usrName,
+ STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbipassword", 0, eCmdHdlrGetWord, NULL, &cs.pwd,
+ STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionlibdbidbname", 0, eCmdHdlrGetWord, NULL, &cs.dbName,
+ STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables,
+ NULL, STD_LOADABLE_MODULE_ID));
+ DBGPRINTF("omlibdbi compiled with version %s loaded, libdbi version %s\n", VERSION, dbi_version());
+ENDmodInit
+
+/* vim:set ai:
+ */