2
* This is the implementation of the build-in output module for MySQL.
4
* NOTE: read comments in module-template.h to understand how this file
7
* File begun on 2007-07-20 by RGerhards (extracted from syslogd.c)
9
* Copyright 2007 Rainer Gerhards and Adiscon GmbH.
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.
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.
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.
25
* A copy of the GPL can be found in the file "COPYING" in this distribution.
37
#include <mysql/mysql.h>
38
#include <mysql/errmsg.h>
40
#include "syslogd-types.h"
44
#include "module-template.h"
46
/* internal structures
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 */
61
CODESTARTcreateInstance
65
BEGINisCompatibleWithFeature
66
CODESTARTisCompatibleWithFeature
67
if(eFeat == sFEATURERepeatedMsgReduction)
69
ENDisCompatibleWithFeature
72
/* The following function is responsible for closing a
74
* Initially added 2004-10-28
76
static void closeMySQL(instanceData *pData)
78
assert(pData != NULL);
80
if(pData->f_hmysql != NULL) { /* just to be on the safe side... */
82
mysql_close(pData->f_hmysql);
83
pData->f_hmysql = NULL;
94
CODESTARTneedUDPSocket
99
CODESTARTdbgPrintInstInfo
100
/* nothing special here */
104
BEGINonSelectReadyWrite
105
CODESTARTonSelectReadyWrite
106
ENDonSelectReadyWrite
109
BEGINgetWriteFDForSelect
110
CODESTARTgetWriteFDForSelect
111
ENDgetWriteFDForSelect
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
118
static void reportDBError(instanceData *pData, int bSilent)
121
unsigned uMySQLErrno;
123
assert(pData != NULL);
125
/* output log message */
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);
136
pData->uLastMySQLErrno = uMySQLErrno;
145
/* The following function is responsible for initializing a
147
* Initially added 2004-10-28 mmeckelein
149
static rsRetVal initMySQL(instanceData *pData, int bSilent)
153
assert(pData != NULL);
154
assert(pData->f_hmysql == NULL);
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;
174
/* The following function writes the current log entry
175
* to an established MySQL session.
176
* Initially added 2004-10-28 mmeckelein
178
rsRetVal writeMySQL(uchar *psz, instanceData *pData)
183
assert(pData != NULL);
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);
199
if(iRet == RS_RET_OK) {
200
pData->uLastMySQLErrno = 0; /* reset error for error supression */
209
if(pData->f_hmysql == NULL) {
210
iRet = initMySQL(pData, 1);
217
iRet = writeMySQL(ppString[0], pData);
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
235
} else if(!strncmp((char*) p, ":ommysql:", sizeof(":ommysql:") - 1)) {
236
p += sizeof(":ommysql:"); /* eat indicator sequence */
238
ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
241
/* ok, if we reach this point, we have something for us */
242
if((iRet = createInstance(&pData)) != RS_RET_OK)
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.
251
if(getSubString(&p, pData->f_dbsrv, MAXHOSTNAMELEN+1, ','))
253
if(*pData->f_dbsrv == '\0')
255
if(getSubString(&p, pData->f_dbname, _DB_MAXDBLEN+1, ','))
257
if(*pData->f_dbname == '\0')
259
if(getSubString(&p, pData->f_dbuid, _DB_MAXUNAMELEN+1, ','))
261
if(*pData->f_dbuid == '\0')
263
if(getSubString(&p, pData->f_dbpwd, _DB_MAXPWDLEN+1, ';'))
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).
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
273
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_RQD_TPL_OPT_SQL, (uchar*) " StdDBFmt"));
275
/* If we detect invalid properties, we disable logging,
276
* because right properties are vital at this place.
277
* Retries make no sense.
280
logerror("Trouble with MySQL connection properties. -MySQL logging disabled");
281
ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
283
CHKiRet(initMySQL(pData, 0));
286
CODE_STD_FINALIZERparseSelectorAct
292
CODEqueryEtryPt_STD_OMOD_QUERIES
298
*ipIFVersProvided = 1; /* so far, we only support the initial definition */
299
CODEmodInit_QueryRegCFSLineHdlr