Merge branch 'omprog' into nextmaster

Conflicts:
	ChangeLog
	runtime/rsyslog.h
This commit is contained in:
Rainer Gerhards 2009-04-14 14:49:01 +02:00
commit 85ccd6e9b7
10 changed files with 392 additions and 141 deletions

View File

@ -1,5 +1,8 @@
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Version 4.3.0 [DEVEL] (rgerhards), 2009-03-?? Version 4.3.0 [DEVEL] (rgerhards), 2009-03-??
- new feature: new output plugin omprog, which permits to start program
and feed it (via its stdin) with syslog messages. If the program
terminates, it is restarted.
- improved internal handling of RainerScript functions, building the - improved internal handling of RainerScript functions, building the
necessary plumbing to support more functions with decent runtime necessary plumbing to support more functions with decent runtime
performance. This is also necessary towards the long-term goal performance. This is also necessary towards the long-term goal

View File

@ -108,6 +108,10 @@ if ENABLE_MAIL
SUBDIRS += plugins/ommail SUBDIRS += plugins/ommail
endif endif
if ENABLE_OMPROG
SUBDIRS += plugins/omprog
endif
if ENABLE_RFC3195 if ENABLE_RFC3195
SUBDIRS += plugins/im3195 SUBDIRS += plugins/im3195
endif endif
@ -127,5 +131,5 @@ SUBDIRS += tests
# temporarily be removed below. The intent behind forcing everthing to compile # temporarily be removed below. The intent behind forcing everthing to compile
# in a make distcheck is so that we detect code that accidently was not updated # in a make distcheck is so that we detect code that accidently was not updated
# when some global update happened. # when some global update happened.
DISTCHECK_CONFIGURE_FLAGS=--enable-gssapi_krb5 --enable-imfile --enable-snmp --enable-pgsql --enable-libdbi --enable-mysql --enable-omtemplate --enable-imtemplate --enable-relp --enable-rsyslogd --enable-mail --enable-klog --enable-diagtools --enable-gnutls --enable-omstdout DISTCHECK_CONFIGURE_FLAGS=--enable-gssapi_krb5 --enable-imfile --enable-snmp --enable-pgsql --enable-libdbi --enable-mysql --enable-omtemplate --enable-imtemplate --enable-relp --enable-rsyslogd --enable-mail --enable-klog --enable-diagtools --enable-gnutls --enable-omstdout --enable-omprog
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4

View File

@ -700,6 +700,20 @@ AM_CONDITIONAL(ENABLE_IMTEMPLATE, test x$enable_imtemplate = xyes)
# end of copy template - be sure to serach for imtemplate to find everything! # end of copy template - be sure to serach for imtemplate to find everything!
# settings for the omprog output module
AC_ARG_ENABLE(omprog,
[AS_HELP_STRING([--enable-omprog],[Compiles omprog template module @<:@default=no@:>@])],
[case "${enableval}" in
yes) enable_omprog="yes" ;;
no) enable_omprog="no" ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-omprog) ;;
esac],
[enable_omprog=no]
)
AM_CONDITIONAL(ENABLE_OMPROG, test x$enable_omprog = xyes)
# end of omprog
# settings for the template output module; copy and modify this code # settings for the template output module; copy and modify this code
# if you intend to add your own module. Be sure to replace omtemplate # if you intend to add your own module. Be sure to replace omtemplate
# by the actual name of your module. # by the actual name of your module.
@ -752,6 +766,7 @@ AC_CONFIG_FILES([Makefile \
plugins/imklog/Makefile \ plugins/imklog/Makefile \
plugins/imtemplate/Makefile \ plugins/imtemplate/Makefile \
plugins/omtemplate/Makefile \ plugins/omtemplate/Makefile \
plugins/omprog/Makefile \
plugins/omstdout/Makefile \ plugins/omstdout/Makefile \
plugins/imfile/Makefile \ plugins/imfile/Makefile \
plugins/imrelp/Makefile \ plugins/imrelp/Makefile \
@ -786,6 +801,7 @@ echo "imdiag enabled: $enable_imdiag"
echo "file input module enabled: $enable_imfile" echo "file input module enabled: $enable_imfile"
echo "input template module will be compiled: $enable_imtemplate" echo "input template module will be compiled: $enable_imtemplate"
echo "output template module will be compiled: $enable_omtemplate" echo "output template module will be compiled: $enable_omtemplate"
echo "omprog module will be compiled: $enable_omprog"
echo "omstdout module will be compiled: $enable_omstdout" echo "omstdout module will be compiled: $enable_omstdout"
echo "Large file support enabled: $enable_largefile" echo "Large file support enabled: $enable_largefile"
echo "Networking support enabled: $enable_inet" echo "Networking support enabled: $enable_inet"

View File

@ -127,7 +127,6 @@ community. Plus, it can be financially attractive: just think about how much les
be to sponsor a feature instead of purchasing a commercial implementation. Also, the benefit be to sponsor a feature instead of purchasing a commercial implementation. Also, the benefit
of being recognised as a sponsor may even drive new customers to your business!</b> of being recognised as a sponsor may even drive new customers to your business!</b>
<ul> <ul>
<li>Finalize the DTN "planetary Internet" space ship mode output plugin
<li>port it to more *nix variants (eg AIX and HP UX) - this <li>port it to more *nix variants (eg AIX and HP UX) - this
needs volunteers with access to those machines and knowledge </li> needs volunteers with access to those machines and knowledge </li>
<li>pcre filtering - maybe (depending on feedback)&nbsp; - <li>pcre filtering - maybe (depending on feedback)&nbsp; -

View File

@ -1,8 +0,0 @@
pkglib_LTLIBRARIES = omdtn.la
omdtn_la_SOURCES = omdtn.c
omdtn_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
omdtn_la_LDFLAGS = -module -avoid-version
omdtn_la_LIBADD =
EXTRA_DIST =

View File

@ -1,130 +0,0 @@
/* omdtn.c
* This is the plugin for rsyslog use in the interplanetary Internet,
* especially useful for rsyslog in space ships of all kinds.
* The core idea was introduced in early 2009 and considered
* doable.
*
* Note that this has not yet been tested for robustness but needs
* to prior to placing it on top of a rocket.
*
* NOTE: read comments in module-template.h for more specifics!
*
* File begun on 2009-04-01 by RGerhards
*
* Copyright 2009 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
* Rsyslog 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 3 of the License, or
* (at your option) any later version.
*
* Rsyslog 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 Rsyslog. If not, see <http://www.gnu.org/licenses/>.
*
* A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
#include "config.h"
#include "rsyslog.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include "dirty.h"
#include "syslogd-types.h"
#include "srUtils.h"
#include "template.h"
#include "module-template.h"
#include "errmsg.h"
#include "cfsysline.h"
MODULE_TYPE_OUTPUT
/* internal structures
*/
DEF_OMOD_STATIC_DATA
typedef struct _instanceData {
} instanceData;
BEGINcreateInstance
CODESTARTcreateInstance
ENDcreateInstance
BEGINisCompatibleWithFeature
CODESTARTisCompatibleWithFeature
if(eFeat == sFEATURERepeatedMsgReduction)
iRet = RS_RET_OK;
ENDisCompatibleWithFeature
BEGINfreeInstance
CODESTARTfreeInstance
ENDfreeInstance
BEGINdbgPrintInstInfo
CODESTARTdbgPrintInstInfo
ENDdbgPrintInstInfo
BEGINtryResume
CODESTARTtryResume
ENDtryResume
BEGINdoAction
CODESTARTdoAction
write(1, (char*)ppString[0], strlen((char*)ppString[0]));
ENDdoAction
BEGINparseSelectorAct
CODESTARTparseSelectorAct
CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* first check if this config line is actually for us */
if(strncmp((char*) p, ":omstdout:", sizeof(":omstdout:") - 1)) {
ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
}
/* ok, if we reach this point, we have something for us */
p += sizeof(":omstdout:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
CHKiRet(createInstance(&pData));
/* check if a non-standard template is to be applied */
if(*(p-1) == ';')
--p;
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, (uchar*) "RSYSLOG_FileFormat"));
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
BEGINmodExit
CODESTARTmodExit
ENDmodExit
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_OMOD_QUERIES
ENDqueryEtryPt
BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
ENDmodInit
/* vi:set ai:
*/

View File

@ -0,0 +1,8 @@
pkglib_LTLIBRARIES = omprog.la
omprog_la_SOURCES = omprog.c
omprog_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS)
omprog_la_LDFLAGS = -module -avoid-version
omprog_la_LIBADD =
EXTRA_DIST =

357
plugins/omprog/omprog.c Normal file
View File

@ -0,0 +1,357 @@
/* omprog.c
* This output plugin enables rsyslog to execute a program and
* feed it the message stream as standard input.
*
* NOTE: read comments in module-template.h for more specifics!
*
* File begun on 2009-04-01 by RGerhards
*
* Copyright 2009 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
* Rsyslog 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 3 of the License, or
* (at your option) any later version.
*
* Rsyslog 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 Rsyslog. If not, see <http://www.gnu.org/licenses/>.
*
* A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
#include "config.h"
#include "rsyslog.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <wait.h>
#include "dirty.h"
#include "syslogd-types.h"
#include "srUtils.h"
#include "template.h"
#include "module-template.h"
#include "errmsg.h"
#include "cfsysline.h"
MODULE_TYPE_OUTPUT
/* internal structures
*/
DEF_OMOD_STATIC_DATA
DEFobjCurrIf(errmsg)
typedef struct _instanceData {
uchar *szBinary; /* name of binary to call */
pid_t pid; /* pid of currently running process */
int fdPipe; /* file descriptor to write to */
int bIsRunning; /* is binary currently running? 0-no, 1-yes */
} instanceData;
/* config settings */
static uchar *szBinary = NULL; /* name of binary to call */
BEGINcreateInstance
CODESTARTcreateInstance
ENDcreateInstance
BEGINisCompatibleWithFeature
CODESTARTisCompatibleWithFeature
if(eFeat == sFEATURERepeatedMsgReduction)
iRet = RS_RET_OK;
ENDisCompatibleWithFeature
BEGINfreeInstance
CODESTARTfreeInstance
if(pData->szBinary != NULL)
free(pData->szBinary);
ENDfreeInstance
BEGINdbgPrintInstInfo
CODESTARTdbgPrintInstInfo
ENDdbgPrintInstInfo
BEGINtryResume
CODESTARTtryResume
ENDtryResume
/* execute the child process (must be called in child context
* after fork).
*/
static void execBinary(instanceData *pData, int fdStdin)
{
int i;
struct sigaction sigAct;
char *newargv[] = { NULL };
char *newenviron[] = { NULL };
assert(pData != NULL);
fclose(stdin);
dup(fdStdin);
//fclose(stdout);
/* we close all file handles as we fork soon
* Is there a better way to do this? - mail me! rgerhards@adiscon.com
*/
# ifndef VALGRIND /* we can not use this with valgrind - too many errors... */
for(i = 3 ; i <= 65535 ; ++i)
close(i);
# endif
/* reset signal handlers to default */
memset(&sigAct, 0, sizeof(sigAct));
sigfillset(&sigAct.sa_mask);
sigAct.sa_handler = SIG_DFL;
for(i = 1 ; i < NSIG ; ++i)
sigaction(i, &sigAct, NULL);
alarm(0);
/* finally exec child */
execve((char*)pData->szBinary, newargv, newenviron);
/* switch to?
execlp((char*)program, (char*) program, (char*)arg, NULL);
*/
/* we should never reach this point, but if we do, we terminate */
exit(1);
}
/* creates a pipe and starts program, uses pipe as stdin for program.
* rgerhards, 2009-04-01
*/
static rsRetVal
openPipe(instanceData *pData)
{
int pipefd[2];
pid_t cpid;
DEFiRet;
assert(pData != NULL);
if(pipe(pipefd) == -1) {
ABORT_FINALIZE(RS_RET_ERR_CREAT_PIPE);
}
DBGPRINTF("executing program '%s'\n", pData->szBinary);
/* NO OUTPUT AFTER FORK! */
cpid = fork();
if(cpid == -1) {
ABORT_FINALIZE(RS_RET_ERR_FORK);
}
if(cpid == 0) {
/* we are now the child, just set the right selectors and
* exec the binary. If that fails, there is not much we can do.
*/
close(pipefd[1]);
execBinary(pData, pipefd[0]);
/*NO CODE HERE - WILL NEVER BE REACHED!*/
}
DBGPRINTF("child has pid %d\n", cpid);
pData->fdPipe = pipefd[1];
pData->pid = cpid;
close(pipefd[0]);
pData->bIsRunning = 1;
finalize_it:
RETiRet;
}
/* clean up after a terminated child
*/
static inline rsRetVal
cleanup(instanceData *pData)
{
int status;
int ret;
char errStr[1024];
DEFiRet;
assert(pData != NULL);
assert(pData->bIsRunning == 1);
RUNLOG_VAR("%d", pData->pid);
ret = waitpid(pData->pid, &status, 0);
if(ret != pData->pid) {
/* if waitpid() fails, we can not do much - try to ignore it... */
DBGPRINTF("waitpid() returned state %d[%s], future malfunction may happen\n", ret,
rs_strerror_r(errno, errStr, sizeof(errStr)));
} else {
/* check if we should print out some diagnostic information */
DBGPRINTF("waitpid status return for program '%s': %2.2x\n",
pData->szBinary, status);
if(WIFEXITED(status)) {
errmsg.LogError(0, NO_ERRCODE, "program '%s' exited normally, state %d",
pData->szBinary, WEXITSTATUS(status));
} else if(WIFSIGNALED(status)) {
errmsg.LogError(0, NO_ERRCODE, "program '%s' terminated by signal %d.",
pData->szBinary, WTERMSIG(status));
}
}
pData->bIsRunning = 0;
RETiRet;
}
/* try to restart the binary when it has stopped.
*/
static inline rsRetVal
tryRestart(instanceData *pData)
{
DEFiRet;
assert(pData != NULL);
assert(pData->bIsRunning == 0);
iRet = openPipe(pData);
RETiRet;
}
/* write to pipe
* note that we do not try to run block-free. If the users fears something
* may block (and this not be acceptable), the action should be run on its
* own action queue.
*/
static rsRetVal
writePipe(instanceData *pData, uchar *szMsg)
{
int lenWritten;
int lenWrite;
int writeOffset;
char errStr[1024];
DEFiRet;
assert(pData != NULL);
lenWrite = strlen((char*)szMsg);
writeOffset = 0;
do
{
lenWritten = write(pData->fdPipe, ((char*)szMsg)+writeOffset, lenWrite);
if(lenWritten == -1) {
switch(errno) {
case EPIPE:
DBGPRINTF("Program '%s' terminated, trying to restart\n",
pData->szBinary);
CHKiRet(cleanup(pData));
CHKiRet(tryRestart(pData));
break;
default:
DBGPRINTF("error %d writing to pipe: %s\n", errno,
rs_strerror_r(errno, errStr, sizeof(errStr)));
ABORT_FINALIZE(RS_RET_ERR_WRITE_PIPE);
break;
}
} else {
writeOffset += lenWritten;
}
} while(lenWritten != lenWrite);
finalize_it:
RETiRet;
}
BEGINdoAction
CODESTARTdoAction
if(pData->bIsRunning == 0) {
openPipe(pData);
}
iRet = writePipe(pData, ppString[0]);
if(iRet != RS_RET_OK)
iRet = RS_RET_SUSPENDED;
ENDdoAction
BEGINparseSelectorAct
CODESTARTparseSelectorAct
CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* first check if this config line is actually for us */
if(strncmp((char*) p, ":omprog:", sizeof(":omprog:") - 1)) {
ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
}
/* ok, if we reach this point, we have something for us */
p += sizeof(":omprog:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
CHKiRet(createInstance(&pData));
CHKmalloc(pData->szBinary = (uchar*) strdup((char*)szBinary));
/* check if a non-standard template is to be applied */
if(*(p-1) == ';')
--p;
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, (uchar*) "RSYSLOG_FileFormat"));
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
BEGINmodExit
CODESTARTmodExit
if(szBinary != NULL) {
free(szBinary);
szBinary = NULL;
}
CHKiRet(objRelease(errmsg, CORE_COMPONENT));
finalize_it:
ENDmodExit
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_OMOD_QUERIES
ENDqueryEtryPt
/* Reset config variables for this module to default values.
*/
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
DEFiRet;
if(szBinary != NULL) {
free(szBinary);
szBinary = NULL;
}
RETiRet;
}
BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomprogbinary", 0, eCmdHdlrGetWord, NULL, &szBinary, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
CODEmodInit_QueryRegCFSLineHdlr
ENDmodInit
/* vi:set ai:
*/

View File

@ -796,7 +796,6 @@ dbgprintf("calling expression parser, pp %p ('%s')\n", *pline, *pline);
/* debug support - print vmprg after construction (uncomment to use) */ /* debug support - print vmprg after construction (uncomment to use) */
/* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */ /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */
vmprgDebugPrint(f->f_filterData.f_expr->pVmprg);
/* we now need to skip whitespace to the action part, else we confuse /* we now need to skip whitespace to the action part, else we confuse
* the legacy rsyslog conf parser. -- rgerhards, 2008-02-25 * the legacy rsyslog conf parser. -- rgerhards, 2008-02-25

View File

@ -263,6 +263,9 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_DUP_FUNC_NAME = -2114, /**< duplicate function name (rainerscript) */ RS_RET_DUP_FUNC_NAME = -2114, /**< duplicate function name (rainerscript) */
RS_RET_UNKNW_FUNC = -2115, /**< unkown function name (rainerscript) */ RS_RET_UNKNW_FUNC = -2115, /**< unkown function name (rainerscript) */
RS_RET_ERR_RLIM_NOFILE = -2116, /**< error setting max. nbr open files process limit */ RS_RET_ERR_RLIM_NOFILE = -2116, /**< error setting max. nbr open files process limit */
RS_RET_ERR_CREAT_PIPE = -2117, /**< error during pipe creation */
RS_RET_ERR_FORK = -2118, /**< error during fork() */
RS_RET_ERR_WRITE_PIPE = -2119, /**< error writing to pipe */
/* RainerScript error messages (range 1000.. 1999) */ /* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */