~ubuntu-branches/ubuntu/karmic/rsyslog/karmic-200908151517

« back to all changes in this revision

Viewing changes to plugins/omlibdbi/omlibdbi.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2008-04-23 16:46:39 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080423164639-5acmt8a4vpxjgnxw
Tags: 3.14.2-3
* debian/rsyslog-doc.install
  - Fix a typo in the install path of the dia files. Closes: #477489
    Thanks to Justin B Rye for the patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* omlibdbi.c
 
2
 * This is the implementation of the dbi output module.
 
3
 *
 
4
 * NOTE: read comments in module-template.h to understand how this file
 
5
 *       works!
 
6
 *
 
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
 
10
 *
 
11
 * File begun on 2008-02-14 by RGerhards (extracted from syslogd.c)
 
12
 *
 
13
 * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
 
14
 *
 
15
 * This file is part of rsyslog.
 
16
 *
 
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.
 
21
 *
 
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.
 
26
 *
 
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/>.
 
29
 *
 
30
 * A copy of the GPL can be found in the file "COPYING" in this distribution.
 
31
 */
 
32
#include "config.h"
 
33
#include "rsyslog.h"
 
34
#include <stdio.h>
 
35
#include <stdarg.h>
 
36
#include <stdlib.h>
 
37
#include <string.h>
 
38
#include <assert.h>
 
39
#include <signal.h>
 
40
#include <errno.h>
 
41
#include <time.h>
 
42
#include <dbi/dbi.h>
 
43
#include "syslogd.h"
 
44
#include "syslogd-types.h"
 
45
#include "cfsysline.h"
 
46
#include "srUtils.h"
 
47
#include "template.h"
 
48
#include "module-template.h"
 
49
#include "debug.h"
 
50
#include "errmsg.h"
 
51
 
 
52
MODULE_TYPE_OUTPUT
 
53
 
 
54
/* internal structures
 
55
 */
 
56
DEF_OMOD_STATIC_DATA
 
57
DEFobjCurrIf(errmsg)
 
58
static int bDbiInitialized = 0; /* dbi_initialize() can only be called one - this keeps track of it */
 
59
 
 
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 */
 
68
} instanceData;
 
69
 
 
70
 
 
71
/* config settings */
 
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 */
 
78
#ifdef HAVE_DBI_R
 
79
static dbi_inst dbiInst;
 
80
#endif
 
81
 
 
82
 
 
83
BEGINcreateInstance
 
84
CODESTARTcreateInstance
 
85
ENDcreateInstance
 
86
 
 
87
 
 
88
BEGINisCompatibleWithFeature
 
89
CODESTARTisCompatibleWithFeature
 
90
        /* we do not like repeated message reduction inside the database */
 
91
ENDisCompatibleWithFeature
 
92
 
 
93
 
 
94
/* The following function is responsible for closing a
 
95
 * database connection.
 
96
 */
 
97
static void closeConn(instanceData *pData)
 
98
{
 
99
        ASSERT(pData != NULL);
 
100
 
 
101
        if(pData->conn != NULL) {       /* just to be on the safe side... */
 
102
                dbi_conn_close(pData->conn);
 
103
                pData->conn = NULL;
 
104
        }
 
105
}
 
106
 
 
107
BEGINfreeInstance
 
108
CODESTARTfreeInstance
 
109
        closeConn(pData);
 
110
ENDfreeInstance
 
111
 
 
112
 
 
113
BEGINdbgPrintInstInfo
 
114
CODESTARTdbgPrintInstInfo
 
115
        /* nothing special here */
 
116
ENDdbgPrintInstInfo
 
117
 
 
118
 
 
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
 
122
 */
 
123
static void
 
124
reportDBError(instanceData *pData, int bSilent)
 
125
{
 
126
        unsigned uDBErrno;
 
127
        char errMsg[1024];
 
128
        const char *pszDbiErr;
 
129
 
 
130
        BEGINfunc
 
131
        ASSERT(pData != NULL);
 
132
 
 
133
        /* output log message */
 
134
        errno = 0;
 
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);
 
142
                else {
 
143
                        pData->uLastDBErrno = uDBErrno;
 
144
                        errmsg.LogError(NO_ERRCODE, "%s", errMsg);
 
145
                }
 
146
        }
 
147
                
 
148
        ENDfunc
 
149
}
 
150
 
 
151
 
 
152
/* The following function is responsible for initializing a connection
 
153
 */
 
154
static rsRetVal initConn(instanceData *pData, int bSilent)
 
155
{
 
156
        DEFiRet;
 
157
        int iDrvrsLoaded;
 
158
 
 
159
        ASSERT(pData != NULL);
 
160
        ASSERT(pData->conn == NULL);
 
161
 
 
162
        if(bDbiInitialized == 0) {
 
163
                /* we need to init libdbi first */
 
164
#               ifdef HAVE_DBI_R
 
165
                iDrvrsLoaded = dbi_initialize_r((char*) dbiDrvrDir, &dbiInst);
 
166
#               else
 
167
                iDrvrsLoaded = dbi_initialize((char*) dbiDrvrDir);
 
168
#               endif
 
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);
 
175
                }
 
176
                bDbiInitialized = 1; /* we are done for the rest of our existence... */
 
177
        }
 
178
 
 
179
#       ifdef HAVE_DBI_R
 
180
        pData->conn = dbi_conn_new_r((char*)pData->drvrName, dbiInst);
 
181
#       else
 
182
        pData->conn = dbi_conn_new((char*)pData->drvrName);
 
183
#       endif
 
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;
 
198
                }
 
199
        }
 
200
 
 
201
finalize_it:
 
202
        RETiRet;
 
203
}
 
204
 
 
205
 
 
206
/* The following function writes the current log entry
 
207
 * to an established database connection.
 
208
 */
 
209
rsRetVal writeDB(uchar *psz, instanceData *pData)
 
210
{
 
211
        DEFiRet;
 
212
        dbi_result dbiRes = NULL;
 
213
 
 
214
        ASSERT(psz != NULL);
 
215
        ASSERT(pData != NULL);
 
216
 
 
217
        /* see if we are ready to proceed */
 
218
        if(pData->conn == NULL) {
 
219
                CHKiRet(initConn(pData, 0));
 
220
        }
 
221
 
 
222
        /* try insert */
 
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);
 
232
                }
 
233
        }
 
234
 
 
235
finalize_it:
 
236
        if(iRet == RS_RET_OK) {
 
237
                pData->uLastDBErrno = 0; /* reset error for error supression */
 
238
        }
 
239
 
 
240
        if(dbiRes != NULL)
 
241
                dbi_result_free(dbiRes);
 
242
 
 
243
        RETiRet;
 
244
}
 
245
 
 
246
 
 
247
BEGINtryResume
 
248
CODESTARTtryResume
 
249
        if(pData->conn == NULL) {
 
250
                iRet = initConn(pData, 1);
 
251
        }
 
252
ENDtryResume
 
253
 
 
254
BEGINdoAction
 
255
CODESTARTdoAction
 
256
        dbgprintf("\n");
 
257
        iRet = writeDB(ppString[0], pData);
 
258
ENDdoAction
 
259
 
 
260
 
 
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'!) */
 
266
        } else {
 
267
                ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
 
268
        }
 
269
 
 
270
        /* ok, if we reach this point, we have something for us */
 
271
        CHKiRet(createInstance(&pData));
 
272
 
 
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);
 
277
        }
 
278
 
 
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
 
282
         */
 
283
        if(host    != NULL)
 
284
                if((pData->host     = (uchar*) strdup((char*)host))     == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
 
285
        if(usrName != NULL)
 
286
                if((pData->usrName  = (uchar*) strdup((char*)usrName))  == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
 
287
        if(dbName  != NULL)
 
288
                if((pData->dbName   = (uchar*) strdup((char*)dbName))   == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
 
289
        if(pwd     != NULL)
 
290
                if((pData->pwd      = (uchar*) strdup((char*)""))       == NULL) ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
 
291
 
 
292
        CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_RQD_TPL_OPT_SQL, (uchar*) " StdDBFmt"));
 
293
 
 
294
CODE_STD_FINALIZERparseSelectorAct
 
295
ENDparseSelectorAct
 
296
 
 
297
 
 
298
BEGINmodExit
 
299
CODESTARTmodExit
 
300
        /* if we initialized libdbi, we now need to cleanup */
 
301
        if(bDbiInitialized) {
 
302
#               ifdef HAVE_DBI_R
 
303
                dbi_shutdown_r(dbiInst);
 
304
#               else
 
305
                dbi_shutdown();
 
306
#               endif
 
307
        }
 
308
ENDmodExit
 
309
 
 
310
 
 
311
BEGINqueryEtryPt
 
312
CODESTARTqueryEtryPt
 
313
CODEqueryEtryPt_STD_OMOD_QUERIES
 
314
ENDqueryEtryPt
 
315
 
 
316
 
 
317
/* Reset config variables for this module to default values.
 
318
 */
 
319
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
 
320
{
 
321
        DEFiRet;
 
322
 
 
323
        if(dbiDrvrDir != NULL) {
 
324
                free(dbiDrvrDir);
 
325
                dbiDrvrDir = NULL;
 
326
        }
 
327
 
 
328
        if(drvrName != NULL) {
 
329
                free(drvrName);
 
330
                drvrName = NULL;
 
331
        }
 
332
 
 
333
        if(host != NULL) {
 
334
                free(host);
 
335
                host = NULL;
 
336
        }
 
337
 
 
338
        if(usrName != NULL) {
 
339
                free(usrName);
 
340
                usrName = NULL;
 
341
        }
 
342
 
 
343
        if(pwd != NULL) {
 
344
                free(pwd);
 
345
                pwd = NULL;
 
346
        }
 
347
 
 
348
        if(dbName != NULL) {
 
349
                free(dbName);
 
350
                dbName = NULL;
 
351
        }
 
352
 
 
353
        RETiRet;
 
354
}
 
355
 
 
356
 
 
357
BEGINmodInit()
 
358
CODESTARTmodInit
 
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));
 
369
ENDmodInit
 
370
 
 
371
/* vim:set ai:
 
372
 */