diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | ommysql.c | 275 | ||||
-rw-r--r-- | ommysql.h | 45 | ||||
-rw-r--r-- | omusrmsg.c | 2 | ||||
-rw-r--r-- | syslogd-types.h | 9 | ||||
-rw-r--r-- | syslogd.c | 241 |
6 files changed, 338 insertions, 236 deletions
diff --git a/Makefile.am b/Makefile.am index 3da81d7f..b1c85466 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ rfc3195d_SOURCES=rfc3195d.c rsyslog.h man_MANS = rfc3195d.8 rklogd.8 rsyslogd.8 rsyslog.conf.5 -rsyslogd_SOURCES=syslogd.c pidfile.c template.c outchannel.c stringbuf.c srUtils.c parse.c syslogd-types.h template.h outchannel.h syslogd.h stringbuf.h parse.h srUtils.h liblogging-stub.h net.h msg.c msg.h omshell.c omshell.h omusrmsg.c omusrmsg.h +rsyslogd_SOURCES=syslogd.c pidfile.c template.c outchannel.c stringbuf.c srUtils.c parse.c syslogd-types.h template.h outchannel.h syslogd.h stringbuf.h parse.h srUtils.h liblogging-stub.h net.h msg.c msg.h omshell.c omshell.h omusrmsg.c omusrmsg.h ommysql.c ommysql.h rsyslogd_CPPFLAGS=$(mysql_includes) rsyslogd_LDADD=$(mysql_libs) $(zlib_libs) $(pthreads_libs) diff --git a/ommysql.c b/ommysql.c new file mode 100644 index 00000000..eda2490a --- /dev/null +++ b/ommysql.c @@ -0,0 +1,275 @@ +/* omusrmsg.c + * This is the implementation of the build-in output module for MySQL. + * + * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c) + * This file is under development and has not yet arrived at being fully + * self-contained and a real object. So far, it is mostly an excerpt + * of the "old" message code without any modifications. However, it + * helps to have things at the right place one we go to the meat of it. + * + * Copyright 2007 Rainer Gerhards and Adiscon GmbH. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#ifdef WITH_DB +#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 "rsyslog.h" +#include "syslogd.h" +#include "syslogd-types.h" +#include "srUtils.h" +#include "ommysql.h" +#include "mysql/mysql.h" +#include "mysql/errmsg.h" + + +/** + * DBErrorHandler + * + * Call this function if an db error apears. It will initiate + * the "delay" handling which stopped the db logging for some + * time. + * + * We now check if we have a valid MySQL handle. If not, we simply + * report an error, but can not be specific. RGerhards, 2007-01-30 + */ +static void DBErrorHandler(register selector_t *f) +{ + char errMsg[512]; + + assert(f != NULL); + + /* TODO: + * NO DB connection -> Can not log to DB + * -------------------- + * Case 1: db server unavailable + * We can check after a specified time interval if the server is up. + * Also a reason can be a down DNS service. + * Case 2: uid, pwd or dbname are incorrect + * If this is a fault in the syslog.conf we have no chance to recover. But + * if it is a problem of the DB we can make a retry after some time. Possible + * are that the admin has not already set up the database table. Or he has not + * created the database user yet. + * Case 3: unkown error + * If we get an unkowon error here, we should in any case try to recover after + * a specified time interval. + * + * Insert failed -> Can not log to DB + * -------------------- + * If the insert fails it is never a good idea to give up. Only an + * invalid sql sturcture (wrong template) force us to disable db + * logging. + * + * Think about different "delay" for different errors! + */ + if(f->f_un.f_mysql.f_hmysql == NULL) { + logerror("unknown DB error occured - called error handler with NULL MySQL handle."); + } else { /* we can ask mysql for the error description... */ + errno = 0; + snprintf(errMsg, sizeof(errMsg)/sizeof(char), + "db error (%d): %s\n", mysql_errno(f->f_un.f_mysql.f_hmysql), + mysql_error(f->f_un.f_mysql.f_hmysql)); + f->f_un.f_mysql.f_iLastDBErrNo = mysql_errno(f->f_un.f_mysql.f_hmysql); + logerror(errMsg); + } + + /* Enable "delay" */ + f->f_un.f_mysql.f_timeResumeOnError = time(&f->f_un.f_mysql.f_timeResumeOnError) + _DB_DELAYTIMEONERROR ; +} + + +/** + * checkDBErrorState + * + * Check if we can go on with database logging or if we should wait + * a little bit longer. It also check if the DB hanlde is still valid. + * If it is necessary, it takes action to reinitiate the db connection. + * + * \ret int Returns 0 if successful (no error) + */ +int checkDBErrorState(register selector_t *f) +{ + time_t now; + assert(f != NULL); + /* dprintf("in checkDBErrorState, timeResumeOnError: %d\n", f->f_timeResumeOnError); */ + + /* If timeResumeOnError == 0 no error occured, + we can return with 0 (no error) */ + if (f->f_un.f_mysql.f_timeResumeOnError == 0) + return 0; + + (void) time(&now); + /* Now we know an error occured. We check timeResumeOnError + if we can process. If we have not reach the resume time + yet, we return an error status. */ + if (f->f_un.f_mysql.f_timeResumeOnError > now) + { + /* dprintf("Wait time is not over yet.\n"); */ + return 1; + } + + /* Ok, we can try to resume the database logging. First + we have to reset the status (timeResumeOnError) and + the last error no. */ + /* To improve this code it would be better to check + if we really need to reInit the db connection. If + only the insert failed and the db conncetcion is + still valid, we need no reInit. + Of course, if an unkown error appeared, we should + reInit. */ + /* rgerhards 2004-12-08: I think it is pretty unlikely + * that we can re-use a connection after the error. So I guess + * the connection must be closed and re-opened in all cases + * (as it is done currently). When we come back to optimize + * this code, we should anyhow see if there are cases where + * we could keep it open. I just doubt this won't be the case. + * I added this comment (and did not remove Michaels) just so + * that we all know what we are looking for. + */ + f->f_un.f_mysql.f_timeResumeOnError = 0; + f->f_un.f_mysql.f_iLastDBErrNo = 0; + reInitMySQL(f); + return 0; + +} + +/* + * The following function is responsible for initializing a + * MySQL connection. + * Initially added 2004-10-28 mmeckelein + */ +void initMySQL(register selector_t *f) +{ + int iCounter = 0; + assert(f != NULL); + + if (checkDBErrorState(f)) + return; + + f->f_un.f_mysql.f_hmysql = mysql_init(NULL); + if(f->f_un.f_mysql.f_hmysql == NULL) { + logerror("can not initialize MySQL handle - ignoring this action"); + /* The next statement causes a redundant message, but it is the + * best thing we can do in this situation. -- rgerhards, 2007-01-30 + */ + f->f_type = F_UNUSED; + } else { /* we could get the handle, now on with work... */ + do { + /* Connect to database */ + if (!mysql_real_connect(f->f_un.f_mysql.f_hmysql, f->f_un.f_mysql.f_dbsrv, f->f_un.f_mysql.f_dbuid, + f->f_un.f_mysql.f_dbpwd, f->f_un.f_mysql.f_dbname, 0, NULL, 0)) { + /* if also the second attempt failed + we call the error handler */ + if(iCounter) + DBErrorHandler(f); + } else { + f->f_un.f_mysql.f_timeResumeOnError = 0; /* We have a working db connection */ + dprintf("connected successfully to db\n"); + } + iCounter++; + } while (mysql_errno(f->f_un.f_mysql.f_hmysql) && iCounter<2); + } +} + +/* + * The following function is responsible for closing a + * MySQL connection. + * Initially added 2004-10-28 + */ +void closeMySQL(register selector_t *f) +{ + assert(f != NULL); + dprintf("in closeMySQL\n"); + if(f->f_un.f_mysql.f_hmysql != NULL) /* just to be on the safe side... */ + mysql_close(f->f_un.f_mysql.f_hmysql); +} + +/* + * Reconnect a MySQL connection. + * Initially added 2004-12-02 + */ +void reInitMySQL(register selector_t *f) +{ + assert(f != NULL); + + dprintf("reInitMySQL\n"); + closeMySQL(f); /* close the current handle */ + initMySQL(f); /* new connection */ +} + + + +/* The following function writes the current log entry + * to an established MySQL session. + * Initially added 2004-10-28 mmeckelein + */ +void writeMySQL(register selector_t *f) +{ + char *psz; + int iCounter=0; + assert(f != NULL); + + iovCreate(f); + psz = iovAsString(f); + + if (checkDBErrorState(f)) + return; + + /* Now we are trying to insert the data. + * + * If the first attampt fails we simply try a second one. If that + * fails too, we discard the message and enable "delay" error handling. + */ + do { + /* query */ + if(mysql_query(f->f_un.f_mysql.f_hmysql, psz)) { + /* if the second attempt fails + we call the error handler */ + if(iCounter) + DBErrorHandler(f); + } + else { + /* dprintf("db insert sucessfully\n"); */ + } + iCounter++; + } while (mysql_errno(f->f_un.f_mysql.f_hmysql) && iCounter<2); +} + +/* call the shell action + * returns 0 if it succeeds, something else otherwise + */ +int doActionMySQL(selector_t *f, time_t now) +{ + assert(f != NULL); + + f->f_time = now; + dprintf("\n"); + writeMySQL(f); + return 0; +} + +#endif /* #ifdef WITH_DB */ +/* + * vi:set ai: + */ diff --git a/ommysql.h b/ommysql.h new file mode 100644 index 00000000..685734db --- /dev/null +++ b/ommysql.h @@ -0,0 +1,45 @@ +/* omusrmsg.c + * These are the definitions for the build-in MySQL output module. + * + * File begun on 2007-07-13 by RGerhards (extracted from syslogd.c) + * + * Copyright 2007 Rainer Gerhards and Adiscon GmbH. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#ifndef OMMYSQL_H_INCLUDED +#define OMMYSQL_H_INCLUDED 1 +#ifdef WITH_DB + +/* prototypes */ +/* prototypes will be removed as syslogd needs no longer to directly + * call into the module! + */ +void initMySQL(register selector_t *f); +void writeMySQL(register selector_t *f); +void closeMySQL(register selector_t *f); +void reInitMySQL(register selector_t *f); +int checkDBErrorState(register selector_t *f); +//void DBErrorHandler(register selector_t *f); + +int doActionMySQL(selector_t *f, time_t now); + +#endif /* #ifdef WITH_DB */ +#endif /* #ifndef OMMYSQL_H_INCLUDED */ +/* + * vi:set ai: + */ @@ -48,7 +48,7 @@ #include "syslogd.h" #include "syslogd-types.h" #include "srUtils.h" -#include "omshell.h" +#include "omusrmsg.h" jmp_buf ttybuf; diff --git a/syslogd-types.h b/syslogd-types.h index 3428db2a..c5da7da4 100644 --- a/syslogd-types.h +++ b/syslogd-types.h @@ -38,6 +38,15 @@ #define MAXUNAMES 20 /* maximum number of user names */ #define MAXFNAME 200 /* max file pathname length */ +#ifdef WITH_DB +#include "mysql/mysql.h" +#define _DB_MAXDBLEN 128 /* maximum number of db */ +#define _DB_MAXUNAMELEN 128 /* maximum number of user name */ +#define _DB_MAXPWDLEN 128 /* maximum number of user's pass */ +#define _DB_DELAYTIMEONERROR 20 /* If an error occur we stop logging until + a delayed time is over */ +#endif + /* we define our own facility and severities */ /* facility and severity codes */ @@ -186,11 +186,6 @@ #include <assert.h> -#ifdef WITH_DB -#include "mysql/mysql.h" -#include "mysql/errmsg.h" -#endif - #ifdef USE_PTHREADS #include <pthread.h> #endif @@ -221,6 +216,11 @@ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) #endif +#ifdef WITH_DB +#include "mysql/mysql.h" +#include "mysql/errmsg.h" +#endif + #include "rsyslog.h" #include "template.h" #include "outchannel.h" @@ -232,6 +232,7 @@ #include "msg.h" #include "omshell.h" #include "omusrmsg.h" +#include "ommysql.h" /* We define our own set of syslog defintions so that we * do not need to rely on (possibly different) implementations. @@ -294,13 +295,6 @@ syslogCODE rs_facilitynames[] = { NULL, -1 } }; -#ifdef WITH_DB -#define _DB_MAXDBLEN 128 /* maximum number of db */ -#define _DB_MAXUNAMELEN 128 /* maximum number of user name */ -#define _DB_MAXPWDLEN 128 /* maximum number of user's pass */ -#define _DB_DELAYTIMEONERROR 20 /* If an error occur we stop logging until - a delayed time is over */ -#endif #ifndef UTMP_FILE #ifdef UTMP_FILENAME @@ -778,14 +772,6 @@ static rsRetVal cfline(char *line, register selector_t *f); static int decode(uchar *name, struct code *codetab); static void sighup_handler(); static void die(int sig); -#ifdef WITH_DB -static void initMySQL(register selector_t *f); -static void writeMySQL(register selector_t *f); -static void closeMySQL(register selector_t *f); -static void reInitMySQL(register selector_t *f); -static int checkDBErrorState(register selector_t *f); -static void DBErrorHandler(register selector_t *f); -#endif static int getSubString(uchar **pSrc, char *pDst, size_t DstSize, char cSep); static void cflineSetTemplateAndIOV(selector_t *f, char *pTemplateName); @@ -5696,9 +5682,7 @@ void fprintlog(register selector_t *f) #ifdef WITH_DB case F_MYSQL: - f->f_time = now; - dprintf("\n"); - writeMySQL(f); + doActionMySQL(f, now); break; #endif @@ -8174,217 +8158,6 @@ void sighup_handler() return; } -#ifdef WITH_DB -/* - * The following function is responsible for initializing a - * MySQL connection. - * Initially added 2004-10-28 mmeckelein - */ -static void initMySQL(register selector_t *f) -{ - int iCounter = 0; - assert(f != NULL); - - if (checkDBErrorState(f)) - return; - - f->f_un.f_mysql.f_hmysql = mysql_init(NULL); - if(f->f_un.f_mysql.f_hmysql == NULL) { - logerror("can not initialize MySQL handle - ignoring this action"); - /* The next statement causes a redundant message, but it is the - * best thing we can do in this situation. -- rgerhards, 2007-01-30 - */ - f->f_type = F_UNUSED; - } else { /* we could get the handle, now on with work... */ - do { - /* Connect to database */ - if (!mysql_real_connect(f->f_un.f_mysql.f_hmysql, f->f_un.f_mysql.f_dbsrv, f->f_un.f_mysql.f_dbuid, - f->f_un.f_mysql.f_dbpwd, f->f_un.f_mysql.f_dbname, 0, NULL, 0)) { - /* if also the second attempt failed - we call the error handler */ - if(iCounter) - DBErrorHandler(f); - } else { - f->f_un.f_mysql.f_timeResumeOnError = 0; /* We have a working db connection */ - dprintf("connected successfully to db\n"); - } - iCounter++; - } while (mysql_errno(f->f_un.f_mysql.f_hmysql) && iCounter<2); - } -} - -/* - * The following function is responsible for closing a - * MySQL connection. - * Initially added 2004-10-28 - */ -static void closeMySQL(register selector_t *f) -{ - assert(f != NULL); - dprintf("in closeMySQL\n"); - if(f->f_un.f_mysql.f_hmysql != NULL) /* just to be on the safe side... */ - mysql_close(f->f_un.f_mysql.f_hmysql); -} - -/* - * Reconnect a MySQL connection. - * Initially added 2004-12-02 - */ -static void reInitMySQL(register selector_t *f) -{ - assert(f != NULL); - - dprintf("reInitMySQL\n"); - closeMySQL(f); /* close the current handle */ - initMySQL(f); /* new connection */ -} - -/* - * The following function writes the current log entry - * to an established MySQL session. - * Initially added 2004-10-28 - */ -static void writeMySQL(register selector_t *f) -{ - char *psz; - int iCounter=0; - assert(f != NULL); - - iovCreate(f); - psz = iovAsString(f); - - if (checkDBErrorState(f)) - return; - - /* Now we are trying to insert the data. - * - * If the first attampt fails we simply try a second one. If that - * fails too, we discard the message and enable "delay" error handling. - */ - do { - /* query */ - if(mysql_query(f->f_un.f_mysql.f_hmysql, psz)) { - /* if the second attempt fails - we call the error handler */ - if(iCounter) - DBErrorHandler(f); - } - else { - /* dprintf("db insert sucessfully\n"); */ - } - iCounter++; - } while (mysql_errno(f->f_un.f_mysql.f_hmysql) && iCounter<2); -} - -/** - * DBErrorHandler - * - * Call this function if an db error apears. It will initiate - * the "delay" handling which stopped the db logging for some - * time. - * - * We now check if we have a valid MySQL handle. If not, we simply - * report an error, but can not be specific. RGerhards, 2007-01-30 - */ -static void DBErrorHandler(register selector_t *f) -{ - char errMsg[512]; - - assert(f != NULL); - - /* TODO: - * NO DB connection -> Can not log to DB - * -------------------- - * Case 1: db server unavailable - * We can check after a specified time interval if the server is up. - * Also a reason can be a down DNS service. - * Case 2: uid, pwd or dbname are incorrect - * If this is a fault in the syslog.conf we have no chance to recover. But - * if it is a problem of the DB we can make a retry after some time. Possible - * are that the admin has not already set up the database table. Or he has not - * created the database user yet. - * Case 3: unkown error - * If we get an unkowon error here, we should in any case try to recover after - * a specified time interval. - * - * Insert failed -> Can not log to DB - * -------------------- - * If the insert fails it is never a good idea to give up. Only an - * invalid sql sturcture (wrong template) force us to disable db - * logging. - * - * Think about different "delay" for different errors! - */ - if(f->f_un.f_mysql.f_hmysql == NULL) { - logerror("unknown DB error occured - called error handler with NULL MySQL handle."); - } else { /* we can ask mysql for the error description... */ - errno = 0; - snprintf(errMsg, sizeof(errMsg)/sizeof(char), - "db error (%d): %s\n", mysql_errno(f->f_un.f_mysql.f_hmysql), - mysql_error(f->f_un.f_mysql.f_hmysql)); - f->f_un.f_mysql.f_iLastDBErrNo = mysql_errno(f->f_un.f_mysql.f_hmysql); - logerror(errMsg); - } - - /* Enable "delay" */ - f->f_un.f_mysql.f_timeResumeOnError = time(&f->f_un.f_mysql.f_timeResumeOnError) + _DB_DELAYTIMEONERROR ; -} - -/** - * checkDBErrorState - * - * Check if we can go on with database logging or if we should wait - * a little bit longer. It also check if the DB hanlde is still valid. - * If it is necessary, it takes action to reinitiate the db connection. - * - * \ret int Returns 0 if successful (no error) - */ -int checkDBErrorState(register selector_t *f) -{ - assert(f != NULL); - /* dprintf("in checkDBErrorState, timeResumeOnError: %d\n", f->f_timeResumeOnError); */ - - /* If timeResumeOnError == 0 no error occured, - we can return with 0 (no error) */ - if (f->f_un.f_mysql.f_timeResumeOnError == 0) - return 0; - - (void) time(&now); - /* Now we know an error occured. We check timeResumeOnError - if we can process. If we have not reach the resume time - yet, we return an error status. */ - if (f->f_un.f_mysql.f_timeResumeOnError > now) - { - /* dprintf("Wait time is not over yet.\n"); */ - return 1; - } - - /* Ok, we can try to resume the database logging. First - we have to reset the status (timeResumeOnError) and - the last error no. */ - /* To improve this code it would be better to check - if we really need to reInit the db connection. If - only the insert failed and the db conncetcion is - still valid, we need no reInit. - Of course, if an unkown error appeared, we should - reInit. */ - /* rgerhards 2004-12-08: I think it is pretty unlikely - * that we can re-use a connection after the error. So I guess - * the connection must be closed and re-opened in all cases - * (as it is done currently). When we come back to optimize - * this code, we should anyhow see if there are cases where - * we could keep it open. I just doubt this won't be the case. - * I added this comment (and did not remove Michaels) just so - * that we all know what we are looking for. - */ - f->f_un.f_mysql.f_timeResumeOnError = 0; - f->f_un.f_mysql.f_iLastDBErrNo = 0; - reInitMySQL(f); - return 0; - -} - -#endif /* #ifdef WITH_DB */ /** * getSubString |