mirror of
https://github.com/rsyslog/rsyslog.git
synced 2025-12-15 12:50:41 +01:00
661 lines
19 KiB
C
661 lines
19 KiB
C
/* 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;
|
|
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 occured - 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);
|
|
free(tmp);
|
|
dbi_conn_set_option(pData->conn, "dbname", bn);
|
|
} 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 occured, 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:
|
|
*/
|