/
githubmirror
/
rsyslog
Обзор
Документация
Войти
/
githubmirror
/
rsyslog
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
plugins/omstdout/omstdout.c
358 строк
11 KB
Rainer Gerhards
omprog/omstdout: guard empty template LF checks
28 июн 2026, 09:39
28 июн 2026, 09:39
3995f55
Код
Авторство
О чём код?
/* omstdout.c * send all output to stdout - this is primarily a test driver (but may * be used for weired use cases). Not tested for robustness! * * NOTE: read comments in module-template.h for more specifics! * * File begun on 2009-03-19 by RGerhards * * Copyright 2009-2017 Adiscon GmbH. * * This file is part of rsyslog. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * -or- * see COPYING.ASL20 in the source distribution * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #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 "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" #include "module-template.h" #include "errmsg.h" #include "cfsysline.h" MODULE_TYPE_OUTPUT; MODULE_TYPE_NOKEEP; MODULE_CNFNAME("omstdout") static rsRetVal resetConfigVariables(uchar __attribute__((unused)) * pp, void __attribute__((unused)) * pVal); /* static data */ /* internal structures */ DEF_OMOD_STATIC_DATA; /* config variables */ typedef struct _instanceData { int bUseArrayInterface; /* uses action use array instead of string template interface? */ int bEnsureLFEnding; /* ensure that a linefeed is written at the end of EACH record (test aid for nettester) */ uchar *templateName; } instanceData; typedef struct wrkrInstanceData { instanceData *pData; } wrkrInstanceData_t; typedef struct configSettings_s { int bUseArrayInterface; /* shall action use array instead of string template interface? */ int bEnsureLFEnding; int templateName; } configSettings_t; static configSettings_t cs; /* tables for interfacing with the v6 config system */ /* action (instance) parameters */ static struct cnfparamdescr actpdescr[] = {{"ensurelfending", eCmdHdlrBinary, 0}, {"template", eCmdHdlrGetWord, 0}}; static struct cnfparamblk actpblk = {CNFPARAMBLK_VERSION, sizeof(actpdescr) / sizeof(struct cnfparamdescr), actpdescr}; struct modConfData_s { rsconf_t *pConf; /* our overall config object */ }; static modConfData_t *loadModConf = NULL; /* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL; /* modConf ptr to use for the current exec process */ BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars; resetConfigVariables(NULL, NULL); ENDinitConfVars BEGINcreateInstance CODESTARTcreateInstance; ENDcreateInstance BEGINcreateWrkrInstance CODESTARTcreateWrkrInstance; ENDcreateWrkrInstance BEGINbeginCnfLoad CODESTARTbeginCnfLoad; loadModConf = pModConf; pModConf->pConf = pConf; ENDbeginCnfLoad BEGINendCnfLoad CODESTARTendCnfLoad; loadModConf = NULL; /* done loading */ ENDendCnfLoad BEGINcheckCnf CODESTARTcheckCnf; ENDcheckCnf BEGINactivateCnf CODESTARTactivateCnf; runModConf = pModConf; ENDactivateCnf BEGINfreeCnf CODESTARTfreeCnf; ENDfreeCnf BEGINisCompatibleWithFeature CODESTARTisCompatibleWithFeature; if (eFeat == sFEATURERepeatedMsgReduction) iRet = RS_RET_OK; ENDisCompatibleWithFeature BEGINfreeInstance CODESTARTfreeInstance; ENDfreeInstance BEGINfreeWrkrInstance CODESTARTfreeWrkrInstance; ENDfreeWrkrInstance BEGINdbgPrintInstInfo CODESTARTdbgPrintInstInfo; dbgprintf("omstdout\n"); dbgprintf("\tensureLFEnding='%d'\n", pData->bEnsureLFEnding); dbgprintf("\ttemplate='%s'\n", pData->templateName); ENDdbgPrintInstInfo BEGINtryResume CODESTARTtryResume; ENDtryResume BEGINdoAction char **szParams; char *toWrite; int iParamVal; int iParam; int iBuf; char szBuf[65564]; size_t len; int r; CODESTARTdoAction; dbgprintf("omstdout: in doAction\n"); if (pWrkrData->pData->bUseArrayInterface) { dbgprintf("omstdout: in ArrayInterface\n"); /* if we use array passing, we need to put together a string * ourselves. At this point, please keep in mind that omstdout is * primarily a testing aid. Other modules may do different processing * if they would like to support downlevel versions which do not support * array-passing, but also use that interface on cores who do... * So this code here is also more or less an example of how to do that. * rgerhards, 2009-04-03 */ szParams = (char **)(void *)(ppString[0]); /* In array-passing mode, ppString[] contains a NULL-terminated array * of char *pointers. */ iParam = 0; iBuf = 0; while (szParams[iParam] != NULL && iBuf < (int)sizeof(szBuf) - 1) { if (iParam > 0) szBuf[iBuf++] = ','; /* all but first need a delimiter */ iParamVal = 0; while (szParams[iParam][iParamVal] != '\0' && iBuf < (int)sizeof(szBuf) - 1) { szBuf[iBuf++] = szParams[iParam][iParamVal++]; } ++iParam; } szBuf[iBuf] = '\0'; toWrite = szBuf; } else { dbgprintf("omstdout: in else\n"); toWrite = (char *)ppString[0]; } len = strlen(toWrite); /* the following if's are just to silence compiler warnings. If someone * actually intends to use this module in production (why???), this code * needs to be more solid. -- rgerhards, 2012-11-28 */ dbgprintf("omstdout: len: %d, toWrite: %s\n", (int)len, toWrite); if (len > 0 && (r = write(1, toWrite, len)) != (int)len) { /* 1 is stdout! */ DBGPRINTF("omstdout: error %d writing to stdout[%zd]: %s\n", r, len, toWrite); } /* A rendered template may legitimately be empty. Treat that like any other * non-LF-terminated message; do not inspect toWrite[-1]. */ if (pWrkrData->pData->bEnsureLFEnding && (len == 0 || toWrite[len - 1] != '\n')) { if ((r = write(1, "\n", 1)) != 1) { /* write missing LF */ DBGPRINTF("omstdout: error %d writing \\n to stdout\n", r); } } ENDdoAction static void setInstParamDefaults(instanceData *pData) { pData->bEnsureLFEnding = 1; pData->templateName = (uchar *)"RSYSLOG_FileFormat"; pData->bUseArrayInterface = 0; } BEGINnewActInst struct cnfparamvals *pvals; int i; int bDestructPValsOnExit; uchar *tplToUse; CODESTARTnewActInst; DBGPRINTF("newActInst (omstdout)\n"); bDestructPValsOnExit = 0; pvals = nvlstGetParams(lst, &actpblk, NULL); if (pvals == NULL) { LogError(0, RS_RET_MISSING_CNFPARAMS, "omstdout: error reading " "config parameters"); ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); } bDestructPValsOnExit = 1; if (Debug) { dbgprintf("action param blk in omstdout:\n"); cnfparamsPrint(&actpblk, pvals); } CHKiRet(createInstance(&pData)); setInstParamDefaults(pData); for (i = 0; i < actpblk.nParams; ++i) { if (!pvals[i].bUsed) { continue; } else if (!strcmp(actpblk.descr[i].name, "ensurelfending")) { pData->bEnsureLFEnding = (int)pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "template")) { CHKmalloc(pData->templateName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL)); } else { DBGPRINTF( "omstdout: program error, non-handled " "param '%s'\n", actpblk.descr[i].name); } } CODE_STD_STRING_REQUESTnewActInst(1); // TODO: make the template a parameter tplToUse = (uchar *)strdup((pData->templateName == NULL) ? "RSYSLOG_FileFormat" : (char *)pData->templateName); CHKiRet(OMSRsetEntry(*ppOMSR, 0, tplToUse, OMSR_NO_RQD_TPL_OPTS)); CODE_STD_FINALIZERnewActInst; if (bDestructPValsOnExit) cnfparamvalsDestruct(pvals, &actpblk); ENDnewActInst BEGINparseSelectorAct int iTplOpts; 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; iTplOpts = (cs.bUseArrayInterface == 0) ? 0 : OMSR_TPL_AS_ARRAY; CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, iTplOpts, (uchar *)"RSYSLOG_FileFormat")); pData->bUseArrayInterface = cs.bUseArrayInterface; pData->bEnsureLFEnding = cs.bEnsureLFEnding; CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct BEGINmodExit CODESTARTmodExit; ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt; CODEqueryEtryPt_STD_OMOD_QUERIES; CODEqueryEtryPt_STD_OMOD8_QUERIES; CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES; CODEqueryEtryPt_STD_CONF2_QUERIES; CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES; ENDqueryEtryPt /* Reset config variables for this module to default values. */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) * pp, void __attribute__((unused)) * pVal) { DEFiRet; cs.bUseArrayInterface = 0; cs.bEnsureLFEnding = 1; RETiRet; } BEGINmodInit() rsRetVal localRet; rsRetVal (*pomsrGetSupportedTplOpts)(unsigned long *pOpts); unsigned long opts; int bArrayPassingSupported; /* does core support template passing as an array? */ CODESTARTmodInit; INITLegCnfVars; *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr /* check if the rsyslog core supports parameter passing code */ bArrayPassingSupported = 0; localRet = pHostQueryEtryPt((uchar *)"OMSRgetSupportedTplOpts", &pomsrGetSupportedTplOpts); if (localRet == RS_RET_OK) { /* found entry point, so let's see if core supports array passing */ CHKiRet((*pomsrGetSupportedTplOpts)(&opts)); if (opts & OMSR_TPL_AS_ARRAY) bArrayPassingSupported = 1; } else if (localRet != RS_RET_ENTRY_POINT_NOT_FOUND) { ABORT_FINALIZE(localRet); /* Something else went wrong, what is not acceptable */ } DBGPRINTF("omstdout: array-passing is %ssupported by rsyslog core.\n", bArrayPassingSupported ? "" : "not "); if (bArrayPassingSupported) { /* enable config comand only if core supports it */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomstdoutarrayinterface", 0, eCmdHdlrBinary, NULL, &cs.bUseArrayInterface, STD_LOADABLE_MODULE_ID)); } CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomstdoutensurelfending", 0, eCmdHdlrBinary, NULL, &cs.bEnsureLFEnding, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit /* vi:set ai: */