~ubuntu-branches/ubuntu/lucid/rsyslog/lucid

« back to all changes in this revision

Viewing changes to plugins/ommysql/ommysql.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2007-10-19 17:21:49 UTC
  • Revision ID: james.westby@ubuntu.com-20071019172149-ie6ej2xve33mxiu7
Tags: upstream-1.19.10
ImportĀ upstreamĀ versionĀ 1.19.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ommysql.c
 
2
 * This is the implementation of the build-in output module for MySQL.
 
3
 *
 
4
 * NOTE: read comments in module-template.h to understand how this file
 
5
 *       works!
 
6
 *
 
7
 * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c)
 
8
 *
 
9
 * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
 
10
 *
 
11
 * This program is free software; you can redistribute it and/or
 
12
 * modify it under the terms of the GNU General Public License
 
13
 * as published by the Free Software Foundation; either version 2
 
14
 * of the License, or (at your option) any later version.
 
15
 *
 
16
 * This program is distributed in the hope that it will be useful,
 
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
 * GNU General Public License for more details.
 
20
 *
 
21
 * You should have received a copy of the GNU General Public License
 
22
 * along with this program; if not, write to the Free Software
 
23
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
24
 *
 
25
 * A copy of the GPL can be found in the file "COPYING" in this distribution.
 
26
 */
 
27
#include "config.h"
 
28
#include "rsyslog.h"
 
29
#include <stdio.h>
 
30
#include <stdarg.h>
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
#include <assert.h>
 
34
#include <signal.h>
 
35
#include <errno.h>
 
36
#include <time.h>
 
37
#include <mysql/mysql.h>
 
38
#include <mysql/errmsg.h>
 
39
#include "syslogd.h"
 
40
#include "syslogd-types.h"
 
41
#include "srUtils.h"
 
42
#include "template.h"
 
43
#include "ommysql.h"
 
44
#include "module-template.h"
 
45
 
 
46
/* internal structures
 
47
 */
 
48
DEF_OMOD_STATIC_DATA
 
49
 
 
50
typedef struct _instanceData {
 
51
        MYSQL   *f_hmysql;              /* handle to MySQL */
 
52
        char    f_dbsrv[MAXHOSTNAMELEN+1];      /* IP or hostname of DB server*/ 
 
53
        char    f_dbname[_DB_MAXDBLEN+1];       /* DB name */
 
54
        char    f_dbuid[_DB_MAXUNAMELEN+1];     /* DB user */
 
55
        char    f_dbpwd[_DB_MAXPWDLEN+1];       /* DB user's password */
 
56
        unsigned uLastMySQLErrno;       /* last errno returned by MySQL or 0 if all is well */
 
57
} instanceData;
 
58
 
 
59
 
 
60
BEGINcreateInstance
 
61
CODESTARTcreateInstance
 
62
ENDcreateInstance
 
63
 
 
64
 
 
65
BEGINisCompatibleWithFeature
 
66
CODESTARTisCompatibleWithFeature
 
67
        if(eFeat == sFEATURERepeatedMsgReduction)
 
68
                iRet = RS_RET_OK;
 
69
ENDisCompatibleWithFeature
 
70
 
 
71
 
 
72
/* The following function is responsible for closing a
 
73
 * MySQL connection.
 
74
 * Initially added 2004-10-28
 
75
 */
 
76
static void closeMySQL(instanceData *pData)
 
77
{
 
78
        assert(pData != NULL);
 
79
 
 
80
        if(pData->f_hmysql != NULL) {   /* just to be on the safe side... */
 
81
                mysql_server_end();
 
82
                mysql_close(pData->f_hmysql);   
 
83
                pData->f_hmysql = NULL;
 
84
        }
 
85
}
 
86
 
 
87
BEGINfreeInstance
 
88
CODESTARTfreeInstance
 
89
        closeMySQL(pData);
 
90
ENDfreeInstance
 
91
 
 
92
 
 
93
BEGINneedUDPSocket
 
94
CODESTARTneedUDPSocket
 
95
ENDneedUDPSocket
 
96
 
 
97
 
 
98
BEGINdbgPrintInstInfo
 
99
CODESTARTdbgPrintInstInfo
 
100
        /* nothing special here */
 
101
ENDdbgPrintInstInfo
 
102
 
 
103
 
 
104
BEGINonSelectReadyWrite
 
105
CODESTARTonSelectReadyWrite
 
106
ENDonSelectReadyWrite
 
107
 
 
108
 
 
109
BEGINgetWriteFDForSelect
 
110
CODESTARTgetWriteFDForSelect
 
111
ENDgetWriteFDForSelect
 
112
 
 
113
 
 
114
/* log a database error with descriptive message.
 
115
 * We check if we have a valid MySQL handle. If not, we simply
 
116
 * report an error, but can not be specific. RGerhards, 2007-01-30
 
117
 */
 
118
static void reportDBError(instanceData *pData, int bSilent)
 
119
{
 
120
        char errMsg[512];
 
121
        unsigned uMySQLErrno;
 
122
 
 
123
        assert(pData != NULL);
 
124
 
 
125
        /* output log message */
 
126
        errno = 0;
 
127
        if(pData->f_hmysql == NULL) {
 
128
                logerror("unknown DB error occured - could not obtain MySQL handle");
 
129
        } else { /* we can ask mysql for the error description... */
 
130
                uMySQLErrno = mysql_errno(pData->f_hmysql);
 
131
                snprintf(errMsg, sizeof(errMsg)/sizeof(char), "db error (%d): %s\n", uMySQLErrno,
 
132
                        mysql_error(pData->f_hmysql));
 
133
                if(bSilent || uMySQLErrno == pData->uLastMySQLErrno)
 
134
                        dbgprintf("mysql, DBError(silent): %s\n", errMsg);
 
135
                else {
 
136
                        pData->uLastMySQLErrno = uMySQLErrno;
 
137
                        logerror(errMsg);
 
138
                }
 
139
        }
 
140
                
 
141
        return;
 
142
}
 
143
 
 
144
 
 
145
/* The following function is responsible for initializing a
 
146
 * MySQL connection.
 
147
 * Initially added 2004-10-28 mmeckelein
 
148
 */
 
149
static rsRetVal initMySQL(instanceData *pData, int bSilent)
 
150
{
 
151
        DEFiRet;
 
152
 
 
153
        assert(pData != NULL);
 
154
        assert(pData->f_hmysql == NULL);
 
155
 
 
156
        pData->f_hmysql = mysql_init(NULL);
 
157
        if(pData->f_hmysql == NULL) {
 
158
                logerror("can not initialize MySQL handle");
 
159
                iRet = RS_RET_SUSPENDED;
 
160
        } else { /* we could get the handle, now on with work... */
 
161
                /* Connect to database */
 
162
                if(mysql_real_connect(pData->f_hmysql, pData->f_dbsrv, pData->f_dbuid,
 
163
                                      pData->f_dbpwd, pData->f_dbname, 0, NULL, 0) == NULL) {
 
164
                        reportDBError(pData, bSilent);
 
165
                        closeMySQL(pData); /* ignore any error we may get */
 
166
                        iRet = RS_RET_SUSPENDED;
 
167
                }
 
168
        }
 
169
 
 
170
        return iRet;
 
171
}
 
172
 
 
173
 
 
174
/* The following function writes the current log entry
 
175
 * to an established MySQL session.
 
176
 * Initially added 2004-10-28 mmeckelein
 
177
 */
 
178
rsRetVal writeMySQL(uchar *psz, instanceData *pData)
 
179
{
 
180
        DEFiRet;
 
181
 
 
182
        assert(psz != NULL);
 
183
        assert(pData != NULL);
 
184
 
 
185
        /* try insert */
 
186
        if(mysql_query(pData->f_hmysql, (char*)psz)) {
 
187
                /* error occured, try to re-init connection and retry */
 
188
                closeMySQL(pData); /* close the current handle */
 
189
                CHKiRet(initMySQL(pData, 0)); /* try to re-open */
 
190
                if(mysql_query(pData->f_hmysql, (char*)psz)) { /* re-try insert */
 
191
                        /* we failed, giving up for now */
 
192
                        reportDBError(pData, 0);
 
193
                        closeMySQL(pData); /* free ressources */
 
194
                        ABORT_FINALIZE(RS_RET_SUSPENDED);
 
195
                }
 
196
        }
 
197
 
 
198
finalize_it:
 
199
        if(iRet == RS_RET_OK) {
 
200
                pData->uLastMySQLErrno = 0; /* reset error for error supression */
 
201
        }
 
202
 
 
203
        return iRet;
 
204
}
 
205
 
 
206
 
 
207
BEGINtryResume
 
208
CODESTARTtryResume
 
209
        if(pData->f_hmysql == NULL) {
 
210
                iRet = initMySQL(pData, 1);
 
211
        }
 
212
ENDtryResume
 
213
 
 
214
BEGINdoAction
 
215
CODESTARTdoAction
 
216
        dbgprintf("\n");
 
217
        iRet = writeMySQL(ppString[0], pData);
 
218
ENDdoAction
 
219
 
 
220
 
 
221
BEGINparseSelectorAct
 
222
        int iMySQLPropErr = 0;
 
223
CODESTARTparseSelectorAct
 
224
CODE_STD_STRING_REQUESTparseSelectorAct(1)
 
225
        /* first check if this config line is actually for us
 
226
         * The first test [*p == '>'] can be skipped if a module shall only
 
227
         * support the newer slection syntax [:modname:]. This is in fact
 
228
         * recommended for new modules. Please note that over time this part
 
229
         * will be handled by rsyslogd itself, but for the time being it is
 
230
         * a good compromise to do it at the module level.
 
231
         * rgerhards, 2007-10-15
 
232
         */
 
233
        if(*p == '>') {
 
234
                p++; /* eat '>' '*/
 
235
        } else if(!strncmp((char*) p, ":ommysql:", sizeof(":ommysql:") - 1)) {
 
236
                p += sizeof(":ommysql:"); /* eat indicator sequence */
 
237
        } else {
 
238
                ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
 
239
        }
 
240
 
 
241
        /* ok, if we reach this point, we have something for us */
 
242
        if((iRet = createInstance(&pData)) != RS_RET_OK)
 
243
                goto finalize_it;
 
244
 
 
245
 
 
246
        /* rger 2004-10-28: added support for MySQL
 
247
         * >server,dbname,userid,password
 
248
         * Now we read the MySQL connection properties 
 
249
         * and verify that the properties are valid.
 
250
         */
 
251
        if(getSubString(&p, pData->f_dbsrv, MAXHOSTNAMELEN+1, ','))
 
252
                iMySQLPropErr++;
 
253
        if(*pData->f_dbsrv == '\0')
 
254
                iMySQLPropErr++;
 
255
        if(getSubString(&p, pData->f_dbname, _DB_MAXDBLEN+1, ','))
 
256
                iMySQLPropErr++;
 
257
        if(*pData->f_dbname == '\0')
 
258
                iMySQLPropErr++;
 
259
        if(getSubString(&p, pData->f_dbuid, _DB_MAXUNAMELEN+1, ','))
 
260
                iMySQLPropErr++;
 
261
        if(*pData->f_dbuid == '\0')
 
262
                iMySQLPropErr++;
 
263
        if(getSubString(&p, pData->f_dbpwd, _DB_MAXPWDLEN+1, ';'))
 
264
                iMySQLPropErr++;
 
265
        /* now check for template
 
266
         * We specify that the SQL option must be present in the template.
 
267
         * This is for your own protection (prevent sql injection).
 
268
         */
 
269
        if(*(p-1) == ';')
 
270
                --p;    /* TODO: the whole parsing of the MySQL module needs to be re-thought - but this here
 
271
                         *       is clean enough for the time being -- rgerhards, 2007-07-30
 
272
                         */
 
273
        CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_RQD_TPL_OPT_SQL, (uchar*) " StdDBFmt"));
 
274
        
 
275
        /* If we detect invalid properties, we disable logging, 
 
276
         * because right properties are vital at this place.  
 
277
         * Retries make no sense. 
 
278
         */
 
279
        if (iMySQLPropErr) { 
 
280
                logerror("Trouble with MySQL connection properties. -MySQL logging disabled");
 
281
                ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
 
282
        } else {
 
283
                CHKiRet(initMySQL(pData, 0));
 
284
        }
 
285
 
 
286
CODE_STD_FINALIZERparseSelectorAct
 
287
ENDparseSelectorAct
 
288
 
 
289
 
 
290
BEGINqueryEtryPt
 
291
CODESTARTqueryEtryPt
 
292
CODEqueryEtryPt_STD_OMOD_QUERIES
 
293
ENDqueryEtryPt
 
294
 
 
295
 
 
296
BEGINmodInit()
 
297
CODESTARTmodInit
 
298
        *ipIFVersProvided = 1; /* so far, we only support the initial definition */
 
299
CODEmodInit_QueryRegCFSLineHdlr
 
300
ENDmodInit
 
301
/*
 
302
 * vi:set ai:
 
303
 */