2
* This is the implementation of the dbi output module.
4
* NOTE: read comments in module-template.h to understand how this file
7
* This depends on libdbi being present with the proper settings. Older
8
* versions do not necessarily have them. Please visit this bug tracker
9
* for details: http://bugzilla.adiscon.com/show_bug.cgi?id=31
11
* File begun on 2008-02-14 by RGerhards (extracted from syslogd.c)
13
* Copyright 2008 Rainer Gerhards and Adiscon GmbH.
15
* This file is part of rsyslog.
17
* Rsyslog is free software: you can redistribute it and/or modify
18
* it under the terms of the GNU General Public License as published by
19
* the Free Software Foundation, either version 3 of the License, or
20
* (at your option) any later version.
22
* Rsyslog is distributed in the hope that it will be useful,
23
* but WITHOUT ANY WARRANTY; without even the implied warranty of
24
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
* GNU General Public License for more details.
27
* You should have received a copy of the GNU General Public License
28
* along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
30
* A copy of the GPL can be found in the file "COPYING" in this distribution.
44
#include "syslogd-types.h"
45
#include "cfsysline.h"
48
#include "module-template.h"
54
/* internal structures
58
static int bDbiInitialized = 0; /* dbi_initialize() can only be called one - this keeps track of it */
60
typedef struct _instanceData {
61
dbi_conn conn; /* handle to database */
62
uchar *drvrName; /* driver to use */
63
uchar *host; /* host to connect to */
64
uchar *usrName; /* user name for connect */
65
uchar *pwd; /* password for connect */
66
uchar *dbName; /* database to use */
67
unsigned uLastDBErrno; /* last errno returned by libdbi or 0 if all is well */
72
static uchar *dbiDrvrDir = NULL;/* global: where do the dbi drivers reside? */
73
static uchar *drvrName = NULL; /* driver to use */
74
static uchar *host = NULL; /* host to connect to */
75
static uchar *usrName = NULL; /* user name for connect */
76
static uchar *pwd = NULL; /* password for connect */
77
static uchar *dbName = NULL; /* database to use */
79
static dbi_inst dbiInst;
84
CODESTARTcreateInstance
88
BEGINisCompatibleWithFeature
89
CODESTARTisCompatibleWithFeature
90
/* we do not like repeated message reduction inside the database */
91
ENDisCompatibleWithFeature
94
/* The following function is responsible for closing a
95
* database connection.
97
static void closeConn(instanceData *pData)
99
ASSERT(pData != NULL);
101
if(pData->conn != NULL) { /* just to be on the safe side... */
102
dbi_conn_close(pData->conn);
108
CODESTARTfreeInstance
113
BEGINdbgPrintInstInfo
114
CODESTARTdbgPrintInstInfo
115
/* nothing special here */
119
/* log a database error with descriptive message.
120
* We check if we have a valid database handle. If not, we simply
121
* report an error, but can not be specific. RGerhards, 2007-01-30
124
reportDBError(instanceData *pData, int bSilent)
128
const char *pszDbiErr;
131
ASSERT(pData != NULL);
133
/* output log message */
135
if(pData->conn == NULL) {
136
errmsg.LogError(NO_ERRCODE, "unknown DB error occured - could not obtain connection handle");
137
} else { /* we can ask dbi for the error description... */
138
uDBErrno = dbi_conn_error(pData->conn, &pszDbiErr);
139
snprintf(errMsg, sizeof(errMsg)/sizeof(char), "db error (%d): %s\n", uDBErrno, pszDbiErr);
140
if(bSilent || uDBErrno == pData->uLastDBErrno)
141
dbgprintf("libdbi, DBError(silent): %s\n", errMsg);
143
pData->uLastDBErrno = uDBErrno;
144
errmsg.LogError(NO_ERRCODE, "%s", errMsg);
152
/* The following function is responsible for initializing a connection
154
static rsRetVal initConn(instanceData *pData, int bSilent)
159
ASSERT(pData != NULL);
160
ASSERT(pData->conn == NULL);
162
if(bDbiInitialized == 0) {
163
/* we need to init libdbi first */
165
iDrvrsLoaded = dbi_initialize_r((char*) dbiDrvrDir, &dbiInst);
167
iDrvrsLoaded = dbi_initialize((char*) dbiDrvrDir);
169
if(iDrvrsLoaded == 0) {
170
errmsg.LogError(NO_ERRCODE, "libdbi error: libdbi or libdbi drivers not present on this system - suspending.");
171
ABORT_FINALIZE(RS_RET_SUSPENDED);
172
} else if(iDrvrsLoaded < 0) {
173
errmsg.LogError(NO_ERRCODE, "libdbi error: libdbi could not be initialized - suspending.");
174
ABORT_FINALIZE(RS_RET_SUSPENDED);
176
bDbiInitialized = 1; /* we are done for the rest of our existence... */
180
pData->conn = dbi_conn_new_r((char*)pData->drvrName, dbiInst);
182
pData->conn = dbi_conn_new((char*)pData->drvrName);
184
if(pData->conn == NULL) {
185
errmsg.LogError(NO_ERRCODE, "can not initialize libdbi connection");
186
iRet = RS_RET_SUSPENDED;
187
} else { /* we could get the handle, now on with work... */
188
/* Connect to database */
189
dbi_conn_set_option(pData->conn, "host", (char*) pData->host);
190
dbi_conn_set_option(pData->conn, "username", (char*) pData->usrName);
191
dbi_conn_set_option(pData->conn, "dbname", (char*) pData->dbName);
192
if(pData->pwd != NULL)
193
dbi_conn_set_option(pData->conn, "password", (char*) pData->pwd);
194
if(dbi_conn_connect(pData->conn) < 0) {
195
reportDBError(pData, bSilent);
196
closeConn(pData); /* ignore any error we may get */
197
iRet = RS_RET_SUSPENDED;
206
/* The following function writes the current log entry
207
* to an established database connection.
209
rsRetVal writeDB(uchar *psz, instanceData *pData)
212
dbi_result dbiRes = NULL;
215
ASSERT(pData != NULL);
217
/* see if we are ready to proceed */
218
if(pData->conn == NULL) {
219
CHKiRet(initConn(pData, 0));
223
if((dbiRes = dbi_conn_query(pData->conn, (const char*)psz)) == NULL) {
224
/* error occured, try to re-init connection and retry */
225
closeConn(pData); /* close the current handle */
226
CHKiRet(initConn(pData, 0)); /* try to re-open */
227
if((dbiRes = dbi_conn_query(pData->conn, (const char*)psz)) == NULL) { /* re-try insert */
228
/* we failed, giving up for now */
229
reportDBError(pData, 0);
230
closeConn(pData); /* free ressources */
231
ABORT_FINALIZE(RS_RET_SUSPENDED);
236
if(iRet == RS_RET_OK) {
237
pData->uLastDBErrno = 0; /* reset error for error supression */
241
dbi_result_free(dbiRes);
249
if(pData->conn == NULL) {
250
iRet = initConn(pData, 1);
257
iRet = writeDB(ppString[0], pData);
261
BEGINparseSelectorAct
262
CODESTARTparseSelectorAct
263
CODE_STD_STRING_REQUESTparseSelectorAct(1)
264
if(!strncmp((char*) p, ":omlibdbi:", sizeof(":omlibdbi:") - 1)) {
265
p += sizeof(":omlibdbi:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
267
ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
270
/* ok, if we reach this point, we have something for us */
271
CHKiRet(createInstance(&pData));
273
/* no create the instance based on what we currently have */
274
if(drvrName == NULL) {
275
errmsg.LogError(NO_ERRCODE, "omlibdbi: no db driver name given - action can not be created");
276
ABORT_FINALIZE(RS_RET_NO_DRIVERNAME);
279
if((pData->drvrName = (uchar*) strdup((char*)drvrName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
280
/* NULL values are supported because drivers have different needs.
281
* They will err out on connect. -- rgerhards, 2008-02-15
284
if((pData->host = (uchar*) strdup((char*)host)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
286
if((pData->usrName = (uchar*) strdup((char*)usrName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
288
if((pData->dbName = (uchar*) strdup((char*)dbName)) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
290
if((pData->pwd = (uchar*) strdup((char*)"")) == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
292
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_RQD_TPL_OPT_SQL, (uchar*) " StdDBFmt"));
294
CODE_STD_FINALIZERparseSelectorAct
300
/* if we initialized libdbi, we now need to cleanup */
301
if(bDbiInitialized) {
303
dbi_shutdown_r(dbiInst);
313
CODEqueryEtryPt_STD_OMOD_QUERIES
317
/* Reset config variables for this module to default values.
319
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
323
if(dbiDrvrDir != NULL) {
328
if(drvrName != NULL) {
338
if(usrName != NULL) {
359
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
360
CODEmodInit_QueryRegCFSLineHdlr
361
CHKiRet(objUse(errmsg, CORE_COMPONENT));
362
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbidriverdirectory", 0, eCmdHdlrGetWord, NULL, &dbiDrvrDir, STD_LOADABLE_MODULE_ID));
363
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbidriver", 0, eCmdHdlrGetWord, NULL, &drvrName, STD_LOADABLE_MODULE_ID));
364
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbihost", 0, eCmdHdlrGetWord, NULL, &host, STD_LOADABLE_MODULE_ID));
365
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbiusername", 0, eCmdHdlrGetWord, NULL, &usrName, STD_LOADABLE_MODULE_ID));
366
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbipassword", 0, eCmdHdlrGetWord, NULL, &pwd, STD_LOADABLE_MODULE_ID));
367
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionlibdbidbname", 0, eCmdHdlrGetWord, NULL, &dbName, STD_LOADABLE_MODULE_ID));
368
CHKiRet(omsdRegCFSLineHdlr( (uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));