From 071c9b511a711725537eff386f82a3af3ca930a8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 4 Sep 2009 14:53:44 +0200 Subject: added $LogRSyslogStatusMessages configuration directive ...permitting to turn off rsyslog start/stop/HUP messages. See Debian ticket http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=463793 --- ChangeLog | 5 +++++ configure.ac | 2 +- doc/manual.html | 2 +- doc/rsyslog_conf_global.html | 4 ++++ tools/syslogd.c | 32 ++++++++++++++++++++------------ 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index c5a3a827..d5670ec0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,9 @@ --------------------------------------------------------------------------- +Version 4.7.0 [v4-devel] (rgerhards), 2009-09-?? +- added $LogRSyslogStatusMessages configuration directive + permitting to turn off rsyslog start/stop/HUP messages. See Debian + ticket http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=463793 +--------------------------------------------------------------------------- Version 4.5.3 [v4-beta] (rgerhards), 2009-08-?? - bugfix: message sanitation had some issues: - control character DEL was not properly escaped diff --git a/configure.ac b/configure.ac index 19d738eb..8cba22ab 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[4.5.2],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[4.7.0],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([ChangeLog]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/manual.html b/doc/manual.html index e1f7480e..52a8380e 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@ rsyslog support available directly from the source!

Please visit the rsyslog sponsor's page to honor the project sponsors or become one yourself! We are very grateful for any help towards the project goals.

-

This documentation is for version 4.5.2 (v4-beta branch) of rsyslog. +

This documentation is for version 4.7.0 (v4-devel branch) of rsyslog. Visit the rsyslog status page to obtain current version information and project status.

If you like rsyslog, you might diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html index 2bbb136e..f2642ca4 100644 --- a/doc/rsyslog_conf_global.html +++ b/doc/rsyslog_conf_global.html @@ -146,6 +146,10 @@ Usually that should not be a big issue, as the restart-type HUP can easily be re something along the lines of "/etc/init.d/rsyslog restart".

  • $IncludeConfig
  • MainMsgQueueCheckpointInterval <number>
  • +
  • $LogRSyslogStatusMessages [on/off] - If set to on (the default), +rsyslog emits message on startup and shutdown as well as when it is HUPed. +This information might be needed by some log analyzers. If set to off, no such +status messages are logged, what may be useful for other scenarios.
  • $MainMsgQueueDequeueSlowdown <number> [number is timeout in microseconds (1000000us is 1sec!), default 0 (no delay). Simple rate-limiting!]
  • diff --git a/tools/syslogd.c b/tools/syslogd.c index 88588621..500b5b1f 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -249,6 +249,8 @@ int bDropTrailingLF = 1; /* drop trailing LF's on reception? */ int iCompatibilityMode = 0; /* version we should be compatible with; 0 means sysklogd. It is the default, so if no -c option is given, we make ourselvs as compatible to sysklogd as possible. */ +#define DFLT_bLogStatusMsgs 1 +static int bLogStatusMsgs = DFLT_bLogStatusMsgs; /* log rsyslog start/stop/HUP messages? */ static int bDebugPrintTemplateList = 1;/* output template list in debug mode? */ static int bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list in debug mode? */ static int bDebugPrintModuleList = 1;/* output module list in debug mode? */ @@ -332,6 +334,7 @@ getFIOPName(unsigned iFIOP) static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { cCCEscapeChar = '#'; + bLogStatusMsgs = DFLT_bLogStatusMsgs; bActExecWhenPrevSusp = 0; iActExecOnceInterval = 0; bDebugPrintTemplateList = 1; @@ -1659,7 +1662,7 @@ die(int sig) thrdTerminateAll(); /* and THEN send the termination log message (see long comment above) */ - if (sig) { + if(sig && bLogStatusMsgs) { (void) snprintf(buf, sizeof(buf) / sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"]" " exiting on signal %d.", @@ -2353,11 +2356,13 @@ init() /* we now generate the startup message. It now includes everything to * identify this instance. -- rgerhards, 2005-08-17 */ - snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char), - " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ - "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] (re)start", - (int) myPid); - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)bufStartUpMsg, 0); + if(bLogStatusMsgs) { + snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char), + " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ + "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] (re)start", + (int) myPid); + logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)bufStartUpMsg, 0); + } memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); @@ -2506,12 +2511,14 @@ doHUP(void) { char buf[512]; - snprintf(buf, sizeof(buf) / sizeof(char), - " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION - "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed, type '%s'.", - (int) myPid, glbl.GetHUPisRestart() ? "restart" : "lightweight"); - errno = 0; - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0); + if(bLogStatusMsgs) { + snprintf(buf, sizeof(buf) / sizeof(char), + " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION + "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed, type '%s'.", + (int) myPid, glbl.GetHUPisRestart() ? "restart" : "lightweight"); + errno = 0; + logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0); + } if(glbl.GetHUPisRestart()) { DBGPRINTF("Received SIGHUP, configured to be restart, reloading rsyslogd.\n"); @@ -2632,6 +2639,7 @@ static rsRetVal loadBuildInModules(void) * is that rsyslog will terminate if we can not register our built-in config commands. * This, I think, is the right thing to do. -- rgerhards, 2007-07-31 */ + CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary, NULL, &bLogStatusMsgs, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeretrycount", 0, eCmdHdlrInt, NULL, &glbliActionResumeRetryCount, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, setCurrRuleset, NULL, NULL)); -- cgit From 5f76568d3707cbbadfa3767558ded52cf5f27f47 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 4 Sep 2009 16:58:00 +0200 Subject: added new config option $InputUnixListenSocketCreatePath backport from v5-devel --- ChangeLog | 5 +++++ doc/imuxsock.html | 28 ++++++++++++++++++++++++++-- plugins/imuxsock/imuxsock.c | 14 ++++++++++++-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index cbfb597b..34406f4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ --------------------------------------------------------------------------- Version 4.7.0 [v4-devel] (rgerhards), 2009-09-?? +- added new config option $InputUnixListenSocketCreatePath + to permit the auto-creation of pathes to additional log sockets. This + turns out to be useful if they reside on temporary file systems and + rsyslogd starts up before the daemons that create these sockets + (rsyslogd always creates the socket itself if it does not exist). - added $LogRSyslogStatusMessages configuration directive permitting to turn off rsyslog start/stop/HUP messages. See Debian ticket http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=463793 diff --git a/doc/imuxsock.html b/doc/imuxsock.html index 472470a0..15c365a6 100644 --- a/doc/imuxsock.html +++ b/doc/imuxsock.html @@ -46,6 +46,18 @@ Ignore timestamps included in the messages, applies to messages received via the
  • $SystemLogSocketName <name-of-socket> -- former -p option
  • $SystemLogFlowControl [on/off] - specifies if flow control should be applied to the system log socket.
  • +
  • $InputUnixListenSocketCreatePath [on/off] - create directories in the socket path +if they do not already exist. They are created with 0755 permissions with the owner being the process under +which rsyslogd runs. The default is not to create directories. Keep in mind, though, that rsyslogd always +creates the socket itself if it does not exist (just not the directories by default). +
    Note that this statement affects the +next $AddUnixListenSocket directive that follows in sequence in the configuration file. It never works +on the system log socket (where it is deemed unnecessary). Also note that it is automatically +being reset to "off" after the $AddUnixListenSocket directive, so if you would have it active +for two additional listen sockets, you need to specify it in front of each one. This option is primarily considered +useful for defining additional sockets that reside on non-permanent file systems. As rsyslogd probably starts +up before the daemons that create these sockets, it is a vehicle to enable rsyslogd to listen to those +sockets even though their directories do not yet exist. [available since 4.7.0 and 5.3.0]
  • $AddUnixListenSocket <name-of-socket> adds additional unix socket, default none -- former -a option
  • $InputUnixListenSocketHostName <hostname> permits to override the hostname that shall be used inside messages taken from the next $AddUnixListenSocket socket. Note that @@ -57,20 +69,32 @@ that the local hostname can be overridden in cases where that is desired.

  • This documentation is sparse and incomplete.

    Sample:

    -

    The following sample is the minimum setup required to accept syslog messages from applications running on the local system.
    +

    The following sample is the minimum setup required to accept syslog messages from applications running +on the local system.

    The following sample is a configuration where rsyslogd pulls logs from two jails, and assigns different hostnames to each of the jails:

    - +

    The following sample is a configuration where rsyslogd reads the openssh log +messages via a separate socket, but this socket is created on a temporary file +system. As rsyslogd starts up before the sshd, it needs to create the socket +directories, because it otherwise can not open the socket and thus not listen +to openssh messages. Note that it is vital not to place any other socket between +the $InputUnixListenSocketCreatePath and the $InputUnixListenSocketHostName.

    +

    [rsyslog.conf overview] [manual index] [rsyslog site]

    This documentation is part of the diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 424d0904..c5fb0cc8 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -77,6 +77,7 @@ static int startIndexUxLocalSockets; /* process funix from that index on (used t */ static int funixParseHost[MAXFUNIX] = { 0, }; /* should parser parse host name? read-only after startup */ static int funixFlags[MAXFUNIX] = { IGNDATE, }; /* should parser parse host name? read-only after startup */ +static int funixCreateSockPath[MAXFUNIX] = { 0, }; /* auto-creation of socket directory? */ static uchar *funixn[MAXFUNIX] = { (uchar*) _PATH_LOG }; /* read-only after startup */ static uchar *funixHName[MAXFUNIX] = { NULL, }; /* host-name override - if set, use this instead of actual name */ static int funixFlowCtl[MAXFUNIX] = { eFLOWCTL_NO_DELAY, }; /* flow control settings for this socket */ @@ -89,6 +90,8 @@ static uchar *pLogSockName = NULL; static uchar *pLogHostName = NULL; /* host name to use with this socket */ static int bUseFlowCtl = 0; /* use flow control or not (if yes, only LIGHT is used! */ static int bIgnoreTimestamp = 1; /* ignore timestamps present in the incoming message? */ +#define DFLT_bCreateSockPath 0 +static int bCreateSockPath = DFLT_bCreateSockPath; /* auto-create socket path? */ /* set the timestamp ignore / not ignore option for the system @@ -132,6 +135,7 @@ static rsRetVal addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNe pLogHostName = NULL; /* re-init for next, not freed because funixHName[] now owns it */ funixFlowCtl[nfunix] = bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; funixFlags[nfunix] = bIgnoreTimestamp ? IGNDATE : NOFLAG; + funixCreateSockPath[nfunix] = bCreateSockPath; funixn[nfunix++] = pNewVal; } else { @@ -165,7 +169,7 @@ static rsRetVal discardFunixn(void) } -static int create_unix_socket(const char *path) +static int create_unix_socket(const char *path, int bCreatePath) { struct sockaddr_un sunx; int fd; @@ -177,6 +181,9 @@ static int create_unix_socket(const char *path) memset(&sunx, 0, sizeof(sunx)); sunx.sun_family = AF_UNIX; + if(bCreatePath) { + makeFileParentDirs((uchar*)path, strlen(path), 0755, -1, -1, 0); + } (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); fd = socket(AF_UNIX, SOCK_DGRAM, 0); if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || @@ -306,7 +313,7 @@ CODESTARTwillRun /* initialize and return if will run or not */ for (i = startIndexUxLocalSockets ; i < nfunix ; i++) { - if ((funix[i] = create_unix_socket((char*) funixn[i])) != -1) + if ((funix[i] = create_unix_socket((char*) funixn[i], funixCreateSockPath[i])) != -1) dbgprintf("Opened UNIX socket '%s' (fd %d).\n", funixn[i], funix[i]); } @@ -376,6 +383,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a nfunix = 1; bIgnoreTimestamp = 1; bUseFlowCtl = 0; + bCreateSockPath = DFLT_bCreateSockPath; return RS_RET_OK; } @@ -409,6 +417,8 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &pLogHostName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary, NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketcreatepath", 0, eCmdHdlrBinary, + NULL, &bCreateSockPath, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord, addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, -- cgit From bfac3c68f47b8769b0936fb80eeea8880793fd2d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 11 Sep 2009 11:23:47 +0200 Subject: added new config directive $omfileForceChown to fix some broken system configs. See ticket for details: http://bugzilla.adiscon.com/show_bug.cgi?id=150 --- ChangeLog | 3 ++ doc/rsconf1_omfileforcechown.html | 64 +++++++++++++++++++++++++++++++++++++++ doc/rsyslog_conf_global.html | 1 + tools/omfile.c | 27 +++++++++++++++-- 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 doc/rsconf1_omfileforcechown.html diff --git a/ChangeLog b/ChangeLog index 5b30621b..7ae02fd8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,9 @@ Version 4.7.0 [v4-devel] (rgerhards), 2009-09-?? - added $LogRSyslogStatusMessages configuration directive permitting to turn off rsyslog start/stop/HUP messages. See Debian ticket http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=463793 +- added new config directive $omfileForceChown to (try to) fix some broken + system configs. + See ticket for details: http://bugzilla.adiscon.com/show_bug.cgi?id=150 --------------------------------------------------------------------------- Version 4.5.3 [v4-beta] (rgerhards), 2009-08-?? - bugfix: repeated messages were incorrectly processed diff --git a/doc/rsconf1_omfileforcechown.html b/doc/rsconf1_omfileforcechown.html new file mode 100644 index 00000000..7415a6f6 --- /dev/null +++ b/doc/rsconf1_omfileforcechown.html @@ -0,0 +1,64 @@ + + +rsyslog.conf file + + +back + +

    $omfileForceChown

    +

    Type: global configuration directive

    +

    Parameter Values: boolean (on/off, yes/no)

    +

    Available since: 4.7.0+, 5.3.0+

    +

    Default: off

    +

    Description:

    +

    Forces rsyslogd to change the ownership for output files that already exist. Please note +that this tries to fix a potential problem that exists outside the scope of rsyslog. Actually, +it tries to fix invalid ownership/permission settings set by the original file creator. +

    Rsyslog changes the ownership during initial execution with root privileges. When a privelege +drop is configured, privileges are dropped after the file owner ship is changed. Not that this currently +is a limitation in rsyslog's privilege drop code, which is on the TODO list to be removed. See Caveats +section below for the important implications. +

    Caveats:

    +

    This directive tries to fix a problem that actually is outside the scope of rsyslog. As such, +there are a couple of restrictions and situations in which it will not work. Users are strongly +encouraged to fix their system instead of turning this directive on - it should only be used +as a last resort. +

    At least in the following scenario, this directive will fail expectedly: +

    It does not address +the situation that someone changes the ownership *after* rsyslogd has started. +Let's, for example, consider a log rotation script. +

      +
    • rsyslog is started +
    • ownership is changed +
    • privileges dropped +
    • log rotation (lr) script starts +
    • lr removes files +
    • lr creates new files with root:adm (or whatever else) +
    • lr HUPs rsyslogd +
    • rsyslogd closes files +
    • rsyslogd tries to open files +
    • rsyslogd tries to change ownership --> fail as we are non-root now +
    • file open fails +
    + +Please note that once the privilege drop code is refactored, this directive will +no longer work, because then privileges will be dropped before any action is performed, +and thus we will no longer be able to chown files that do not belong to the +user rsyslogd is configured to run under. + +

    So expect the directive to go away. It will not +be removed in version 4, but may disappear at any time for any version greater than 4. + +

    Sample:

    +

    $FileOwner loguser +
    $omfileForceChown on

    + +

    [rsyslog.conf overview] [manual +index] [rsyslog site]

    +

    This documentation is part of the +rsyslog project.
    +Copyright © 2007 by Rainer Gerhards and +Adiscon. Released under the GNU GPL +version 2 or higher.

    + + diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html index 74255c54..5f80f92e 100644 --- a/doc/rsyslog_conf_global.html +++ b/doc/rsyslog_conf_global.html @@ -225,6 +225,7 @@ error recovery thus can handle write errors without data loss. Note that this op severely reduces the effect of zip compression and should be switched to off for that use case. Note that the default -off- is primarily an aid to preserve the traditional syslogd behaviour. +
  • $omfileForceChown - force ownership change for all files
  • $RepeatedMsgContainsOriginalMsg [on/off] - "last message repeated n times" messages, if generated, have a different format that contains the message that is being repeated. Note that only the first "n" characters are included, with n to be at least 80 characters, most diff --git a/tools/omfile.c b/tools/omfile.c index bb12b4b6..eaffa70e 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -88,11 +88,13 @@ typedef struct s_dynaFileCacheEntry dynaFileCacheEntry; #define IOBUF_DFLT_SIZE 1024 /* default size for io buffers */ #define FLUSH_INTRVL_DFLT 1 /* default buffer flush interval (in seconds) */ +#define DFLT_bForceChown 0 /* globals for default values */ static int iDynaFileCacheSize = 10; /* max cache for dynamic files */ static int fCreateMode = 0644; /* mode to use when creating files */ static int fDirCreateMode = 0700; /* mode to use when creating files */ static int bFailOnChown; /* fail if chown fails? */ +static int bForceChown = DFLT_bForceChown; /* Force chown() on existing files? */ static uid_t fileUID; /* UID to be used for newly created files */ static uid_t fileGID; /* GID to be used for newly created files */ static uid_t dirUID; /* UID to be used for newly created directories */ @@ -115,6 +117,7 @@ typedef struct _instanceData { int fDirCreateMode; /* creation mode for mkdir() */ int bCreateDirs; /* auto-create directories? */ int bSyncFile; /* should the file by sync()'ed? 1- yes, 0- no */ + bool bForceChown; /* force chown() on existing files? */ uid_t fileUID; /* IDs for creation */ uid_t dirUID; gid_t fileGID; @@ -152,12 +155,14 @@ CODESTARTdbgPrintInstInfo "\tcreate directories: %s\n" "\tfile owner %d, group %d\n" "\tdirectory owner %d, group %d\n" + "\tforce chown() for all files: %s\n" "\tfail if owner/group can not be set: %s\n", pData->f_fname, pData->iDynaFileCacheSize, pData->bCreateDirs ? "yes" : "no", pData->fileUID, pData->fileGID, pData->dirUID, pData->dirGID, + pData->bForceChown ? "yes" : "no", pData->bFailOnChown ? "yes" : "no" ); } else { /* regular file */ @@ -346,7 +351,22 @@ prepareFile(instanceData *pData, uchar *newFileName) int fd; DEFiRet; - if(access((char*)newFileName, F_OK) != 0) { + if(access((char*)newFileName, F_OK) == 0) { + if(pData->bForceChown) { + /* Try to fix wrong ownership set by someone else. Note that this code + * will no longer work once we have made the $PrivDrop code fully secure. + * This change is based on an idea of Michael Terry, provided as part of + * the effort to make rsyslogd the Ubuntu default syslogd. + * rgerhards, 2009-09-11 + */ + if(chown((char*)newFileName, pData->fileUID, pData->fileGID) != 0) { + if(pData->bFailOnChown) { + int eSave = errno; + errno = eSave; + } + } + } + } else { /* file does not exist, create it (and eventually parent directories */ fd = -1; if(pData->bCreateDirs) { @@ -367,7 +387,7 @@ prepareFile(instanceData *pData, uchar *newFileName) pData->fCreateMode); if(fd != -1) { /* check and set uid/gid */ - if(pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) { + if(pData->bForceChown || pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) { /* we need to set owner/group */ if(fchown(fd, pData->fileUID, pData->fileGID) != 0) { if(pData->bFailOnChown) { @@ -678,6 +698,7 @@ CODESTARTparseSelectorAct pData->fDirCreateMode = fDirCreateMode; pData->bCreateDirs = bCreateDirs; pData->bFailOnChown = bFailOnChown; + pData->bForceChown = bForceChown; pData->fileUID = fileUID; pData->fileGID = fileGID; pData->dirUID = dirUID; @@ -712,6 +733,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a dirUID = -1; dirGID = -1; bFailOnChown = 1; + bForceChown = DFLT_bForceChown; iDynaFileCacheSize = 10; fCreateMode = 0644; fDirCreateMode = 0700; @@ -778,6 +800,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(omsdRegCFSLineHdlr((uchar *)"filecreatemode", 0, eCmdHdlrFileCreateMode, NULL, &fCreateMode, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"createdirs", 0, eCmdHdlrBinary, NULL, &bCreateDirs, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &bFailOnChown, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileForceChown", 0, eCmdHdlrBinary, NULL, &bForceChown, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfileenablesync", 0, eCmdHdlrBinary, NULL, &bEnableSync, STD_LOADABLE_MODULE_ID)); CHKiRet(regCfSysLineHdlr((uchar *)"actionfiledefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszTplName, NULL)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); -- cgit From e4ca8a3119ece504819605b340a3f5ba36b3eab6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 3 Nov 2009 09:20:02 +0100 Subject: added function getenv() to RainerScript --- ChangeLog | 1 + doc/expression.html | 21 +++++++++++-------- doc/rainerscript.html | 18 +++++++++++++--- runtime/vm.c | 44 ++++++++++++++++++++++++++++++++++++++++ tests/Makefile.am | 3 +++ tests/diag.sh | 2 +- tests/rsf_getenv.sh | 17 ++++++++++++++++ tests/testsuites/rsf_getenv.conf | 17 ++++++++++++++++ 8 files changed, 111 insertions(+), 12 deletions(-) create mode 100755 tests/rsf_getenv.sh create mode 100644 tests/testsuites/rsf_getenv.conf diff --git a/ChangeLog b/ChangeLog index c36dbbad..d9466e9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ --------------------------------------------------------------------------- Version 4.7.0 [v4-devel] (rgerhards), 2009-09-?? +- added function getenv() to RainerScript - added new config option $InputUnixListenSocketCreatePath to permit the auto-creation of pathes to additional log sockets. This turns out to be useful if they reside on temporary file systems and diff --git a/doc/expression.html b/doc/expression.html index 9e37cb7a..c401d9ab 100644 --- a/doc/expression.html +++ b/doc/expression.html @@ -1,17 +1,22 @@ -Expressions + +Expressions in rsyslog -back -

    Expressions

    +back to rsyslog filter conditions +

    Expressions in rsyslog

    Rsyslog supports expressions at a growing number of places. So -far, they are supported for filtering messages.

    Expression support is provided by RainerScript. For now, please see the formal expression definition in RainerScript ABNF. It is the "expr" node.

    C-like comments (/* some comment */) are supported inside the expression, but not yet in the rest of the configuration file.

    [rsyslog.conf overview] +far, they are supported for filtering messages.

    +

    Expression support is provided by RainerScript. Please see the +RainerScript documentation for more details.

    +

    C-like comments (/* some comment */) are supported inside the expression, +but not yet in the rest of the configuration file.

    + +

    [rsyslog.conf overview] [manual index] [rsyslog site]

    This documentation is part of the -rsyslog -project.
    -Copyright © 2008 by Rainer -Gerhards and +rsyslog project.
    +Copyright © 2008, 2009 by Rainer Gerhards and Adiscon. Released under the GNU GPL version 3 or higher.

    diff --git a/doc/rainerscript.html b/doc/rainerscript.html index ef0e41cb..63a79040 100644 --- a/doc/rainerscript.html +++ b/doc/rainerscript.html @@ -51,13 +51,25 @@ of a and b should be tested as "a <> b". The "not" operator should be reserved to cases where it actually is needed to form a complex boolean expression. In those cases, parenthesis are highly recommended. +

    Functions

    +

    RainerScript supports a currently quite limited set of functions: +

      +
    • getenv(str) - like the OS call, returns the value of the environment +variable, if it exists. Returns an empty string if it does not exist. +
    • strlen(str) - returns the length of the provided string +
    • tolower(str) - converts the provided string into lowercase +
    +

    The following example can be used to build a dynamic filter based on some environment +variable: +

    +if $msg contains getenv('TRIGGERVAR') then /path/to/errfile
    +

    [rsyslog.conf overview] [manual index] [rsyslog site]

    This documentation is part of the rsyslog project.
    -Copyright © 2008 by Rainer -Gerhards and +Copyright © 2008, 2009 by Rainer Gerhards and Adiscon. Released under the GNU GPL version 3 or higher.

    - \ No newline at end of file + diff --git a/runtime/vm.c b/runtime/vm.c index d7cd52d5..a1d992c3 100644 --- a/runtime/vm.c +++ b/runtime/vm.c @@ -34,6 +34,7 @@ #include "vm.h" #include "sysvar.h" #include "stringbuf.h" +#include "unicode-helper.h" /* static data */ DEFobjStaticHelpers @@ -41,6 +42,8 @@ DEFobjCurrIf(vmstk) DEFobjCurrIf(var) DEFobjCurrIf(sysvar) +static pthread_mutex_t mutGetenv; /* we need to make this global because otherwise we can not guarantee proper init! */ + /* ------------------------------ function registry code and structures ------------------------------ */ /* we maintain a registry of known functions */ @@ -539,6 +542,42 @@ finalize_it: } +/* The getenv function. Note that we guard the OS call by a mutex, as that + * function is not guaranteed to be thread-safe. This implementation here is far from + * being optimal, at least we should cache the result. This is left TODO for + * a later revision. + * rgerhards, 2009-11-03 + */ +static rsRetVal +rsf_getenv(vmstk_t *pStk, int numOperands) +{ + DEFiRet; + var_t *operand1; + char *envResult; + cstr_t *pCstr; + + if(numOperands != 1) + ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); + + /* pop args and do operaton (trivial case here...) */ + vmstk.PopString(pStk, &operand1); + d_pthread_mutex_lock(&mutGetenv); + envResult = getenv((char*) rsCStrGetSzStr(operand1->val.pStr)); + DBGPRINTF("rsf_getenv(): envvar '%s', return '%s'\n", rsCStrGetSzStr(operand1->val.pStr), + envResult == NULL ? "(NULL)" : envResult); + iRet = rsCStrConstructFromszStr(&pCstr, (envResult == NULL) ? UCHAR_CONSTANT("") : (uchar*)envResult); + d_pthread_mutex_unlock(&mutGetenv); + if(iRet != RS_RET_OK) + FINALIZE; /* need to do this after mutex is unlocked! */ + + /* Store result and cleanup */ + var.SetString(operand1, pCstr); + vmstk.Push(pStk, operand1); +finalize_it: + RETiRet; +} + + /* The "tolower" function, which converts its sole argument to lower case. * Quite honestly, currently this is primarily a test driver for me... * rgerhards, 2009-04-06 @@ -756,6 +795,8 @@ BEGINObjClassExit(vm, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(sysvar, CORE_COMPONENT); objRelease(var, CORE_COMPONENT); objRelease(vmstk, CORE_COMPONENT); + + pthread_mutex_destroy(&mutGetenv); ENDObjClassExit(vm) @@ -776,6 +817,9 @@ BEGINObjClassInit(vm, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* register built-in functions // TODO: move to its own module */ CHKiRet(rsfrAddFunction((uchar*)"strlen", rsf_strlen)); CHKiRet(rsfrAddFunction((uchar*)"tolower", rsf_tolower)); + CHKiRet(rsfrAddFunction((uchar*)"getenv", rsf_getenv)); + + pthread_mutex_init(&mutGetenv, NULL); ENDObjClassInit(vm) diff --git a/tests/Makefile.am b/tests/Makefile.am index c5deaa47..33f94eef 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,6 +7,7 @@ TESTS = $(TESTRUNS) cfg.sh \ diskqueue.sh \ diskqueue-fsync.sh \ manytcp.sh \ + rsf_getenv.sh \ queue-persist.sh if ENABLE_OMSTDOUT @@ -90,6 +91,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ killrsyslog.sh \ parsertest.sh \ fieldtest.sh \ + rsf_getenv.sh \ + testsuites/rsf_getenv.conf \ diskqueue.sh \ testsuites/diskqueue.conf \ diskqueue-fsync.sh \ diff --git a/tests/diag.sh b/tests/diag.sh index 13bb877d..b2bd13ac 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -9,7 +9,7 @@ #valgrind="valgrind --tool=drd --log-fd=1" #valgrind="valgrind --tool=helgrind --log-fd=1" #set -o xtrace -#export RSYSLOG_DEBUG="debug nostdout printmutexaction" +#export RSYSLOG_DEBUG="debug nostdout noprintmutexaction" #export RSYSLOG_DEBUGLOG="log" case $1 in 'init') $srcdir/killrsyslog.sh # kill rsyslogd if it runs for some reason diff --git a/tests/rsf_getenv.sh b/tests/rsf_getenv.sh new file mode 100755 index 00000000..42de20fe --- /dev/null +++ b/tests/rsf_getenv.sh @@ -0,0 +1,17 @@ +# Test for the getenv() rainerscript function +# this is a quick test, but it gurantees that the code path is +# at least progressed (but we do not check for unset envvars!) +# added 2009-11-03 by Rgerhards +# This file is part of the rsyslog project, released under GPLv3 +# uncomment for debugging support: +echo =============================================================================== +echo \[rsf_getenv.sh\]: testing RainerScript getenv\(\) function +export MSGNUM="msgnum:" +source $srcdir/diag.sh init +source $srcdir/diag.sh startup rsf_getenv.conf +source $srcdir/diag.sh tcpflood 127.0.0.1 13514 1 10000 +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown +source $srcdir/diag.sh seq-check 0 9999 +unset MSGNUM +source $srcdir/diag.sh exit diff --git a/tests/testsuites/rsf_getenv.conf b/tests/testsuites/rsf_getenv.conf new file mode 100644 index 00000000..2f2eb58c --- /dev/null +++ b/tests/testsuites/rsf_getenv.conf @@ -0,0 +1,17 @@ +# Test for RainerScript getenv() function (see .sh file for details) +# Note envvar MSGNUM must be set to "msgnum:" +# rgerhards, 2009-11-03 +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imtcp/.libs/imtcp +$MainMsgQueueTimeoutShutdown 10000 +$InputTCPServerRun 13514 + +# set spool locations and switch queue to disk-only mode +$WorkDirectory test-spool +$MainMsgQueueFilename mainq +$MainMsgQueueType disk + +$template outfmt,"%msg:F,58:2%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +if $msg contains getenv('MSGNUM') then ?dynfile;outfmt -- cgit From cc50b6824e21d9ebb3491bbd4c6d7d8f09be9657 Mon Sep 17 00:00:00 2001 From: Luis Fernando Munoz Mejias Date: Thu, 12 Nov 2009 14:34:55 +0100 Subject: If the server disconnects the handle is no longer valid and we need to call tryResume(), so we have to return RS_RET_SUSPENDED. Otherwise, we may keep losing messages until rsyslog is restarted. --- plugins/omoracle/omoracle.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index 331b7dd4..ee0c226a 100644 --- a/plugins/omoracle/omoracle.c +++ b/plugins/omoracle/omoracle.c @@ -180,6 +180,9 @@ static int oci_errors(void* handle, ub4 htype, sword status) break; case OCI_INVALID_HANDLE: errmsg.LogError(0, NO_ERRCODE, "OCI INVALID HANDLE\n"); + /* In this case we may have to trigger a call to + * tryResume(). */ + return RS_RET_SUSPENDED; break; case OCI_STILL_EXECUTING: errmsg.LogError(0, NO_ERRCODE, "Still executing...\n"); -- cgit From d06b63272d9d5eb568201026bfd42be2be845b18 Mon Sep 17 00:00:00 2001 From: Luis Fernando Munoz Mejias Date: Thu, 12 Nov 2009 14:37:14 +0100 Subject: doc --- doc/omoracle.html | 11 ++++++----- plugins/omoracle/omoracle.c | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/omoracle.html b/doc/omoracle.html index cfcf277f..2bb6aa5d 100644 --- a/doc/omoracle.html +++ b/doc/omoracle.html @@ -13,10 +13,11 @@

    Available since: : 4.3.0

    Status: : contributed module, not maitained by rsyslog core authors

    Description:

    -

    This module provides native support for logging to Oracle databases. It offers -superior performance over the more generic omlibdbi module. -It also includes a number of enhancements, most importantly prepared statements and -batching, what provides a big performance improvements. +

    This module provides native support for logging to Oracle +databases. It offers superior performance over the more +generic omlibdbi module. It also includes +a number of enhancements, most importantly prepared statements and +batching, what provides a big performance improvement.

    Note that this module is maintained by its original author. If you need assistance with it, it is suggested to post questions to the @@ -63,7 +64,7 @@ it is suggested to post questions to the $OmoracleStatement \ insert into foo(hostname,message)values(:host,:message) - Also note that identifiers to placeholders are arbitrarry. You + Also note that identifiers to placeholders are arbitrary. You need to define the properties on the template in the correct order you want them passed to the statement! diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index ee0c226a..ccb1593f 100644 --- a/plugins/omoracle/omoracle.c +++ b/plugins/omoracle/omoracle.c @@ -47,9 +47,9 @@ $OmoracleStatement \ insert into foo(hostname,message)values(:host,:message) - Also note that identifiers to placeholders are arbitrarry. You - need to define the properties on the template in the correct order - you want them passed to the statement! + Also note that identifiers to placeholders are arbitrary. You need + to define the properties on the template in the correct order you + want them passed to the statement! This file is licensed under the terms of the GPL version 3 or, at your choice, any later version. Exceptionally (perhaps), you are -- cgit From 4ed50bb87466ecaba05e6fc53892926997120c18 Mon Sep 17 00:00:00 2001 From: Luis Fernando Munoz Mejias Date: Thu, 12 Nov 2009 14:40:30 +0100 Subject: Improve the handling of OCI_SUCCESS_WITH_INFO. Stop considering it as an error, and make it display the information from the Oracle server. --- plugins/omoracle/omoracle.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index ccb1593f..35478ef4 100644 --- a/plugins/omoracle/omoracle.c +++ b/plugins/omoracle/omoracle.c @@ -87,7 +87,8 @@ MODULE_TYPE_OUTPUT DEF_OMOD_STATIC_DATA DEFobjCurrIf(errmsg) -/** */ +/** Structure defining a batch of items to be sent to the database in + * the same statement execution. */ struct oracle_batch { /* Batch size */ @@ -162,8 +163,10 @@ static int oci_errors(void* handle, ub4 htype, sword status) return OCI_SUCCESS; break; case OCI_SUCCESS_WITH_INFO: - errmsg.LogError(0, NO_ERRCODE, "OCI SUCCESS - With info\n"); - break; + OCIErrorGet(handle, 1, NULL, &errcode, buf, sizeof buf, htype); + errmsg.LogError(0, NO_ERRCODE, "OCI SUCCESS - With info: %s", + buf); + return OCI_SUCCESS; case OCI_NEED_DATA: errmsg.LogError(0, NO_ERRCODE, "OCI NEEDS MORE DATA\n"); break; -- cgit From 54672aa273f3fa19435e1c300f258ec6059745d8 Mon Sep 17 00:00:00 2001 From: Luis Fernando Munoz Mejias Date: Thu, 12 Nov 2009 14:43:44 +0100 Subject: Report errors when OCI_SUCCESS_WITH_INFO happens --- plugins/omoracle/omoracle.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index 35478ef4..67b0cff0 100644 --- a/plugins/omoracle/omoracle.c +++ b/plugins/omoracle/omoracle.c @@ -166,7 +166,7 @@ static int oci_errors(void* handle, ub4 htype, sword status) OCIErrorGet(handle, 1, NULL, &errcode, buf, sizeof buf, htype); errmsg.LogError(0, NO_ERRCODE, "OCI SUCCESS - With info: %s", buf); - return OCI_SUCCESS; + return OCI_SUCCESS_WITH_INFO; case OCI_NEED_DATA: errmsg.LogError(0, NO_ERRCODE, "OCI NEEDS MORE DATA\n"); break; @@ -338,6 +338,30 @@ CODESTARTcreateInstance finalize_it: ENDcreateInstance +static void log_detailed_err(instanceData* pData) +{ + int errs, i, row, code; + OCIError *er, *er2; + unsigned char buf[MAX_BUFSIZE]; + + OCIAttrGet(pData->statement, OCI_HTYPE_STMT, &errs, 0, + OCI_ATTR_NUM_DML_ERRORS, pData->error); + + for (i = 0; i < errs; i++) { + OCIHandleAlloc(pData->environment, &er2, OCI_HTYPE_ERROR, + 0, NULL); + OCIParamGet(pData->error, OCI_HTYPE_ERROR, + er2, &er, i); + OCIAttrGet(er, OCI_HTYPE_ERROR, &row, 0, + OCI_ATTR_DML_ROW_OFFSET, er2); + OCIErrorGet(er, row, NULL, &code, buf, sizeof buf, + OCI_HTYPE_ERROR); + errmsg.LogError(0, NO_ERRCODE, "FAILURE DETAILS: %s", buf); + OCIHandleFree(er2, OCI_HTYPE_ERROR); + } +} + + /* Inserts all stored statements into the database, releasing any * allocated memory. */ static int insert_to_db(instanceData* pData) @@ -352,6 +376,10 @@ static int insert_to_db(instanceData* pData) OCI_BATCH_ERRORS)); finalize_it: + if (iRet == OCI_SUCCESS_WITH_INFO) { + log_detailed_err(pData); + iRet = RS_RET_OK; + } pData->batch.n = 0; OCITransCommit(pData->service, pData->error, 0); dbgprintf ("omoracle insertion to DB %s\n", iRet == RS_RET_OK ? -- cgit From 4be35fbc60c94ee504f5a0428270b59d8438c9f4 Mon Sep 17 00:00:00 2001 From: Luis Fernando Munoz Mejias Date: Thu, 12 Nov 2009 14:44:30 +0100 Subject: Debug output to find out a crash --- plugins/omoracle/omoracle.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index 67b0cff0..c3acfb38 100644 --- a/plugins/omoracle/omoracle.c +++ b/plugins/omoracle/omoracle.c @@ -346,14 +346,18 @@ static void log_detailed_err(instanceData* pData) OCIAttrGet(pData->statement, OCI_HTYPE_STMT, &errs, 0, OCI_ATTR_NUM_DML_ERRORS, pData->error); - + dbgprintf("There were %d errors\n", errs); for (i = 0; i < errs; i++) { + dbgprintf("Allocating stuff %d\n", i); OCIHandleAlloc(pData->environment, &er2, OCI_HTYPE_ERROR, 0, NULL); + dbgprintf("ParamGet %d\n", i); OCIParamGet(pData->error, OCI_HTYPE_ERROR, er2, &er, i); + dbgprintf("AttrGet %d\n", i); OCIAttrGet(er, OCI_HTYPE_ERROR, &row, 0, OCI_ATTR_DML_ROW_OFFSET, er2); + dbgprintf("ErrorGet %d\n", i); OCIErrorGet(er, row, NULL, &code, buf, sizeof buf, OCI_HTYPE_ERROR); errmsg.LogError(0, NO_ERRCODE, "FAILURE DETAILS: %s", buf); -- cgit From 774fdc6c799e9671c8e0eac5271a83a3f8fb4646 Mon Sep 17 00:00:00 2001 From: Luis Fernando Munoz Mejias Date: Thu, 12 Nov 2009 14:45:05 +0100 Subject: Improve the debug messages Improve traceability while testing. --- plugins/omoracle/omoracle.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index c3acfb38..31e498f7 100644 --- a/plugins/omoracle/omoracle.c +++ b/plugins/omoracle/omoracle.c @@ -346,23 +346,23 @@ static void log_detailed_err(instanceData* pData) OCIAttrGet(pData->statement, OCI_HTYPE_STMT, &errs, 0, OCI_ATTR_NUM_DML_ERRORS, pData->error); - dbgprintf("There were %d errors\n", errs); + errmsg.LogError(0, NO_ERRCODE, "%d errors in statement execution\n", + errs); + OCIHandleAlloc(pData->environment, &er, OCI_HTYPE_ERROR, + 0, NULL); + OCIHandleAlloc(pData->environment, &er2, OCI_HTYPE_ERROR, + 0, NULL); for (i = 0; i < errs; i++) { - dbgprintf("Allocating stuff %d\n", i); - OCIHandleAlloc(pData->environment, &er2, OCI_HTYPE_ERROR, - 0, NULL); - dbgprintf("ParamGet %d\n", i); OCIParamGet(pData->error, OCI_HTYPE_ERROR, er2, &er, i); - dbgprintf("AttrGet %d\n", i); OCIAttrGet(er, OCI_HTYPE_ERROR, &row, 0, OCI_ATTR_DML_ROW_OFFSET, er2); - dbgprintf("ErrorGet %d\n", i); OCIErrorGet(er, row, NULL, &code, buf, sizeof buf, OCI_HTYPE_ERROR); errmsg.LogError(0, NO_ERRCODE, "FAILURE DETAILS: %s", buf); - OCIHandleFree(er2, OCI_HTYPE_ERROR); } + OCIHandleFree(er, OCI_HTYPE_ERROR); + OCIHandleFree(er2, OCI_HTYPE_ERROR); } -- cgit From f5676115b54cb9620cc5092a898d83531f22b502 Mon Sep 17 00:00:00 2001 From: Luis Fernando Munoz Mejias Date: Thu, 12 Nov 2009 14:46:09 +0100 Subject: Give even better output Tell which statement is failing, which element in the batch, and give its details. --- plugins/omoracle/omoracle.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index 31e498f7..48ee1fa4 100644 --- a/plugins/omoracle/omoracle.c +++ b/plugins/omoracle/omoracle.c @@ -338,29 +338,43 @@ CODESTARTcreateInstance finalize_it: ENDcreateInstance +/* Analyses the errors during a batch statement execution, and logs + * all the corresponding ORA-MESSAGES, together with some useful + * information. */ static void log_detailed_err(instanceData* pData) { - int errs, i, row, code; - OCIError *er, *er2; + DEFiRet; + int errs, i, row, code, j; + OCIError *er = NULL, *er2 = NULL; unsigned char buf[MAX_BUFSIZE]; OCIAttrGet(pData->statement, OCI_HTYPE_STMT, &errs, 0, OCI_ATTR_NUM_DML_ERRORS, pData->error); - errmsg.LogError(0, NO_ERRCODE, "%d errors in statement execution\n", - errs); - OCIHandleAlloc(pData->environment, &er, OCI_HTYPE_ERROR, - 0, NULL); - OCIHandleAlloc(pData->environment, &er2, OCI_HTYPE_ERROR, - 0, NULL); + errmsg.LogError(0, NO_ERRCODE, "OCI: %d errors in execution of " + "statement: %s", errs, pData->txt_statement); + + CHECKENV(pData->environment, + OCIHandleAlloc(pData->environment, &er, OCI_HTYPE_ERROR, + 0, NULL)); + CHECKENV(pData->environment, + OCIHandleAlloc(pData->environment, &er2, OCI_HTYPE_ERROR, + 0, NULL)); + for (i = 0; i < errs; i++) { OCIParamGet(pData->error, OCI_HTYPE_ERROR, er2, &er, i); OCIAttrGet(er, OCI_HTYPE_ERROR, &row, 0, OCI_ATTR_DML_ROW_OFFSET, er2); - OCIErrorGet(er, row, NULL, &code, buf, sizeof buf, + errmsg.LogError(0, NO_ERRCODE, "OCI failure in row %d:", row); + for (j = 0; j < pData->batch.arguments; j++) + errmsg.LogError(0, NO_ERRCODE, "%s", + pData->batch.parameters[j][row]); + OCIErrorGet(er, 1, NULL, &code, buf, sizeof buf, OCI_HTYPE_ERROR); errmsg.LogError(0, NO_ERRCODE, "FAILURE DETAILS: %s", buf); } + +finalize_it: OCIHandleFree(er, OCI_HTYPE_ERROR); OCIHandleFree(er2, OCI_HTYPE_ERROR); } -- cgit From 30c2e42ec305bb97bd04172e5c02b89eeea53e35 Mon Sep 17 00:00:00 2001 From: varmojfekoj Date: Tue, 17 Nov 2009 09:00:01 +0100 Subject: added option to use unlimited-size select() calls Thanks to varmjofekoj for the patch Signed-off-by: Rainer Gerhards --- ChangeLog | 2 ++ configure.ac | 16 ++++++++++++++ gss-misc.c | 23 +++++++++++++++----- plugins/imgssapi/imgssapi.c | 16 ++++++++++---- plugins/imudp/imudp.c | 20 ++++++++++++------ plugins/imuxsock/imuxsock.c | 20 ++++++++++++------ runtime/Makefile.am | 1 + runtime/glbl.c | 12 +++++++++++ runtime/glbl.h | 3 +++ runtime/nsdsel_ptcp.c | 51 ++++++++++++++++++++++++++++++++++++--------- runtime/nsdsel_ptcp.h | 5 +++++ tools/syslogd.c | 3 +++ 12 files changed, 141 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b16824d..e8273528 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +- added option to use unlimited-size select() calls + Thanks to varmjofekoj for the patch --------------------------------------------------------------------------- Version 4.4.2 [v4-stable] (rgerhards), 2009-10-09 - bugfix: invalid handling of zero-sized messages, could lead to mis- diff --git a/configure.ac b/configure.ac index 66a2d70d..932a5fc5 100644 --- a/configure.ac +++ b/configure.ac @@ -341,6 +341,21 @@ AC_ARG_ENABLE([fsstnd], ]) +# support for unlimited select() syscall +AC_ARG_ENABLE(unlimited_select, + [AS_HELP_STRING([--enable-unlimited-select],[Enable unlimited select() syscall @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_unlimited_select="yes" ;; + no) enable_unlimited_select="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-unlimited-select) ;; + esac], + [enable_unlimited_select="no"] +) +if test "$enable_unlimited_select" = "yes"; then + AC_DEFINE(USE_UNLIMITED_SELECT, 1, [If defined, the select() syscall won't be limited to a particular number of file descriptors.]) +fi + + # debug AC_ARG_ENABLE(debug, [AS_HELP_STRING([--enable-debug],[Enable debug mode @<:@default=no@:>@])], @@ -843,6 +858,7 @@ echo " Zlib compression support enabled: $enable_zlib" echo " rsyslog runtime will be built: $enable_rsyslogrt" echo " rsyslogd will be built: $enable_rsyslogd" echo " custom module 1 will be built: $enable_cust1" +echo " Unlimited select() support enabled: $enable_unlimited_select" echo echo "---{ input plugins }---" echo " Klog functionality enabled: $enable_klog ($os_type)" diff --git a/gss-misc.c b/gss-misc.c index c9220595..2bfaf9c5 100644 --- a/gss-misc.c +++ b/gss-misc.c @@ -51,11 +51,14 @@ #include "obj.h" #include "errmsg.h" #include "gss-misc.h" +#include "glbl.h" +#include "unlimited_select.h" MODULE_TYPE_LIB /* static data */ DEFobjStaticHelpers +DEFobjCurrIf(glbl) DEFobjCurrIf(errmsg) static void display_status_(char *m, OM_uint32 code, int type) @@ -108,28 +111,38 @@ static int read_all(int fd, char *buf, unsigned int nbyte) { int ret; char *ptr; - fd_set rfds; struct timeval tv; +#ifdef USE_UNLIMITED_SELECT + fd_set *pRfds = malloc(glbl.GetFdSetSize()); +#else + fd_set rfds; + fd_set *pRfds = &rfds; +#endif for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) { - FD_ZERO(&rfds); - FD_SET(fd, &rfds); + FD_ZERO(pRfds); + FD_SET(fd, pRfds); tv.tv_sec = 1; tv.tv_usec = 0; - if ((ret = select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) <= 0 - || !FD_ISSET(fd, &rfds)) + if ((ret = select(FD_SETSIZE, pRfds, NULL, NULL, &tv)) <= 0 + || !FD_ISSET(fd, pRfds)) { + freeFdSet(pRfds); return ret; + } ret = recv(fd, ptr, nbyte, 0); if (ret < 0) { if (errno == EINTR) continue; + freeFdSet(pRfds); return (ret); } else if (ret == 0) { + freeFdSet(pRfds); return (ptr - buf); } } + freeFdSet(pRfds); return (ptr - buf); } diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c index d8791880..1aad6622 100644 --- a/plugins/imgssapi/imgssapi.c +++ b/plugins/imgssapi/imgssapi.c @@ -56,6 +56,7 @@ #include "errmsg.h" #include "netstrm.h" #include "glbl.h" +#include "unlimited_select.h" MODULE_TYPE_INPUT @@ -414,15 +415,20 @@ OnSessAcceptGSS(tcpsrv_t *pThis, tcps_sess_t *pSess) CHKiRet(netstrm.GetSock(pSess->pStrm, &fdSess)); // TODO: method access! if (allowedMethods & ALLOWEDMETHOD_TCP) { int len; - fd_set fds; struct timeval tv; +#ifdef USE_UNLIMITED_SELECT + fd_set *pFds = malloc(glbl.GetFdSetSize()); +#else + fd_set fds; + fd_set *pFds = &fds; +#endif do { - FD_ZERO(&fds); - FD_SET(fdSess, &fds); + FD_ZERO(pFds); + FD_SET(fdSess, pFds); tv.tv_sec = 1; tv.tv_usec = 0; - ret = select(fdSess + 1, &fds, NULL, NULL, &tv); + ret = select(fdSess + 1, pFds, NULL, NULL, &tv); } while (ret < 0 && errno == EINTR); if (ret < 0) { errmsg.LogError(0, RS_RET_ERR, "TCP session %p will be closed, error ignored\n", pSess); @@ -475,6 +481,8 @@ OnSessAcceptGSS(tcpsrv_t *pThis, tcps_sess_t *pSess) pGSess->allowedMethods = ALLOWEDMETHOD_TCP; ABORT_FINALIZE(RS_RET_OK); // TODO: define good error codes } + + freeFdSet(pFds); } context = &pGSess->gss_context; diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 6f4a6384..b5c97f2c 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -44,6 +44,7 @@ #include "parser.h" #include "datetime.h" #include "unicode-helper.h" +#include "unlimited_select.h" MODULE_TYPE_INPUT @@ -256,12 +257,18 @@ BEGINrunInput int maxfds; int nfds; int i; - fd_set readfds; struct sockaddr_storage frominetPrev; int bIsPermitted; uchar fromHost[NI_MAXHOST]; uchar fromHostIP[NI_MAXHOST]; uchar fromHostFQDN[NI_MAXHOST]; +#ifdef USE_UNLIMITED_SELECT + fd_set *pReadfds = malloc(glbl.GetFdSetSize()); +#else + fd_set readfds; + fd_set *pReadfds = &readfds; +#endif + CODESTARTrunInput /* start "name caching" algo by making sure the previous system indicator * is invalidated. @@ -280,30 +287,30 @@ CODESTARTrunInput * is given without -a, we do not need to listen at all.. */ maxfds = 0; - FD_ZERO (&readfds); + FD_ZERO (pReadfds); /* Add the UDP listen sockets to the list of read descriptors. */ for (i = 0; i < *udpLstnSocks; i++) { if (udpLstnSocks[i+1] != -1) { if(Debug) net.debugListenInfo(udpLstnSocks[i+1], "UDP"); - FD_SET(udpLstnSocks[i+1], &readfds); + FD_SET(udpLstnSocks[i+1], pReadfds); if(udpLstnSocks[i+1]>maxfds) maxfds=udpLstnSocks[i+1]; } } if(Debug) { dbgprintf("--------imUDP calling select, active file descriptors (max %d): ", maxfds); for (nfds = 0; nfds <= maxfds; ++nfds) - if ( FD_ISSET(nfds, &readfds) ) + if ( FD_ISSET(nfds, pReadfds) ) dbgprintf("%d ", nfds); dbgprintf("\n"); } /* wait for io to become ready */ - nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL); + nfds = select(maxfds+1, (fd_set *) pReadfds, NULL, NULL, NULL); for(i = 0; nfds && i < *udpLstnSocks; i++) { - if(FD_ISSET(udpLstnSocks[i+1], &readfds)) { + if(FD_ISSET(udpLstnSocks[i+1], pReadfds)) { processSocket(udpLstnSocks[i+1], &frominetPrev, &bIsPermitted, fromHost, fromHostFQDN, fromHostIP); --nfds; /* indicate we have processed one descriptor */ @@ -312,6 +319,7 @@ CODESTARTrunInput /* end of a run, back to loop for next recv() */ } + freeFdSet(pReadfds); return iRet; ENDrunInput diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 1d88a2b5..28f8d6b5 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -43,6 +43,7 @@ #include "net.h" #include "glbl.h" #include "msg.h" +#include "unlimited_select.h" MODULE_TYPE_INPUT @@ -245,7 +246,13 @@ BEGINrunInput int nfds; int i; int fd; - fd_set readfds; +#ifdef USE_UNLIMITED_SELECT + fd_set *pReadfds = malloc(glbl.GetFdSetSize()); +#else + fd_set readfds; + fd_set *pReadfds = &readfds; +#endif + CODESTARTrunInput /* this is an endless loop - it is terminated when the thread is * signalled to do so. This, however, is handled by the framework, @@ -259,11 +266,11 @@ CODESTARTrunInput * is given without -a, we do not need to listen at all.. */ maxfds = 0; - FD_ZERO (&readfds); + FD_ZERO (pReadfds); /* Copy master connections */ for (i = startIndexUxLocalSockets; i < nfunix; i++) { if (funix[i] != -1) { - FD_SET(funix[i], &readfds); + FD_SET(funix[i], pReadfds); if (funix[i]>maxfds) maxfds=funix[i]; } } @@ -271,22 +278,23 @@ CODESTARTrunInput if(Debug) { dbgprintf("--------imuxsock calling select, active file descriptors (max %d): ", maxfds); for (nfds= 0; nfds <= maxfds; ++nfds) - if ( FD_ISSET(nfds, &readfds) ) + if ( FD_ISSET(nfds, pReadfds) ) dbgprintf("%d ", nfds); dbgprintf("\n"); } /* wait for io to become ready */ - nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL); + nfds = select(maxfds+1, (fd_set *) pReadfds, NULL, NULL, NULL); for (i = 0; i < nfunix && nfds > 0; i++) { - if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) { + if ((fd = funix[i]) != -1 && FD_ISSET(fd, pReadfds)) { readSocket(fd, i); --nfds; /* indicate we have processed one */ } } } + freeFdSet(pReadfds); RETiRet; ENDrunInput diff --git a/runtime/Makefile.am b/runtime/Makefile.am index eeb656d6..006b7459 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -15,6 +15,7 @@ librsyslog_la_SOURCES = \ nsd.h \ glbl.h \ glbl.c \ + unlimited_select.h \ conf.c \ conf.h \ parser.h \ diff --git a/runtime/glbl.c b/runtime/glbl.c index 28f14320..a443b948 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -68,6 +68,9 @@ static uchar *pszDfltNetstrmDrvr = NULL; /* module name of default netstream dri static uchar *pszDfltNetstrmDrvrCAF = NULL; /* default CA file for the netstrm driver */ static uchar *pszDfltNetstrmDrvrKeyFile = NULL; /* default key file for the netstrm driver (server) */ static uchar *pszDfltNetstrmDrvrCertFile = NULL; /* default cert file for the netstrm driver (server) */ +#ifdef USE_UNLIMITED_SELECT +static int iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); /* size of select() bitmask in bytes */ +#endif /* define a macro for the simple properties' set and get functions @@ -100,6 +103,9 @@ SIMP_PROP(DisableDNS, bDisableDNS, int) SIMP_PROP(LocalDomain, LocalDomain, uchar*) SIMP_PROP(StripDomains, StripDomains, char**) SIMP_PROP(LocalHosts, LocalHosts, char**) +#ifdef USE_UNLIMITED_SELECT +SIMP_PROP(FdSetSize, iFdSetSize, int) +#endif SIMP_PROP_SET(LocalFQDNName, LocalFQDNName, uchar*) SIMP_PROP_SET(LocalHostName, LocalHostName, uchar*) @@ -217,6 +223,9 @@ CODESTARTobjQueryInterface(glbl) SIMP_PROP(DfltNetstrmDrvrCAF) SIMP_PROP(DfltNetstrmDrvrKeyFile) SIMP_PROP(DfltNetstrmDrvrCertFile) +#ifdef USE_UNLIMITED_SELECT + SIMP_PROP(FdSetSize) +#endif #undef SIMP_PROP finalize_it: ENDobjQueryInterface(glbl) @@ -251,6 +260,9 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a bOptimizeUniProc = 1; bHUPisRestart = 1; bPreserveFQDN = 0; +#ifdef USE_UNLIMITED_SELECT + iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); +#endif return RS_RET_OK; } diff --git a/runtime/glbl.h b/runtime/glbl.h index 5bdf4f57..fb72a965 100644 --- a/runtime/glbl.h +++ b/runtime/glbl.h @@ -57,6 +57,9 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */ SIMP_PROP(DfltNetstrmDrvrCAF, uchar*) SIMP_PROP(DfltNetstrmDrvrKeyFile, uchar*) SIMP_PROP(DfltNetstrmDrvrCertFile, uchar*) +#ifdef USE_UNLIMITED_SELECT + SIMP_PROP(FdSetSize, int) +#endif #undef SIMP_PROP ENDinterface(glbl) #define glblCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ diff --git a/runtime/nsdsel_ptcp.c b/runtime/nsdsel_ptcp.c index 41b85e0c..e2cfca7c 100644 --- a/runtime/nsdsel_ptcp.c +++ b/runtime/nsdsel_ptcp.c @@ -36,6 +36,7 @@ #include "errmsg.h" #include "nsd_ptcp.h" #include "nsdsel_ptcp.h" +#include "unlimited_select.h" /* static data */ DEFobjStaticHelpers @@ -47,14 +48,23 @@ DEFobjCurrIf(glbl) */ BEGINobjConstruct(nsdsel_ptcp) /* be sure to specify the object type also in END macro! */ pThis->maxfds = 0; +#ifdef USE_UNLIMITED_SELECT + pThis->pReadfds = calloc(1, glbl.GetFdSetSize()); + pThis->pWritefds = calloc(1, glbl.GetFdSetSize()); +#else FD_ZERO(&pThis->readfds); FD_ZERO(&pThis->writefds); +#endif ENDobjConstruct(nsdsel_ptcp) /* destructor for the nsdsel_ptcp object */ BEGINobjDestruct(nsdsel_ptcp) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(nsdsel_ptcp) +#ifdef USE_UNLIMITED_SELECT + freeFdSet(pThis->pReadfds); + freeFdSet(pThis->pWritefds); +#endif ENDobjDestruct(nsdsel_ptcp) @@ -65,20 +75,27 @@ Add(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp) DEFiRet; nsdsel_ptcp_t *pThis = (nsdsel_ptcp_t*) pNsdsel; nsd_ptcp_t *pSock = (nsd_ptcp_t*) pNsd; +#ifdef USE_UNLIMITED_SELECT + fd_set *pReadfds = pThis->pReadfds; + fd_set *pWritefds = pThis->pWritefds; +#else + fd_set *pReadfds = &pThis->readfds; + fd_set *pWritefds = &pThis->writefds; +#endif ISOBJ_TYPE_assert(pSock, nsd_ptcp); ISOBJ_TYPE_assert(pThis, nsdsel_ptcp); switch(waitOp) { case NSDSEL_RD: - FD_SET(pSock->sock, &pThis->readfds); + FD_SET(pSock->sock, pReadfds); break; case NSDSEL_WR: - FD_SET(pSock->sock, &pThis->writefds); + FD_SET(pSock->sock, pWritefds); break; case NSDSEL_RDWR: - FD_SET(pSock->sock, &pThis->readfds); - FD_SET(pSock->sock, &pThis->writefds); + FD_SET(pSock->sock, pReadfds); + FD_SET(pSock->sock, pWritefds); break; } @@ -98,6 +115,13 @@ Select(nsdsel_t *pNsdsel, int *piNumReady) DEFiRet; int i; nsdsel_ptcp_t *pThis = (nsdsel_ptcp_t*) pNsdsel; +#ifdef USE_UNLIMITED_SELECT + fd_set *pReadfds = pThis->pReadfds; + fd_set *pWritefds = pThis->pWritefds; +#else + fd_set *pReadfds = &pThis->readfds; + fd_set *pWritefds = &pThis->writefds; +#endif ISOBJ_TYPE_assert(pThis, nsdsel_ptcp); assert(piNumReady != NULL); @@ -106,13 +130,13 @@ Select(nsdsel_t *pNsdsel, int *piNumReady) // TODO: name in dbgprintf! dbgprintf("-------- calling select, active fds (max %d): ", pThis->maxfds); for(i = 0; i <= pThis->maxfds; ++i) - if(FD_ISSET(i, &pThis->readfds) || FD_ISSET(i, &pThis->writefds)) + if(FD_ISSET(i, pReadfds) || FD_ISSET(i, pWritefds)) dbgprintf("%d ", i); dbgprintf("\n"); } /* now do the select */ - *piNumReady = select(pThis->maxfds+1, &pThis->readfds, &pThis->writefds, NULL, NULL); + *piNumReady = select(pThis->maxfds+1, pReadfds, pWritefds, NULL, NULL); RETiRet; } @@ -125,6 +149,13 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp, int *pbIsReady) DEFiRet; nsdsel_ptcp_t *pThis = (nsdsel_ptcp_t*) pNsdsel; nsd_ptcp_t *pSock = (nsd_ptcp_t*) pNsd; +#ifdef USE_UNLIMITED_SELECT + fd_set *pReadfds = pThis->pReadfds; + fd_set *pWritefds = pThis->pWritefds; +#else + fd_set *pReadfds = &pThis->readfds; + fd_set *pWritefds = &pThis->writefds; +#endif ISOBJ_TYPE_assert(pThis, nsdsel_ptcp); ISOBJ_TYPE_assert(pSock, nsd_ptcp); @@ -132,14 +163,14 @@ IsReady(nsdsel_t *pNsdsel, nsd_t *pNsd, nsdsel_waitOp_t waitOp, int *pbIsReady) switch(waitOp) { case NSDSEL_RD: - *pbIsReady = FD_ISSET(pSock->sock, &pThis->readfds); + *pbIsReady = FD_ISSET(pSock->sock, pReadfds); break; case NSDSEL_WR: - *pbIsReady = FD_ISSET(pSock->sock, &pThis->writefds); + *pbIsReady = FD_ISSET(pSock->sock, pWritefds); break; case NSDSEL_RDWR: - *pbIsReady = FD_ISSET(pSock->sock, &pThis->readfds) - | FD_ISSET(pSock->sock, &pThis->writefds); + *pbIsReady = FD_ISSET(pSock->sock, pReadfds) + | FD_ISSET(pSock->sock, pWritefds); break; } diff --git a/runtime/nsdsel_ptcp.h b/runtime/nsdsel_ptcp.h index 6c0c7fa7..f9ec8210 100644 --- a/runtime/nsdsel_ptcp.h +++ b/runtime/nsdsel_ptcp.h @@ -31,8 +31,13 @@ typedef nsdsel_if_t nsdsel_ptcp_if_t; /* we just *implement* this interface */ struct nsdsel_ptcp_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ int maxfds; +#ifdef USE_UNLIMITED_SELECT + fd_set *pReadfds; + fd_set *pWritefds; +#else fd_set readfds; fd_set writefds; +#endif }; /* interface is defined in nsd.h, we just implement it! */ diff --git a/tools/syslogd.c b/tools/syslogd.c index 5f6b480f..687f2217 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -2150,6 +2150,9 @@ static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles) iFiles, errStr, (long) maxFiles.rlim_max); ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE); } +#ifdef USE_UNLIMITED_SELECT + glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask)); +#endif DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max); finalize_it: -- cgit From 9e28d47aaa506709a9e80e318527ceb4443cbffe Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 17 Nov 2009 10:14:02 +0100 Subject: worked a bit on "unlimited select()" patch - potential segfault in gss-misc.c - glbl interface needed different version ID - some compile time warning cleanup --- gss-misc.c | 2 ++ runtime/glbl.h | 8 ++++++-- runtime/unlimited_select.h | 6 ++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/gss-misc.c b/gss-misc.c index 2bfaf9c5..978454ff 100644 --- a/gss-misc.c +++ b/gss-misc.c @@ -277,6 +277,7 @@ BEGINObjClassExit(gssutil, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END M CODESTARTObjClassExit(gssutil) /* release objects we no longer need */ objRelease(errmsg, CORE_COMPONENT); + objRelease(glbl, CORE_COMPONENT); ENDObjClassExit(gssutil) @@ -287,6 +288,7 @@ ENDObjClassExit(gssutil) BEGINAbstractObjClassInit(gssutil, 1, OBJ_IS_LOADABLE_MODULE) /* class, version - CHANGE class also in END MACRO! */ /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(glbl, CORE_COMPONENT)); ENDObjClassInit(gssutil) diff --git a/runtime/glbl.h b/runtime/glbl.h index c55c2536..6a332576 100644 --- a/runtime/glbl.h +++ b/runtime/glbl.h @@ -62,14 +62,18 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */ /* added v3, 2009-06-30 */ rsRetVal (*GenerateLocalHostNameProperty)(void); prop_t* (*GetLocalHostNameProp)(void); - /* added v4, 2009-11-16 as part of varmojfekoj's "unlimited select()" patch + /* note: v4, v5 are already used by more recent versions, so we need to skip them! */ + /* added v6, 2009-11-16 as part of varmojfekoj's "unlimited select()" patch * Note that it must be always present, otherwise the interface would have different * versions depending on compile settings, what is not acceptable. + * Use this property with care, it is only truly available if UNLIMITED_SELECT is enabled + * (I did not yet further investigate the details, because that code hopefully can be removed + * at some later stage). */ SIMP_PROP(FdSetSize, int) #undef SIMP_PROP ENDinterface(glbl) -#define glblCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */ +#define glblCURR_IF_VERSION 6 /* increment whenever you change the interface structure! */ /* version 2 had PreserveFQDN added - rgerhards, 2008-12-08 */ /* the remaining prototypes */ diff --git a/runtime/unlimited_select.h b/runtime/unlimited_select.h index 61a2baca..32dadc03 100644 --- a/runtime/unlimited_select.h +++ b/runtime/unlimited_select.h @@ -34,10 +34,12 @@ # define FD_ZERO(set) memset((set), 0, glbl.GetFdSetSize()); #endif -void freeFdSet(fd_set *p) { #ifdef USE_UNLIMITED_SELECT +void freeFdSet(fd_set *p) { free(p); -#endif } +#else +# define freeFdSet(x) +#endif #endif /* #ifndef UNLIMITED_SELECT_H_INCLUDED */ -- cgit From 5b55ab75e27861241981ae447ed3d1b8ad968deb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 20 Nov 2009 18:41:04 +0100 Subject: debugondemand mode caused backgrounding to fail This is close to a bug, but I'd consider the ability to background in this mode a new feature... --- ChangeLog | 8 +++++--- runtime/debug.c | 4 ++-- runtime/debug.h | 5 +++++ tools/syslogd.c | 10 +++++----- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9e54bd1b..e3194389 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,3 @@ -- added option to use unlimited-size select() calls - Thanks to varmjofekoj for the patch --------------------------------------------------------------------------- Version 4.7.0 [v4-devel] (rgerhards), 2009-09-?? - added function getenv() to RainerScript @@ -14,7 +12,11 @@ Version 4.7.0 [v4-devel] (rgerhards), 2009-09-?? - added new config directive $omfileForceChown to (try to) fix some broken system configs. See ticket for details: http://bugzilla.adiscon.com/show_bug.cgi?id=150 -- imported changes from 4.5.6 and below +- added option to use unlimited-size select() calls + Thanks to varmjofekoj for the patch +- debugondemand mode caused backgrounding to fail - close to a bug, but I'd + consider the ability to background in this mode a new feature... +- imported changes from 4.5.7 and below --------------------------------------------------------------------------- Version 4.5.7 [v4-beta] (rgerhards), 2009-11-18 - added a so-called "On Demand Debug" mode, in which debug output can diff --git a/runtime/debug.c b/runtime/debug.c index 9547eee6..c23dec3b 100644 --- a/runtime/debug.c +++ b/runtime/debug.c @@ -1271,11 +1271,11 @@ dbgGetRuntimeOptions(void) /* this is earlier in the process than the -d option, as such it * allows us to spit out debug messages from the very beginning. */ - Debug = 1; + Debug = DEBUG_FULL; debugging_on = 1; } else if(!strcasecmp((char*)optname, "debugondemand")) { /* Enables debugging, but turns off debug output */ - Debug = 1; + Debug = DEBUG_ONDEMAND; debugging_on = 1; dbgprintf("Note: debug on demand turned on via configuraton file, " "use USR1 signal to activate.\n"); diff --git a/runtime/debug.h b/runtime/debug.h index dcbfb930..cfdf819c 100644 --- a/runtime/debug.h +++ b/runtime/debug.h @@ -29,6 +29,11 @@ #include #include "obj-types.h" +/* some settings for various debug modes */ +#define DEBUG_OFF 0 +#define DEBUG_ONDEMAND 1 +#define DEBUG_FULL 2 + /* external static data elements (some time to be replaced) */ extern int Debug; /* debug flag - read-only after startup */ extern int debugging_on; /* read-only, except on sig USR1 */ diff --git a/tools/syslogd.c b/tools/syslogd.c index e03bf4d8..f11808f3 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -904,7 +904,7 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags) * permits us to process unmodified config files which otherwise contain a * supressor statement. */ - if(((Debug || NoFork) && bErrMsgToStderr) || iConfigVerify) { + if(((Debug == DEBUG_FULL || NoFork) && bErrMsgToStderr) || iConfigVerify) { if(LOG_PRI(pri) == LOG_ERR) fprintf(stderr, "rsyslogd: %s\n", msg); } @@ -1644,10 +1644,10 @@ static void doDie(int sig) # define MSG1 "DoDie called.\n" # define MSG2 "DoDie called 5 times - unconditional exit\n" static int iRetries = 0; /* debug aid */ - if(Debug) + if(Debug == DEBUG_FULL) write(1, MSG1, sizeof(MSG1) - 1); if(iRetries++ == 4) { - if(Debug) + if(Debug == DEBUG_FULL) write(1, MSG2, sizeof(MSG2) - 1); abort(); } @@ -2881,7 +2881,7 @@ static rsRetVal mainThread() * is still in its infancy (and not really done), we currently accept this issue. * rgerhards, 2009-06-29 */ - if(!(Debug || NoFork)) { + if(!(Debug == DEBUG_FULL || NoFork)) { close(1); close(2); bErrMsgToStderr = 0; @@ -3072,7 +3072,7 @@ doGlblProcessInit(void) thrdInit(); - if( !(Debug || NoFork) ) + if( !(Debug == DEBUG_FULL || NoFork) ) { DBGPRINTF("Checking pidfile.\n"); if (!check_pid(PidFile)) -- cgit From 549ed00c4aeb5c4d73e91f2b64c619b562ddcbf2 Mon Sep 17 00:00:00 2001 From: Jonathan Bond-Caron Date: Fri, 27 Nov 2009 10:30:47 +0100 Subject: added $EscapeControlCharacterTab config directive --- ChangeLog | 6 ++++-- dirty.h | 1 + tools/syslogd.c | 10 ++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 63355bf3..b6deefb9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,10 +12,14 @@ Version 4.7.0 [v4-devel] (rgerhards), 2009-09-?? - added new config directive $omfileForceChown to (try to) fix some broken system configs. See ticket for details: http://bugzilla.adiscon.com/show_bug.cgi?id=150 +- added $EscapeControlCharacterTab config directive + Thanks to Jonathan Bond-Caron for the patch. - added option to use unlimited-size select() calls Thanks to varmjofekoj for the patch - debugondemand mode caused backgrounding to fail - close to a bug, but I'd consider the ability to background in this mode a new feature... +- bugfix (kind of): check if TCP connection is still alive if using TLS + Thanks to Jonathan Bond-Caron for the patch. - imported changes from 4.5.7 and below --------------------------------------------------------------------------- Version 4.5.7 [v4-beta] (rgerhards), 2009-11-18 @@ -23,8 +27,6 @@ Version 4.5.7 [v4-beta] (rgerhards), 2009-11-18 be generated only after the process has started, but not right from the beginning. This is assumed to be useful for hard-to-find bugs. Also improved the doc on the debug system. -- bugfix (kind of): check if TCP connection is still alive if using TLS - Thanks to Jonathan Bond-Caron for the patch. - bugfix [imported from 4.4.3]: $ActionExecOnlyOnceEveryInterval did not work. --------------------------------------------------------------------------- diff --git a/dirty.h b/dirty.h index 0153cb69..f1904574 100644 --- a/dirty.h +++ b/dirty.h @@ -54,6 +54,7 @@ extern int bReduceRepeatMsgs; extern int bDropTrailingLF; extern uchar cCCEscapeChar; extern int bEscapeCCOnRcv; +extern int bEscapeTab; #ifdef USE_NETZIP /* config param: minimum message size to try compression. The smaller * the message, the less likely is any compression gain. We check for diff --git a/tools/syslogd.c b/tools/syslogd.c index f11808f3..2806921c 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -254,8 +254,9 @@ static int bLogStatusMsgs = DFLT_bLogStatusMsgs; /* log rsyslog start/stop/HUP m static int bDebugPrintTemplateList = 1;/* output template list in debug mode? */ static int bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list in debug mode? */ static int bDebugPrintModuleList = 1;/* output module list in debug mode? */ -uchar cCCEscapeChar = '\\';/* character to be used to start an escape sequence for control chars */ +uchar cCCEscapeChar = '#';/* character to be used to start an escape sequence for control chars */ int bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */ +int bEscapeTab = 1; /* treat tab as escape control character: 0 - no, 1 - yes */ static int bErrMsgToStderr = 1; /* print error messages to stderr (in addition to everything else)? */ int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */ int bActExecWhenPrevSusp; /* execute action only when previous one was suspended? */ @@ -341,6 +342,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a bDebugPrintCfSysLineHandlerList = 1; bDebugPrintModuleList = 1; bEscapeCCOnRcv = 1; /* default is to escape control characters */ + bEscapeTab = 1; bReduceRepeatMsgs = 0; free(pszMainMsgQFName); pszMainMsgQFName = NULL; @@ -807,7 +809,7 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla /* log an error? Very questionable... rgerhards, 2006-11-30 */ /* decided: we do not log an error, it won't help... rger, 2007-06-21 */ ++pData; - } else if(bEscapeCCOnRcv && iscntrl((int) *pData)) { + } else if(bEscapeCCOnRcv && iscntrl((int) *pData) && (*pData != '\t' || bEscapeTab)) { /* we are configured to escape control characters. Please note * that this most probably break non-western character sets like * Japanese, Korean or Chinese. rgerhards, 2007-07-17 @@ -1197,8 +1199,7 @@ int parseLegacySyslogMsg(msg_t *pMsg, int flags) assert(pMsg != NULL); assert(pMsg->pszRawMsg != NULL); lenMsg = pMsg->iLenRawMsg - (pMsg->offAfterPRI + 1); -RUNLOG_VAR("%d", pMsg->offAfterPRI); -RUNLOG_VAR("%d", lenMsg); + p2parse = pMsg->pszRawMsg + pMsg->offAfterPRI; /* point to start of text, after PRI */ /* Check to see if msg contains a timestamp. We start by assuming @@ -2724,6 +2725,7 @@ static rsRetVal loadBuildInModules(void) CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactertab", 0, eCmdHdlrBinary, NULL, &bEscapeTab, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_TEMPLATE, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL)); -- cgit From 26893eb8edfa38fb06c61379919a817dadf01615 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 27 Nov 2009 10:39:46 +0100 Subject: added at least minimal doc for $EscapeControlCharacterTab --- doc/rsyslog_conf_global.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html index 5f80f92e..76dce26d 100644 --- a/doc/rsyslog_conf_global.html +++ b/doc/rsyslog_conf_global.html @@ -130,6 +130,7 @@ our paper on using multiple rule sets in rsyslog$DropTrailingLFOnReception

  • $DynaFileCacheSize
  • $EscapeControlCharactersOnReceive
  • +
  • $EscapeControlCharactersOnReceive [on|off] - escape USASCII HT character
  • $ErrorMessagesToStderr [on|off] - direct rsyslogd error message to stderr (in addition to other targets)
  • $FailOnChownFailure
  • $FileCreateMode
  • -- cgit From 2a494ffc41cd33124bbfea01ad41750b8967efed Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 2 Mar 2010 10:18:33 +0100 Subject: added include needed for Solaris --- tools/ompipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ompipe.c b/tools/ompipe.c index 5fb9b27e..7cf61822 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "syslogd.h" -- cgit From 396e211e5cfd195b7135947d425b089a0447fa88 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 5 Mar 2010 08:27:26 +0100 Subject: enabled compilation by using "racy" replacements for atomic instructions ... but this is not considered a real solution. For some of the uses, it may acutally be sufficient, but the implications need to be analyzed in detail. --- runtime/atomic.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/atomic.h b/runtime/atomic.h index d5aaf56b..62ceb8b3 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -66,6 +66,9 @@ # define ATOMIC_DEC_AND_FETCH(data) (--(data)) # define ATOMIC_FETCH_32BIT(data) (data) # define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1 +# define ATOMIC_STORE_1_TO_INT(data) (data) = 1 +# define ATOMIC_STORE_0_TO_INT(data) (data) = 0 +# define ATOMIC_CAS_VAL(data, oldVal, newVal) (data) = (newVal) #endif #endif /* #ifndef INCLUDED_ATOMIC_H */ -- cgit From e0afe5c8258d4b70ade84f1176c44ae6d593f2df Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 23 Mar 2010 08:03:21 +0100 Subject: added some diagnostics info to startup --- tests/diag.sh | 4 ++-- tools/syslogd.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/diag.sh b/tests/diag.sh index 27b60582..08e94548 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -37,8 +37,8 @@ case $1 in ;; 'wait-startup') # wait for rsyslogd startup ($2 is the instance) while test ! -f rsyslogd$2.started; do - #true - sleep 0.1 # if this is not supported by all platforms, use above! + true + #sleep 0.1 # if this is not supported by all platforms, use above! done echo "rsyslogd$2 started with pid " `cat rsyslog$2.pid` ;; diff --git a/tools/syslogd.c b/tools/syslogd.c index 64b23566..a61d1e5d 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -3174,6 +3174,7 @@ int realMain(int argc, char **argv) uchar *LocalHostName; uchar *LocalDomain; uchar *LocalFQDNName; + char cwdbuf[128]; /* buffer to obtain/display current working directory */ /* first, parse the command line options. We do not carry out any actual work, just * see what we should do. This relieves us from certain anomalies and we can process @@ -3260,8 +3261,9 @@ int realMain(int argc, char **argv) if ((argc -= optind)) usage(); - DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s'\n", - VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath); + DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s', cwd:%s\n", + VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath, + getcwd(cwdbuf, sizeof(cwdbuf))); /* we are done with the initial option parsing and processing. Now we init the system. */ -- cgit From 072fc663a83b2050d961d1c7ec7aa16f12842c9a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 23 Mar 2010 15:04:24 +0100 Subject: added replacements for atomic instructions on systems that do not support them. [backport of Stefen Sledz' patch for v5] --- ChangeLog | 2 + configure.ac | 4 ++ runtime/Makefile.am | 1 + runtime/atomic.h | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++ runtime/rsyslog.c | 14 +++++++ 5 files changed, 138 insertions(+) diff --git a/ChangeLog b/ChangeLog index dc12e856..b8deeb74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ Version 4.6.2 [v4-stable] (rgerhards), 2010-03-?? - new feature: "." action type added to support writing files to relative pathes (this is primarily meant as a debug aid) +- added replacements for atomic instructions on systems that do not + support them. [backport of Stefen Sledz' patch for v5) - added new property replacer option "date-rfc3164-buggyday" primarily to ease migration from syslog-ng. See property replacer doc for details. [backport from 5.5.3 because urgently needed by some] diff --git a/configure.ac b/configure.ac index b059fe75..fcd70c30 100644 --- a/configure.ac +++ b/configure.ac @@ -84,6 +84,7 @@ AC_TYPE_UINT8_T AC_HEADER_TIME AC_STRUCT_TM AC_C_VOLATILE +AC_C_TYPEOF sa_includes="\ $ac_includes_default @@ -126,6 +127,9 @@ AC_TRY_COMPILE([ # check for availability of atomic operations RS_ATOMIC_OPERATIONS +# fall back to POSIX sems for atomic operations (cpu expensive) +AC_CHECK_HEADERS([semaphore.h]) + # Additional module directories AC_ARG_WITH(moddirs, diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 14abe722..e5b3ccdf 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -9,6 +9,7 @@ librsyslog_la_SOURCES = \ rsyslog.h \ unicode-helper.h \ atomic.h \ + atomic-posix-sem.c \ syslogd-types.h \ module-template.h \ obj-types.h \ diff --git a/runtime/atomic.h b/runtime/atomic.h index 62ceb8b3..ea3be37a 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -53,6 +53,122 @@ # define ATOMIC_CAS(data, oldVal, newVal) __sync_bool_compare_and_swap(&(data), (oldVal), (newVal)); # define ATOMIC_CAS_VAL(data, oldVal, newVal) __sync_val_compare_and_swap(&(data), (oldVal), (newVal)); #else +#ifdef HAVE_SEMAPHORE_H + /* we use POSIX semaphores instead */ + +#include "rsyslog.h" +#include + +extern sem_t atomicSem; +rsRetVal atomicSemInit(void); +void atomicSemExit(void); + +#if HAVE_TYPEOF +#define my_typeof(x) typeof(x) +#else /* sorry, can't determine types, using 'int' */ +#define my_typeof(x) int +#endif + +# define ATOMIC_SUB(data, val) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data -= val; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_ADD(data, val) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data += val; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_INC_AND_FETCH(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data += 1; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_INC(data) ((void) ATOMIC_INC_AND_FETCH(data)) + +# define ATOMIC_DEC_AND_FETCH(data) \ +({ \ + sem_wait(&atomicSem); \ + data -= 1; \ + sem_post(&atomicSem); \ + data; \ +}) + +# define ATOMIC_DEC(data) ((void) ATOMIC_DEC_AND_FETCH(data)) + +# define ATOMIC_FETCH_32BIT(data) ((unsigned) ATOMIC_ADD((data), 0xffffffff)) + +# define ATOMIC_STORE_1_TO_32BIT(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data = 1; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_STORE_0_TO_INT(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data = 0; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_STORE_1_TO_INT(data) \ +({ \ + my_typeof(data) tmp; \ + sem_wait(&atomicSem); \ + tmp = data; \ + data = 1; \ + sem_post(&atomicSem); \ + tmp; \ +}) + +# define ATOMIC_CAS(data, oldVal, newVal) \ +({ \ + int ret; \ + sem_wait(&atomicSem); \ + if(data != oldVal) ret = 0; \ + else \ + { \ + data = newVal; \ + ret = 1; \ + } \ + sem_post(&atomicSem); \ + ret; \ +}) + +# define ATOMIC_CAS_VAL(data, oldVal, newVal) \ +({ \ + sem_wait(&atomicSem); \ + if(data == oldVal) \ + { \ + data = newVal; \ + } \ + sem_post(&atomicSem); \ + data; \ +}) + +#else /* not HAVE_SEMAPHORE_H */ /* note that we gained parctical proof that theoretical problems DO occur * if we do not properly address them. See this blog post for details: * http://blog.gerhards.net/2009/01/rsyslog-data-race-analysis.html @@ -70,5 +186,6 @@ # define ATOMIC_STORE_0_TO_INT(data) (data) = 0 # define ATOMIC_CAS_VAL(data, oldVal, newVal) (data) = (newVal) #endif +#endif #endif /* #ifndef INCLUDED_ATOMIC_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 443d0f41..5750ca76 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -80,6 +80,7 @@ #include "prop.h" #include "rule.h" #include "ruleset.h" +#include "atomic.h" /* forward definitions */ static rsRetVal dfltErrLogger(int, uchar *errMsg); @@ -139,6 +140,12 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(objClassInit(NULL)); /* *THIS* *MUST* always be the first class initilizer being called! */ CHKiRet(objGetObjInterface(pObjIF)); /* this provides the root pointer for all other queries */ +#ifndef HAVE_ATOMIC_BUILTINS +#ifdef HAVE_SEMAPHORE_H + CHKiRet(atomicSemInit()); +#endif /* HAVE_SEMAPHORE_H */ +#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ + /* initialize core classes. We must be very careful with the order of events. Some * classes use others and if we do not initialize them in the right order, we may end * up with an invalid call. The most important thing that can happen is that an error @@ -215,6 +222,13 @@ rsrtExit(void) glblClassExit(); rulesetClassExit(); ruleClassExit(); + +#ifndef HAVE_ATOMIC_BUILTINS +#ifdef HAVE_SEMAPHORE_H + atomicSemExit(); +#endif /* HAVE_SEMAPHORE_H */ +#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ + objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */ } -- cgit From 2f8b5cafd0dcc5f09b7b64f5015a2aebd1c7b31c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 23 Mar 2010 15:05:34 +0100 Subject: forgot to add file with last commit --- runtime/atomic-posix-sem.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 runtime/atomic-posix-sem.c diff --git a/runtime/atomic-posix-sem.c b/runtime/atomic-posix-sem.c new file mode 100644 index 00000000..979fae02 --- /dev/null +++ b/runtime/atomic-posix-sem.c @@ -0,0 +1,70 @@ +/* atomic_posix_sem.c: This file supplies an emulation for atomic operations using + * POSIX semaphores. + * + * Copyright 2010 DResearch Digital Media Systems GmbH + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The rsyslog runtime library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ + +#include "config.h" +#ifndef HAVE_ATOMIC_BUILTINS +#ifdef HAVE_SEMAPHORE_H +#include +#include + +#include "atomic.h" +#include "rsyslog.h" +#include "srUtils.h" + +sem_t atomicSem; + +rsRetVal +atomicSemInit(void) +{ + DEFiRet; + + dbgprintf("init posix semaphore for atomics emulation\n"); + if(sem_init(&atomicSem, 0, 1) == -1) + { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("init posix semaphore for atomics emulation failed: %s\n", errStr); + iRet = RS_RET_SYS_ERR; /* the right error code ??? */ + } + + RETiRet; +} + +void +atomicSemExit(void) +{ + dbgprintf("destroy posix semaphore for atomics emulation\n"); + if(sem_destroy(&atomicSem) == -1) + { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("destroy posix semaphore for atomics emulation failed: %s\n", errStr); + } +} + +#endif /* HAVE_SEMAPHORE_H */ +#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ + +/* vim:set ai: + */ -- cgit From 5deea302b0c594b267e0450bdbb82954d2459a61 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 09:35:49 +0100 Subject: replaced sleep in test suite by a small self-crafted tool subsecond sleep did not work on all platforms --- tests/Makefile.am | 3 ++- tests/diag.sh | 6 ++---- tests/msleep.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 tests/msleep.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 9e04ea1e..2a4213f8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ if ENABLE_TESTBENCH TESTRUNS = rt_init rscript -check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq +check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep TESTS = $(TESTRUNS) cfg.sh \ validation-run.sh \ imtcp-multiport.sh \ @@ -193,6 +193,7 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ cfg.sh ourtail_SOURCES = ourtail.c +msleep_SOURCES = msleep.c chkseq_SOURCES = chkseq.c tcpflood_SOURCES = tcpflood.c diff --git a/tests/diag.sh b/tests/diag.sh index 08e94548..173219da 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -37,16 +37,14 @@ case $1 in ;; 'wait-startup') # wait for rsyslogd startup ($2 is the instance) while test ! -f rsyslogd$2.started; do - true - #sleep 0.1 # if this is not supported by all platforms, use above! + ./msleep 100 # wait 100 milliseconds done echo "rsyslogd$2 started with pid " `cat rsyslog$2.pid` ;; 'wait-shutdown') # actually, we wait for rsyslog.pid to be deleted. $2 is the # instance while test -f rsyslog$2.pid; do - #true - sleep 0.1 # if this is not supported by all platforms, use above! + ./msleep 100 # wait 100 milliseconds done ;; 'wait-queueempty') # wait for main message queue to be empty. $2 is the instance. diff --git a/tests/msleep.c b/tests/msleep.c new file mode 100644 index 00000000..6fa57b79 --- /dev/null +++ b/tests/msleep.c @@ -0,0 +1,50 @@ +/* sleeps for the specified number of MILLIseconds. + * Primarily meant as a portable tool available everywhere for the + * testbench (sleep 0.1 does not work on all platforms). + * + * Part of the testbench for rsyslog. + * + * Copyright 2010 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include + +int main(int argc, char *argv[]) +{ + struct timeval tvSelectTimeout; + long sleepTime; + + if(argc != 2) { + fprintf(stderr, "usage: msleep \n"); + exit(1); + } + + sleepTime = atoi(argv[1]); + tvSelectTimeout.tv_sec = sleepTime / 1000; + tvSelectTimeout.tv_usec = (sleepTime % 1000) * 1000; /* micro seconds */ + if(select(0, NULL, NULL, NULL, &tvSelectTimeout) == -1) { + perror("select"); + exit(1); + } + + return 0; +} + -- cgit From bdb632e6d2ed6fe86f2f6d3163932e33fc2959a9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 10:12:36 +0100 Subject: added some instructions for building rsyslog on Solaris --- solaris/README | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 solaris/README diff --git a/solaris/README b/solaris/README new file mode 100644 index 00000000..0700642e --- /dev/null +++ b/solaris/README @@ -0,0 +1,34 @@ +Notes for Solaris + +Rsyslog will be fully supported on Solaris in the future. To build it, the GNU build +tools (and most of the GNU environment) is needed. This software can be +found at the excellent http://www.blastwave.org site. + +PREQUISITES +It is strongly recommended to use GCC4 with support for +atomic instructions (if available for the platform). While rsyslog can +be built without atomic instructin support (and will work well then), +it then falls back to POSIX semaphores, which require much more CPU +time than atomic instructions. Note that even on intel platforms the +(current, as of 2010-03-25) blastwave gcc4 version targets too-old +processors by default. To change that, use "-imarch=I686" in your +CFLAGS. + +CONFIGURE OPTIONS +A number of GNU tools are renamed g* so that they not conflict with +the native Solaris tools. As we need the GNU replacements, this +must be specified on the ./configure line. +Also, we must tell the linker where to find the glibc library when +building the plugins. This is done via the LDFLAGS variable as +shown below (based on the good information availabe at +http://prefetch.net/articles/linkers.badldlibrary.html + +The working sample configure sequence I use is: + +export LDFLAGS="-R/usr/local/lib" +./configure AR=gar ...other options... + + +NOT YET SUPPORTED +* local log socket +* kernel log -- cgit From 7e1060295a63242bc22394b6873de6e6db2b4765 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 11:21:10 +0100 Subject: manytcp test tool must tell OS to provide enough file handles On some platforms, the default is too low to carry out all test cases --- tests/tcpflood.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 32bf959d..259b84b3 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -370,6 +370,20 @@ int main(int argc, char *argv[]) } } + if(numConnections > 20) { + /* if we use many (whatever this means, 20 is randomly picked) + * connections, we need to make sure we have a high enough + * limit. -- rgerhards, 2010-03-25 + */ + struct rlimit maxFiles; + maxFiles.rlim_cur = numConnections + 20; + maxFiles.rlim_max = numConnections + 20; + if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) { + perror("setrlimit to increase file handles failed"); + exit(1); + } + } + if(openConnections() != 0) { printf("error opening connections\n"); exit(1); -- cgit From ec883905c13920de0bc33e5bdd0a75c80535b55c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 14:58:23 +0100 Subject: testbench improved to run on Solaris --- tests/complex1.sh | 5 +++-- tests/diag.sh | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/complex1.sh b/tests/complex1.sh index b5dc2c9d..7395bf21 100755 --- a/tests/complex1.sh +++ b/tests/complex1.sh @@ -10,12 +10,13 @@ source $srcdir/diag.sh init export RSYSLOG_DEBUG="debug nostdout" export RSYSLOG_DEBUGLOG="log" source $srcdir/diag.sh startup complex1.conf -# send 30,000 messages of 400 bytes plus header max, via three dest ports +# send 40,000 messages of 400 bytes plus header max, via three dest ports source $srcdir/diag.sh tcpflood -m40000 -rd400 -P129 -f5 -n3 -c15 -i1 sleep 2 # due to large messages, we need this time for the tcp receiver to settle... source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages source $srcdir/diag.sh wait-shutdown # and wait for it to terminate ls rsyslog.out.*.log -zcat rsyslog.out.*.log > rsyslog.out.log +source $srcdir/diag.sh setzcat # find out which zcat to use +$ZCAT rsyslog.out.*.log > rsyslog.out.log source $srcdir/diag.sh seq-check 1 40000 -E source $srcdir/diag.sh exit diff --git a/tests/diag.sh b/tests/diag.sh index 173219da..383cd818 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -128,5 +128,12 @@ case $1 in exit 1 fi ;; + 'setzcat') # find out name of zcat tool + if [ `uname` == SunOS ]; then + ZCAT=gzcat + else + ZCAT=zcat + fi + ;; *) echo "invalid argument" $1 esac -- cgit From b628ec633ebd8bdf2e1ddb168b7b63ea2c1bb87c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 17:21:36 +0100 Subject: added missing header --- tests/tcpflood.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 259b84b3..68c1c097 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -54,6 +54,7 @@ #include #include #include +#include #define EXIT_FAILURE 1 #define INVALID_SOCKET -1 -- cgit From 92369b253c302c7be30156b69b62f5ad90369cf0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 18:22:14 +0100 Subject: added some starting point for a solaris imklog driver ... far from being functional at this time! --- configure.ac | 1 + plugins/imklog/Makefile.am | 4 + plugins/imklog/solaris_cddl.c | 292 ++++++++++++++++++++++++++++++++++++++++++ solaris/cddllicense.txt | 242 ++++++++++++++++++++++++++++++++++ 4 files changed, 539 insertions(+) create mode 100644 plugins/imklog/solaris_cddl.c create mode 100644 solaris/cddllicense.txt diff --git a/configure.ac b/configure.ac index fcd70c30..c24468be 100644 --- a/configure.ac +++ b/configure.ac @@ -278,6 +278,7 @@ AC_ARG_ENABLE(klog, AM_CONDITIONAL(ENABLE_IMKLOG, test x$enable_klog = xyes) AM_CONDITIONAL(ENABLE_IMKLOG_BSD, test x$os_type = xbsd) AM_CONDITIONAL(ENABLE_IMKLOG_LINUX, test x$os_type = xlinux) +AM_CONDITIONAL(ENABLE_IMKLOG_SOLARIS, test x$os_type = xsolaris) # diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am index 5d4d0465..85305ce3 100644 --- a/plugins/imklog/Makefile.am +++ b/plugins/imklog/Makefile.am @@ -11,6 +11,10 @@ if ENABLE_IMKLOG_LINUX imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c endif +if ENABLE_IMKLOG_SOLARIS +imklog_la_SOURCES += solaris_cddl.c +endif + imklog_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) imklog_la_LDFLAGS = -module -avoid-version imklog_la_LIBADD = diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c new file mode 100644 index 00000000..df783c46 --- /dev/null +++ b/plugins/imklog/solaris_cddl.c @@ -0,0 +1,292 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Portions Copyright 2010 by Rainer Gerhards and Adiscon + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T + * All Rights Reserved + */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#include "config.h" + + + +/* + * Attempts to open the local log device + * and return a file descriptor. + */ +int +sun_oopenklog(char *name, int mode) +{ + int fd; + struct strioctl str; + pthread_t mythreadno; + + if (Debug) { + mythreadno = pthread_self(); + } + + if ((fd = open(name, mode)) < 0) { + logerror("cannot open %s", name); + DPRINT3(1, "openklog(%u): cannot create %s (%d)\n", + mythreadno, name, errno); + return (-1); + } + str.ic_cmd = I_CONSLOG; + str.ic_timout = 0; + str.ic_len = 0; + str.ic_dp = NULL; + if (ioctl(fd, I_STR, &str) < 0) { + logerror("cannot register to log console messages"); + DPRINT2(1, "openklog(%u): cannot register to log " + "console messages (%d)\n", mythreadno, errno); + return (-1); + } + return (fd); +} + + +/* + * Open the log device, and pull up all pending messages. + */ +void +sun_prepare_sys_poll() +{ + int nfds, funix; + + if ((funix = openklog(LogName, O_RDONLY)) < 0) { + logerror("can't open kernel log device - fatal"); + exit(1); + } + + Pfd.fd = funix; + Pfd.events = POLLIN; + + for (;;) { + nfds = poll(&Pfd, 1, 0); + if (nfds <= 0) { + if (sys_init_msg_count > 0) + flushmsg(SYNC_FILE); + break; + } + + if (Pfd.revents & POLLIN) { + getkmsg(0); + } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + logerror("kernel log driver poll error"); + break; + } + } + +} + +/* + * this thread listens to the local stream log driver for log messages + * generated by this host, formats them, and queues them to the logger + * thread. + */ +/*ARGSUSED*/ +void * +sun_sys_poll(void *ap) +{ + int nfds; + static int klogerrs = 0; + pthread_t mythreadno; + + if (Debug) { + mythreadno = pthread_self(); + } + + DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno); + + /* + * Try to process as many messages as we can without blocking on poll. + * We count such "initial" messages with sys_init_msg_count and + * enqueue them without the SYNC_FILE flag. When no more data is + * waiting on the local log device, we set timeout to INFTIM, + * clear sys_init_msg_count, and generate a flush message to sync + * the previously counted initial messages out to disk. + */ + + sys_init_msg_count = 0; + + for (;;) { + errno = 0; + t_errno = 0; + + nfds = poll(&Pfd, 1, INFTIM); + + if (nfds == 0) + continue; + + if (nfds < 0) { + if (errno != EINTR) + logerror("poll"); + continue; + } + if (Pfd.revents & POLLIN) { + getkmsg(INFTIM); + } else { + if (shutting_down) { + pthread_exit(0); + } + if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + logerror("kernel log driver poll error"); + (void) close(Pfd.fd); + Pfd.fd = -1; + } + } + + while (Pfd.fd == -1 && klogerrs++ < 10) { + Pfd.fd = openklog(LogName, O_RDONLY); + } + if (klogerrs >= 10) { + logerror("can't reopen kernel log device - fatal"); + exit(1); + } + } + /*NOTREACHED*/ + return (NULL); +} + +/* + * Pull up one message from log driver. + */ +void +sun_getkmsg(int timeout) +{ + int flags = 0, i; + char *lastline; + struct strbuf ctl, dat; + struct log_ctl hdr; + char buf[MAXLINE+1]; + size_t buflen; + size_t len; + char tmpbuf[MAXLINE+1]; + pthread_t mythreadno; + + if (Debug) { + mythreadno = pthread_self(); + } + + dat.maxlen = MAXLINE; + dat.buf = buf; + ctl.maxlen = sizeof (struct log_ctl); + ctl.buf = (caddr_t)&hdr; + + while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) { + lastline = &dat.buf[dat.len]; + *lastline = '\0'; + + DPRINT2(5, "sys_poll:(%u): getmsg: dat.len = %d\n", + mythreadno, dat.len); + buflen = strlen(buf); + len = findnl_bkwd(buf, buflen); + + (void) memcpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + + /* + * Format sys will enqueue the log message. + * Set the sync flag if timeout != 0, which + * means that we're done handling all the + * initial messages ready during startup. + */ + if (timeout == 0) { + formatsys(&hdr, tmpbuf, 0); + sys_init_msg_count++; + } else { + formatsys(&hdr, tmpbuf, 1); + } + sys_msg_count++; + + if (len != buflen) { + /* If anything remains in buf */ + size_t remlen; + + if (buf[len] == '\n') { + /* skip newline */ + len++; + } + + /* + * Move the remaining bytes to + * the beginnning of buf. + */ + + remlen = buflen - len; + (void) memcpy(buf, &buf[len], remlen); + dat.maxlen = MAXLINE - remlen; + dat.buf = &buf[remlen]; + } else { + dat.maxlen = MAXLINE; + dat.buf = buf; + } + } + + if (i == 0 && dat.len > 0) { + dat.buf[dat.len] = '\0'; + /* + * Format sys will enqueue the log message. + * Set the sync flag if timeout != 0, which + * means that we're done handling all the + * initial messages ready during startup. + */ + DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n", + mythreadno, dat.maxlen); + DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n", + mythreadno, dat.len); + DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n", + mythreadno, strlen(dat.buf)); + DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n", + mythreadno, dat.buf); + DPRINT2(5, "getkmsg(%u): buf len = %d\n", + mythreadno, strlen(buf)); + if (timeout == 0) { + formatsys(&hdr, buf, 0); + sys_init_msg_count++; + } else { + formatsys(&hdr, buf, 1); + } + sys_msg_count++; + } else if (i < 0 && errno != EINTR) { + if (!shutting_down) { + logerror("kernel log driver read error"); + } + (void) close(Pfd.fd); + Pfd.fd = -1; + } +} diff --git a/solaris/cddllicense.txt b/solaris/cddllicense.txt new file mode 100644 index 00000000..a10bba27 --- /dev/null +++ b/solaris/cddllicense.txt @@ -0,0 +1,242 @@ + COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) + Version 1.0 + + +1. Definitions. + + 1.1. “Contributor” means each individual or entity that creates or contributes to the creation of Modifications. + + 1.2. “Contributor Version” means the combination of the Original Software, prior Modifications used by a Contributor + (if any), and the Modifications made by that particular Contributor. + + 1.3. “Covered Software” means (a) the Original Software, or (b) Modifications, or (c) the combination + of files containing Original Software with files containing Modifications, in each case including portions thereof. + + 1.4. “Executable” means the Covered Software in any form other than Source Code. + + 1.5. “Initial Developer” means the individual or entity that first makes Original Software available under this License. + + 1.6. “Larger Work” means a work which combines Covered Software or portions thereof with code not governed by the terms + of this License. + + 1.7. “License” means this document. + + 1.8. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the + initial grant or subsequently acquired, any and all of the rights conveyed herein. + + 1.9. “Modifications” means the Source Code and Executable form of any of the following: + A. Any file that results from an addition to, deletion from or modification of the contents of a file + containing Original Software or previous Modifications; + B. Any new file that contains any part of the Original Software or previous Modification; or + C. Any new file that is contributed or otherwise made available under the terms of this License. + + 1.10. “Original Software” means the Source Code and Executable form of computer software code that is originally + released under this License. + + 1.11. “Patent Claims” means any patent claim(s), now owned or hereafter acquired, including without limitation, + method, process, and apparatus claims, in any patent Licensable by grantor. + + 1.12. “Source Code” means (a) the common form of computer software code in which modifications are made and + (b) associated documentation included in or with such code. + + 1.13. “You” (or “Your”) means an individual or a legal entity exercising rights under, and complying with all of + the terms of, this License. For legal entities, “You” includes any entity which controls, is controlled by, or is + under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more + than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. License Grants. + + 2.1. The Initial Developer Grant. + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, + the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, + to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions + thereof), with or without Modifications, and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, + use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). + + (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first + distributes or otherwise makes the Original Software available to a third party under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from + the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, + or (ii) the combination of the Original Software with other software or devices. + + 2.2. Contributor Grant. + Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, + each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: + + (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, + reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor + (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or + as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor + either alone and/or in combination with its Contributor Version (or portions of such combination), to make, + use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor + (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes + or otherwise makes the Modifications available to a third party. + + (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has + deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of + Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software + (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered + Software in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Availability of Source Code. + Any Covered Software that You distribute or otherwise make available in Executable form must also be made available + in Source Code form and that Source Code form must be distributed only under the terms of this License. You must + include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or + otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they + can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used + for software exchange. + + 3.2. Modifications. + The Modifications that You create or to which You contribute are governed by the terms of this License. You + represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to + grant the rights conveyed by this License. + + 3.3. Required Notices. + You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. + You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or + any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. + + 3.4. Application of Additional Terms. + You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the + applicable version of this License or the recipients’ rights hereunder. You may choose to offer, and to charge a + fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. + However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. + You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered + by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability + incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability + terms You offer. + + 3.5. Distribution of Executable Versions. + You may distribute the Executable form of the Covered Software under the terms of this License or under the terms + of a license of Your choice, which may contain terms different from this License, provided that You are in compliance + with the terms of this License and that the license for the Executable form does not attempt to limit or alter + the recipient’s rights in the Source Code form from the rights set forth in this License. If You distribute the + Covered Software in Executable form under a different license, You must make it absolutely clear that any terms + which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby + agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer + or such Contributor as a result of any such terms You offer. + + 3.6. Larger Works. + You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License + and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this + License are fulfilled for the Covered Software. + +4. Versions of the License. + + 4.1. New Versions. + Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License + from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, + no one other than the license steward has the right to modify this License. + + 4.2. Effect of New Versions. + You may always continue to use, distribute or otherwise make the Covered Software available under the terms of + the version of the License under which You originally received the Covered Software. If the Initial Developer + includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under + any subsequent version of the License, You must distribute and make the Covered Software available under the terms + of the version of the License under which You originally received the Covered Software. Otherwise, You may also + choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version + of the License published by the license steward. + + 4.3. Modified Versions. + When You are an Initial Developer and You want to create a new license for Your Original Software, You may create + and use a modified version of this License if You: (a) rename the license and remove any references to the name of + the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that + the license contains terms which differ from this License. + +5. DISCLAIMER OF WARRANTY. + +COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR +IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A +PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. +SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE +COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. +NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +6. TERMINATION. + + 6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms + herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their + nature, must remain in effect beyond the termination of this License shall survive. + + 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as + “Participant”) alleging that the Participant Software (meaning the Contributor Version where the Participant + is a Contributor or the Original Software where the Participant is the Initial Developer) directly or + indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, + the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 + and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically + at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with + respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement + with Participant. + + 6.3. If You assert a patent infringement claim against Participant alleging that the Participant Software directly + or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the + initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant + under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. + + 6.4. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted + by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) + shall survive termination. + +7. LIMITATION OF LIABILITY. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE +INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO +ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR +LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY +SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL +INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE +EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +8. U.S. GOVERNMENT END USERS. + +The Covered Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of +“commercial computer software” (as that term is defined at 48 C.F.R. § 252.227-7014(a)(1)) and “commercial computer software documentation” +as such terms are used in 48 C.F.R. 12.212 Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), +all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, +and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. + +9. MISCELLANEOUS. + +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed +by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, +provides otherwise), excluding such jurisdiction’s conflict-of-law provisions. Any litigation relating to this License shall be subject +to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the +losing party responsible for costs, including, without limitation, court costs and reasonable attorneys’ fees and expenses. The application of +the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that +the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for +compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, +distribute or otherwise make available any Covered Software. + +10. RESPONSIBILITY FOR CLAIMS. + +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of +its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on +an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. + +-------- + +NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION +LICENSE (CDDL) + +The OpenSolaris code released under the CDDL shall be governed by the laws +of the State of California (excluding conflict-of-law provisions). Any +litigation relating to this License shall be subject to the jurisdiction of +the Federal Courts of the Northern District of California and the state +courts of the State of California, with venue lying in Santa Clara County, +California. + -- cgit From da65d88017e1824fe60574fef1ef83f1932ab0a6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 18:36:27 +0100 Subject: added forgotten file --- plugins/imklog/solaris.c | 545 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 plugins/imklog/solaris.c diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c new file mode 100644 index 00000000..97aead22 --- /dev/null +++ b/plugins/imklog/solaris.c @@ -0,0 +1,545 @@ +/* klog driver for solaris + * + * This contains OS-specific functionality to read the + * kernel log. For a general overview, see head comment in + * imklog.c. + * + * This file relies on Sun code in solaris_cddl.c. We have split + * it from Sun's code to keep the copyright issue as simple as possible. + * + * 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. + * + * If that may be required, an exception is granted to permit linking + * this code to the code in solaris_cddl.c that is under the cddl license. + * + * 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include "cfsysline.h" +#include "template.h" +#include "msg.h" +#include "module-template.h" +#include "imklog.h" +#include "unicode-helper.h" + + +/* Includes. */ +#include +#include +#include +#include + +#if HAVE_TIME_H +# include +#endif + +#include +#include +#include "ksyms.h" + +#define __LIBRARY__ +#include + + +#if !defined(__GLIBC__) +# define __NR_ksyslog __NR_syslog +_syscall3(int,ksyslog,int, type, char *, buf, int, len); +#else +#include +#define ksyslog klogctl +#endif + + + +#ifndef _PATH_KLOG +#define _PATH_KLOG "/proc/kmsg" +#endif + +#define LOG_BUFFER_SIZE 4096 +#define LOG_LINE_LENGTH 1000 + +static int kmsg; +static char log_buffer[LOG_BUFFER_SIZE]; + +static enum LOGSRC {none, proc, kernel} logsrc; + + +/* Function prototypes. */ +extern int ksyslog(int type, char *buf, int len); + + +static uchar *GetPath(void) +{ + return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); +} + +static void CloseLogSrc(void) +{ + /* Turn on logging of messages to console, but only if a log level was speficied */ + if(console_log_level != -1) + ksyslog(7, NULL, 0); + + /* Shutdown the log sources. */ + switch(logsrc) { + case kernel: + ksyslog(0, NULL, 0); + imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped."); + break; + case proc: + close(kmsg); + imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped."); + break; + case none: + break; + } + + return; +} + + +static enum LOGSRC GetKernelLogSrc(void) +{ + auto struct stat sb; + + /* Set level of kernel console messaging.. */ + if ( (console_log_level != -1) && + (ksyslog(8, NULL, console_log_level) < 0) && + (errno == EINVAL) ) + { + /* + * An invalid arguement error probably indicates that + * a pre-0.14 kernel is being run. At this point we + * issue an error message and simply shut-off console + * logging completely. + */ + imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling " + "console output."); + } + + /* + * First do a stat to determine whether or not the proc based + * file system is available to get kernel messages from. + */ + if ( use_syscall || + ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) ) + { + /* Initialize kernel logging. */ + ksyslog(1, NULL, 0); + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = ksyslog " + "started.", VERSION); + return(kernel); + } + + if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 ) + { + imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno); + ksyslog(7, NULL, 0); + return(none); + } + + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath()); + return(proc); +} + + +/* Copy characters from ptr to line until a char in the delim + * string is encountered or until min( space, len ) chars have + * been copied. + * + * Returns the actual number of chars copied. + */ +static int copyin( uchar *line, int space, + const char *ptr, int len, + const char *delim ) +{ + auto int i; + auto int count; + + count = len < space ? len : space; + + for(i=0; i]", + * where "aaaaaa" is the address. These are replaced with + * "[symbolname+offset/size]" in the output line - symbolname, + * offset, and size come from the kernel symbol table. + * + * If a kernel symbol happens to fall at the end of a message close + * in length to LOG_LINE_LENGTH, the symbol will not be expanded. + * (This should never happen, since the kernel should never generate + * messages that long. + * + * To preserve the original addresses, lines containing kernel symbols + * are output twice. Once with the symbols converted and again with the + * original text. Just in case somebody wants to run their own Oops + * analysis on the syslog, e.g. ksymoops. + */ +static void LogLine(char *ptr, int len) +{ + enum parse_state_enum { + PARSING_TEXT, + PARSING_SYMSTART, /* at < */ + PARSING_SYMBOL, + PARSING_SYMEND /* at ] */ + }; + + static uchar line_buff[LOG_LINE_LENGTH]; + + static uchar *line =line_buff; + static enum parse_state_enum parse_state = PARSING_TEXT; + static int space = sizeof(line_buff)-1; + + static uchar *sym_start; /* points at the '<' of a symbol */ + + auto int delta = 0; /* number of chars copied */ + auto int symbols_expanded = 0; /* 1 if symbols were expanded */ + auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */ + auto char *save_ptr = ptr; /* save start of input line */ + auto int save_len = len; /* save length at start of input line */ + + while( len > 0 ) + { + if( space == 0 ) /* line buffer is full */ + { + /* + ** Line too long. Start a new line. + */ + *line = 0; /* force null terminator */ + + //dbgprintf("Line buffer full:\n"); + //dbgprintf("\tLine: %s\n", line); + + Syslog(LOG_INFO, line_buff); + line = line_buff; + space = sizeof(line_buff)-1; + parse_state = PARSING_TEXT; + symbols_expanded = 0; + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + + switch( parse_state ) + { + case PARSING_TEXT: + delta = copyin(line, space, ptr, len, "\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + + if( *ptr == '\0' ) /* zero byte */ + { + ptr++; /* skip zero byte */ + space -= 1; + len -= 1; + + break; + } + + if( *ptr == '\n' ) /* newline */ + { + ptr++; /* skip newline */ + space -= 1; + len -= 1; + + *line = 0; /* force null terminator */ + Syslog(LOG_INFO, line_buff); + line = line_buff; + space = sizeof(line_buff)-1; + if (symbols_twice) { + if (symbols_expanded) { + /* reprint this line without symbol lookup */ + symbols_expanded = 0; + skip_symbol_lookup = 1; + ptr = save_ptr; + len = save_len; + } + else + { + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + } + break; + } + if( *ptr == '[' ) /* possible kernel symbol */ + { + *line++ = *ptr++; + space -= 1; + len -= 1; + if (!skip_symbol_lookup) + parse_state = PARSING_SYMSTART; /* at < */ + break; + } + /* Now that line_buff is no longer fed to *printf as format + * string, '%'s are no longer "dangerous". + */ + break; + + case PARSING_SYMSTART: + if( *ptr != '<' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** Save this character for now. If this turns out to + ** be a valid symbol, this char will be replaced later. + ** If not, we'll just leave it there. + */ + + sym_start = line; /* this will point at the '<' */ + + *line++ = *ptr++; + space -= 1; + len -= 1; + parse_state = PARSING_SYMBOL; /* symbol... */ + break; + + case PARSING_SYMBOL: + delta = copyin( line, space, ptr, len, ">\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + if( *ptr != '>' ) + { + parse_state = PARSING_TEXT; + break; + } + + *line++ = *ptr++; /* copy the '>' */ + space -= 1; + len -= 1; + + parse_state = PARSING_SYMEND; + + break; + + case PARSING_SYMEND: + if( *ptr != ']' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** It's really a symbol! Replace address with the + ** symbol text. + */ + { + auto int sym_space; + + unsigned long value; + auto struct symbol sym; + auto char *symbol; + + *(line-1) = 0; /* null terminate the address string */ + value = strtoul((char*)(sym_start+1), (char **) 0, 16); + *(line-1) = '>'; /* put back delim */ + + if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) + { + parse_state = PARSING_TEXT; + break; + } + + /* + ** verify there is room in the line buffer + */ + sym_space = space + ( line - sym_start ); + if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ + { + parse_state = PARSING_TEXT; /* not enough space */ + break; + } + + // TODO: sprintf!!!! + delta = sprintf( (char*) sym_start, "%s+%d/%d]", + symbol, sym.offset, sym.size ); + + space = sym_space + delta; + line = sym_start + delta; + symbols_expanded = 1; + } + ptr++; + len--; + parse_state = PARSING_TEXT; + break; + + default: /* Can't get here! */ + parse_state = PARSING_TEXT; + + } + } + + return; +} + + +static void LogKernelLine(void) +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel log + * messages into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 ) + { + if(errno == EINTR) + return; + imklogLogIntMsg(LOG_ERR, "imklog Error return from sys_sycall: %d\n", errno); + } + else + LogLine(log_buffer, rdcnt); + return; +} + + +static void LogProcLine(void) +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel messages + * from the message pseudo-file into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) { + if ( errno == EINTR ) + return; + imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); + } else { + LogLine(log_buffer, rdcnt); + } + + return; +} + + +/* to be called in the module's WillRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogLogKMsg(void) +{ + DEFiRet; + switch(logsrc) { + case kernel: + LogKernelLine(); + break; + case proc: + LogProcLine(); + break; + case none: + /* TODO: We need to handle this case here somewhat more intelligent + * This is now at least partly done - code should never reach this point + * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17 + */ + pause(); + break; + } + RETiRet; +} + + +/* to be called in the module's WillRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogWillRun(void) +{ + DEFiRet; + /* Initialize this module. If that fails, we tell the engine we don't like to run */ + /* Determine where kernel logging information is to come from. */ + logsrc = GetKernelLogSrc(); + if(logsrc == none) { + iRet = RS_RET_NO_KERNEL_LOGSRC; + } else { + if (symbol_lookup) { + symbol_lookup = (InitKsyms(symfile) == 1); + symbol_lookup |= InitMsyms(); + if (symbol_lookup == 0) { + imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups"); + } + } + } + + RETiRet; +} + + +/* to be called in the module's AfterRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogAfterRun(void) +{ + DEFiRet; + /* cleanup here */ + if(logsrc != none) + CloseLogSrc(); + + DeinitKsyms(); + DeinitMsyms(); + + RETiRet; +} + + +/* provide the (system-specific) default facility for internal messages + * rgerhards, 2008-04-14 + */ +int +klogFacilIntMsg(void) +{ + return LOG_KERN; +} + + +/* vi:set ai: + */ -- cgit From ee6ce30b474c033c71f5f5e9edf7941e29ea30b6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 09:14:31 +0100 Subject: interim commit: imklog/solaris compiles, but does not work saving this area of work, because some further clarification is needed. Do not try to run the current imklog, it will fail. --- plugins/imklog/Makefile.am | 2 +- plugins/imklog/solaris.c | 589 ++++++++++-------------------------------- plugins/imklog/solaris_cddl.c | 402 +++++++++++++++++----------- 3 files changed, 389 insertions(+), 604 deletions(-) diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am index 85305ce3..06d4013c 100644 --- a/plugins/imklog/Makefile.am +++ b/plugins/imklog/Makefile.am @@ -12,7 +12,7 @@ imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c endif if ENABLE_IMKLOG_SOLARIS -imklog_la_SOURCES += solaris_cddl.c +imklog_la_SOURCES += solaris.c solaris_cddl.c endif imklog_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index 97aead22..294efa7c 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -27,507 +27,181 @@ * * A copy of the GPL can be found in the file "COPYING" in this distribution. */ -#include "config.h" -#include "rsyslog.h" -#include -#include -#include -#include -#include -#include -#include "cfsysline.h" -#include "template.h" -#include "msg.h" -#include "module-template.h" -#include "imklog.h" -#include "unicode-helper.h" - - -/* Includes. */ -#include -#include -#include -#include -#if HAVE_TIME_H -# include +#ifdef HAVE_CONFIG_H +# include "config.h" #endif - -#include -#include -#include "ksyms.h" - -#define __LIBRARY__ +#include #include +#include +#include +#include +#include -#if !defined(__GLIBC__) -# define __NR_ksyslog __NR_syslog -_syscall3(int,ksyslog,int, type, char *, buf, int, len); -#else -#include -#define ksyslog klogctl -#endif - +#include "rsyslog.h" +#include "imklog.h" +#include "unicode-helper.h" +#include "solaris_cddl.h" +/* globals */ +static int fklog; // TODO: remove #ifndef _PATH_KLOG -#define _PATH_KLOG "/proc/kmsg" +# define _PATH_KLOG "/dev/log" #endif -#define LOG_BUFFER_SIZE 4096 -#define LOG_LINE_LENGTH 1000 - -static int kmsg; -static char log_buffer[LOG_BUFFER_SIZE]; - -static enum LOGSRC {none, proc, kernel} logsrc; - - -/* Function prototypes. */ -extern int ksyslog(int type, char *buf, int len); - - -static uchar *GetPath(void) -{ - return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); -} - -static void CloseLogSrc(void) -{ - /* Turn on logging of messages to console, but only if a log level was speficied */ - if(console_log_level != -1) - ksyslog(7, NULL, 0); - - /* Shutdown the log sources. */ - switch(logsrc) { - case kernel: - ksyslog(0, NULL, 0); - imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped."); - break; - case proc: - close(kmsg); - imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped."); - break; - case none: - break; - } - - return; -} - +// HELPER +/* handle some defines missing on more than one platform */ +#ifndef SUN_LEN +#define SUN_LEN(su) \ + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) +#endif -static enum LOGSRC GetKernelLogSrc(void) +int solaris_create_unix_socket(const char *path) { - auto struct stat sb; - - /* Set level of kernel console messaging.. */ - if ( (console_log_level != -1) && - (ksyslog(8, NULL, console_log_level) < 0) && - (errno == EINVAL) ) - { - /* - * An invalid arguement error probably indicates that - * a pre-0.14 kernel is being run. At this point we - * issue an error message and simply shut-off console - * logging completely. - */ - imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling " - "console output."); - } - - /* - * First do a stat to determine whether or not the proc based - * file system is available to get kernel messages from. - */ - if ( use_syscall || - ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) ) - { - /* Initialize kernel logging. */ - ksyslog(1, NULL, 0); - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = ksyslog " - "started.", VERSION); - return(kernel); - } - - if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 ) - { - imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno); - ksyslog(7, NULL, 0); - return(none); + struct sockaddr_un sunx; + int fd; + +return; + if (path[0] == '\0') + return -1; + + unlink(path); + + memset(&sunx, 0, sizeof(sunx)); + sunx.sun_family = AF_UNIX; + (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || + chmod(path, 0666) < 0) { + //errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path); + dbgprintf("cannot create %s (%d).\n", path, errno); + close(fd); + return -1; } - - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath()); - return(proc); + return fd; } +// END HELPER -/* Copy characters from ptr to line until a char in the delim - * string is encountered or until min( space, len ) chars have - * been copied. - * - * Returns the actual number of chars copied. - */ -static int copyin( uchar *line, int space, - const char *ptr, int len, - const char *delim ) +static uchar *GetPath(void) { - auto int i; - auto int count; - - count = len < space ? len : space; - - for(i=0; i]", - * where "aaaaaa" is the address. These are replaced with - * "[symbolname+offset/size]" in the output line - symbolname, - * offset, and size come from the kernel symbol table. - * - * If a kernel symbol happens to fall at the end of a message close - * in length to LOG_LINE_LENGTH, the symbol will not be expanded. - * (This should never happen, since the kernel should never generate - * messages that long. - * - * To preserve the original addresses, lines containing kernel symbols - * are output twice. Once with the symbols converted and again with the - * original text. Just in case somebody wants to run their own Oops - * analysis on the syslog, e.g. ksymoops. +/* open the kernel log - will be called inside the willRun() imklog + * entry point. -- rgerhards, 2008-04-09 */ -static void LogLine(char *ptr, int len) -{ - enum parse_state_enum { - PARSING_TEXT, - PARSING_SYMSTART, /* at < */ - PARSING_SYMBOL, - PARSING_SYMEND /* at ] */ - }; - - static uchar line_buff[LOG_LINE_LENGTH]; - - static uchar *line =line_buff; - static enum parse_state_enum parse_state = PARSING_TEXT; - static int space = sizeof(line_buff)-1; - - static uchar *sym_start; /* points at the '<' of a symbol */ - - auto int delta = 0; /* number of chars copied */ - auto int symbols_expanded = 0; /* 1 if symbols were expanded */ - auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */ - auto char *save_ptr = ptr; /* save start of input line */ - auto int save_len = len; /* save length at start of input line */ - - while( len > 0 ) - { - if( space == 0 ) /* line buffer is full */ - { - /* - ** Line too long. Start a new line. - */ - *line = 0; /* force null terminator */ - - //dbgprintf("Line buffer full:\n"); - //dbgprintf("\tLine: %s\n", line); - - Syslog(LOG_INFO, line_buff); - line = line_buff; - space = sizeof(line_buff)-1; - parse_state = PARSING_TEXT; - symbols_expanded = 0; - skip_symbol_lookup = 0; - save_ptr = ptr; - save_len = len; - } - - switch( parse_state ) - { - case PARSING_TEXT: - delta = copyin(line, space, ptr, len, "\n[" ); - line += delta; - ptr += delta; - space -= delta; - len -= delta; - - if( space == 0 || len == 0 ) - { - break; /* full line_buff or end of input buffer */ - } - - if( *ptr == '\0' ) /* zero byte */ - { - ptr++; /* skip zero byte */ - space -= 1; - len -= 1; - - break; - } - - if( *ptr == '\n' ) /* newline */ - { - ptr++; /* skip newline */ - space -= 1; - len -= 1; - - *line = 0; /* force null terminator */ - Syslog(LOG_INFO, line_buff); - line = line_buff; - space = sizeof(line_buff)-1; - if (symbols_twice) { - if (symbols_expanded) { - /* reprint this line without symbol lookup */ - symbols_expanded = 0; - skip_symbol_lookup = 1; - ptr = save_ptr; - len = save_len; - } - else - { - skip_symbol_lookup = 0; - save_ptr = ptr; - save_len = len; - } - } - break; - } - if( *ptr == '[' ) /* possible kernel symbol */ - { - *line++ = *ptr++; - space -= 1; - len -= 1; - if (!skip_symbol_lookup) - parse_state = PARSING_SYMSTART; /* at < */ - break; - } - /* Now that line_buff is no longer fed to *printf as format - * string, '%'s are no longer "dangerous". - */ - break; - - case PARSING_SYMSTART: - if( *ptr != '<' ) - { - parse_state = PARSING_TEXT; /* not a symbol */ - break; - } - - /* - ** Save this character for now. If this turns out to - ** be a valid symbol, this char will be replaced later. - ** If not, we'll just leave it there. - */ - - sym_start = line; /* this will point at the '<' */ - - *line++ = *ptr++; - space -= 1; - len -= 1; - parse_state = PARSING_SYMBOL; /* symbol... */ - break; - - case PARSING_SYMBOL: - delta = copyin( line, space, ptr, len, ">\n[" ); - line += delta; - ptr += delta; - space -= delta; - len -= delta; - if( space == 0 || len == 0 ) - { - break; /* full line_buff or end of input buffer */ - } - if( *ptr != '>' ) - { - parse_state = PARSING_TEXT; - break; - } - - *line++ = *ptr++; /* copy the '>' */ - space -= 1; - len -= 1; - - parse_state = PARSING_SYMEND; - - break; - - case PARSING_SYMEND: - if( *ptr != ']' ) - { - parse_state = PARSING_TEXT; /* not a symbol */ - break; - } - - /* - ** It's really a symbol! Replace address with the - ** symbol text. - */ - { - auto int sym_space; - - unsigned long value; - auto struct symbol sym; - auto char *symbol; - - *(line-1) = 0; /* null terminate the address string */ - value = strtoul((char*)(sym_start+1), (char **) 0, 16); - *(line-1) = '>'; /* put back delim */ - - if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) - { - parse_state = PARSING_TEXT; - break; - } - - /* - ** verify there is room in the line buffer - */ - sym_space = space + ( line - sym_start ); - if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ - { - parse_state = PARSING_TEXT; /* not enough space */ - break; - } - - // TODO: sprintf!!!! - delta = sprintf( (char*) sym_start, "%s+%d/%d]", - symbol, sym.offset, sym.size ); - - space = sym_space + delta; - line = sym_start + delta; - symbols_expanded = 1; - } - ptr++; - len--; - parse_state = PARSING_TEXT; - break; - - default: /* Can't get here! */ - parse_state = PARSING_TEXT; - - } - } - - return; -} - - -static void LogKernelLine(void) +rsRetVal +klogWillRun(void) { - auto int rdcnt; - - /* - * Zero-fill the log buffer. This should cure a multitude of - * problems with klogd logging the tail end of the message buffer - * which will contain old messages. Then read the kernel log - * messages into this fresh buffer. - */ - memset(log_buffer, '\0', sizeof(log_buffer)); - if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 ) - { - if(errno == EINTR) - return; - imklogLogIntMsg(LOG_ERR, "imklog Error return from sys_sycall: %d\n", errno); + DEFiRet; + + fklog = sun_openklog((char*) GetPath(), O_RDONLY); + if (fklog < 0) { + char errStr[1024]; + int err = errno; +perror("XXX"); + rs_strerror_r(err, errStr, sizeof(errStr)); + DBGPRINTF("error %d opening log socket %s: %s\n", + GetPath(), errStr); + iRet = RS_RET_ERR; // TODO: better error code } - else - LogLine(log_buffer, rdcnt); - return; + + RETiRet; } -static void LogProcLine(void) +/* Read /dev/klog while data are available, split into lines. + * Contrary to standard BSD syslogd, we do a blocking read. We can + * afford this as imklog is running on its own threads. So if we have + * a single file, it really doesn't matter if we wait inside a 1-file + * select or the read() directly. + */ +static void +readklog(void) { - auto int rdcnt; - - /* - * Zero-fill the log buffer. This should cure a multitude of - * problems with klogd logging the tail end of the message buffer - * which will contain old messages. Then read the kernel messages - * from the message pseudo-file into this fresh buffer. + char *p, *q; + int len, i; + int iMaxLine; + uchar bufRcv[4096+1]; + uchar *pRcv = NULL; /* receive buffer */ + + iMaxLine = klog_getMaxLine(); + + /* we optimize performance: if iMaxLine is below 4K (which it is in almost all + * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory + * is used. We could use alloca() to achive a similar aspect, but there are so + * many issues with alloca() that I do not want to take that route. + * rgerhards, 2008-09-02 */ - memset(log_buffer, '\0', sizeof(log_buffer)); - if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) { - if ( errno == EINTR ) - return; - imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); + if((size_t) iMaxLine < sizeof(bufRcv) - 1) { + pRcv = bufRcv; } else { - LogLine(log_buffer, rdcnt); - } + if((pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))) == NULL) + iMaxLine = sizeof(bufRcv) - 1; /* better this than noting */ + } - return; -} + len = 0; + for (;;) { + dbgprintf("----------imklog(BSD) waiting for kernel log line\n"); + i = read(fklog, pRcv + len, iMaxLine - len); + if (i > 0) { + pRcv[i + len] = '\0'; + } else { + if (i < 0 && errno != EINTR && errno != EAGAIN) { + imklogLogIntMsg(LOG_ERR, + "imklog error %d reading kernel log - shutting down imklog", + errno); + fklog = -1; + } + break; + } + for (p = pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) { + *q = '\0'; + Syslog(LOG_INFO, (uchar*) p); + } + len = strlen(p); + if (len >= iMaxLine - 1) { + Syslog(LOG_INFO, (uchar*)p); + len = 0; + } + if (len > 0) + memmove(pRcv, p, len + 1); + } + if (len > 0) + Syslog(LOG_INFO, pRcv); -/* to be called in the module's WillRun entry point - * rgerhards, 2008-04-09 - */ -rsRetVal klogLogKMsg(void) -{ - DEFiRet; - switch(logsrc) { - case kernel: - LogKernelLine(); - break; - case proc: - LogProcLine(); - break; - case none: - /* TODO: We need to handle this case here somewhat more intelligent - * This is now at least partly done - code should never reach this point - * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17 - */ - pause(); - break; - } - RETiRet; + if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) + free(pRcv); } -/* to be called in the module's WillRun entry point +/* to be called in the module's AfterRun entry point * rgerhards, 2008-04-09 */ -rsRetVal klogWillRun(void) +rsRetVal klogAfterRun(void) { DEFiRet; - /* Initialize this module. If that fails, we tell the engine we don't like to run */ - /* Determine where kernel logging information is to come from. */ - logsrc = GetKernelLogSrc(); - if(logsrc == none) { - iRet = RS_RET_NO_KERNEL_LOGSRC; - } else { - if (symbol_lookup) { - symbol_lookup = (InitKsyms(symfile) == 1); - symbol_lookup |= InitMsyms(); - if (symbol_lookup == 0) { - imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups"); - } - } - } - + if(fklog != -1) + close(fklog); RETiRet; } -/* to be called in the module's AfterRun entry point + +/* to be called in the module's WillRun entry point, this is the main + * "message pull" mechanism. * rgerhards, 2008-04-09 */ -rsRetVal klogAfterRun(void) +rsRetVal klogLogKMsg(void) { DEFiRet; - /* cleanup here */ - if(logsrc != none) - CloseLogSrc(); - - DeinitKsyms(); - DeinitMsyms(); - - RETiRet; + sun_sys_poll(); + //readklog(); + RETiRet; } @@ -537,9 +211,6 @@ rsRetVal klogAfterRun(void) int klogFacilIntMsg(void) { - return LOG_KERN; + return LOG_SYSLOG; } - -/* vi:set ai: - */ diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index df783c46..f45c5e62 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -1,3 +1,4 @@ +#define MAXLINE 4096 /* * CDDL HEADER START * @@ -41,28 +42,153 @@ */ #include "config.h" +#include +#include +#include +#include +#include + +//--------- +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//-------- + + +#include "rsyslog.h" + +static struct pollfd Pfd; /* Pollfd for local the log device */ + /* - * Attempts to open the local log device - * and return a file descriptor. + * findnl_bkwd: + * Scans each character in buf until it finds the last newline in buf, + * or the scanned character becomes the last COMPLETE character in buf. + * Returns the number of scanned bytes. + * + * buf - pointer to a buffer containing the message string + * len - the length of the buffer */ -int -sun_oopenklog(char *name, int mode) +size_t +findnl_bkwd(const char *buf, const size_t len) { - int fd; - struct strioctl str; + const char *p; + size_t mb_cur_max; pthread_t mythreadno; if (Debug) { mythreadno = pthread_self(); } + if (len == 0) { + return (0); + } + + mb_cur_max = MB_CUR_MAX; + + if (mb_cur_max == 1) { + /* single-byte locale */ + for (p = buf + len - 1; p != buf; p--) { + if (*p == '\n') { + return ((size_t)(p - buf)); + } + } + return ((size_t)len); + } else { + /* multi-byte locale */ + int mlen; + const char *nl; + size_t rem; + + p = buf; + nl = NULL; + for (rem = len; rem >= mb_cur_max; ) { + mlen = mblen(p, mb_cur_max); + if (mlen == -1) { + /* + * Invalid character found. + */ + dbgprintf("findnl_bkwd(%u): Invalid MB " + "sequence\n", mythreadno); + /* + * handle as a single byte character. + */ + p++; + rem--; + } else { + /* + * It's guaranteed that *p points to + * the 1st byte of a multibyte character. + */ + if (*p == '\n') { + nl = p; + } + p += mlen; + rem -= mlen; + } + } + if (nl) { + return ((size_t)(nl - buf)); + } + /* + * no newline nor null byte found. + * Also it's guaranteed that *p points to + * the 1st byte of a (multibyte) character + * at this point. + */ + return (len - rem); + } +} +//___ end + +/* + * Attempts to open the local log device + * and return a file descriptor. + */ +int +sun_openklog(char *name, int mode) +{ + int fd; + struct strioctl str; + + solaris_create_unix_socket(name); if ((fd = open(name, mode)) < 0) { - logerror("cannot open %s", name); - DPRINT3(1, "openklog(%u): cannot create %s (%d)\n", - mythreadno, name, errno); + //logerror("cannot open %s", name); + dbgprintf("openklog: cannot open %s (%d)\n", + name, errno); return (-1); } str.ic_cmd = I_CONSLOG; @@ -70,15 +196,114 @@ sun_oopenklog(char *name, int mode) str.ic_len = 0; str.ic_dp = NULL; if (ioctl(fd, I_STR, &str) < 0) { - logerror("cannot register to log console messages"); - DPRINT2(1, "openklog(%u): cannot register to log " - "console messages (%d)\n", mythreadno, errno); + //logerror("cannot register to log console messages"); + dbgprintf("openklog: cannot register to log " + "console messages (%d)\n", errno); return (-1); } + Pfd.fd = fd; return (fd); } +/* + * Pull up one message from log driver. + */ +void +sun_getkmsg(int timeout) +{ + int flags = 0, i; + char *lastline; + struct strbuf ctl, dat; + struct log_ctl hdr; + char buf[MAXLINE+1]; + size_t buflen; + size_t len; + char tmpbuf[MAXLINE+1]; + + dat.maxlen = MAXLINE; + dat.buf = buf; + ctl.maxlen = sizeof (struct log_ctl); + ctl.buf = (caddr_t)&hdr; + + while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) { + lastline = &dat.buf[dat.len]; + *lastline = '\0'; + + dbgprintf("sys_poll: getmsg: dat.len = %d\n", dat.len); + buflen = strlen(buf); + len = findnl_bkwd(buf, buflen); + + (void) memcpy(tmpbuf, buf, len); + tmpbuf[len] = '\0'; + + /* Format sys will enqueue the log message. + * Set the sync flag if timeout != 0, which + * means that we're done handling all the + * initial messages ready during startup. + */ + Syslog(LOG_INFO, buf); + /*if (timeout == 0) { + formatsys(&hdr, tmpbuf, 0); + //sys_init_msg_count++; + } else { + formatsys(&hdr, tmpbuf, 1); + }*/ + + if (len != buflen) { + /* If anything remains in buf */ + size_t remlen; + + if (buf[len] == '\n') { + /* skip newline */ + len++; + } + + /* Move the remaining bytes to + * the beginnning of buf. + */ + + remlen = buflen - len; + (void) memcpy(buf, &buf[len], remlen); + dat.maxlen = MAXLINE - remlen; + dat.buf = &buf[remlen]; + } else { + dat.maxlen = MAXLINE; + dat.buf = buf; + } + } + + if (i == 0 && dat.len > 0) { + dat.buf[dat.len] = '\0'; + /* + * Format sys will enqueue the log message. + * Set the sync flag if timeout != 0, which + * means that we're done handling all the + * initial messages ready during startup. + */ + dbgprintf("getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen); + dbgprintf("getkmsg: getmsg: dat.len = %d\n", dat.len); + dbgprintf("getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf)); + dbgprintf("getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf); + dbgprintf("getkmsg: buf len = %d\n", strlen(buf)); + //if (timeout == 0) { + //formatsys(&hdr, buf, 0); + //--sys_init_msg_count++; + //} else { + //formatsys(&hdr, buf, 1); + //} + Syslog(LOG_INFO, buf); + } else if (i < 0 && errno != EINTR) { + if(1){ // (!shutting_down) { + dbgprintf("kernel log driver read error"); + } + // TODO trigger retry logic + //(void) close(Pfd.fd); + //Pfd.fd = -1; + } +} + + /* * Open the log device, and pull up all pending messages. */ @@ -87,26 +312,30 @@ sun_prepare_sys_poll() { int nfds, funix; - if ((funix = openklog(LogName, O_RDONLY)) < 0) { +/* + if ((funix = sun_openklog(LogName, O_RDONLY)) < 0) { logerror("can't open kernel log device - fatal"); exit(1); } +*/ Pfd.fd = funix; Pfd.events = POLLIN; for (;;) { nfds = poll(&Pfd, 1, 0); + /* if (nfds <= 0) { if (sys_init_msg_count > 0) flushmsg(SYNC_FILE); break; - } + }*/ if (Pfd.revents & POLLIN) { - getkmsg(0); + sun_getkmsg(0); } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - logerror("kernel log driver poll error"); + //logerror("kernel log driver poll error"); + dbgprintf("kernel log driver poll error"); break; } } @@ -123,14 +352,8 @@ void * sun_sys_poll(void *ap) { int nfds; - static int klogerrs = 0; - pthread_t mythreadno; - - if (Debug) { - mythreadno = pthread_self(); - } - DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno); + dbgprintf("sys_poll: sys_thread started\n"); /* * Try to process as many messages as we can without blocking on poll. @@ -141,11 +364,8 @@ sun_sys_poll(void *ap) * the previously counted initial messages out to disk. */ - sys_init_msg_count = 0; - for (;;) { errno = 0; - t_errno = 0; nfds = poll(&Pfd, 1, INFTIM); @@ -154,139 +374,33 @@ sun_sys_poll(void *ap) if (nfds < 0) { if (errno != EINTR) - logerror("poll"); + dbgprintf("poll error");// logerror("poll"); continue; } if (Pfd.revents & POLLIN) { - getkmsg(INFTIM); + sun_getkmsg(INFTIM); } else { - if (shutting_down) { - pthread_exit(0); - } + // TODO: shutdown, the rsyslog way + //if (shutting_down) { + //pthread_exit(0); + //} if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - logerror("kernel log driver poll error"); + // TODO: trigger retry logic +/* logerror("kernel log driver poll error"); (void) close(Pfd.fd); Pfd.fd = -1; + */ } } - while (Pfd.fd == -1 && klogerrs++ < 10) { - Pfd.fd = openklog(LogName, O_RDONLY); +/* while (Pfd.fd == -1 && klogerrs++ < 10) { + Pfd.fd = sun_openklog(LogName, O_RDONLY); } if (klogerrs >= 10) { logerror("can't reopen kernel log device - fatal"); exit(1); - } + }*/ } /*NOTREACHED*/ return (NULL); } - -/* - * Pull up one message from log driver. - */ -void -sun_getkmsg(int timeout) -{ - int flags = 0, i; - char *lastline; - struct strbuf ctl, dat; - struct log_ctl hdr; - char buf[MAXLINE+1]; - size_t buflen; - size_t len; - char tmpbuf[MAXLINE+1]; - pthread_t mythreadno; - - if (Debug) { - mythreadno = pthread_self(); - } - - dat.maxlen = MAXLINE; - dat.buf = buf; - ctl.maxlen = sizeof (struct log_ctl); - ctl.buf = (caddr_t)&hdr; - - while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) { - lastline = &dat.buf[dat.len]; - *lastline = '\0'; - - DPRINT2(5, "sys_poll:(%u): getmsg: dat.len = %d\n", - mythreadno, dat.len); - buflen = strlen(buf); - len = findnl_bkwd(buf, buflen); - - (void) memcpy(tmpbuf, buf, len); - tmpbuf[len] = '\0'; - - /* - * Format sys will enqueue the log message. - * Set the sync flag if timeout != 0, which - * means that we're done handling all the - * initial messages ready during startup. - */ - if (timeout == 0) { - formatsys(&hdr, tmpbuf, 0); - sys_init_msg_count++; - } else { - formatsys(&hdr, tmpbuf, 1); - } - sys_msg_count++; - - if (len != buflen) { - /* If anything remains in buf */ - size_t remlen; - - if (buf[len] == '\n') { - /* skip newline */ - len++; - } - - /* - * Move the remaining bytes to - * the beginnning of buf. - */ - - remlen = buflen - len; - (void) memcpy(buf, &buf[len], remlen); - dat.maxlen = MAXLINE - remlen; - dat.buf = &buf[remlen]; - } else { - dat.maxlen = MAXLINE; - dat.buf = buf; - } - } - - if (i == 0 && dat.len > 0) { - dat.buf[dat.len] = '\0'; - /* - * Format sys will enqueue the log message. - * Set the sync flag if timeout != 0, which - * means that we're done handling all the - * initial messages ready during startup. - */ - DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n", - mythreadno, dat.maxlen); - DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n", - mythreadno, dat.len); - DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n", - mythreadno, strlen(dat.buf)); - DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n", - mythreadno, dat.buf); - DPRINT2(5, "getkmsg(%u): buf len = %d\n", - mythreadno, strlen(buf)); - if (timeout == 0) { - formatsys(&hdr, buf, 0); - sys_init_msg_count++; - } else { - formatsys(&hdr, buf, 1); - } - sys_msg_count++; - } else if (i < 0 && errno != EINTR) { - if (!shutting_down) { - logerror("kernel log driver read error"); - } - (void) close(Pfd.fd); - Pfd.fd = -1; - } -} -- cgit From 91a5e176d609d77d4451d7d7b1bf00dfdac5fe50 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 15:49:39 +0100 Subject: added initial files for door support & fixed imklog imklog now basically works, but needs quite some more work to do --- Makefile.am | 4 + configure.ac | 15 ++ plugins/imdoor/Makefile.am | 6 + plugins/imdoor/imdoor.c | 430 ++++++++++++++++++++++++++++++ plugins/imdoor/sun_cddl.c | 592 ++++++++++++++++++++++++++++++++++++++++++ plugins/imklog/solaris.c | 35 +-- plugins/imklog/solaris_cddl.c | 33 ++- 7 files changed, 1067 insertions(+), 48 deletions(-) create mode 100644 plugins/imdoor/Makefile.am create mode 100644 plugins/imdoor/imdoor.c create mode 100644 plugins/imdoor/sun_cddl.c diff --git a/Makefile.am b/Makefile.am index a050e95e..e69349d8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -59,6 +59,10 @@ if ENABLE_IMKLOG SUBDIRS += plugins/imklog endif +if ENABLE_IMDOOR +SUBDIRS += plugins/imdoor +endif + if ENABLE_GSSAPI SUBDIRS += plugins/omgssapi plugins/imgssapi endif diff --git a/configure.ac b/configure.ac index c24468be..64f4fdc8 100644 --- a/configure.ac +++ b/configure.ac @@ -715,6 +715,19 @@ AC_ARG_ENABLE(imfile, AM_CONDITIONAL(ENABLE_IMFILE, test x$enable_imfile = xyes) +# settings for the door input module (under solaris, thus default off) +AC_ARG_ENABLE(imdoor, + [AS_HELP_STRING([--enable-imdoor],[door input module enabled @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_imdoor="yes" ;; + no) enable_imdoor="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-imdoor) ;; + esac], + [enable_imdoor=no] +) +AM_CONDITIONAL(ENABLE_IMDOOR, test x$enable_imdoor = xyes) + + # settings for the omprog output module AC_ARG_ENABLE(omprog, [AS_HELP_STRING([--enable-omprog],[Compiles omprog module @<:@default=no@:>@])], @@ -816,6 +829,7 @@ AC_CONFIG_FILES([Makefile \ plugins/omprog/Makefile \ plugins/omstdout/Makefile \ plugins/imfile/Makefile \ + plugins/imdoor/Makefile \ plugins/imrelp/Makefile \ plugins/imdiag/Makefile \ plugins/omtesting/Makefile \ @@ -847,6 +861,7 @@ echo "---{ input plugins }---" echo " Klog functionality enabled: $enable_klog ($os_type)" echo " imdiag enabled: $enable_imdiag" echo " file input module enabled: $enable_imfile" +echo " Solaris door input module enabled: $enable_imdoor" echo " input template module will be compiled: $enable_imtemplate" echo echo "---{ output plugins }---" diff --git a/plugins/imdoor/Makefile.am b/plugins/imdoor/Makefile.am new file mode 100644 index 00000000..6ad7a904 --- /dev/null +++ b/plugins/imdoor/Makefile.am @@ -0,0 +1,6 @@ +pkglib_LTLIBRARIES = imdoor.la + +imdoor_la_SOURCES = imdoor.c sun_cddl.c +imdoor_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) +imdoor_la_LDFLAGS = -module -avoid-version +imdoor_la_LIBADD = diff --git a/plugins/imdoor/imdoor.c b/plugins/imdoor/imdoor.c new file mode 100644 index 00000000..83890d03 --- /dev/null +++ b/plugins/imdoor/imdoor.c @@ -0,0 +1,430 @@ +/* imdoor.c + * This input module is used to receive syslog messages via the Solaris + * door mechanism. Not surprisingly, it most probably can not be built + * on other platforms. + * + * NOTE: read comments in module-template.h to understand how this file + * works! + * + * File begun on 2010-03-26 by RGerhards + * + * Copyright 2010 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "dirty.h" +#include "cfsysline.h" +#include "unicode-helper.h" +#include "module-template.h" +#include "srUtils.h" +#include "errmsg.h" +#include "net.h" +#include "glbl.h" +#include "msg.h" +#include "prop.h" + +MODULE_TYPE_INPUT + +/* defines */ +#define MAXFUNIX 20 +#ifndef _PATH_LOG +#ifdef BSD +#define _PATH_LOG "/var/run/log" +#else +#define _PATH_LOG "/dev/log" +#endif +#endif + + +/* handle some defines missing on more than one platform */ +#ifndef SUN_LEN +#define SUN_LEN(su) \ + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) +#endif +/* Module static data */ +DEF_IMOD_STATIC_DATA +DEFobjCurrIf(errmsg) +DEFobjCurrIf(glbl) +DEFobjCurrIf(prop) + +static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */ +static int startIndexUxLocalSockets; /* process funix from that index on (used to + * suppress local logging. rgerhards 2005-08-01 + * read-only after startup + */ +static int funixParseHost[MAXFUNIX] = { 0, }; /* should parser parse host name? read-only after startup */ +static int funixFlags[MAXFUNIX] = { IGNDATE, }; /* should parser parse host name? read-only after startup */ +static uchar *funixn[MAXFUNIX] = { (uchar*) _PATH_LOG }; /* read-only after startup */ +static uchar *funixHName[MAXFUNIX] = { NULL, }; /* host-name override - if set, use this instead of actual name */ +static int funixFlowCtl[MAXFUNIX] = { eFLOWCTL_NO_DELAY, }; /* flow control settings for this socket */ +static int funix[MAXFUNIX] = { -1, }; /* read-only after startup */ +static int nfunix = 1; /* number of Unix sockets open / read-only after startup */ + +/* config settings */ +static int bOmitLocalLogging = 0; +static uchar *pLogSockName = NULL; +static uchar *pLogHostName = NULL; /* host name to use with this socket */ +static int bUseFlowCtl = 0; /* use flow control or not (if yes, only LIGHT is used! */ +static int bIgnoreTimestamp = 1; /* ignore timestamps present in the incoming message? */ + + +/* set the timestamp ignore / not ignore option for the system + * log socket. This must be done separtely, as it is not added via a command + * but present by default. -- rgerhards, 2008-03-06 + */ +static rsRetVal setSystemLogTimestampIgnore(void __attribute__((unused)) *pVal, int iNewVal) +{ + DEFiRet; + funixFlags[0] = iNewVal ? IGNDATE : NOFLAG; + RETiRet; +} + +/* set flowcontrol for the system log socket + */ +static rsRetVal setSystemLogFlowControl(void __attribute__((unused)) *pVal, int iNewVal) +{ + DEFiRet; + funixFlowCtl[0] = iNewVal ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; + RETiRet; +} + +/* add an additional listen socket. Socket names are added + * until the array is filled up. It is never reset, only at + * module unload. + * TODO: we should change the array to a list so that we + * can support any number of listen socket names. + * rgerhards, 2007-12-20 + * added capability to specify hostname for socket -- rgerhards, 2008-08-01 + */ +static rsRetVal addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNewVal) +{ + if(nfunix < MAXFUNIX) { + if(*pNewVal == ':') { + funixParseHost[nfunix] = 1; + } + else { + funixParseHost[nfunix] = 0; + } + funixHName[nfunix] = pLogHostName; + pLogHostName = NULL; /* re-init for next, not freed because funixHName[] now owns it */ + funixFlowCtl[nfunix] = bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; + funixFlags[nfunix] = bIgnoreTimestamp ? IGNDATE : NOFLAG; + funixn[nfunix++] = pNewVal; + } + else { + errmsg.LogError(0, NO_ERRCODE, "Out of unix socket name descriptors, ignoring %s\n", + pNewVal); + } + + return RS_RET_OK; +} + +/* free the funixn[] socket names - needed as cleanup on several places + * note that nfunix is NOT reset! funixn[0] is never freed, as it comes from + * the constant memory pool - and if not, it is freeed via some other pointer. + */ +static rsRetVal discardFunixn(void) +{ + int i; + + for (i = 1; i < nfunix; i++) { + if(funixn[i] != NULL) { + free(funixn[i]); + funixn[i] = NULL; + } + if(funixHName[i] != NULL) { + free(funixHName[i]); + funixHName[i] = NULL; + } + } + + return RS_RET_OK; +} + + +static int create_unix_socket(const char *path) +{ + struct sockaddr_un sunx; + int fd; + + if (path[0] == '\0') + return -1; + + unlink(path); + + memset(&sunx, 0, sizeof(sunx)); + sunx.sun_family = AF_UNIX; + (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || + chmod(path, 0666) < 0) { + errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path); + dbgprintf("cannot create %s (%d).\n", path, errno); + close(fd); + return -1; + } + return fd; +} + + +/* This function receives data from a socket indicated to be ready + * to receive and submits the message received for processing. + * rgerhards, 2007-12-20 + * Interface changed so that this function is passed the array index + * of the socket which is to be processed. This eases access to the + * growing number of properties. -- rgerhards, 2008-08-01 + */ +static rsRetVal readSocket(int fd, int iSock) +{ + DEFiRet; + int iRcvd; + int iMaxLine; + uchar bufRcv[4096+1]; + uchar *pRcv = NULL; /* receive buffer */ + + assert(iSock >= 0); + + iMaxLine = glbl.GetMaxLine(); + + /* we optimize performance: if iMaxLine is below 4K (which it is in almost all + * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory + * is used. We could use alloca() to achive a similar aspect, but there are so + * many issues with alloca() that I do not want to take that route. + * rgerhards, 2008-09-02 + */ + if((size_t) iMaxLine < sizeof(bufRcv) - 1) { + pRcv = bufRcv; + } else { + CHKmalloc(pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))); + } + + iRcvd = recv(fd, pRcv, iMaxLine, 0); + dbgprintf("Message from UNIX socket: #%d\n", fd); + if (iRcvd > 0) { + parseAndSubmitMessage(funixHName[iSock] == NULL ? glbl.GetLocalHostName() : funixHName[iSock], + (uchar*)"127.0.0.1", pRcv, + iRcvd, funixParseHost[iSock] ? (funixFlags[iSock] | PARSE_HOSTNAME) : funixFlags[iSock], + funixFlowCtl[iSock], pInputName, NULL, 0); + } else if (iRcvd < 0 && errno != EINTR) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("UNIX socket error: %d = %s.\n", errno, errStr); + errmsg.LogError(errno, NO_ERRCODE, "recvfrom UNIX"); + } + +finalize_it: + if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) + free(pRcv); + + RETiRet; +} + + +/* This function is called to gather input. */ +BEGINrunInput + int maxfds; + int nfds; + int i; + int fd; + fd_set readfds; +CODESTARTrunInput + /* this is an endless loop - it is terminated when the thread is + * signalled to do so. This, however, is handled by the framework, + * right into the sleep below. + */ + while(1) { + /* Add the Unix Domain Sockets to the list of read + * descriptors. + * rgerhards 2005-08-01: we must now check if there are + * any local sockets to listen to at all. If the -o option + * is given without -a, we do not need to listen at all.. + */ + maxfds = 0; + FD_ZERO (&readfds); + /* Copy master connections */ + for (i = startIndexUxLocalSockets; i < nfunix; i++) { + if (funix[i] != -1) { + FD_SET(funix[i], &readfds); + if (funix[i]>maxfds) maxfds=funix[i]; + } + } + + if(Debug) { + dbgprintf("--------imuxsock calling select, active file descriptors (max %d): ", maxfds); + for (nfds= 0; nfds <= maxfds; ++nfds) + if ( FD_ISSET(nfds, &readfds) ) + dbgprintf("%d ", nfds); + dbgprintf("\n"); + } + + /* wait for io to become ready */ + nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL); + + for (i = 0; i < nfunix && nfds > 0; i++) { + if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) { + readSocket(fd, i); + --nfds; /* indicate we have processed one */ + } + } + } + + RETiRet; +ENDrunInput + + +BEGINwillRun +CODESTARTwillRun + register int i; + + /* first apply some config settings */ + startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0; + if(pLogSockName != NULL) + funixn[0] = pLogSockName; + + /* initialize and return if will run or not */ + for (i = startIndexUxLocalSockets ; i < nfunix ; i++) { + if ((funix[i] = create_unix_socket((char*) funixn[i])) != -1) + dbgprintf("Opened UNIX socket '%s' (fd %d).\n", funixn[i], funix[i]); + } + + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imuxsock"), sizeof("imuxsock") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); + +finalize_it: +ENDwillRun + + +BEGINafterRun +CODESTARTafterRun + int i; + /* do cleanup here */ + /* Close the UNIX sockets. */ + for (i = 0; i < nfunix; i++) + if (funix[i] != -1) + close(funix[i]); + + /* Clean-up files. */ + for (i = 0; i < nfunix; i++) + if (funixn[i] && funix[i] != -1) + unlink((char*) funixn[i]); + /* free no longer needed string */ + if(pLogSockName != NULL) + free(pLogSockName); + if(pLogHostName != NULL) { + free(pLogHostName); + } + + discardFunixn(); + nfunix = 1; + + if(pInputName != NULL) + prop.Destruct(&pInputName); +ENDafterRun + + +BEGINmodExit +CODESTARTmodExit + objRelease(glbl, CORE_COMPONENT); + objRelease(errmsg, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_IMOD_QUERIES +ENDqueryEtryPt + +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + bOmitLocalLogging = 0; + if(pLogSockName != NULL) { + free(pLogSockName); + pLogSockName = NULL; + } + if(pLogHostName != NULL) { + free(pLogHostName); + pLogHostName = NULL; + } + + discardFunixn(); + nfunix = 1; + bIgnoreTimestamp = 1; + bUseFlowCtl = 0; + + return RS_RET_OK; +} + + +BEGINmodInit() + int i; +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ +CODEmodInit_QueryRegCFSLineHdlr + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); + + dbgprintf("imuxsock version %s initializing\n", PACKAGE_VERSION); + + /* initialize funixn[] array */ + for(i = 1 ; i < MAXFUNIX ; ++i) { + funixn[i] = NULL; + funix[i] = -1; + } + + /* register config file handlers */ + CHKiRet(omsdRegCFSLineHdlr((uchar *)"omitlocallogging", 0, eCmdHdlrBinary, + NULL, &bOmitLocalLogging, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketignoremsgtimestamp", 0, eCmdHdlrBinary, + NULL, &bIgnoreTimestamp, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketname", 0, eCmdHdlrGetWord, + NULL, &pLogSockName, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensockethostname", 0, eCmdHdlrGetWord, + NULL, &pLogHostName, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary, + NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord, + addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, + resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); + /* the following one is a (dirty) trick: the system log socket is not added via + * an "addUnixListenSocket" config format. As such, it's properties can not be modified + * via $InputUnixListenSocket*". So we need to add a special directive + * for that. We should revisit all of that once we have the new config format... + * rgerhards, 2008-03-06 + */ + CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketignoremsgtimestamp", 0, eCmdHdlrBinary, + setSystemLogTimestampIgnore, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketflowcontrol", 0, eCmdHdlrBinary, + setSystemLogFlowControl, NULL, STD_LOADABLE_MODULE_ID)); +ENDmodInit +/* vim:set ai: + */ diff --git a/plugins/imdoor/sun_cddl.c b/plugins/imdoor/sun_cddl.c new file mode 100644 index 00000000..8e9714d9 --- /dev/null +++ b/plugins/imdoor/sun_cddl.c @@ -0,0 +1,592 @@ +#define MAXLINE 4096 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Portions Copyright 2010 by Rainer Gerhards and Adiscon + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T + * All Rights Reserved + */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rsyslog.h" +#include "debug.h" + +#define DOORFILE "/var/run/syslog_door" +#define RELATIVE_DOORFILE "../var/run/syslog_door" +#define OLD_DOORFILE "/etc/.syslog_door" + +static int DoorFd = -1; +static int DoorCreated = 0; +static char *DoorFileName = DOORFILE; + +/* for managing door server threads */ +static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER; +static uint_t door_server_cnt = 0; +static pthread_attr_t door_thr_attr; + +/* + * the 'server' function that we export via the door. It does + * nothing but return. + */ +/*ARGSUSED*/ +static void +server(void *cookie, char *argp, size_t arg_size, + door_desc_t *dp, uint_t n) +{ + (void) door_return(NULL, 0, NULL, 0); + /* NOTREACHED */ +} + +/*ARGSUSED*/ +static void * +create_door_thr(void *arg) +{ + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + (void) door_return(NULL, 0, NULL, 0); + + /* + * If there is an error in door_return(), it will return here and + * the thread will exit. Hence we need to decrement door_server_cnt. + */ + (void) pthread_mutex_lock(&door_server_cnt_lock); + door_server_cnt--; + (void) pthread_mutex_unlock(&door_server_cnt_lock); + return (NULL); +} + +/* + * Max number of door server threads for syslogd. Since door is used + * to check the health of syslogd, we don't need large number of + * server threads. + */ +#define MAX_DOOR_SERVER_THR 3 + +/* + * Manage door server thread pool. + */ +/*ARGSUSED*/ +static void +door_server_pool(door_info_t *dip) +{ + (void) pthread_mutex_lock(&door_server_cnt_lock); + if (door_server_cnt <= MAX_DOOR_SERVER_THR && + pthread_create(NULL, &door_thr_attr, create_door_thr, NULL) == 0) { + door_server_cnt++; + (void) pthread_mutex_unlock(&door_server_cnt_lock); + return; + } + + (void) pthread_mutex_unlock(&door_server_cnt_lock); +} + +static void +delete_doorfiles(void) +{ + pthread_t mythreadno; + struct stat sb; + int err; + char line[MAXLINE+1]; + + if (Debug) { + mythreadno = pthread_self(); + } + + + if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (unlink(DoorFileName) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed - fatal", DoorFileName); + errno = err; + DBGPRINTF("%s", line);//logerror(line); + DBGPRINTF("delete_doorfiles(%u): error: %s, " + "errno=%d\n", mythreadno, line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles(%u): deleted %s\n", + mythreadno, DoorFileName); + } + + if (strcmp(DoorFileName, DOORFILE) == 0) { + if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (unlink(OLD_DOORFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed", OLD_DOORFILE); + DBGPRINTF("delete_doorfiles(%u): %s\n", + mythreadno, line); + + if (err != EROFS) { + errno = err; + (void) strlcat(line, " - fatal", + sizeof (line)); + logerror(line); + DBGPRINTF("delete_doorfiles(%u): " + "error: %s, errno=%d\n", + mythreadno, line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles(%u): unlink() " + "failure OK on RO file system\n", + mythreadno); + } + + DBGPRINTF("delete_doorfiles(%u): deleted %s\n", + mythreadno, OLD_DOORFILE); + } + } + +#if 0 + if (lstat(PidFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (unlink(PidFileName) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed - fatal", PidFileName); + errno = err; + logerror(line); + DBGPRINTF("delete_doorfiles(%u): error: %s, " + "errno=%d\n", mythreadno, line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles(%u): deleted %s\n", mythreadno, + PidFileName); + } + + if (strcmp(PidFileName, PIDFILE) == 0) { + if (lstat(OLD_PIDFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (unlink(OLD_PIDFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed", OLD_PIDFILE); + DBGPRINTF(5, "delete_doorfiles(%u): %s, \n", + mythreadno, line); + + if (err != EROFS) { + errno = err; + (void) strlcat(line, " - fatal", + sizeof (line)); + logerror(line); + DBGPRINTF(1, "delete_doorfiles(%u): " + "error: %s, errno=%d\n", + mythreadno, line, err); + exit(1); + } + + DBGPRINTF(5, "delete_doorfiles(%u): unlink " + "failure OK on RO file system\n", + mythreadno); + } + + DBGPRINTF(5, "delete_doorfiles(%u): deleted %s\n", + mythreadno, OLD_PIDFILE); + } + } +#endif + + if (DoorFd != -1) { + (void) door_revoke(DoorFd); + } + + DBGPRINTF("delete_doorfiles(%u): revoked door: DoorFd=%d\n", + mythreadno, DoorFd); +} + + +/* + * Create the door file and the pid file in /var/run. If the filesystem + * containing /etc is writable, create symlinks /etc/.syslog_door and + * /etc/syslog.pid to them. On systems that do not support /var/run, create + * /etc/.syslog_door and /etc/syslog.pid directly. + * + * Note: it is not considered fatal to fail to create the pid file or its + * symlink. Attempts to use them in the usual way will fail, of course, but + * syslogd will function nicely without it (not so for the door file). + */ + +static void +sun_open_door(void) +{ + struct stat buf; + door_info_t info; + char line[MAXLINE+1]; + pthread_t mythreadno; + int err; + + if (Debug) { + mythreadno = pthread_self(); + } + + /* + * first see if another syslogd is running by trying + * a door call - if it succeeds, there is already + * a syslogd process active + */ + + if (!DoorCreated) { + int door; + + if ((door = open(DoorFileName, O_RDONLY)) >= 0) { + DBGPRINTF("open_door(%u): %s opened " + "successfully\n", mythreadno, DoorFileName); + + if (door_info(door, &info) >= 0) { + DBGPRINTF("open_door(%u): " + "door_info:info.di_target = %ld\n", + mythreadno, info.di_target); + + if (info.di_target > 0) { + (void) sprintf(line, "syslogd pid %ld" + " already running. Cannot " + "start another syslogd pid %ld", + info.di_target, getpid()); + DBGPRINTF("open_door(%u): error: " + "%s\n", mythreadno, line); + errno = 0; + //logerror(line); + exit(1); + } + } + + (void) close(door); + } else { + if (lstat(DoorFileName, &buf) < 0) { + err = errno; + + DBGPRINTF("open_door(%u): lstat() of %s " + "failed, errno=%d\n", + mythreadno, DoorFileName, err); + + if ((door = creat(DoorFileName, 0644)) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "creat() of %s failed - fatal", + DoorFileName); + DBGPRINTF("open_door(%u): error: %s, " + "errno=%d\n", mythreadno, line, + err); + errno = err; + //logerror(line); + delete_doorfiles(); + exit(1); + } + + (void) fchmod(door, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + + DBGPRINTF("open_door(%u): creat() of %s " + "succeeded\n", mythreadno, + DoorFileName); + + (void) close(door); + } + } + + if (strcmp(DoorFileName, DOORFILE) == 0) { + if (lstat(OLD_DOORFILE, &buf) == 0) { + DBGPRINTF("open_door(%u): lstat() of %s " + "succeeded\n", mythreadno, + OLD_DOORFILE); + + if (S_ISDIR(buf.st_mode)) { + (void) snprintf(line, sizeof (line), + "%s is a directory - fatal", + OLD_DOORFILE); + DBGPRINTF("open_door(%u): error: " + "%s\n", mythreadno, line); + errno = 0; + //logerror(line); + delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): %s is not a " + "directory\n", + mythreadno, OLD_DOORFILE); + + if (unlink(OLD_DOORFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed", + OLD_DOORFILE); + DBGPRINTF("open_door(%u): %s\n", + mythreadno, line); + + if (err != EROFS) { + DBGPRINTF("open_door(%u): " + "error: %s, " + "errno=%d\n", + mythreadno, line, err); + (void) strcat(line, " - fatal"); + errno = err; + //logerror(line); + delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): unlink " + "failure OK on RO file " + "system\n", mythreadno); + } + } else { + DBGPRINTF("open_door(%u): file %s doesn't " + "exist\n", mythreadno, OLD_DOORFILE); + } + + if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "symlink %s -> %s failed", OLD_DOORFILE, + RELATIVE_DOORFILE); + DBGPRINTF("open_door(%u): %s\n", mythreadno, + line); + + if (err != EROFS) { + DBGPRINTF("open_door(%u): error: %s, " + "errno=%d\n", mythreadno, line, + err); + errno = err; + (void) strcat(line, " - fatal"); + //logerror(line); + delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): symlink failure OK " + "on RO file system\n", mythreadno); + } else { + DBGPRINTF("open_door(%u): symlink %s -> %s " + "succeeded\n", mythreadno, + OLD_DOORFILE, RELATIVE_DOORFILE); + } + } + + if ((DoorFd = door_create(server, 0, + DOOR_REFUSE_DESC)) < 0) { + //???? DOOR_NO_CANEL requires newer libs??? DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { + err = errno; + (void) sprintf(line, "door_create() failed - fatal"); + DBGPRINTF("open_door(%u): error: %s, errno=%d\n", + mythreadno, line, err); + errno = err; + //logerror(line); + delete_doorfiles(); + exit(1); + } + //???? (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0); + DBGPRINTF("open_door(%u): door_create() succeeded, " + "DoorFd=%d\n", mythreadno, DoorFd); + + DoorCreated = 1; + } + + (void) fdetach(DoorFileName); /* just in case... */ + + (void) door_server_create(door_server_pool); + + if (fattach(DoorFd, DoorFileName) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), "fattach() of fd" + " %d to %s failed - fatal", DoorFd, DoorFileName); + DBGPRINTF("open_door(%u): error: %s, errno=%d\n", mythreadno, + line, err); + errno = err; + //logerror(line); + delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): attached server() to %s\n", mythreadno, + DoorFileName); + +#if 0 + /* + * create pidfile anyway, so those using it to control + * syslogd (with kill `cat /etc/syslog.pid` perhaps) + * don't get broken. + */ + + if (!PidfileCreated) { + int pidfd; + + PidfileCreated = 1; + + if ((pidfd = open(PidFileName, O_RDWR|O_CREAT|O_TRUNC, 0644)) + < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "open() of %s failed", PidFileName); + DBGPRINTF(1, "open_door(%u): warning: %s, errno=%d\n", + mythreadno, line, err); + errno = err; + //logerror(line); + return; + } + + (void) fchmod(pidfd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + (void) sprintf(line, "%ld\n", getpid()); + + if (write(pidfd, line, strlen(line)) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "write to %s on fd %d failed", PidFileName, pidfd); + DBGPRINTF(1, "open_door(%u): warning: %s, errno=%d\n", + mythreadno, line, err); + errno = err; + //logerror(line); + return; + } + + (void) close(pidfd); + + DBGPRINTF("open_door(%u): %s created\n", + mythreadno, PidFileName); + + if (strcmp(PidFileName, PIDFILE) == 0) { + if (lstat(OLD_PIDFILE, &buf) == 0) { + DBGPRINTF("open_door(%u): lstat() of %s " + "succeded\n", mythreadno, OLD_PIDFILE); + + if (S_ISDIR(buf.st_mode)) { + (void) snprintf(line, sizeof (line), + "file %s is a directory", + OLD_PIDFILE); + DBGPRINTF("open_door(%u): warning: " + "%s\n", mythreadno, line); + errno = 0; + //logerror(line); + return; + } + + if (unlink(OLD_PIDFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed", + OLD_PIDFILE); + DBGPRINTF("open_door(%u): %s\n", + mythreadno, line); + + if (err != EROFS) { + DBGPRINTF(1, "open_door (%u): " + "warning: %s, " + "errno=%d\n", + mythreadno, line, err); + errno = err; + //logerror(line); + return; + } + + DBGPRINTF(5, "open_door(%u): unlink " + "failure OK on RO file " + "system\n", mythreadno); + } + } else { + DBGPRINTF("open_door(%u): file %s doesn't " + "exist\n", mythreadno, OLD_PIDFILE); + } + + if (symlink(RELATIVE_PIDFILE, OLD_PIDFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "symlink %s -> %s failed", OLD_PIDFILE, + RELATIVE_PIDFILE); + DBGPRINTF("open_door(%u): %s\n", mythreadno, + line); + + if (err != EROFS) { + DBGPRINTF(1, "open_door(%u): warning: " + "%s, errno=%d\n", mythreadno, + line, err); + errno = err; + //logerror(line); + return; + } + + DBGPRINTF(5, "open_door(%u): symlink failure OK " + "on RO file system\n", mythreadno); + return; + } + + DBGPRINTF(5, "open_door(%u): symlink %s -> %s " + "succeeded\n", mythreadno, OLD_PIDFILE, + RELATIVE_PIDFILE); + } + } +#endif +} + + diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index 294efa7c..a0e85dc7 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -51,39 +51,6 @@ static int fklog; // TODO: remove # define _PATH_KLOG "/dev/log" #endif -// HELPER -/* handle some defines missing on more than one platform */ -#ifndef SUN_LEN -#define SUN_LEN(su) \ - (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) -#endif - -int solaris_create_unix_socket(const char *path) -{ - struct sockaddr_un sunx; - int fd; - -return; - if (path[0] == '\0') - return -1; - - unlink(path); - - memset(&sunx, 0, sizeof(sunx)); - sunx.sun_family = AF_UNIX; - (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); - fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || - chmod(path, 0666) < 0) { - //errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path); - dbgprintf("cannot create %s (%d).\n", path, errno); - close(fd); - return -1; - } - return fd; -} -// END HELPER - static uchar *GetPath(void) { @@ -104,7 +71,7 @@ klogWillRun(void) int err = errno; perror("XXX"); rs_strerror_r(err, errStr, sizeof(errStr)); - DBGPRINTF("error %d opening log socket %s: %s\n", + DBGPRINTF("error %d opening log socket: %s\n", GetPath(), errStr); iRet = RS_RET_ERR; // TODO: better error code } diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index f45c5e62..700e0ab3 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -141,7 +141,7 @@ findnl_bkwd(const char *buf, const size_t len) /* * Invalid character found. */ - dbgprintf("findnl_bkwd(%u): Invalid MB " + dbgprintf("klog:findnl_bkwd(%u): Invalid MB " "sequence\n", mythreadno); /* * handle as a single byte character. @@ -184,10 +184,9 @@ sun_openklog(char *name, int mode) int fd; struct strioctl str; - solaris_create_unix_socket(name); if ((fd = open(name, mode)) < 0) { //logerror("cannot open %s", name); - dbgprintf("openklog: cannot open %s (%d)\n", + dbgprintf("klog:openklog: cannot open %s (%d)\n", name, errno); return (-1); } @@ -197,11 +196,12 @@ sun_openklog(char *name, int mode) str.ic_dp = NULL; if (ioctl(fd, I_STR, &str) < 0) { //logerror("cannot register to log console messages"); - dbgprintf("openklog: cannot register to log " + dbgprintf("klog:openklog: cannot register to log " "console messages (%d)\n", errno); return (-1); } Pfd.fd = fd; + Pfd.events = POLLIN; return (fd); } @@ -230,7 +230,7 @@ sun_getkmsg(int timeout) lastline = &dat.buf[dat.len]; *lastline = '\0'; - dbgprintf("sys_poll: getmsg: dat.len = %d\n", dat.len); + dbgprintf("klog:sys_poll: getmsg: dat.len = %d\n", dat.len); buflen = strlen(buf); len = findnl_bkwd(buf, buflen); @@ -281,11 +281,11 @@ sun_getkmsg(int timeout) * means that we're done handling all the * initial messages ready during startup. */ - dbgprintf("getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen); - dbgprintf("getkmsg: getmsg: dat.len = %d\n", dat.len); - dbgprintf("getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf)); - dbgprintf("getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf); - dbgprintf("getkmsg: buf len = %d\n", strlen(buf)); + dbgprintf("klog:getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen); + dbgprintf("klog:getkmsg: getmsg: dat.len = %d\n", dat.len); + dbgprintf("klog:getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf)); + dbgprintf("klog:getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf); + dbgprintf("klog:getkmsg: buf len = %d\n", strlen(buf)); //if (timeout == 0) { //formatsys(&hdr, buf, 0); //--sys_init_msg_count++; @@ -295,7 +295,7 @@ sun_getkmsg(int timeout) Syslog(LOG_INFO, buf); } else if (i < 0 && errno != EINTR) { if(1){ // (!shutting_down) { - dbgprintf("kernel log driver read error"); + dbgprintf("klog:kernel log driver read error"); } // TODO trigger retry logic //(void) close(Pfd.fd); @@ -304,6 +304,7 @@ sun_getkmsg(int timeout) } +#if 0 /* * Open the log device, and pull up all pending messages. */ @@ -335,12 +336,14 @@ sun_prepare_sys_poll() sun_getkmsg(0); } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { //logerror("kernel log driver poll error"); - dbgprintf("kernel log driver poll error"); + dbgprintf("klog:kernel log driver poll error"); break; } } } +#endif + /* * this thread listens to the local stream log driver for log messages @@ -353,7 +356,7 @@ sun_sys_poll(void *ap) { int nfds; - dbgprintf("sys_poll: sys_thread started\n"); + dbgprintf("klog:sys_poll: sys_thread started\n"); /* * Try to process as many messages as we can without blocking on poll. @@ -366,15 +369,17 @@ sun_sys_poll(void *ap) for (;;) { errno = 0; +dbgprintf("XXX: before poll\n"); nfds = poll(&Pfd, 1, INFTIM); +dbgprintf("XXX: after poll, nfds %d\n", nfds); if (nfds == 0) continue; if (nfds < 0) { if (errno != EINTR) - dbgprintf("poll error");// logerror("poll"); + dbgprintf("klog:poll error");// logerror("poll"); continue; } if (Pfd.revents & POLLIN) { -- cgit From b67b5b8f73074931285dad4cb2e6d760923a19f8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 16:38:34 +0100 Subject: bugfix: local unix system log socket was deleted even when it was not configured Also made sure that /dev/log will not be processed by imuxsock when running under Solaris -- otherwise, the module may had accidently deleted the log socket and cause problems. --- ChangeLog | 4 ++++ plugins/imuxsock/imuxsock.c | 13 +++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e064b2e..26dfda48 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ --------------------------------------------------------------------------- +Version 4.6.3 [v4-stable] (rgerhards), 2010-03-?? +- bugfix: local unix system log socket was deleted even when it was + not configured +--------------------------------------------------------------------------- Version 4.6.2 [v4-stable] (rgerhards), 2010-03-?? - new feature: "." action type added to support writing files to relative pathes (this is primarily meant as a debug aid) diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 5567a405..1ab67826 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -300,7 +300,16 @@ CODESTARTwillRun register int i; /* first apply some config settings */ - startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0; +# ifdef OS_SOLARIS + /* under solaris, we must NEVER process the local log socket, because + * it is implemented there differently. If we used it, we would actually + * delete it and render the system partly unusable. So don't do that. + * rgerhards, 2010-03-26 + */ + startIndexUxLocalSockets = 1; +# else + startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0; +# endif if(pLogSockName != NULL) funixn[0] = pLogSockName; @@ -329,7 +338,7 @@ CODESTARTafterRun close(funix[i]); /* Clean-up files. */ - for (i = 0; i < nfunix; i++) + for(i = startIndexUxLocalSockets; i < nfunix; i++) if (funixn[i] && funix[i] != -1) unlink((char*) funixn[i]); /* free no longer needed string */ -- cgit From 3ab759c40d34f518744efa9b266640784fc3655f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 16:59:00 +0100 Subject: cleanup in solaris components for imklog --- plugins/imklog/solaris.c | 2 - plugins/imklog/solaris_cddl.c | 104 ++++-------------------------------------- 2 files changed, 8 insertions(+), 98 deletions(-) diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index a0e85dc7..c2aec30a 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -69,7 +69,6 @@ klogWillRun(void) if (fklog < 0) { char errStr[1024]; int err = errno; -perror("XXX"); rs_strerror_r(err, errStr, sizeof(errStr)); DBGPRINTF("error %d opening log socket: %s\n", GetPath(), errStr); @@ -167,7 +166,6 @@ rsRetVal klogLogKMsg(void) { DEFiRet; sun_sys_poll(); - //readklog(); RETiRet; } diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index 700e0ab3..1053de66 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -40,61 +40,24 @@ * software developed by the University of California, Berkeley, and its * contributors. */ - #include "config.h" #include #include #include #include #include - -//--------- -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include - -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//-------- - #include "rsyslog.h" static struct pollfd Pfd; /* Pollfd for local the log device */ - - -/* - * findnl_bkwd: +/* findnl_bkwd: * Scans each character in buf until it finds the last newline in buf, * or the scanned character becomes the last COMPLETE character in buf. * Returns the number of scanned bytes. @@ -174,8 +137,8 @@ findnl_bkwd(const char *buf, const size_t len) } //___ end -/* - * Attempts to open the local log device + +/* Attempts to open the local log device * and return a file descriptor. */ int @@ -210,7 +173,7 @@ sun_openklog(char *name, int mode) * Pull up one message from log driver. */ void -sun_getkmsg(int timeout) +sun_getkmsg() { int flags = 0, i; char *lastline; @@ -304,55 +267,13 @@ sun_getkmsg(int timeout) } -#if 0 -/* - * Open the log device, and pull up all pending messages. - */ -void -sun_prepare_sys_poll() -{ - int nfds, funix; - -/* - if ((funix = sun_openklog(LogName, O_RDONLY)) < 0) { - logerror("can't open kernel log device - fatal"); - exit(1); - } -*/ - - Pfd.fd = funix; - Pfd.events = POLLIN; - - for (;;) { - nfds = poll(&Pfd, 1, 0); - /* - if (nfds <= 0) { - if (sys_init_msg_count > 0) - flushmsg(SYNC_FILE); - break; - }*/ - - if (Pfd.revents & POLLIN) { - sun_getkmsg(0); - } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - //logerror("kernel log driver poll error"); - dbgprintf("klog:kernel log driver poll error"); - break; - } - } - -} -#endif - - -/* - * this thread listens to the local stream log driver for log messages +/* this thread listens to the local stream log driver for log messages * generated by this host, formats them, and queues them to the logger * thread. */ /*ARGSUSED*/ void * -sun_sys_poll(void *ap) +sun_sys_poll() { int nfds; @@ -369,10 +290,8 @@ sun_sys_poll(void *ap) for (;;) { errno = 0; -dbgprintf("XXX: before poll\n"); nfds = poll(&Pfd, 1, INFTIM); -dbgprintf("XXX: after poll, nfds %d\n", nfds); if (nfds == 0) continue; @@ -383,9 +302,9 @@ dbgprintf("XXX: after poll, nfds %d\n", nfds); continue; } if (Pfd.revents & POLLIN) { - sun_getkmsg(INFTIM); + sun_getkmsg(); } else { - // TODO: shutdown, the rsyslog way + // TODO: shutdown, the rsyslog way (in v5!) //if (shutting_down) { //pthread_exit(0); //} @@ -398,13 +317,6 @@ dbgprintf("XXX: after poll, nfds %d\n", nfds); } } -/* while (Pfd.fd == -1 && klogerrs++ < 10) { - Pfd.fd = sun_openklog(LogName, O_RDONLY); - } - if (klogerrs >= 10) { - logerror("can't reopen kernel log device - fatal"); - exit(1); - }*/ } /*NOTREACHED*/ return (NULL); -- cgit From cb2fe4a585d4cb78175770938ebf361d023e999d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 29 Mar 2010 17:14:43 +0200 Subject: added some more useful info to Solaris README --- solaris/README | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/solaris/README b/solaris/README index 0700642e..3f88431d 100644 --- a/solaris/README +++ b/solaris/README @@ -25,9 +25,13 @@ http://prefetch.net/articles/linkers.badldlibrary.html The working sample configure sequence I use is: -export LDFLAGS="-R/usr/local/lib" +export LDFLAGS="-R/opt/csw/gcc4/lib" ./configure AR=gar ...other options... +As a "quick and dirty" fix, one may set the following library +path before executing rsyslog (may be useful to avoid recompile): + +export LD_LIBRARY_PATH=/opt/csw/gcc4/lib NOT YET SUPPORTED * local log socket -- cgit From 23a3fdb094cd992b2081db014d583b975c03ca57 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 1 Apr 2010 15:16:05 +0200 Subject: git "bugfix": added file previously forgotten --- plugins/imklog/solaris_cddl.h | 1 + 1 file changed, 1 insertion(+) create mode 100644 plugins/imklog/solaris_cddl.h diff --git a/plugins/imklog/solaris_cddl.h b/plugins/imklog/solaris_cddl.h new file mode 100644 index 00000000..22295658 --- /dev/null +++ b/plugins/imklog/solaris_cddl.h @@ -0,0 +1 @@ +int sun_openklog(char *name, int mode); -- cgit From 2cd132eebb84dbcffcf0c20b9354c14f797c29cd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 7 Apr 2010 12:42:41 +0200 Subject: enhanced nettester tool so that it re-uses it's callers environment this enables us to work with the "usual" environment tweaks (for debugging and other purposes), without the need for any special handling in nettester itself --- ChangeLog | 7 ++ runtime/msg.c | 9 +- runtime/parser.c | 9 +- tests/Makefile.am | 8 +- tests/diag.sh | 4 +- tests/nettester.c | 13 +-- tests/random.sh | 20 +++++ tests/randomgen.c | 130 +++++++++++++++++++++++++++ tests/rt-init.c | 2 +- tests/tcpflood.c | 142 +++++++++++++++++++++++------- tests/testsuites/random.conf | 13 +++ tests/testsuites/samples.snare_ccoff_udp2 | 18 ++-- tools/syslogd.c | 2 +- 13 files changed, 314 insertions(+), 63 deletions(-) create mode 100755 tests/random.sh create mode 100644 tests/randomgen.c create mode 100644 tests/testsuites/random.conf diff --git a/ChangeLog b/ChangeLog index 131539a5..dce06dfc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,13 @@ +- improvded testbench + - added test with truly random data received via syslog to test + robustness - bugfix: testbench failed when not executed in UTC+1 timezone accidently, the time zone information was kept inside some to-be-checked-for responses +- temporary bugfix replaced by permanent one for + message-induced off-by-one error (potential segfault) (see 4.6.2) + The analysis has been completed and a better fix been crafted and + integrated. --------------------------------------------------------------------------- Version 4.6.3 [v4-stable] (rgerhards), 2010-03-?? - bugfix: local unix system log socket was deleted even when it was diff --git a/runtime/msg.c b/runtime/msg.c index 2ce7843a..91057f97 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -2010,6 +2010,8 @@ finalize_it: /* set raw message in message object. Size of message is provided. + * The function makes sure that the stored rawmsg is properly + * terminated by '\0'. * rgerhards, 2009-06-16 */ void MsgSetRawMsg(msg_t *pThis, char* pszRawMsg, size_t lenMsg) @@ -2319,13 +2321,6 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, *pPropLen = sizeof("**INVALID PROPERTY NAME**") - 1; return UCHAR_CONSTANT("**INVALID PROPERTY NAME**"); } - /* the following line fixes the symptom, but not the root cause -- at least MSG sometimes - * returns a size of one too less. To prevent all troubles, we recalculate the sizes based - * on what we actually got. TODO: remove once root cause is found. - * rgerhards, 2010-03-23 - */ - bufLen = ustrlen(pRes); - /* If we did not receive a template pointer, we are already done... */ if(pTpe == NULL) { diff --git a/runtime/parser.c b/runtime/parser.c index 466066e7..36e88ebd 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -176,7 +176,10 @@ sanitizeMessage(msg_t *pMsg) pszMsg = pMsg->pszRawMsg; lenMsg = pMsg->iLenRawMsg; - /* remove NUL character at end of message (see comment in function header) */ + /* remove NUL character at end of message (see comment in function header) + * Note that we do not need to add a NUL character in this case, because it + * is already present ;) + */ if(pszMsg[lenMsg-1] == '\0') { DBGPRINTF("dropped NUL at very end of message\n"); bUpdatedLen = TRUE; @@ -190,8 +193,9 @@ sanitizeMessage(msg_t *pMsg) */ if(bDropTrailingLF && pszMsg[lenMsg-1] == '\n') { DBGPRINTF("dropped LF at very end of message (DropTrailingLF is set)\n"); - bUpdatedLen = TRUE; lenMsg--; + pszMsg[lenMsg] = '\0'; + bUpdatedLen = TRUE; } /* it is much quicker to sweep over the message and see if it actually @@ -245,6 +249,7 @@ sanitizeMessage(msg_t *pMsg) } ++iSrc; } + pDst[iDst] = '\0'; MsgSetRawMsg(pMsg, (char*)pDst, iDst); /* save sanitized string */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 7ca40766..53ca9cb0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ if ENABLE_TESTBENCH TESTRUNS = rt_init rscript -check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep +check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen TESTS = $(TESTRUNS) cfg.sh \ validation-run.sh \ imtcp-multiport.sh \ @@ -24,6 +24,7 @@ TESTS = $(TESTRUNS) cfg.sh \ dynfile_invld_sync.sh \ dynfile_invalid2.sh \ complex1.sh \ + random.sh \ queue-persist.sh \ pipeaction.sh execonlyonce.sh \ @@ -180,6 +181,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/gzipwr_large_dynfile.conf \ complex1.sh \ testsuites/complex1.conf \ + random.sh \ + testsuites/random.conf \ dynfile_invld_async.sh \ dynfile_invld_sync.sh \ dynfile_cachemiss.sh \ @@ -204,6 +207,9 @@ chkseq_SOURCES = chkseq.c tcpflood_SOURCES = tcpflood.c tcpflood_LDADD = $(SOL_LIBS) +randomgen_SOURCES = randomgen.c +randomgen_LDADD = $(SOL_LIBS) + nettester_SOURCES = nettester.c getline.c nettester_LDADD = $(SOL_LIBS) diff --git a/tests/diag.sh b/tests/diag.sh index c0f736b8..2cc652ad 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -17,7 +17,7 @@ case $1 in cp $srcdir/testsuites/diag-common.conf diag-common.conf cp $srcdir/testsuites/diag-common2.conf diag-common2.conf rm -f rsyslog.action.*.include - rm -f rsyslogd.started work-*.conf + rm -f rsyslogd.started work-*.conf rsyslog.random.data rm -f rsyslogd2.started work-*.conf rm -f work rsyslog.out.log rsyslog.out.log.save # common work files rm -f rsyslog.out.*.log @@ -28,7 +28,7 @@ case $1 in 'exit') rm -f rsyslogd.started work-*.conf diag-common.conf rm -f rsyslogd2.started diag-common2.conf rsyslog.action.*.include rm -f work rsyslog.out.log rsyslog.out.log.save # common work files - rm -f rsyslog.out.*.log + rm -f rsyslog.out.*.log rsyslog.random.data rm -rf test-spool ;; 'startup') # start rsyslogd with default params. $2 is the config file name to use diff --git a/tests/nettester.c b/tests/nettester.c index e1ecbcb5..eff5929b 100644 --- a/tests/nettester.c +++ b/tests/nettester.c @@ -62,7 +62,7 @@ static char *testSuite = NULL; /* name of current test suite */ static int iPort = 12514; /* port which shall be used for sending data */ static char* pszCustomConf = NULL; /* custom config file, use -c conf to specify */ static int verbose = 0; /* verbose output? -v option */ -static int useDebugEnv = 0; /* activate debugging environment (for rsyslog debug log)? */ +static char **ourEnvp; /* these two are quick hacks... */ int iFailed = 0; @@ -218,9 +218,6 @@ int openPipe(char *configFile, pid_t *pid, int *pfd) char *newargv[] = {"../tools/rsyslogd", "dummy", "-c4", "-u2", "-n", "-irsyslog.pid", "-M../runtime/.libs:../.libs", NULL }; char confFile[1024]; - char *newenviron[] = { NULL }; - char *newenvironDeb[] = { "RSYSLOG_DEBUG=debug nostdout", - "RSYSLOG_DEBUGLOG=log", NULL }; sprintf(confFile, "-f%s/testsuites/%s.conf", srcdir, (pszCustomConf == NULL) ? configFile : pszCustomConf); @@ -243,7 +240,7 @@ int openPipe(char *configFile, pid_t *pid, int *pfd) close(pipefd[1]); close(pipefd[0]); fclose(stdin); - execve("../tools/rsyslogd", newargv, (useDebugEnv) ? newenvironDeb : newenviron); + execve("../tools/rsyslogd", newargv, ourEnvp); } else { close(pipefd[1]); *pid = cpid; @@ -450,7 +447,7 @@ void doAtExit(void) * of this file. * rgerhards, 2009-04-03 */ -int main(int argc, char *argv[]) +int main(int argc, char *argv[], char *envp[]) { int fd; int opt; @@ -459,14 +456,12 @@ int main(int argc, char *argv[]) char buf[4096]; char testcases[4096]; + ourEnvp = envp; while((opt = getopt(argc, argv, "dc:i:p:t:v")) != EOF) { switch((char)opt) { case 'c': pszCustomConf = optarg; break; - case 'd': - useDebugEnv = 1; - break; case 'i': if(!strcmp(optarg, "udp")) inputMode = inputUDP; diff --git a/tests/random.sh b/tests/random.sh new file mode 100755 index 00000000..79f704c7 --- /dev/null +++ b/tests/random.sh @@ -0,0 +1,20 @@ +# Test if rsyslog survives sending truely random data to it... +# +# added 2010-04-01 by Rgerhards +# This file is part of the rsyslog project, released under GPLv3 +echo =============================================================================== +echo TEST: \[random.sh\]: testing random data +source $srcdir/diag.sh init +# uncomment for debugging support: +#export RSYSLOG_DEBUG="debug nostdout noprintmutexaction" +#export RSYSLOG_DEBUGLOG="log" +source $srcdir/diag.sh startup random.conf +# generate random data +./randomgen -f rsyslog.random.data -s 100000 +ls -l rsyslog.random.data +source $srcdir/diag.sh tcpflood -B -I rsyslog.random.data -c5 -C10 +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown # and wait for it to terminate +# we do not check anything yet, the point is if rsyslog survived ;) +# TODO: check for exit message, but we'll notice an abort anyhow, so not that important +#source $srcdir/diag.sh exit diff --git a/tests/randomgen.c b/tests/randomgen.c new file mode 100644 index 00000000..9ba56954 --- /dev/null +++ b/tests/randomgen.c @@ -0,0 +1,130 @@ +/* generates random data for later use in test cases. Of course, + * we could generate random data during the testcase itself, but + * the core idea is that we record the random data so that we have + * a chance to reproduce a problem should it occur. IMHO this + * provides the best compromise, by a) having randomness but + * b) knowing what was used during the test. + * + * Params + * -f output file name (stdout if not given) + * -s size of test data, plain number is size in k, 1MB default + * -u uses /dev/urandom instead of libc random number generator + * (when available). Note that this is usually much slower. + * + * Part of the testbench for rsyslog. + * + * Copyright 2010 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXIT_FAILURE 1 + +static char *fileName = NULL; /* name of output file */ +static int tryUseURandom = 0; /* try to use /dev/urandom? */ +static long long fileSize = 1024*1024; /* file size in K, 1MB default */ + + +/* generate the random file. This code really can be improved (e.g. read /dev/urandom + * when available) + */ +static inline void +genFile() +{ + long i; + FILE *fp; + FILE *rfp = NULL; + + if(fileName == NULL) { + fp = stdout; + } else { + if((fp = fopen(fileName, "w")) == NULL) { + perror(fileName); + } + } + + /* try to use /dev/urandom, if available */ + if(tryUseURandom) + rfp = fopen("/dev/urandom", "r"); + + if(rfp == NULL) { + /* fallback, use libc random number generator */ + for(i = 0 ; i < fileSize ; ++i) { + if(fputc((char) rand(), fp) == EOF) { + perror(fileName); + exit(1); + } + } + } else { + /* use /dev/urandom */ + printf("using /dev/urandom"); + for(i = 0 ; i < fileSize ; ++i) { + if(fputc(fgetc(rfp), fp) == EOF) { + perror(fileName); + exit(1); + } + } + } + + if(fileName != NULL) + fclose(fp); +} + + +/* Run the test. + * rgerhards, 2009-04-03 + */ +int main(int argc, char *argv[]) +{ + int ret = 0; + int opt; + + srand(time(NULL)); /* seed is good enough for our needs */ + + while((opt = getopt(argc, argv, "f:s:u")) != -1) { + switch (opt) { + case 'f': fileName = optarg; + break; + case 's': fileSize = atol(optarg) * 1024; + break; + case 'u': tryUseURandom = 1; + break; + default: printf("invalid option '%c' or value missing - terminating...\n", opt); + exit (1); + break; + } + } + + printf("generating random data file '%s' of %ldkb - may take a short while...\n", + fileName, (long) (fileSize / 1024)); + genFile(); + + exit(ret); +} diff --git a/tests/rt-init.c b/tests/rt-init.c index 66a9ad32..dbe94b4a 100644 --- a/tests/rt-init.c +++ b/tests/rt-init.c @@ -39,6 +39,6 @@ ENDExit BEGINTest CODESTARTTest -finalize_it: +/*finalize_it:*/ /* room for custom error reporter, leave blank if not needed */ ENDTest diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 68c1c097..e92d1308 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -20,6 +20,14 @@ * one field to the right. Zero (default) disables this functionality. * -M the message to be sent. Disables all message format options, as * only that exact same message is sent. + * -I read specified input file, do NOT generate own test data. The test + * completes when eof is reached. + * -B The specified file (-I) is binary. No data processing is done by + * tcpflood. If multiple connections are specified, data is read in + * chunks and spread across the connections without taking any record + * delemiters into account. + * -C when input from a file is read, this file is transmitted -C times + * (C like cycle, running out of meaningful option switches ;)) * * Part of the testbench for rsyslog. * @@ -76,6 +84,10 @@ static int *sockArray; /* array of sockets to use */ static int msgNum = 0; /* initial message number to start with */ static int bShowProgress = 1; /* show progress messages */ static char *MsgToSend = NULL; /* if non-null, this is the actual message to send */ +static int bBinaryFile = 0; /* is -I file binary */ +static char *dataFile = NULL; /* name of data file, if NULL, generate own data */ +static int numFileIterations = 1;/* how often is file data to be sent? */ +FILE *dataFP = NULL; /* file pointer for data file, if used */ /* open a single tcp connection @@ -167,8 +179,8 @@ int openConnections(void) void closeConnections(void) { int i; - char msgBuf[128]; size_t lenMsg; + char msgBuf[128]; if(bShowProgress) write(1, " close connections", sizeof(" close connections")-1); @@ -187,6 +199,62 @@ void closeConnections(void) } +/* generate the message to be sent according to program command line parameters. + * this has been moved to its own function as we now have various different ways + * of constructing test messages. -- rgerhards, 2010-03-31 + */ +static inline void +genMsg(char *buf, size_t maxBuf, int *pLenBuf) +{ + int edLen; /* actual extra data length to use */ + char extraData[MAX_EXTRADATA_LEN + 1]; + char dynFileIDBuf[128] = ""; + static int numMsgsGen = 0; + int done; + + if(dataFP != NULL) { + /* get message from file */ + do { + done = 1; + *pLenBuf = fread(buf, 1, 1024, dataFP); + if(feof(dataFP)) { + if(--numFileIterations > 0) { + rewind(dataFP); + done = 0; /* need new iteration */ + } else { + *pLenBuf = 0; + goto finalize_it; + } + } + } while(!done); /* Attention: do..while()! */ + } else if(MsgToSend == NULL) { + if(dynFileIDs > 0) { + snprintf(dynFileIDBuf, maxBuf, "%d:", rand() % dynFileIDs); + } + if(extraDataLen == 0) { + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", + msgPRI, dynFileIDBuf, msgNum); + } else { + if(bRandomizeExtraData) + edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; + else + edLen = extraDataLen; + memset(extraData, 'X', edLen); + extraData[edLen] = '\0'; + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", + msgPRI, dynFileIDBuf, msgNum, edLen, extraData); + } + } else { + /* use fixed message format from command line */ + *pLenBuf = snprintf(buf, maxBuf, "%s\n", MsgToSend); + } + + if(numMsgsGen++ >= numMsgsToSend) + *pLenBuf = 0; /* indicate end of run */ + +finalize_it: ; +} + /* send messages to the tcp connections we keep open. We use * a very basic format that helps identify the message * (via msgnum:: e.g. msgnum:00000001:). This format is suitable @@ -197,52 +265,42 @@ void closeConnections(void) */ int sendMessages(void) { - int i; + int i = 0; int socknum; int lenBuf; int lenSend; - int edLen; /* actual extra data length to use */ - char dynFileIDBuf[128] = ""; + char *statusText; char buf[MAX_EXTRADATA_LEN + 1024]; - char extraData[MAX_EXTRADATA_LEN + 1]; - printf("Sending %d messages.\n", numMsgsToSend); + if(dataFile == NULL) { + printf("Sending %d messages.\n", numMsgsToSend); + statusText = "messages"; + } else { + printf("Sending file '%s' %d times.\n", dataFile, numFileIterations); + statusText = "kb"; + } if(bShowProgress) - printf("\r%8.8d messages sent", 0); - for(i = 0 ; i < numMsgsToSend ; ++i) { + printf("\r%8.8d %s sent", 0, statusText); + while(1) { /* broken inside loop! */ if(i < numConnections) socknum = i; else if(i >= numMsgsToSend - numConnections) socknum = i - (numMsgsToSend - numConnections); - else - socknum = rand() % numConnections; - if(MsgToSend == NULL) { - if(dynFileIDs > 0) { - sprintf(dynFileIDBuf, "%d:", rand() % dynFileIDs); - } - if(extraDataLen == 0) { - lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", - msgPRI, dynFileIDBuf, msgNum); - } else { - if(bRandomizeExtraData) - edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; - else - edLen = extraDataLen; - memset(extraData, 'X', edLen); - extraData[edLen] = '\0'; - lenBuf = sprintf(buf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", - msgPRI, dynFileIDBuf, msgNum, edLen, extraData); - } - } else { - /* use fixed message format from command line */ - lenBuf = sprintf(buf, "%s\n", MsgToSend); + else { + int rnd = rand(); + //socknum = rand() % numConnections; + socknum = rnd % numConnections; } + genMsg(buf, sizeof(buf), &lenBuf); /* generate the message to send according to params */ + if(lenBuf == 0) + break; /* end of processing! */ lenSend = send(sockArray[socknum], buf, lenBuf, 0); if(lenSend != lenBuf) { printf("\r%5.5d\n", i); fflush(stdout); perror("send test data"); - printf("send() failed at socket %d, index %d, msgNum %d\n", socknum, i, msgNum); + printf("send() failed at socket %d, index %d, msgNum %d\n", + sockArray[socknum], i, msgNum); fflush(stderr); return(1); } @@ -251,8 +309,9 @@ int sendMessages(void) printf("\r%8.8d", i); } ++msgNum; + ++i; } - printf("\r%8.8d messages sent\n", i); + printf("\r%8.8d %s sent\n", i, statusText); return 0; } @@ -336,7 +395,7 @@ int main(int argc, char *argv[]) if(!isatty(1)) bShowProgress = 0; - while((opt = getopt(argc, argv, "f:t:p:c:m:i:P:d:n:M:r")) != -1) { + while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:n:M:rB")) != -1) { switch (opt) { case 't': targetIP = optarg; break; @@ -346,6 +405,8 @@ int main(int argc, char *argv[]) break; case 'c': numConnections = atoi(optarg); break; + case 'C': numFileIterations = atoi(optarg); + break; case 'm': numMsgsToSend = atoi(optarg); break; case 'i': msgNum = atoi(optarg); @@ -365,6 +426,14 @@ int main(int argc, char *argv[]) break; case 'M': MsgToSend = optarg; break; + case 'I': dataFile = optarg; + /* in this mode, we do not know the num messages to send, so + * we set a (high) number to keep the code happy. + */ + numMsgsToSend = 1000000; + break; + case 'B': bBinaryFile = 1; + break; default: printf("invalid option '%c' or value missing - terminating...\n", opt); exit (1); break; @@ -385,6 +454,13 @@ int main(int argc, char *argv[]) } } + if(dataFile != NULL) { + if((dataFP = fopen(dataFile, "r")) == NULL) { + perror(dataFile); + exit(1); + } + } + if(openConnections() != 0) { printf("error opening connections\n"); exit(1); diff --git a/tests/testsuites/random.conf b/tests/testsuites/random.conf new file mode 100644 index 00000000..a7079df1 --- /dev/null +++ b/tests/testsuites/random.conf @@ -0,0 +1,13 @@ +# we write to /dev/null, as we have no chance to verify the output +# in any case. What we really check is that rsyslogd does not +# segfault or otherwise abort. +# rgerhards, 2010-04-01 +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imtcp/.libs/imtcp +$MainMsgQueueTimeoutShutdown 10000 +$InputTCPServerRun 13514 + +$template outfmt,"%rawmsg%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +*.* /dev/null diff --git a/tests/testsuites/samples.snare_ccoff_udp2 b/tests/testsuites/samples.snare_ccoff_udp2 index 7837b820..337cd97c 100644 --- a/tests/testsuites/samples.snare_ccoff_udp2 +++ b/tests/testsuites/samples.snare_ccoff_udp2 @@ -9,14 +9,18 @@ # to be adapted. We do NOT try to preserve misbehaviour on such seriously malformed # messages. # +# this is a very simple test, though not snare-based +test +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('', 1, 'test',5, '20100321185328', '20100321185328', 1, '') +# and yet another one we have seen in practice +UX=Abcd-efg-hij-klmno; XXXXX=1111111111, Z123=192.12.231.245:11111, S1234=123456789, XXXXXX=111111111 +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' XXXXX=1111111111, Z123=192.12.231.245:11111, S1234=123456789, XXXXXX=111111111', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'UX=Abcd-efg-hij-klmno;') # Sample 1 - note the absence of PRI! windowsserver MSWinEventLog 1 Security 1167 Fri Mar 19 15:33:30 2010 540 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Successful Network Logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Logon Type: 3 Logon Process: Kerberos Authentication Package: Kerberos Workstation Name: Logon GUID: {79b6eb79-7bcc-8a2e-7dad-953c51dc00fd} Caller User Name: - Caller Domain: - Caller Logon ID: - Caller Process ID: - Transited Services: - Source Network Address: 10.11.11.3 Source Port: 3306 733\n -insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 540 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Successful Network Logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Logon Type: 3 Logon Process: Kerberos Authentication Package: Kerberos Workstation Name: Logon GUID: {79b6eb79-7bcc-8a2e-7dad-953c51dc00fd} Caller User Name: - Caller Domain: - Caller Logon ID: - Caller Process ID: - Transited Services: - Source Network Address: 10.11.11.3 Source Port: 3306 733 ', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1167 Fri') +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 540 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Successful Network Logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Logon Type: 3 Logon Process: Kerberos Authentication Package: Kerberos Workstation Name: Logon GUID: {79b6eb79-7bcc-8a2e-7dad-953c51dc00fd} Caller User Name: - Caller Domain: - Caller Logon ID: - Caller Process ID: - Transited Services: - Source Network Address: 10.11.11.3 Source Port: 3306 733', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1167 Fri') # Sample 2 -# the samples below need to be disabled for the "workaround patch" for the message -# parser to work. They need to be re-enabled once a final solution has been crafted -#windowsserver MSWinEventLog 1 Security 1166 Fri Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732\n -#insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1166 Fri') +windowsserver MSWinEventLog 1 Security 1166 Fri Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732\n +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 576 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff Special privileges assigned to new logon: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF88396) Privileges: SeSecurityPrivilege SeBackupPrivilege SeRestorePrivilege SeTakeOwnershipPrivilege SeDebugPrivilege SeSystemEnvironmentPrivilege SeLoadDriverPrivilege SeImpersonatePrivilege SeEnableDelegationPrivilege 732', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1166 Fri') # Sample 3 -#windowsserver MSWinEventLog 1 Security 1165 Fri Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731\n -#insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1165 Fri') +windowsserver MSWinEventLog 1 Security 1165 Fri Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731\n +insert into windows (Message, Facility,FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values (' Mar 19 15:33:30 2010 538 Security SYSTEM User Success Audit WINDOWSSERVER Logon/Logoff User Logoff: User Name: WINDOWSSERVER$ Domain: DOMX Logon ID: (0x0,0xF8830B) Logon Type: 3 731', 1, 'localhost',5, '20100321185328', '20100321185328', 1, 'windowsserver MSWinEventLog 1 Security 1165 Fri') diff --git a/tools/syslogd.c b/tools/syslogd.c index a61d1e5d..a93b588f 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -792,7 +792,7 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla * (I couldn't do any more smart things anyway...). * rgerhards, 2007-9-20 */ - DBGPRINTF("internal error: iMsg > max msg size in printchopped()\n"); + DBGPRINTF("internal error: iMsg > max msg size in parseAndSubmitMessage()\n"); } FINALIZE; /* in this case, we are done... nothing left we can do */ } -- cgit From 7db6ffbce3e2a709e77ff05782f703ec112ed84b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 7 Apr 2010 13:57:46 +0200 Subject: bugfix: the T/P/E config size specifiers did not work properly under call 32-bit platforms --- ChangeLog | 2 ++ runtime/cfsysline.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index dce06dfc..cda52c3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,8 @@ message-induced off-by-one error (potential segfault) (see 4.6.2) The analysis has been completed and a better fix been crafted and integrated. +- bugfix: the T/P/E config size specifiers did not work properly under + all 32-bit platforms --------------------------------------------------------------------------- Version 4.6.3 [v4-stable] (rgerhards), 2010-03-?? - bugfix: local unix system log socket was deleted even when it was diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index 184c0d87..5df8e64c 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -217,9 +217,11 @@ static rsRetVal doGetSize(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void * case 'K': i *= 1000; ++(*pp); break; case 'M': i *= 1000000; ++(*pp); break; case 'G': i *= 1000000000; ++(*pp); break; - case 'T': i *= 1000000000000; ++(*pp); break; /* tera */ - case 'P': i *= 1000000000000000; ++(*pp); break; /* peta */ - case 'E': i *= 1000000000000000000; ++(*pp); break; /* exa */ + /* we need to use the multiplication below because otherwise + * the compiler gets an error during constant parsing */ + case 'T': i *= (int64) 1000 * 1000000000; ++(*pp); break; /* tera */ + case 'P': i *= (int64) 1000000 * 1000000000; ++(*pp); break; /* peta */ + case 'E': i *= (int64) 1000000000 * 1000000000; ++(*pp); break; /* exa */ } /* done */ -- cgit From 0a1d0172d3e0ffa395cfc37f38d48cf948508b25 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 12 Apr 2010 09:10:27 +0200 Subject: adopted rsf_getenv.sh test case to new tcpflood calling conventions --- tests/rsf_getenv.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rsf_getenv.sh b/tests/rsf_getenv.sh index 42de20fe..fd083bce 100755 --- a/tests/rsf_getenv.sh +++ b/tests/rsf_getenv.sh @@ -9,7 +9,7 @@ echo \[rsf_getenv.sh\]: testing RainerScript getenv\(\) function export MSGNUM="msgnum:" source $srcdir/diag.sh init source $srcdir/diag.sh startup rsf_getenv.conf -source $srcdir/diag.sh tcpflood 127.0.0.1 13514 1 10000 +source $srcdir/diag.sh tcpflood -m10000 source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages source $srcdir/diag.sh wait-shutdown source $srcdir/diag.sh seq-check 0 9999 -- cgit From 9cb14f56572ec3def8b294a12b448b1796418d7b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 12 Apr 2010 09:14:26 +0200 Subject: mentioned new Solaris support in ChangeLog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index a5bcefde..f682ad72 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ --------------------------------------------------------------------------- Version 4.7.0 [v4-devel] (rgerhards), 2009-09-?? +- new: support for Solaris added (but not yet the Solaris door API) - added function getenv() to RainerScript - added new config option $InputUnixListenSocketCreatePath to permit the auto-creation of pathes to additional log sockets. This -- cgit From 9eee9d8d3dc8d8254c6d781d11513bbfcb807090 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 12 Apr 2010 12:59:09 +0200 Subject: bugfix/testbench: nettester did not work reliably under Solaris --- tests/nettester.c | 70 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/tests/nettester.c b/tests/nettester.c index eff5929b..24e20422 100644 --- a/tests/nettester.c +++ b/tests/nettester.c @@ -117,6 +117,10 @@ void readLine(int fd, char *ln) * We use traditional framing '\n' at EOR for this tester. It may be * worth considering additional framing modes. * rgerhards, 2009-04-08 + * Note: we re-create the socket within the retry loop, because this + * seems to be needed under Solaris. If we do not do that, we run + * into troubles (maybe something wrongly initialized then?) + * -- rgerhards, 2010-04-12 */ int tcpSend(char *buf, int lenBuf) @@ -124,30 +128,34 @@ tcpSend(char *buf, int lenBuf) static int sock = INVALID_SOCKET; struct sockaddr_in addr; int retries; + int ret; + int iRet = 0; /* 0 OK, anything else error */ if(sock == INVALID_SOCKET) { /* first time, need to connect to target */ - if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) { - perror("socket()"); - return(1); - } - - memset((char *) &addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(iPort); - if(inet_aton("127.0.0.1", &addr.sin_addr)==0) { - fprintf(stderr, "inet_aton() failed\n"); - return(1); - } retries = 0; while(1) { /* loop broken inside */ - if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) { + /* first time, need to connect to target */ + if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) { + perror("socket()"); + iRet = 1; + goto finalize_it; + } + memset((char *) &addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(iPort); + if(inet_aton("127.0.0.1", &addr.sin_addr)==0) { + fprintf(stderr, "inet_aton() failed\n"); + iRet = 1; + goto finalize_it; + } + if((ret = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) == 0) { break; } else { if(retries++ == 50) { - ++iFailed; fprintf(stderr, "connect() failed\n"); - return(1); + iRet = 1; + goto finalize_it; } else { usleep(100000); /* 0.1 sec, these are us! */ } @@ -156,20 +164,32 @@ tcpSend(char *buf, int lenBuf) } /* send test data */ - if(send(sock, buf, lenBuf, 0) != lenBuf) { + if((ret = send(sock, buf, lenBuf, 0)) != lenBuf) { perror("send test data"); - fprintf(stderr, "send() failed\n"); - return(1); + fprintf(stderr, "send() failed, sock=%d, ret=%d\n", sock, ret); + iRet = 1; + goto finalize_it; } /* send record terminator */ if(send(sock, "\n", 1, 0) != 1) { perror("send record terminator"); fprintf(stderr, "send() failed\n"); - return(1); + iRet = 1; + goto finalize_it; } - return 0; +finalize_it: + if(iRet != 0) { + /* need to do some (common) cleanup */ + if(sock != INVALID_SOCKET) { + close(sock); + sock = INVALID_SOCKET; + } + ++iFailed; + } + + return iRet; } @@ -242,6 +262,7 @@ int openPipe(char *configFile, pid_t *pid, int *pfd) fclose(stdin); execve("../tools/rsyslogd", newargv, ourEnvp); } else { + usleep(10000); close(pipefd[1]); *pid = cpid; *pfd = pipefd[0]; @@ -361,6 +382,7 @@ processTestFile(int fd, char *pszFileName) expected[strlen(expected)-1] = '\0'; /* remove \n */ /* pull response from server and then check if it meets our expectation */ +//printf("try pull pipe...\n"); readLine(fd, buf); if(strcmp(expected, buf)) { ++iFailed; @@ -423,7 +445,8 @@ doTests(int fd, char *files) printf("Error: no test cases found, no tests executed.\n"); iFailed = 1; } else { - printf("Number of tests run: %d, number of failures: %d\n", iTests, iFailed); + printf("Number of tests run: %3d, number of failures: %d, test: %s/%s\n", + iTests, iFailed, testSuite, inputMode2Str(inputMode)); } return(iFailed); @@ -515,6 +538,11 @@ int main(int argc, char *argv[], char *envp[]) } fclose(fp); + /* make sure we do not abort if there is an issue with pipes. + * our code does the necessary error handling. + */ + sigset(SIGPIPE, SIG_IGN); + /* start to be tested rsyslogd */ openPipe(testSuite, &rsyslogdPid, &fd); readLine(fd, buf); -- cgit From 2a8d484a73654c26e427a11fb10162a41a7be79d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 12 Apr 2010 17:09:50 +0200 Subject: some cleanup of solaris imklog --- plugins/imklog/solaris.c | 9 ++++--- plugins/imklog/solaris_cddl.c | 62 +++++++++++-------------------------------- plugins/imklog/solaris_cddl.h | 1 + 3 files changed, 23 insertions(+), 49 deletions(-) diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index c2aec30a..8a6d5af1 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -42,6 +42,7 @@ #include "rsyslog.h" #include "imklog.h" +#include "srUtils.h" #include "unicode-helper.h" #include "solaris_cddl.h" @@ -70,8 +71,8 @@ klogWillRun(void) char errStr[1024]; int err = errno; rs_strerror_r(err, errStr, sizeof(errStr)); - DBGPRINTF("error %d opening log socket: %s\n", - GetPath(), errStr); + DBGPRINTF("error %s opening log socket: %s\n", + errStr, GetPath()); iRet = RS_RET_ERR; // TODO: better error code } @@ -79,6 +80,7 @@ klogWillRun(void) } +#if 0 /* Read /dev/klog while data are available, split into lines. * Contrary to standard BSD syslogd, we do a blocking read. We can * afford this as imklog is running on its own threads. So if we have @@ -125,7 +127,7 @@ readklog(void) break; } - for (p = pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) { + for(p = pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) { *q = '\0'; Syslog(LOG_INFO, (uchar*) p); } @@ -143,6 +145,7 @@ readklog(void) if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) free(pRcv); } +#endif /* to be called in the module's AfterRun entry point diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index 1053de66..7e86c68c 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -1,4 +1,3 @@ -#define MAXLINE 4096 /* * CDDL HEADER START * @@ -53,6 +52,15 @@ #include #include "rsyslog.h" +#include "imklog.h" + +/* TODO: this define should be changed over time to the more generic + * system-provided (configurable) upper limit. However, it is quite + * unexpected that Solaris-emitted messages are so long, so it seems + * acceptable to set a fixed (relatively high) limit for the time + * being -- and gain some experience with it. -- rgerhars, 2010-04-12 + */ +#define MAXLINE 4096 static struct pollfd Pfd; /* Pollfd for local the log device */ @@ -70,11 +78,6 @@ findnl_bkwd(const char *buf, const size_t len) { const char *p; size_t mb_cur_max; - pthread_t mythreadno; - - if (Debug) { - mythreadno = pthread_self(); - } if (len == 0) { return (0); @@ -104,8 +107,7 @@ findnl_bkwd(const char *buf, const size_t len) /* * Invalid character found. */ - dbgprintf("klog:findnl_bkwd(%u): Invalid MB " - "sequence\n", mythreadno); + dbgprintf("klog:findnl_bkwd: Invalid MB sequence\n"); /* * handle as a single byte character. */ @@ -148,7 +150,6 @@ sun_openklog(char *name, int mode) struct strioctl str; if ((fd = open(name, mode)) < 0) { - //logerror("cannot open %s", name); dbgprintf("klog:openklog: cannot open %s (%d)\n", name, errno); return (-1); @@ -158,7 +159,6 @@ sun_openklog(char *name, int mode) str.ic_len = 0; str.ic_dp = NULL; if (ioctl(fd, I_STR, &str) < 0) { - //logerror("cannot register to log console messages"); dbgprintf("klog:openklog: cannot register to log " "console messages (%d)\n", errno); return (-1); @@ -200,18 +200,7 @@ sun_getkmsg() (void) memcpy(tmpbuf, buf, len); tmpbuf[len] = '\0'; - /* Format sys will enqueue the log message. - * Set the sync flag if timeout != 0, which - * means that we're done handling all the - * initial messages ready during startup. - */ - Syslog(LOG_INFO, buf); - /*if (timeout == 0) { - formatsys(&hdr, tmpbuf, 0); - //sys_init_msg_count++; - } else { - formatsys(&hdr, tmpbuf, 1); - }*/ + Syslog(LOG_INFO, (uchar*) buf); if (len != buflen) { /* If anything remains in buf */ @@ -238,8 +227,7 @@ sun_getkmsg() if (i == 0 && dat.len > 0) { dat.buf[dat.len] = '\0'; - /* - * Format sys will enqueue the log message. + /* Format sys will enqueue the log message. * Set the sync flag if timeout != 0, which * means that we're done handling all the * initial messages ready during startup. @@ -249,15 +237,9 @@ sun_getkmsg() dbgprintf("klog:getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf)); dbgprintf("klog:getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf); dbgprintf("klog:getkmsg: buf len = %d\n", strlen(buf)); - //if (timeout == 0) { - //formatsys(&hdr, buf, 0); - //--sys_init_msg_count++; - //} else { - //formatsys(&hdr, buf, 1); - //} - Syslog(LOG_INFO, buf); + Syslog(LOG_INFO, (uchar*) buf); } else if (i < 0 && errno != EINTR) { - if(1){ // (!shutting_down) { + if(1){ /* V5-TODO: rsyslog-like termination! (!shutting_down) { */ dbgprintf("klog:kernel log driver read error"); } // TODO trigger retry logic @@ -279,15 +261,6 @@ sun_sys_poll() dbgprintf("klog:sys_poll: sys_thread started\n"); - /* - * Try to process as many messages as we can without blocking on poll. - * We count such "initial" messages with sys_init_msg_count and - * enqueue them without the SYNC_FILE flag. When no more data is - * waiting on the local log device, we set timeout to INFTIM, - * clear sys_init_msg_count, and generate a flush message to sync - * the previously counted initial messages out to disk. - */ - for (;;) { errno = 0; @@ -298,16 +271,13 @@ sun_sys_poll() if (nfds < 0) { if (errno != EINTR) - dbgprintf("klog:poll error");// logerror("poll"); + dbgprintf("klog:poll error"); continue; } if (Pfd.revents & POLLIN) { sun_getkmsg(); } else { - // TODO: shutdown, the rsyslog way (in v5!) - //if (shutting_down) { - //pthread_exit(0); - //} + /* TODO: shutdown, the rsyslog way (in v5!) -- check shutdown flag */ if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { // TODO: trigger retry logic /* logerror("kernel log driver poll error"); diff --git a/plugins/imklog/solaris_cddl.h b/plugins/imklog/solaris_cddl.h index 22295658..d48ef628 100644 --- a/plugins/imklog/solaris_cddl.h +++ b/plugins/imklog/solaris_cddl.h @@ -1 +1,2 @@ +void *sun_sys_poll(); int sun_openklog(char *name, int mode); -- cgit From 54ae07e33cf28aead4d9318dfc28762cb7211a22 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 14 Apr 2010 08:30:15 +0200 Subject: slightly improved/cleaned up debugging system --- runtime/debug.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/runtime/debug.c b/runtime/debug.c index c82a411d..da471609 100644 --- a/runtime/debug.c +++ b/runtime/debug.c @@ -154,7 +154,9 @@ static pthread_key_t keyCallStack; */ static void dbgMutexCancelCleanupHdlr(void *pmut) { - pthread_mutex_unlock((pthread_mutex_t*) pmut); + int ret; + ret = pthread_mutex_unlock((pthread_mutex_t*) pmut); + assert(ret == 0); } @@ -846,6 +848,7 @@ dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg) size_t lenWriteBuf; struct timespec t; uchar *pszObjName = NULL; + int ret; /* we must get the object name before we lock the mutex, because the object * potentially calls back into us. If we locked the mutex, we would deadlock @@ -857,7 +860,8 @@ dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg) pszObjName = obj.GetName(pObj); } - pthread_mutex_lock(&mutdbgprint); + ret = pthread_mutex_lock(&mutdbgprint); + assert(ret == 0); /* make sure mutex operation does not fail */ pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint); /* The bWasNL handler does not really work. It works if no thread @@ -941,6 +945,15 @@ dbgoprint(obj_t *pObj, char *fmt, ...) va_start(ap, fmt); lenWriteBuf = vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap); va_end(ap); + if(lenWriteBuf >= sizeof(pszWriteBuf)) { + /* prevent buffer overrruns and garbagge display */ + pszWriteBuf[sizeof(pszWriteBuf) - 5] = '.'; + pszWriteBuf[sizeof(pszWriteBuf) - 4] = '.'; + pszWriteBuf[sizeof(pszWriteBuf) - 3] = '.'; + pszWriteBuf[sizeof(pszWriteBuf) - 2] = '\n'; + pszWriteBuf[sizeof(pszWriteBuf) - 1] = '\0'; + lenWriteBuf = sizeof(pszWriteBuf); + } dbgprint(pObj, pszWriteBuf, lenWriteBuf); } @@ -952,7 +965,7 @@ void dbgprintf(char *fmt, ...) { va_list ap; - char pszWriteBuf[20480]; + char pszWriteBuf[32*1024]; size_t lenWriteBuf; if(!(Debug && debugging_on)) -- cgit From f0e1a6588f96820a785b6b1940efcfad7ff85625 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 14 Apr 2010 16:25:52 +0200 Subject: preparing for 4.7.0 --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 8fc06ec0..9232528e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 4.7.0 [v4-devel] (rgerhards), 2009-09-?? +Version 4.7.0 [v4-devel] (rgerhards), 2010-04-14 - new: support for Solaris added (but not yet the Solaris door API) - added function getenv() to RainerScript - added new config option $InputUnixListenSocketCreatePath -- cgit From b00e7946e8dec90270f35c1060ac6d0abfe9df3e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 15 Apr 2010 17:59:38 +0200 Subject: first version of imsolaris created, cleanup for solaris done more cleanup required, but things now basically work --- ChangeLog | 6 + Makefile.am | 4 +- configure.ac | 18 +- plugins/imdoor/Makefile.am | 6 - plugins/imdoor/imdoor.c | 430 ------------------------------ plugins/imdoor/sun_cddl.c | 592 ------------------------------------------ plugins/imklog/Makefile.am | 4 - plugins/imsolaris/Makefile.am | 6 + plugins/imsolaris/imsolaris.c | 281 ++++++++++++++++++++ plugins/imsolaris/sun_cddl.c | 532 +++++++++++++++++++++++++++++++++++++ plugins/imsolaris/sun_cddl.h | 5 + runtime/rsyslog.h | 2 + 12 files changed, 843 insertions(+), 1043 deletions(-) delete mode 100644 plugins/imdoor/Makefile.am delete mode 100644 plugins/imdoor/imdoor.c delete mode 100644 plugins/imdoor/sun_cddl.c create mode 100644 plugins/imsolaris/Makefile.am create mode 100644 plugins/imsolaris/imsolaris.c create mode 100644 plugins/imsolaris/sun_cddl.c create mode 100644 plugins/imsolaris/sun_cddl.h diff --git a/ChangeLog b/ChangeLog index 9232528e..d0cab9e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ --------------------------------------------------------------------------- +Version 4.7.1 [v4-devel] (rgerhards), 2010-04-?? +- Solaris support much improved -- was not truely usable in 4.7.0 + Solaris is no longer supported in imklog, but rather there is a new + plugin imsolaris, which is used to pull local log sources on a Solaris + machine. +--------------------------------------------------------------------------- Version 4.7.0 [v4-devel] (rgerhards), 2010-04-14 - new: support for Solaris added (but not yet the Solaris door API) - added function getenv() to RainerScript diff --git a/Makefile.am b/Makefile.am index a02fa6a2..8401606a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -59,8 +59,8 @@ if ENABLE_IMKLOG SUBDIRS += plugins/imklog endif -if ENABLE_IMDOOR -SUBDIRS += plugins/imdoor +if ENABLE_IMSOLARIS +SUBDIRS += plugins/imsolaris endif if ENABLE_GSSAPI diff --git a/configure.ac b/configure.ac index a6ac2abc..287534cd 100644 --- a/configure.ac +++ b/configure.ac @@ -748,16 +748,16 @@ AM_CONDITIONAL(ENABLE_IMFILE, test x$enable_imfile = xyes) # settings for the door input module (under solaris, thus default off) -AC_ARG_ENABLE(imdoor, - [AS_HELP_STRING([--enable-imdoor],[door input module enabled @<:@default=no@:>@])], +AC_ARG_ENABLE(imsolaris, + [AS_HELP_STRING([--enable-imsolaris],[door input module enabled @<:@default=no@:>@])], [case "${enableval}" in - yes) enable_imdoor="yes" ;; - no) enable_imdoor="no" ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-imdoor) ;; + yes) enable_imsolaris="yes" ;; + no) enable_imsolaris="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-imsolaris) ;; esac], - [enable_imdoor=no] + [enable_imsolaris=no] ) -AM_CONDITIONAL(ENABLE_IMDOOR, test x$enable_imdoor = xyes) +AM_CONDITIONAL(ENABLE_IMSOLARIS, test x$enable_imsolaris = xyes) # settings for the omprog output module @@ -861,7 +861,7 @@ AC_CONFIG_FILES([Makefile \ plugins/omprog/Makefile \ plugins/omstdout/Makefile \ plugins/imfile/Makefile \ - plugins/imdoor/Makefile \ + plugins/imsolaris/Makefile \ plugins/imrelp/Makefile \ plugins/imdiag/Makefile \ plugins/omtesting/Makefile \ @@ -894,7 +894,7 @@ echo "---{ input plugins }---" echo " Klog functionality enabled: $enable_klog ($os_type)" echo " imdiag enabled: $enable_imdiag" echo " file input module enabled: $enable_imfile" -echo " Solaris door input module enabled: $enable_imdoor" +echo " Solaris input module enabled: $enable_imsolaris" echo " input template module will be compiled: $enable_imtemplate" echo echo "---{ output plugins }---" diff --git a/plugins/imdoor/Makefile.am b/plugins/imdoor/Makefile.am deleted file mode 100644 index 6ad7a904..00000000 --- a/plugins/imdoor/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -pkglib_LTLIBRARIES = imdoor.la - -imdoor_la_SOURCES = imdoor.c sun_cddl.c -imdoor_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) -imdoor_la_LDFLAGS = -module -avoid-version -imdoor_la_LIBADD = diff --git a/plugins/imdoor/imdoor.c b/plugins/imdoor/imdoor.c deleted file mode 100644 index 83890d03..00000000 --- a/plugins/imdoor/imdoor.c +++ /dev/null @@ -1,430 +0,0 @@ -/* imdoor.c - * This input module is used to receive syslog messages via the Solaris - * door mechanism. Not surprisingly, it most probably can not be built - * on other platforms. - * - * NOTE: read comments in module-template.h to understand how this file - * works! - * - * File begun on 2010-03-26 by RGerhards - * - * Copyright 2010 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 . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#include "config.h" -#include "rsyslog.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "dirty.h" -#include "cfsysline.h" -#include "unicode-helper.h" -#include "module-template.h" -#include "srUtils.h" -#include "errmsg.h" -#include "net.h" -#include "glbl.h" -#include "msg.h" -#include "prop.h" - -MODULE_TYPE_INPUT - -/* defines */ -#define MAXFUNIX 20 -#ifndef _PATH_LOG -#ifdef BSD -#define _PATH_LOG "/var/run/log" -#else -#define _PATH_LOG "/dev/log" -#endif -#endif - - -/* handle some defines missing on more than one platform */ -#ifndef SUN_LEN -#define SUN_LEN(su) \ - (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) -#endif -/* Module static data */ -DEF_IMOD_STATIC_DATA -DEFobjCurrIf(errmsg) -DEFobjCurrIf(glbl) -DEFobjCurrIf(prop) - -static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */ -static int startIndexUxLocalSockets; /* process funix from that index on (used to - * suppress local logging. rgerhards 2005-08-01 - * read-only after startup - */ -static int funixParseHost[MAXFUNIX] = { 0, }; /* should parser parse host name? read-only after startup */ -static int funixFlags[MAXFUNIX] = { IGNDATE, }; /* should parser parse host name? read-only after startup */ -static uchar *funixn[MAXFUNIX] = { (uchar*) _PATH_LOG }; /* read-only after startup */ -static uchar *funixHName[MAXFUNIX] = { NULL, }; /* host-name override - if set, use this instead of actual name */ -static int funixFlowCtl[MAXFUNIX] = { eFLOWCTL_NO_DELAY, }; /* flow control settings for this socket */ -static int funix[MAXFUNIX] = { -1, }; /* read-only after startup */ -static int nfunix = 1; /* number of Unix sockets open / read-only after startup */ - -/* config settings */ -static int bOmitLocalLogging = 0; -static uchar *pLogSockName = NULL; -static uchar *pLogHostName = NULL; /* host name to use with this socket */ -static int bUseFlowCtl = 0; /* use flow control or not (if yes, only LIGHT is used! */ -static int bIgnoreTimestamp = 1; /* ignore timestamps present in the incoming message? */ - - -/* set the timestamp ignore / not ignore option for the system - * log socket. This must be done separtely, as it is not added via a command - * but present by default. -- rgerhards, 2008-03-06 - */ -static rsRetVal setSystemLogTimestampIgnore(void __attribute__((unused)) *pVal, int iNewVal) -{ - DEFiRet; - funixFlags[0] = iNewVal ? IGNDATE : NOFLAG; - RETiRet; -} - -/* set flowcontrol for the system log socket - */ -static rsRetVal setSystemLogFlowControl(void __attribute__((unused)) *pVal, int iNewVal) -{ - DEFiRet; - funixFlowCtl[0] = iNewVal ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; - RETiRet; -} - -/* add an additional listen socket. Socket names are added - * until the array is filled up. It is never reset, only at - * module unload. - * TODO: we should change the array to a list so that we - * can support any number of listen socket names. - * rgerhards, 2007-12-20 - * added capability to specify hostname for socket -- rgerhards, 2008-08-01 - */ -static rsRetVal addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNewVal) -{ - if(nfunix < MAXFUNIX) { - if(*pNewVal == ':') { - funixParseHost[nfunix] = 1; - } - else { - funixParseHost[nfunix] = 0; - } - funixHName[nfunix] = pLogHostName; - pLogHostName = NULL; /* re-init for next, not freed because funixHName[] now owns it */ - funixFlowCtl[nfunix] = bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; - funixFlags[nfunix] = bIgnoreTimestamp ? IGNDATE : NOFLAG; - funixn[nfunix++] = pNewVal; - } - else { - errmsg.LogError(0, NO_ERRCODE, "Out of unix socket name descriptors, ignoring %s\n", - pNewVal); - } - - return RS_RET_OK; -} - -/* free the funixn[] socket names - needed as cleanup on several places - * note that nfunix is NOT reset! funixn[0] is never freed, as it comes from - * the constant memory pool - and if not, it is freeed via some other pointer. - */ -static rsRetVal discardFunixn(void) -{ - int i; - - for (i = 1; i < nfunix; i++) { - if(funixn[i] != NULL) { - free(funixn[i]); - funixn[i] = NULL; - } - if(funixHName[i] != NULL) { - free(funixHName[i]); - funixHName[i] = NULL; - } - } - - return RS_RET_OK; -} - - -static int create_unix_socket(const char *path) -{ - struct sockaddr_un sunx; - int fd; - - if (path[0] == '\0') - return -1; - - unlink(path); - - memset(&sunx, 0, sizeof(sunx)); - sunx.sun_family = AF_UNIX; - (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); - fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || - chmod(path, 0666) < 0) { - errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path); - dbgprintf("cannot create %s (%d).\n", path, errno); - close(fd); - return -1; - } - return fd; -} - - -/* This function receives data from a socket indicated to be ready - * to receive and submits the message received for processing. - * rgerhards, 2007-12-20 - * Interface changed so that this function is passed the array index - * of the socket which is to be processed. This eases access to the - * growing number of properties. -- rgerhards, 2008-08-01 - */ -static rsRetVal readSocket(int fd, int iSock) -{ - DEFiRet; - int iRcvd; - int iMaxLine; - uchar bufRcv[4096+1]; - uchar *pRcv = NULL; /* receive buffer */ - - assert(iSock >= 0); - - iMaxLine = glbl.GetMaxLine(); - - /* we optimize performance: if iMaxLine is below 4K (which it is in almost all - * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory - * is used. We could use alloca() to achive a similar aspect, but there are so - * many issues with alloca() that I do not want to take that route. - * rgerhards, 2008-09-02 - */ - if((size_t) iMaxLine < sizeof(bufRcv) - 1) { - pRcv = bufRcv; - } else { - CHKmalloc(pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))); - } - - iRcvd = recv(fd, pRcv, iMaxLine, 0); - dbgprintf("Message from UNIX socket: #%d\n", fd); - if (iRcvd > 0) { - parseAndSubmitMessage(funixHName[iSock] == NULL ? glbl.GetLocalHostName() : funixHName[iSock], - (uchar*)"127.0.0.1", pRcv, - iRcvd, funixParseHost[iSock] ? (funixFlags[iSock] | PARSE_HOSTNAME) : funixFlags[iSock], - funixFlowCtl[iSock], pInputName, NULL, 0); - } else if (iRcvd < 0 && errno != EINTR) { - char errStr[1024]; - rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("UNIX socket error: %d = %s.\n", errno, errStr); - errmsg.LogError(errno, NO_ERRCODE, "recvfrom UNIX"); - } - -finalize_it: - if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) - free(pRcv); - - RETiRet; -} - - -/* This function is called to gather input. */ -BEGINrunInput - int maxfds; - int nfds; - int i; - int fd; - fd_set readfds; -CODESTARTrunInput - /* this is an endless loop - it is terminated when the thread is - * signalled to do so. This, however, is handled by the framework, - * right into the sleep below. - */ - while(1) { - /* Add the Unix Domain Sockets to the list of read - * descriptors. - * rgerhards 2005-08-01: we must now check if there are - * any local sockets to listen to at all. If the -o option - * is given without -a, we do not need to listen at all.. - */ - maxfds = 0; - FD_ZERO (&readfds); - /* Copy master connections */ - for (i = startIndexUxLocalSockets; i < nfunix; i++) { - if (funix[i] != -1) { - FD_SET(funix[i], &readfds); - if (funix[i]>maxfds) maxfds=funix[i]; - } - } - - if(Debug) { - dbgprintf("--------imuxsock calling select, active file descriptors (max %d): ", maxfds); - for (nfds= 0; nfds <= maxfds; ++nfds) - if ( FD_ISSET(nfds, &readfds) ) - dbgprintf("%d ", nfds); - dbgprintf("\n"); - } - - /* wait for io to become ready */ - nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL); - - for (i = 0; i < nfunix && nfds > 0; i++) { - if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) { - readSocket(fd, i); - --nfds; /* indicate we have processed one */ - } - } - } - - RETiRet; -ENDrunInput - - -BEGINwillRun -CODESTARTwillRun - register int i; - - /* first apply some config settings */ - startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0; - if(pLogSockName != NULL) - funixn[0] = pLogSockName; - - /* initialize and return if will run or not */ - for (i = startIndexUxLocalSockets ; i < nfunix ; i++) { - if ((funix[i] = create_unix_socket((char*) funixn[i])) != -1) - dbgprintf("Opened UNIX socket '%s' (fd %d).\n", funixn[i], funix[i]); - } - - /* we need to create the inputName property (only once during our lifetime) */ - CHKiRet(prop.Construct(&pInputName)); - CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imuxsock"), sizeof("imuxsock") - 1)); - CHKiRet(prop.ConstructFinalize(pInputName)); - -finalize_it: -ENDwillRun - - -BEGINafterRun -CODESTARTafterRun - int i; - /* do cleanup here */ - /* Close the UNIX sockets. */ - for (i = 0; i < nfunix; i++) - if (funix[i] != -1) - close(funix[i]); - - /* Clean-up files. */ - for (i = 0; i < nfunix; i++) - if (funixn[i] && funix[i] != -1) - unlink((char*) funixn[i]); - /* free no longer needed string */ - if(pLogSockName != NULL) - free(pLogSockName); - if(pLogHostName != NULL) { - free(pLogHostName); - } - - discardFunixn(); - nfunix = 1; - - if(pInputName != NULL) - prop.Destruct(&pInputName); -ENDafterRun - - -BEGINmodExit -CODESTARTmodExit - objRelease(glbl, CORE_COMPONENT); - objRelease(errmsg, CORE_COMPONENT); - objRelease(prop, CORE_COMPONENT); -ENDmodExit - - -BEGINqueryEtryPt -CODESTARTqueryEtryPt -CODEqueryEtryPt_STD_IMOD_QUERIES -ENDqueryEtryPt - -static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) -{ - bOmitLocalLogging = 0; - if(pLogSockName != NULL) { - free(pLogSockName); - pLogSockName = NULL; - } - if(pLogHostName != NULL) { - free(pLogHostName); - pLogHostName = NULL; - } - - discardFunixn(); - nfunix = 1; - bIgnoreTimestamp = 1; - bUseFlowCtl = 0; - - return RS_RET_OK; -} - - -BEGINmodInit() - int i; -CODESTARTmodInit - *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ -CODEmodInit_QueryRegCFSLineHdlr - CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(objUse(glbl, CORE_COMPONENT)); - CHKiRet(objUse(prop, CORE_COMPONENT)); - - dbgprintf("imuxsock version %s initializing\n", PACKAGE_VERSION); - - /* initialize funixn[] array */ - for(i = 1 ; i < MAXFUNIX ; ++i) { - funixn[i] = NULL; - funix[i] = -1; - } - - /* register config file handlers */ - CHKiRet(omsdRegCFSLineHdlr((uchar *)"omitlocallogging", 0, eCmdHdlrBinary, - NULL, &bOmitLocalLogging, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketignoremsgtimestamp", 0, eCmdHdlrBinary, - NULL, &bIgnoreTimestamp, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketname", 0, eCmdHdlrGetWord, - NULL, &pLogSockName, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensockethostname", 0, eCmdHdlrGetWord, - NULL, &pLogHostName, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary, - NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord, - addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, - resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); - /* the following one is a (dirty) trick: the system log socket is not added via - * an "addUnixListenSocket" config format. As such, it's properties can not be modified - * via $InputUnixListenSocket*". So we need to add a special directive - * for that. We should revisit all of that once we have the new config format... - * rgerhards, 2008-03-06 - */ - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketignoremsgtimestamp", 0, eCmdHdlrBinary, - setSystemLogTimestampIgnore, NULL, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketflowcontrol", 0, eCmdHdlrBinary, - setSystemLogFlowControl, NULL, STD_LOADABLE_MODULE_ID)); -ENDmodInit -/* vim:set ai: - */ diff --git a/plugins/imdoor/sun_cddl.c b/plugins/imdoor/sun_cddl.c deleted file mode 100644 index 8e9714d9..00000000 --- a/plugins/imdoor/sun_cddl.c +++ /dev/null @@ -1,592 +0,0 @@ -#define MAXLINE 4096 -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* Portions Copyright 2010 by Rainer Gerhards and Adiscon - */ -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T - * All Rights Reserved - */ - -/* - * University Copyright- Copyright (c) 1982, 1986, 1988 - * The Regents of the University of California - * All Rights Reserved - * - * University Acknowledgment- Portions of this document are derived from - * software developed by the University of California, Berkeley, and its - * contributors. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rsyslog.h" -#include "debug.h" - -#define DOORFILE "/var/run/syslog_door" -#define RELATIVE_DOORFILE "../var/run/syslog_door" -#define OLD_DOORFILE "/etc/.syslog_door" - -static int DoorFd = -1; -static int DoorCreated = 0; -static char *DoorFileName = DOORFILE; - -/* for managing door server threads */ -static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER; -static uint_t door_server_cnt = 0; -static pthread_attr_t door_thr_attr; - -/* - * the 'server' function that we export via the door. It does - * nothing but return. - */ -/*ARGSUSED*/ -static void -server(void *cookie, char *argp, size_t arg_size, - door_desc_t *dp, uint_t n) -{ - (void) door_return(NULL, 0, NULL, 0); - /* NOTREACHED */ -} - -/*ARGSUSED*/ -static void * -create_door_thr(void *arg) -{ - (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - (void) door_return(NULL, 0, NULL, 0); - - /* - * If there is an error in door_return(), it will return here and - * the thread will exit. Hence we need to decrement door_server_cnt. - */ - (void) pthread_mutex_lock(&door_server_cnt_lock); - door_server_cnt--; - (void) pthread_mutex_unlock(&door_server_cnt_lock); - return (NULL); -} - -/* - * Max number of door server threads for syslogd. Since door is used - * to check the health of syslogd, we don't need large number of - * server threads. - */ -#define MAX_DOOR_SERVER_THR 3 - -/* - * Manage door server thread pool. - */ -/*ARGSUSED*/ -static void -door_server_pool(door_info_t *dip) -{ - (void) pthread_mutex_lock(&door_server_cnt_lock); - if (door_server_cnt <= MAX_DOOR_SERVER_THR && - pthread_create(NULL, &door_thr_attr, create_door_thr, NULL) == 0) { - door_server_cnt++; - (void) pthread_mutex_unlock(&door_server_cnt_lock); - return; - } - - (void) pthread_mutex_unlock(&door_server_cnt_lock); -} - -static void -delete_doorfiles(void) -{ - pthread_t mythreadno; - struct stat sb; - int err; - char line[MAXLINE+1]; - - if (Debug) { - mythreadno = pthread_self(); - } - - - if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { - if (unlink(DoorFileName) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "unlink() of %s failed - fatal", DoorFileName); - errno = err; - DBGPRINTF("%s", line);//logerror(line); - DBGPRINTF("delete_doorfiles(%u): error: %s, " - "errno=%d\n", mythreadno, line, err); - exit(1); - } - - DBGPRINTF("delete_doorfiles(%u): deleted %s\n", - mythreadno, DoorFileName); - } - - if (strcmp(DoorFileName, DOORFILE) == 0) { - if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) { - if (unlink(OLD_DOORFILE) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "unlink() of %s failed", OLD_DOORFILE); - DBGPRINTF("delete_doorfiles(%u): %s\n", - mythreadno, line); - - if (err != EROFS) { - errno = err; - (void) strlcat(line, " - fatal", - sizeof (line)); - logerror(line); - DBGPRINTF("delete_doorfiles(%u): " - "error: %s, errno=%d\n", - mythreadno, line, err); - exit(1); - } - - DBGPRINTF("delete_doorfiles(%u): unlink() " - "failure OK on RO file system\n", - mythreadno); - } - - DBGPRINTF("delete_doorfiles(%u): deleted %s\n", - mythreadno, OLD_DOORFILE); - } - } - -#if 0 - if (lstat(PidFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { - if (unlink(PidFileName) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "unlink() of %s failed - fatal", PidFileName); - errno = err; - logerror(line); - DBGPRINTF("delete_doorfiles(%u): error: %s, " - "errno=%d\n", mythreadno, line, err); - exit(1); - } - - DBGPRINTF("delete_doorfiles(%u): deleted %s\n", mythreadno, - PidFileName); - } - - if (strcmp(PidFileName, PIDFILE) == 0) { - if (lstat(OLD_PIDFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) { - if (unlink(OLD_PIDFILE) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "unlink() of %s failed", OLD_PIDFILE); - DBGPRINTF(5, "delete_doorfiles(%u): %s, \n", - mythreadno, line); - - if (err != EROFS) { - errno = err; - (void) strlcat(line, " - fatal", - sizeof (line)); - logerror(line); - DBGPRINTF(1, "delete_doorfiles(%u): " - "error: %s, errno=%d\n", - mythreadno, line, err); - exit(1); - } - - DBGPRINTF(5, "delete_doorfiles(%u): unlink " - "failure OK on RO file system\n", - mythreadno); - } - - DBGPRINTF(5, "delete_doorfiles(%u): deleted %s\n", - mythreadno, OLD_PIDFILE); - } - } -#endif - - if (DoorFd != -1) { - (void) door_revoke(DoorFd); - } - - DBGPRINTF("delete_doorfiles(%u): revoked door: DoorFd=%d\n", - mythreadno, DoorFd); -} - - -/* - * Create the door file and the pid file in /var/run. If the filesystem - * containing /etc is writable, create symlinks /etc/.syslog_door and - * /etc/syslog.pid to them. On systems that do not support /var/run, create - * /etc/.syslog_door and /etc/syslog.pid directly. - * - * Note: it is not considered fatal to fail to create the pid file or its - * symlink. Attempts to use them in the usual way will fail, of course, but - * syslogd will function nicely without it (not so for the door file). - */ - -static void -sun_open_door(void) -{ - struct stat buf; - door_info_t info; - char line[MAXLINE+1]; - pthread_t mythreadno; - int err; - - if (Debug) { - mythreadno = pthread_self(); - } - - /* - * first see if another syslogd is running by trying - * a door call - if it succeeds, there is already - * a syslogd process active - */ - - if (!DoorCreated) { - int door; - - if ((door = open(DoorFileName, O_RDONLY)) >= 0) { - DBGPRINTF("open_door(%u): %s opened " - "successfully\n", mythreadno, DoorFileName); - - if (door_info(door, &info) >= 0) { - DBGPRINTF("open_door(%u): " - "door_info:info.di_target = %ld\n", - mythreadno, info.di_target); - - if (info.di_target > 0) { - (void) sprintf(line, "syslogd pid %ld" - " already running. Cannot " - "start another syslogd pid %ld", - info.di_target, getpid()); - DBGPRINTF("open_door(%u): error: " - "%s\n", mythreadno, line); - errno = 0; - //logerror(line); - exit(1); - } - } - - (void) close(door); - } else { - if (lstat(DoorFileName, &buf) < 0) { - err = errno; - - DBGPRINTF("open_door(%u): lstat() of %s " - "failed, errno=%d\n", - mythreadno, DoorFileName, err); - - if ((door = creat(DoorFileName, 0644)) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "creat() of %s failed - fatal", - DoorFileName); - DBGPRINTF("open_door(%u): error: %s, " - "errno=%d\n", mythreadno, line, - err); - errno = err; - //logerror(line); - delete_doorfiles(); - exit(1); - } - - (void) fchmod(door, - S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - - DBGPRINTF("open_door(%u): creat() of %s " - "succeeded\n", mythreadno, - DoorFileName); - - (void) close(door); - } - } - - if (strcmp(DoorFileName, DOORFILE) == 0) { - if (lstat(OLD_DOORFILE, &buf) == 0) { - DBGPRINTF("open_door(%u): lstat() of %s " - "succeeded\n", mythreadno, - OLD_DOORFILE); - - if (S_ISDIR(buf.st_mode)) { - (void) snprintf(line, sizeof (line), - "%s is a directory - fatal", - OLD_DOORFILE); - DBGPRINTF("open_door(%u): error: " - "%s\n", mythreadno, line); - errno = 0; - //logerror(line); - delete_doorfiles(); - exit(1); - } - - DBGPRINTF("open_door(%u): %s is not a " - "directory\n", - mythreadno, OLD_DOORFILE); - - if (unlink(OLD_DOORFILE) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "unlink() of %s failed", - OLD_DOORFILE); - DBGPRINTF("open_door(%u): %s\n", - mythreadno, line); - - if (err != EROFS) { - DBGPRINTF("open_door(%u): " - "error: %s, " - "errno=%d\n", - mythreadno, line, err); - (void) strcat(line, " - fatal"); - errno = err; - //logerror(line); - delete_doorfiles(); - exit(1); - } - - DBGPRINTF("open_door(%u): unlink " - "failure OK on RO file " - "system\n", mythreadno); - } - } else { - DBGPRINTF("open_door(%u): file %s doesn't " - "exist\n", mythreadno, OLD_DOORFILE); - } - - if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "symlink %s -> %s failed", OLD_DOORFILE, - RELATIVE_DOORFILE); - DBGPRINTF("open_door(%u): %s\n", mythreadno, - line); - - if (err != EROFS) { - DBGPRINTF("open_door(%u): error: %s, " - "errno=%d\n", mythreadno, line, - err); - errno = err; - (void) strcat(line, " - fatal"); - //logerror(line); - delete_doorfiles(); - exit(1); - } - - DBGPRINTF("open_door(%u): symlink failure OK " - "on RO file system\n", mythreadno); - } else { - DBGPRINTF("open_door(%u): symlink %s -> %s " - "succeeded\n", mythreadno, - OLD_DOORFILE, RELATIVE_DOORFILE); - } - } - - if ((DoorFd = door_create(server, 0, - DOOR_REFUSE_DESC)) < 0) { - //???? DOOR_NO_CANEL requires newer libs??? DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { - err = errno; - (void) sprintf(line, "door_create() failed - fatal"); - DBGPRINTF("open_door(%u): error: %s, errno=%d\n", - mythreadno, line, err); - errno = err; - //logerror(line); - delete_doorfiles(); - exit(1); - } - //???? (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0); - DBGPRINTF("open_door(%u): door_create() succeeded, " - "DoorFd=%d\n", mythreadno, DoorFd); - - DoorCreated = 1; - } - - (void) fdetach(DoorFileName); /* just in case... */ - - (void) door_server_create(door_server_pool); - - if (fattach(DoorFd, DoorFileName) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), "fattach() of fd" - " %d to %s failed - fatal", DoorFd, DoorFileName); - DBGPRINTF("open_door(%u): error: %s, errno=%d\n", mythreadno, - line, err); - errno = err; - //logerror(line); - delete_doorfiles(); - exit(1); - } - - DBGPRINTF("open_door(%u): attached server() to %s\n", mythreadno, - DoorFileName); - -#if 0 - /* - * create pidfile anyway, so those using it to control - * syslogd (with kill `cat /etc/syslog.pid` perhaps) - * don't get broken. - */ - - if (!PidfileCreated) { - int pidfd; - - PidfileCreated = 1; - - if ((pidfd = open(PidFileName, O_RDWR|O_CREAT|O_TRUNC, 0644)) - < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "open() of %s failed", PidFileName); - DBGPRINTF(1, "open_door(%u): warning: %s, errno=%d\n", - mythreadno, line, err); - errno = err; - //logerror(line); - return; - } - - (void) fchmod(pidfd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - (void) sprintf(line, "%ld\n", getpid()); - - if (write(pidfd, line, strlen(line)) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "write to %s on fd %d failed", PidFileName, pidfd); - DBGPRINTF(1, "open_door(%u): warning: %s, errno=%d\n", - mythreadno, line, err); - errno = err; - //logerror(line); - return; - } - - (void) close(pidfd); - - DBGPRINTF("open_door(%u): %s created\n", - mythreadno, PidFileName); - - if (strcmp(PidFileName, PIDFILE) == 0) { - if (lstat(OLD_PIDFILE, &buf) == 0) { - DBGPRINTF("open_door(%u): lstat() of %s " - "succeded\n", mythreadno, OLD_PIDFILE); - - if (S_ISDIR(buf.st_mode)) { - (void) snprintf(line, sizeof (line), - "file %s is a directory", - OLD_PIDFILE); - DBGPRINTF("open_door(%u): warning: " - "%s\n", mythreadno, line); - errno = 0; - //logerror(line); - return; - } - - if (unlink(OLD_PIDFILE) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "unlink() of %s failed", - OLD_PIDFILE); - DBGPRINTF("open_door(%u): %s\n", - mythreadno, line); - - if (err != EROFS) { - DBGPRINTF(1, "open_door (%u): " - "warning: %s, " - "errno=%d\n", - mythreadno, line, err); - errno = err; - //logerror(line); - return; - } - - DBGPRINTF(5, "open_door(%u): unlink " - "failure OK on RO file " - "system\n", mythreadno); - } - } else { - DBGPRINTF("open_door(%u): file %s doesn't " - "exist\n", mythreadno, OLD_PIDFILE); - } - - if (symlink(RELATIVE_PIDFILE, OLD_PIDFILE) < 0) { - err = errno; - (void) snprintf(line, sizeof (line), - "symlink %s -> %s failed", OLD_PIDFILE, - RELATIVE_PIDFILE); - DBGPRINTF("open_door(%u): %s\n", mythreadno, - line); - - if (err != EROFS) { - DBGPRINTF(1, "open_door(%u): warning: " - "%s, errno=%d\n", mythreadno, - line, err); - errno = err; - //logerror(line); - return; - } - - DBGPRINTF(5, "open_door(%u): symlink failure OK " - "on RO file system\n", mythreadno); - return; - } - - DBGPRINTF(5, "open_door(%u): symlink %s -> %s " - "succeeded\n", mythreadno, OLD_PIDFILE, - RELATIVE_PIDFILE); - } - } -#endif -} - - diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am index 06d4013c..5d4d0465 100644 --- a/plugins/imklog/Makefile.am +++ b/plugins/imklog/Makefile.am @@ -11,10 +11,6 @@ if ENABLE_IMKLOG_LINUX imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c endif -if ENABLE_IMKLOG_SOLARIS -imklog_la_SOURCES += solaris.c solaris_cddl.c -endif - imklog_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) imklog_la_LDFLAGS = -module -avoid-version imklog_la_LIBADD = diff --git a/plugins/imsolaris/Makefile.am b/plugins/imsolaris/Makefile.am new file mode 100644 index 00000000..2980fc6f --- /dev/null +++ b/plugins/imsolaris/Makefile.am @@ -0,0 +1,6 @@ +pkglib_LTLIBRARIES = imsolaris.la + +imsolaris_la_SOURCES = imsolaris.c sun_cddl.c sun_cddl.h +imsolaris_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) +imsolaris_la_LDFLAGS = -module -avoid-version +imsolaris_la_LIBADD = -ldoor -lpthread diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c new file mode 100644 index 00000000..a2238a29 --- /dev/null +++ b/plugins/imsolaris/imsolaris.c @@ -0,0 +1,281 @@ +/* imsolaris.c + * This input module is used to gather local log data under Solaris. This + * includes messages from local applications AS WELL AS the kernel log. + * I first considered to make all of this available via imklog, but that + * did not lock appropriately on second thought. So I created this module + * that does anything for local message recption. + * + * This module is not meant to be used on plaforms other than Solaris. As + * such, trying to compile it elswhere will probably fail with all sorts + * of errors. + * + * Some notes on the Solaris syslog mechanism: + * Both system (kernel) and application log messages are provided via + * a single message stream. + * + * Solaris checks if the syslogd is running. If so, syslog() emits messages + * to the log socket, only. Otherwise, it emits messages to the console. + * It is possible to gather these console messages as well. However, then + * we clutter the console. + * Solaris does this "syslogd alive check" in a somewhat unexpected way + * (at least unexpected for me): it uses the so-called "door" mechanism, a + * fast RPC facility. I first thought that the door API was used to submit + * the actual syslog messages. But this is not the case. Instead, a door + * call is done, and the server process inside rsyslog simply does NOTHING + * but return. All that Solaris sylsogd() is interested in is if the door + * server (we) responds and thus can be considered alive. The actual message + * is then submitted via the usual stream. I have to admit I do not + * understand why the message itself is not passed via this high-performance + * API. But anyhow, that's nothing I can change, so the most important thing + * is to note how Solaris does this thing ;) + * The syslog() library call checks syslogd state for *each* call (what a + * waste of time...) and decides each time if the message should go to the + * console or not. According to OpenSolaris sources, it looks like there is + * message loss potential when the door file is created before all data has + * been pulled from the stream. While I have to admit that I do not fully + * understand that problem, I will follow the original code advise and do + * one complete pull cycle on the log socket (until it has no further data + * available) and only thereafter create the door file and start the "regular" + * pull cycle. As of my understanding, there is a minimal race between the + * point where the intial pull cycle has ended and the door file is created, + * but that race is also present in OpenSolaris syslogd code, so it should + * not matter that much (plus, I do not know how to avoid it...) + * + * File begun on 2010-04-15 by RGerhards + * + * Copyright 2010 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include +#include "dirty.h" +#include "cfsysline.h" +#include "unicode-helper.h" +#include "module-template.h" +#include "srUtils.h" +#include "errmsg.h" +#include "net.h" +#include "glbl.h" +#include "msg.h" +#include "prop.h" +#include "sun_cddl.h" + +MODULE_TYPE_INPUT + +/* defines */ +#define PATH_LOG "/dev/log" + + +/* Module static data */ +DEF_IMOD_STATIC_DATA +DEFobjCurrIf(errmsg) +DEFobjCurrIf(glbl) +DEFobjCurrIf(prop) + + +static int logfd = -1; /* file descriptor to access the system log */ + + +/* config settings */ +static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */ +static char *LogName = NULL; /* the log socket name TODO: make configurable! */ + + + +/* This function receives data from a socket indicated to be ready + * to receive and submits the message received for processing. + * rgerhards, 2007-12-20 + * Interface changed so that this function is passed the array index + * of the socket which is to be processed. This eases access to the + * growing number of properties. -- rgerhards, 2008-08-01 + */ +rsRetVal +solaris_readLog(int fd) +{ + DEFiRet; + int iRcvd; + int iMaxLine; + struct strbuf data; + struct strbuf ctl; + struct log_ctl hdr; + int flags; + msg_t *pMsg; + int ret; + uchar bufRcv[4096+1]; + uchar *pRcv = NULL; /* receive buffer */ + char errStr[1024]; + uchar fmtBuf[10240]; // TODO: use better solution + + assert(logfd >= 0); + + iMaxLine = glbl.GetMaxLine(); + + /* we optimize performance: if iMaxLine is below 4K (which it is in almost all + * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory + * is used. We could use alloca() to achive a similar aspect, but there are so + * many issues with alloca() that I do not want to take that route. + * rgerhards, 2008-09-02 + */ + if((size_t) iMaxLine < sizeof(bufRcv) - 1) { + pRcv = bufRcv; + } else { + CHKmalloc(pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))); + } + + data.buf = (char*)pRcv; + data.maxlen = iMaxLine; + ctl.maxlen = sizeof (struct log_ctl); + ctl.buf = (caddr_t)&hdr; + flags = 0; + ret = getmsg(fd, &ctl, &data, &flags); + if(ret < 0) { + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("imsolaris: getmsg() error on fd %d: %s.\n", fd, errStr); + } + dbgprintf("imsolaris: getmsg() returns %d\n", ret); + dbgprintf("imsolaris: message from log socket: #%d: %s\n", fd, pRcv); + if (1) {//iRcvd > 0) { + // TODO: use hdr info! This whole section is a work-around to get + // it going. +#if 0 + CHKiRet(msgConstruct(&pMsg)); + //MsgSetFlowControlType(pMsg, eFLOWCTL_FULL_DELAY); + MsgSetInputName(pMsg, pInputName); + MsgSetRawMsg(pMsg, (char*)pRcv, strlen((char*)pRcv)); + MsgSetMSGoffs(pMsg, 0); /* we do not have a header... */ + MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())); + //MsgSetTAG(pMsg, pInfo->pszTag, pInfo->lenTag); + //pMsg->iFacility = LOG_FAC(pInfo->iFacility); + //pMsg->iSeverity = LOG_PRI(pInfo->iSeverity); + pMsg->bParseHOSTNAME = 0; + CHKiRet(submitMsg(pMsg)); +#else + iRcvd = snprintf((char*)fmtBuf, sizeof(fmtBuf), "<%d>%s", hdr.pri, (char*) pRcv); + parseAndSubmitMessage(glbl.GetLocalHostName(), + (uchar*)"127.0.0.1", fmtBuf, + iRcvd, 0, + 0, pInputName, NULL, 0); +#endif + } else if (iRcvd < 0 && errno != EINTR) { + int en = errno; + rs_strerror_r(en, errStr, sizeof(errStr)); + dbgprintf("imsolaris: stream error: %d = %s.\n", errno, errStr); + //errmsg.LogError(en, NO_ERRCODE, "imsolaris: socket error UNIX"); + } + +finalize_it: + if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) + free(pRcv); + + RETiRet; +} + + +/* This function is called to gather input. */ +BEGINrunInput +CODESTARTrunInput + /* this is an endless loop - it is terminated when the thread is + * signalled to do so. This, however, is handled by the framework, + * right into the sleep below. + */ + + dbgprintf("imsolaris: prepare_sys_poll()\n"); + prepare_sys_poll(); + + /* note: sun's syslogd code claims that the door should only + * be opened when the log socket has been polled. So file header + * comment of this file for more details. + */ + sun_open_door(); + dbgprintf("imsolaris: starting regular poll loop\n"); + while(1) { + sun_sys_poll(); + } + + RETiRet; +ENDrunInput + + +BEGINwillRun +CODESTARTwillRun + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imsolaris"), sizeof("imsolaris") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); + + iRet = sun_openklog((LogName == NULL) ? PATH_LOG : LogName, &logfd); + dbgprintf("imsolaris opened system log socket as fd %d\n", logfd); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error opening system log socket"); + } +finalize_it: +ENDwillRun + + +BEGINafterRun +CODESTARTafterRun + /* do cleanup here */ + if(pInputName != NULL) + prop.Destruct(&pInputName); +ENDafterRun + + +BEGINmodExit +CODESTARTmodExit + sun_delete_doorfiles(); + objRelease(glbl, CORE_COMPONENT); + objRelease(errmsg, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_IMOD_QUERIES +ENDqueryEtryPt + +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + return RS_RET_OK; +} + + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ +CODEmodInit_QueryRegCFSLineHdlr + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); + + dbgprintf("imsolaris version %s initializing\n", PACKAGE_VERSION); + + /* register config file handlers */ + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, + resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); +ENDmodInit +/* vim:set ai: + */ diff --git a/plugins/imsolaris/sun_cddl.c b/plugins/imsolaris/sun_cddl.c new file mode 100644 index 00000000..1de23660 --- /dev/null +++ b/plugins/imsolaris/sun_cddl.c @@ -0,0 +1,532 @@ +#define MAXLINE 4096 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Portions Copyright 2010 by Rainer Gerhards and Adiscon + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T + * All Rights Reserved + */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rsyslog.h" +#include "srUtils.h" +#include "debug.h" + +#define DOORFILE "/var/run/syslog_door" +#define RELATIVE_DOORFILE "../var/run/syslog_door" +#define OLD_DOORFILE "/etc/.syslog_door" + +static struct pollfd Pfd; /* Pollfd for local the log device */ + +static int DoorFd = -1; +static int DoorCreated = 0; +static char *DoorFileName = DOORFILE; + +/* for managing door server threads */ +static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER; +static uint_t door_server_cnt = 0; +static pthread_attr_t door_thr_attr; + +/* + * the 'server' function that we export via the door. It does + * nothing but return. + */ +/*ARGSUSED*/ +static void +server(void __attribute__((unused)) *cookie, char __attribute__((unused)) *argp, size_t __attribute__((unused)) arg_size, + door_desc_t __attribute__((unused)) *dp, __attribute__((unused)) uint_t n) +{ + (void) door_return(NULL, 0, NULL, 0); + /* NOTREACHED */ +} + +/*ARGSUSED*/ +static void * +create_door_thr(void __attribute__((unused)) *arg) +{ + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + (void) door_return(NULL, 0, NULL, 0); + + /* + * If there is an error in door_return(), it will return here and + * the thread will exit. Hence we need to decrement door_server_cnt. + */ + (void) pthread_mutex_lock(&door_server_cnt_lock); + door_server_cnt--; + (void) pthread_mutex_unlock(&door_server_cnt_lock); + return (NULL); +} + +/* + * Max number of door server threads for syslogd. Since door is used + * to check the health of syslogd, we don't need large number of + * server threads. + */ +#define MAX_DOOR_SERVER_THR 3 + +/* + * Manage door server thread pool. + */ +/*ARGSUSED*/ +static void +door_server_pool(door_info_t __attribute__((unused)) *dip) +{ + (void) pthread_mutex_lock(&door_server_cnt_lock); + if (door_server_cnt <= MAX_DOOR_SERVER_THR && + pthread_create(NULL, &door_thr_attr, create_door_thr, NULL) == 0) { + door_server_cnt++; + (void) pthread_mutex_unlock(&door_server_cnt_lock); + return; + } + + (void) pthread_mutex_unlock(&door_server_cnt_lock); +} + +void +sun_delete_doorfiles(void) +{ + pthread_t mythreadno; + struct stat sb; + int err; + char line[MAXLINE+1]; + + if (Debug) { + mythreadno = pthread_self(); + } + + + if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (unlink(DoorFileName) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed - fatal", DoorFileName); + errno = err; + DBGPRINTF("%s", line);//logerror(line); + DBGPRINTF("delete_doorfiles(%u): error: %s, " + "errno=%d\n", mythreadno, line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles(%u): deleted %s\n", + mythreadno, DoorFileName); + } + + if (strcmp(DoorFileName, DOORFILE) == 0) { + if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (unlink(OLD_DOORFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed", OLD_DOORFILE); + DBGPRINTF("delete_doorfiles(%u): %s\n", + mythreadno, line); + + if (err != EROFS) { + errno = err; + (void) strlcat(line, " - fatal", + sizeof (line)); + //logerror(line); + DBGPRINTF("delete_doorfiles(%u): " + "error: %s, errno=%d\n", + mythreadno, line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles(%u): unlink() " + "failure OK on RO file system\n", + mythreadno); + } + + DBGPRINTF("delete_doorfiles(%u): deleted %s\n", + mythreadno, OLD_DOORFILE); + } + } + + if (DoorFd != -1) { + (void) door_revoke(DoorFd); + } + + DBGPRINTF("delete_doorfiles(%u): revoked door: DoorFd=%d\n", + mythreadno, DoorFd); +} + + +/* Create the door file. If the filesystem + * containing /etc is writable, create symlinks /etc/.syslog_door + * to them. On systems that do not support /var/run, create + * /etc/.syslog_door directly. + */ + +void +sun_open_door(void) +{ + struct stat buf; + door_info_t info; + char line[MAXLINE+1]; + pthread_t mythreadno; + int err; + + if (Debug) { + mythreadno = pthread_self(); + } + + /* + * first see if another syslogd is running by trying + * a door call - if it succeeds, there is already + * a syslogd process active + */ + + if (!DoorCreated) { + int door; + + if ((door = open(DoorFileName, O_RDONLY)) >= 0) { + DBGPRINTF("open_door(%u): %s opened " + "successfully\n", mythreadno, DoorFileName); + + if (door_info(door, &info) >= 0) { + DBGPRINTF("open_door(%u): " + "door_info:info.di_target = %ld\n", + mythreadno, info.di_target); + + if (info.di_target > 0) { + (void) sprintf(line, "syslogd pid %ld" + " already running. Cannot " + "start another syslogd pid %ld", + info.di_target, getpid()); + DBGPRINTF("open_door(%u): error: " + "%s\n", mythreadno, line); + errno = 0; + //logerror(line); + exit(1); + } + } + + (void) close(door); + } else { + if (lstat(DoorFileName, &buf) < 0) { + err = errno; + + DBGPRINTF("open_door(%u): lstat() of %s " + "failed, errno=%d\n", + mythreadno, DoorFileName, err); + + if ((door = creat(DoorFileName, 0644)) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "creat() of %s failed - fatal", + DoorFileName); + DBGPRINTF("open_door(%u): error: %s, " + "errno=%d\n", mythreadno, line, + err); + errno = err; + //logerror(line); + sun_delete_doorfiles(); + exit(1); + } + + (void) fchmod(door, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + + DBGPRINTF("open_door(%u): creat() of %s " + "succeeded\n", mythreadno, + DoorFileName); + + (void) close(door); + } + } + + if (strcmp(DoorFileName, DOORFILE) == 0) { + if (lstat(OLD_DOORFILE, &buf) == 0) { + DBGPRINTF("open_door(%u): lstat() of %s " + "succeeded\n", mythreadno, + OLD_DOORFILE); + + if (S_ISDIR(buf.st_mode)) { + (void) snprintf(line, sizeof (line), + "%s is a directory - fatal", + OLD_DOORFILE); + DBGPRINTF("open_door(%u): error: " + "%s\n", mythreadno, line); + errno = 0; + //logerror(line); + sun_delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): %s is not a " + "directory\n", + mythreadno, OLD_DOORFILE); + + if (unlink(OLD_DOORFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "unlink() of %s failed", + OLD_DOORFILE); + DBGPRINTF("open_door(%u): %s\n", + mythreadno, line); + + if (err != EROFS) { + DBGPRINTF("open_door(%u): " + "error: %s, " + "errno=%d\n", + mythreadno, line, err); + (void) strcat(line, " - fatal"); + errno = err; + //logerror(line); + sun_delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): unlink " + "failure OK on RO file " + "system\n", mythreadno); + } + } else { + DBGPRINTF("open_door(%u): file %s doesn't " + "exist\n", mythreadno, OLD_DOORFILE); + } + + if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "symlink %s -> %s failed", OLD_DOORFILE, + RELATIVE_DOORFILE); + DBGPRINTF("open_door(%u): %s\n", mythreadno, + line); + + if (err != EROFS) { + DBGPRINTF("open_door(%u): error: %s, " + "errno=%d\n", mythreadno, line, + err); + errno = err; + (void) strcat(line, " - fatal"); + //logerror(line); + sun_delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): symlink failure OK " + "on RO file system\n", mythreadno); + } else { + DBGPRINTF("open_door(%u): symlink %s -> %s " + "succeeded\n", mythreadno, + OLD_DOORFILE, RELATIVE_DOORFILE); + } + } + + if ((DoorFd = door_create(server, 0, + DOOR_REFUSE_DESC)) < 0) { + //???? DOOR_NO_CANEL requires newer libs??? DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { + err = errno; + (void) sprintf(line, "door_create() failed - fatal"); + DBGPRINTF("open_door(%u): error: %s, errno=%d\n", + mythreadno, line, err); + errno = err; + //logerror(line); + sun_delete_doorfiles(); + exit(1); + } + //???? (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0); + DBGPRINTF("open_door(%u): door_create() succeeded, " + "DoorFd=%d\n", mythreadno, DoorFd); + + DoorCreated = 1; + } + + (void) fdetach(DoorFileName); /* just in case... */ + + (void) door_server_create(door_server_pool); + + if (fattach(DoorFd, DoorFileName) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), "fattach() of fd" + " %d to %s failed - fatal", DoorFd, DoorFileName); + DBGPRINTF("open_door(%u): error: %s, errno=%d\n", mythreadno, + line, err); + errno = err; + //logerror(line); + sun_delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door(%u): attached server() to %s\n", mythreadno, + DoorFileName); + +} + + +/* Attempts to open the local log device + * and return a file descriptor. + */ +rsRetVal +sun_openklog(char *name, int *fd) +{ + DEFiRet; + struct strioctl str; + char errBuf[1024]; + + if((*fd = open(name, O_RDONLY)) < 0) { + rs_strerror_r(errno, errBuf, sizeof(errBuf)); + dbgprintf("imsolaris:openklog: cannot open %s: %s\n", + name, errBuf); + ABORT_FINALIZE(RS_RET_ERR_OPEN_KLOG); + } + str.ic_cmd = I_CONSLOG; + str.ic_timout = 0; + str.ic_len = 0; + str.ic_dp = NULL; + if (ioctl(*fd, I_STR, &str) < 0) { + rs_strerror_r(errno, errBuf, sizeof(errBuf)); + dbgprintf("imsolaris:openklog: cannot register to log " + "console messages: %s\n", errBuf); + ABORT_FINALIZE(RS_RET_ERR_AQ_CONLOG); + } + Pfd.fd = *fd; + Pfd.events = POLLIN; + dbgprintf("imsolaris/openklog: opened '%s' as fd %d.\n", name, *fd); + +finalize_it: + RETiRet; +} + + +/* this thread listens to the local stream log driver for log messages + * generated by this host, formats them, and queues them to the logger + * thread. + */ +/*ARGSUSED*/ +void +sun_sys_poll() +{ + int nfds; + + dbgprintf("imsolaris:sys_poll: sys_thread started\n"); + + for (;;) { + errno = 0; + + dbgprintf("imsolaris:sys_poll waiting for next message...\n"); + nfds = poll(&Pfd, 1, INFTIM); + + if (nfds == 0) + continue; + + if (nfds < 0) { + if (errno != EINTR) + dbgprintf("imsolaris:poll error"); + continue; + } + if (Pfd.revents & POLLIN) { + solaris_readLog(Pfd.fd); + } else { + /* TODO: shutdown, the rsyslog way (in v5!) -- check shutdown flag */ + if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + // TODO: trigger retry logic +/* logerror("kernel log driver poll error"); + (void) close(Pfd.fd); + Pfd.fd = -1; + */ + } + } + + } + /*NOTREACHED*/ +} + + +/* Open the log device, and pull up all pending messages. + */ +void +prepare_sys_poll() +{ + int nfds; + + Pfd.events = POLLIN; + + for (;;) { + dbgprintf("imsolaris:prepare_sys_poll waiting for next message...\n"); + nfds = poll(&Pfd, 1, 0); + if (nfds <= 0) { + break; + } + + if (Pfd.revents & POLLIN) { + solaris_readLog(Pfd.fd); + } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + //logerror("kernel log driver poll error"); + break; + } + } + +} diff --git a/plugins/imsolaris/sun_cddl.h b/plugins/imsolaris/sun_cddl.h new file mode 100644 index 00000000..0139b3d8 --- /dev/null +++ b/plugins/imsolaris/sun_cddl.h @@ -0,0 +1,5 @@ +rsRetVal sun_openklog(char *name, int *); +void prepare_sys_poll(void); +void sun_sys_poll(void); +void sun_open_door(void); +void sun_delete_doorfiles(void); diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 8979893a..173f15a8 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -360,6 +360,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_VAR_NOT_FOUND = -2142, /**< variable not found */ RS_RET_EMPTY_MSG = -2143, /**< provided (raw) MSG is empty */ RS_RET_PEER_CLOSED_CONN = -2144, /**< remote peer closed connection (information, no error) */ + RS_RET_ERR_OPEN_KLOG = -2145, /**< error opening the kernel log socket (primarily solaris) */ + RS_RET_ERR_AQ_CONLOG = -2146, /**< error aquiring console log (on solaris) */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ -- cgit From e858af4fb02e9e38bc07ee64c64d15303fc8a89d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 15 Apr 2010 18:15:47 +0200 Subject: minor cleanup (cosmetic) --- plugins/imsolaris/sun_cddl.c | 119 +++++++++++++++++++------------------------ plugins/omprog/omprog.c | 3 +- 2 files changed, 52 insertions(+), 70 deletions(-) diff --git a/plugins/imsolaris/sun_cddl.c b/plugins/imsolaris/sun_cddl.c index 1de23660..0d18f972 100644 --- a/plugins/imsolaris/sun_cddl.c +++ b/plugins/imsolaris/sun_cddl.c @@ -157,16 +157,10 @@ door_server_pool(door_info_t __attribute__((unused)) *dip) void sun_delete_doorfiles(void) { - pthread_t mythreadno; struct stat sb; int err; char line[MAXLINE+1]; - if (Debug) { - mythreadno = pthread_self(); - } - - if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { if (unlink(DoorFileName) < 0) { err = errno; @@ -174,13 +168,12 @@ sun_delete_doorfiles(void) "unlink() of %s failed - fatal", DoorFileName); errno = err; DBGPRINTF("%s", line);//logerror(line); - DBGPRINTF("delete_doorfiles(%u): error: %s, " - "errno=%d\n", mythreadno, line, err); + DBGPRINTF("delete_doorfiles: error: %s, " + "errno=%d\n", line, err); exit(1); } - DBGPRINTF("delete_doorfiles(%u): deleted %s\n", - mythreadno, DoorFileName); + DBGPRINTF("delete_doorfiles: deleted %s\n", DoorFileName); } if (strcmp(DoorFileName, DOORFILE) == 0) { @@ -189,27 +182,25 @@ sun_delete_doorfiles(void) err = errno; (void) snprintf(line, sizeof (line), "unlink() of %s failed", OLD_DOORFILE); - DBGPRINTF("delete_doorfiles(%u): %s\n", - mythreadno, line); + DBGPRINTF("delete_doorfiles: %s\n", line); if (err != EROFS) { errno = err; (void) strlcat(line, " - fatal", sizeof (line)); //logerror(line); - DBGPRINTF("delete_doorfiles(%u): " + DBGPRINTF("delete_doorfiles: " "error: %s, errno=%d\n", - mythreadno, line, err); + line, err); exit(1); } - DBGPRINTF("delete_doorfiles(%u): unlink() " - "failure OK on RO file system\n", - mythreadno); + DBGPRINTF("delete_doorfiles: unlink() " + "failure OK on RO file system\n"); } - DBGPRINTF("delete_doorfiles(%u): deleted %s\n", - mythreadno, OLD_DOORFILE); + DBGPRINTF("delete_doorfiles: deleted %s\n", + OLD_DOORFILE); } } @@ -217,8 +208,8 @@ sun_delete_doorfiles(void) (void) door_revoke(DoorFd); } - DBGPRINTF("delete_doorfiles(%u): revoked door: DoorFd=%d\n", - mythreadno, DoorFd); + DBGPRINTF("delete_doorfiles: revoked door: DoorFd=%d\n", + DoorFd); } @@ -234,13 +225,8 @@ sun_open_door(void) struct stat buf; door_info_t info; char line[MAXLINE+1]; - pthread_t mythreadno; int err; - if (Debug) { - mythreadno = pthread_self(); - } - /* * first see if another syslogd is running by trying * a door call - if it succeeds, there is already @@ -251,21 +237,21 @@ sun_open_door(void) int door; if ((door = open(DoorFileName, O_RDONLY)) >= 0) { - DBGPRINTF("open_door(%u): %s opened " - "successfully\n", mythreadno, DoorFileName); + DBGPRINTF("open_door: %s opened " + "successfully\n", DoorFileName); if (door_info(door, &info) >= 0) { - DBGPRINTF("open_door(%u): " + DBGPRINTF("open_door: " "door_info:info.di_target = %ld\n", - mythreadno, info.di_target); + info.di_target); if (info.di_target > 0) { (void) sprintf(line, "syslogd pid %ld" " already running. Cannot " "start another syslogd pid %ld", info.di_target, getpid()); - DBGPRINTF("open_door(%u): error: " - "%s\n", mythreadno, line); + DBGPRINTF("open_door: error: " + "%s\n", line); errno = 0; //logerror(line); exit(1); @@ -277,17 +263,17 @@ sun_open_door(void) if (lstat(DoorFileName, &buf) < 0) { err = errno; - DBGPRINTF("open_door(%u): lstat() of %s " + DBGPRINTF("open_door: lstat() of %s " "failed, errno=%d\n", - mythreadno, DoorFileName, err); + DoorFileName, err); if ((door = creat(DoorFileName, 0644)) < 0) { err = errno; (void) snprintf(line, sizeof (line), "creat() of %s failed - fatal", DoorFileName); - DBGPRINTF("open_door(%u): error: %s, " - "errno=%d\n", mythreadno, line, + DBGPRINTF("open_door: error: %s, " + "errno=%d\n", line, err); errno = err; //logerror(line); @@ -298,8 +284,8 @@ sun_open_door(void) (void) fchmod(door, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - DBGPRINTF("open_door(%u): creat() of %s " - "succeeded\n", mythreadno, + DBGPRINTF("open_door: creat() of %s " + "succeeded\n", DoorFileName); (void) close(door); @@ -308,39 +294,36 @@ sun_open_door(void) if (strcmp(DoorFileName, DOORFILE) == 0) { if (lstat(OLD_DOORFILE, &buf) == 0) { - DBGPRINTF("open_door(%u): lstat() of %s " - "succeeded\n", mythreadno, - OLD_DOORFILE); + DBGPRINTF("open_door: lstat() of %s " + "succeeded\n", OLD_DOORFILE); if (S_ISDIR(buf.st_mode)) { (void) snprintf(line, sizeof (line), "%s is a directory - fatal", OLD_DOORFILE); - DBGPRINTF("open_door(%u): error: " - "%s\n", mythreadno, line); + DBGPRINTF("open_door: error: " + "%s\n", line); errno = 0; //logerror(line); sun_delete_doorfiles(); exit(1); } - DBGPRINTF("open_door(%u): %s is not a " - "directory\n", - mythreadno, OLD_DOORFILE); - + DBGPRINTF("open_door: %s is not a " + "directory\n", OLD_DOORFILE); if (unlink(OLD_DOORFILE) < 0) { err = errno; (void) snprintf(line, sizeof (line), "unlink() of %s failed", OLD_DOORFILE); - DBGPRINTF("open_door(%u): %s\n", - mythreadno, line); + DBGPRINTF("open_door: %s\n", + line); if (err != EROFS) { - DBGPRINTF("open_door(%u): " + DBGPRINTF("open_door: " "error: %s, " "errno=%d\n", - mythreadno, line, err); + line, err); (void) strcat(line, " - fatal"); errno = err; //logerror(line); @@ -348,13 +331,13 @@ sun_open_door(void) exit(1); } - DBGPRINTF("open_door(%u): unlink " + DBGPRINTF("open_door: unlink " "failure OK on RO file " - "system\n", mythreadno); + "system\n"); } } else { - DBGPRINTF("open_door(%u): file %s doesn't " - "exist\n", mythreadno, OLD_DOORFILE); + DBGPRINTF("open_door: file %s doesn't " + "exist\n", OLD_DOORFILE); } if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) { @@ -362,12 +345,12 @@ sun_open_door(void) (void) snprintf(line, sizeof (line), "symlink %s -> %s failed", OLD_DOORFILE, RELATIVE_DOORFILE); - DBGPRINTF("open_door(%u): %s\n", mythreadno, + DBGPRINTF("open_door: %s\n", line); if (err != EROFS) { - DBGPRINTF("open_door(%u): error: %s, " - "errno=%d\n", mythreadno, line, + DBGPRINTF("open_door: error: %s, " + "errno=%d\n", line, err); errno = err; (void) strcat(line, " - fatal"); @@ -376,11 +359,11 @@ sun_open_door(void) exit(1); } - DBGPRINTF("open_door(%u): symlink failure OK " - "on RO file system\n", mythreadno); + DBGPRINTF("open_door: symlink failure OK " + "on RO file system\n"); } else { - DBGPRINTF("open_door(%u): symlink %s -> %s " - "succeeded\n", mythreadno, + DBGPRINTF("open_door: symlink %s -> %s " + "succeeded\n", OLD_DOORFILE, RELATIVE_DOORFILE); } } @@ -390,16 +373,16 @@ sun_open_door(void) //???? DOOR_NO_CANEL requires newer libs??? DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { err = errno; (void) sprintf(line, "door_create() failed - fatal"); - DBGPRINTF("open_door(%u): error: %s, errno=%d\n", - mythreadno, line, err); + DBGPRINTF("open_door: error: %s, errno=%d\n", + line, err); errno = err; //logerror(line); sun_delete_doorfiles(); exit(1); } //???? (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0); - DBGPRINTF("open_door(%u): door_create() succeeded, " - "DoorFd=%d\n", mythreadno, DoorFd); + DBGPRINTF("open_door: door_create() succeeded, " + "DoorFd=%d\n", DoorFd); DoorCreated = 1; } @@ -412,7 +395,7 @@ sun_open_door(void) err = errno; (void) snprintf(line, sizeof (line), "fattach() of fd" " %d to %s failed - fatal", DoorFd, DoorFileName); - DBGPRINTF("open_door(%u): error: %s, errno=%d\n", mythreadno, + DBGPRINTF("open_door: error: %s, errno=%d\n", line, err); errno = err; //logerror(line); @@ -420,7 +403,7 @@ sun_open_door(void) exit(1); } - DBGPRINTF("open_door(%u): attached server() to %s\n", mythreadno, + DBGPRINTF("open_door: attached server() to %s\n", DoorFileName); } diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c index 01fa7cea..2687e7a3 100644 --- a/plugins/omprog/omprog.c +++ b/plugins/omprog/omprog.c @@ -169,7 +169,7 @@ openPipe(instanceData *pData) /*NO CODE HERE - WILL NEVER BE REACHED!*/ } - DBGPRINTF("child has pid %d\n", cpid); + DBGPRINTF("child has pid %d\n", (int) cpid); pData->fdPipe = pipefd[1]; pData->pid = cpid; close(pipefd[0]); @@ -191,7 +191,6 @@ cleanup(instanceData *pData) 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... */ -- cgit From 71406206d5e35cc4d4648b8dc5fe7cd295e5778b Mon Sep 17 00:00:00 2001 From: Peter Bray Date: Mon, 19 Apr 2010 11:38:36 +0200 Subject: some platforms seem to need time.h inside msleep.c Signed-off-by: Rainer Gerhards --- tests/msleep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/msleep.c b/tests/msleep.c index 6fa57b79..36fa01b5 100644 --- a/tests/msleep.c +++ b/tests/msleep.c @@ -26,6 +26,7 @@ #include "config.h" #include #include +#include int main(int argc, char *argv[]) { -- cgit From 9039fad4019cb9a0f96eb296835476841b453dd3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Apr 2010 12:00:06 +0200 Subject: some more cleanup --- plugins/imsolaris/Makefile.am | 2 +- plugins/imsolaris/imsolaris.h | 1 + plugins/imsolaris/sun_cddl.c | 37 +++++++++---------------------------- 3 files changed, 11 insertions(+), 29 deletions(-) create mode 100644 plugins/imsolaris/imsolaris.h diff --git a/plugins/imsolaris/Makefile.am b/plugins/imsolaris/Makefile.am index 2980fc6f..b4ee1c29 100644 --- a/plugins/imsolaris/Makefile.am +++ b/plugins/imsolaris/Makefile.am @@ -1,6 +1,6 @@ pkglib_LTLIBRARIES = imsolaris.la -imsolaris_la_SOURCES = imsolaris.c sun_cddl.c sun_cddl.h +imsolaris_la_SOURCES = imsolaris.c sun_cddl.c sun_cddl.h imsolaris.h imsolaris_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) imsolaris_la_LDFLAGS = -module -avoid-version imsolaris_la_LIBADD = -ldoor -lpthread diff --git a/plugins/imsolaris/imsolaris.h b/plugins/imsolaris/imsolaris.h new file mode 100644 index 00000000..9637220b --- /dev/null +++ b/plugins/imsolaris/imsolaris.h @@ -0,0 +1 @@ +rsRetVal solaris_readLog(int fd); diff --git a/plugins/imsolaris/sun_cddl.c b/plugins/imsolaris/sun_cddl.c index 0d18f972..69636df0 100644 --- a/plugins/imsolaris/sun_cddl.c +++ b/plugins/imsolaris/sun_cddl.c @@ -1,4 +1,3 @@ -#define MAXLINE 4096 /* * CDDL HEADER START * @@ -41,53 +40,37 @@ * contributors. */ #include -#include #include #include #include -#include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include #include -#include -#include #include #include #include -#include #include -#include -#include -#include -#include #include #include #include "rsyslog.h" #include "srUtils.h" #include "debug.h" +#include "imsolaris.h" #define DOORFILE "/var/run/syslog_door" #define RELATIVE_DOORFILE "../var/run/syslog_door" #define OLD_DOORFILE "/etc/.syslog_door" +/* Buffer to allocate for error messages: */ +#define ERRMSG_LEN 1024 + static struct pollfd Pfd; /* Pollfd for local the log device */ static int DoorFd = -1; @@ -159,7 +142,7 @@ sun_delete_doorfiles(void) { struct stat sb; int err; - char line[MAXLINE+1]; + char line[ERRMSG_LEN+1]; if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) { if (unlink(DoorFileName) < 0) { @@ -218,19 +201,17 @@ sun_delete_doorfiles(void) * to them. On systems that do not support /var/run, create * /etc/.syslog_door directly. */ - void sun_open_door(void) { struct stat buf; door_info_t info; - char line[MAXLINE+1]; + char line[ERRMSG_LEN+1]; int err; - /* - * first see if another syslogd is running by trying - * a door call - if it succeeds, there is already - * a syslogd process active + /* first see if another instance of imsolaris OR another + * syslogd is running by trying a door call - if it succeeds, + * there is already one active. */ if (!DoorCreated) { -- cgit From 393c67ba5bc20613436552a26a6f0a20d4dda9fe Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Apr 2010 15:38:11 +0200 Subject: minor cleanup --- template.c | 1 - tools/omfile.c | 4 ++-- tools/ompipe.c | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/template.c b/template.c index 5a43cba3..68c57be1 100644 --- a/template.c +++ b/template.c @@ -61,7 +61,6 @@ static inline rsRetVal ExtendBuf(uchar **pBuf, size_t *pLenBuf, size_t iMinSize) CHKmalloc(pNewBuf = (uchar*) realloc(*pBuf, iNewSize)); *pBuf = pNewBuf; *pLenBuf = iNewSize; -dbgprintf("extend buf to at least %ld, done %ld\n", iMinSize, iNewSize); finalize_it: RETiRet; diff --git a/tools/omfile.c b/tools/omfile.c index 74b22019..a45d904b 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -166,9 +166,9 @@ CODESTARTdbgPrintInstInfo dbgprintf("\tflush interval=%d\n", pData->iFlushInterval); dbgprintf("\tfile cache size=%d\n", pData->iDynaFileCacheSize); dbgprintf("\tcreate directories: %s\n", pData->bCreateDirs ? "yes" : "no"); - dbgprintf("\tfile owner %d, group %d\n", pData->fileUID, pData->fileGID); + dbgprintf("\tfile owner %d, group %d\n", (int) pData->fileUID, (int) pData->fileGID); dbgprintf("\tforce chown() for all files: %s\n", pData->bForceChown ? "yes" : "no"); - dbgprintf("\tdirectory owner %d, group %d\n", pData->dirUID, pData->dirGID); + dbgprintf("\tdirectory owner %d, group %d\n", (int) pData->dirUID, (int) pData->dirGID); dbgprintf("\tdir create mode 0%3.3o, file create mode 0%3.3o\n", pData->fDirCreateMode, pData->fCreateMode); dbgprintf("\tfail if owner/group can not be set: %s\n", pData->bFailOnChown ? "yes" : "no"); diff --git a/tools/ompipe.c b/tools/ompipe.c index 7cf61822..2d621e0e 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include -- cgit From 587036bfb03167d86b0a2fbfe998db1a916cabb3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Apr 2010 17:03:08 +0200 Subject: changed imsolaris to use submitMsg() API This includes a modification to the rsyslog engine so that messages without PRI inside the message can properly be handled. --- plugins/imsolaris/imsolaris.c | 20 ++++---------------- runtime/msg.h | 1 + runtime/parser.c | 29 +++++++++++++++++------------ 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c index a2238a29..67aa479d 100644 --- a/plugins/imsolaris/imsolaris.c +++ b/plugins/imsolaris/imsolaris.c @@ -127,7 +127,6 @@ solaris_readLog(int fd) uchar bufRcv[4096+1]; uchar *pRcv = NULL; /* receive buffer */ char errStr[1024]; - uchar fmtBuf[10240]; // TODO: use better solution assert(logfd >= 0); @@ -158,32 +157,21 @@ solaris_readLog(int fd) dbgprintf("imsolaris: getmsg() returns %d\n", ret); dbgprintf("imsolaris: message from log socket: #%d: %s\n", fd, pRcv); if (1) {//iRcvd > 0) { - // TODO: use hdr info! This whole section is a work-around to get - // it going. -#if 0 CHKiRet(msgConstruct(&pMsg)); //MsgSetFlowControlType(pMsg, eFLOWCTL_FULL_DELAY); MsgSetInputName(pMsg, pInputName); MsgSetRawMsg(pMsg, (char*)pRcv, strlen((char*)pRcv)); - MsgSetMSGoffs(pMsg, 0); /* we do not have a header... */ MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())); - //MsgSetTAG(pMsg, pInfo->pszTag, pInfo->lenTag); - //pMsg->iFacility = LOG_FAC(pInfo->iFacility); - //pMsg->iSeverity = LOG_PRI(pInfo->iSeverity); + pMsg->iFacility = LOG_FAC(hdr.pri); + pMsg->iSeverity = LOG_PRI(hdr.pri); pMsg->bParseHOSTNAME = 0; + pMsg->msgFlags = NEEDS_PARSING | NO_PRI_IN_RAW; CHKiRet(submitMsg(pMsg)); -#else - iRcvd = snprintf((char*)fmtBuf, sizeof(fmtBuf), "<%d>%s", hdr.pri, (char*) pRcv); - parseAndSubmitMessage(glbl.GetLocalHostName(), - (uchar*)"127.0.0.1", fmtBuf, - iRcvd, 0, - 0, pInputName, NULL, 0); -#endif } else if (iRcvd < 0 && errno != EINTR) { int en = errno; rs_strerror_r(en, errStr, sizeof(errStr)); dbgprintf("imsolaris: stream error: %d = %s.\n", errno, errStr); - //errmsg.LogError(en, NO_ERRCODE, "imsolaris: socket error UNIX"); + errmsg.LogError(en, NO_ERRCODE, "imsolaris: stream input error: %s", errStr); } finalize_it: diff --git a/runtime/msg.h b/runtime/msg.h index 3a02365b..f10c919c 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -130,6 +130,7 @@ struct msg { #define MARK 0x008 /* this message is a mark */ #define NEEDS_PARSING 0x010 /* raw message, must be parsed before processing can be done */ #define PARSE_HOSTNAME 0x020 /* parse the hostname during message parsing */ +#define NO_PRI_IN_RAW 0x040 /* rawmsg does not include a PRI (Solaris!), but PRI is already set correctly in the msg object */ /* function prototypes diff --git a/runtime/parser.c b/runtime/parser.c index 36e88ebd..810bf42b 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -287,19 +287,24 @@ rsRetVal parseMsg(msg_t *pMsg) msg = pMsg->pszRawMsg; pri = DEFUPRI; iPriText = 0; - if(*msg == '<') { - /* while we process the PRI, we also fill the PRI textual representation - * inside the msg object. This may not be ideal from an OOP point of view, - * but it offers us performance... - */ - pri = 0; - while(--lenMsg > 0 && isdigit((int) *++msg)) { - pri = 10 * pri + (*msg - '0'); + if(pMsg->msgFlags & NO_PRI_IN_RAW) { + /* In this case, simply do so as if the pri would be right at top */ + MsgSetAfterPRIOffs(pMsg, 0); + } else { + if(*msg == '<') { + /* while we process the PRI, we also fill the PRI textual representation + * inside the msg object. This may not be ideal from an OOP point of view, + * but it offers us performance... + */ + pri = 0; + while(--lenMsg > 0 && isdigit((int) *++msg)) { + pri = 10 * pri + (*msg - '0'); + } + if(*msg == '>') + ++msg; + if(pri & ~(LOG_FACMASK|LOG_PRIMASK)) + pri = DEFUPRI; } - if(*msg == '>') - ++msg; - if(pri & ~(LOG_FACMASK|LOG_PRIMASK)) - pri = DEFUPRI; } pMsg->iFacility = LOG_FAC(pri); pMsg->iSeverity = LOG_PRI(pri); -- cgit From 6b8e9477a2bd4810010ac91ba76909713b0dbb15 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Apr 2010 17:14:09 +0200 Subject: changed flag value for v5-compatibility --- runtime/msg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/msg.h b/runtime/msg.h index f10c919c..0d3314b7 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -130,7 +130,7 @@ struct msg { #define MARK 0x008 /* this message is a mark */ #define NEEDS_PARSING 0x010 /* raw message, must be parsed before processing can be done */ #define PARSE_HOSTNAME 0x020 /* parse the hostname during message parsing */ -#define NO_PRI_IN_RAW 0x040 /* rawmsg does not include a PRI (Solaris!), but PRI is already set correctly in the msg object */ +#define NO_PRI_IN_RAW 0x100 /* rawmsg does not include a PRI (Solaris!), but PRI is already set correctly in the msg object */ /* function prototypes -- cgit From 84084ea2a178f782184d75db10f252efdc62fb5f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Apr 2010 18:39:55 +0200 Subject: improved quality of imsolaris code including refctoring for a more simple solution --- plugins/imsolaris/imsolaris.c | 146 ++++++++++++++++++++++++++++++++++++------ plugins/imsolaris/imsolaris.h | 1 + plugins/imsolaris/sun_cddl.c | 143 ++++++++++------------------------------- plugins/imsolaris/sun_cddl.h | 4 +- runtime/rsyslog.h | 1 + runtime/stream.c | 3 +- 6 files changed, 166 insertions(+), 132 deletions(-) diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c index 67aa479d..c8076d93 100644 --- a/plugins/imsolaris/imsolaris.c +++ b/plugins/imsolaris/imsolaris.c @@ -66,6 +66,7 @@ #include "rsyslog.h" #include #include +#include #include #include #include @@ -96,9 +97,6 @@ DEFobjCurrIf(glbl) DEFobjCurrIf(prop) -static int logfd = -1; /* file descriptor to access the system log */ - - /* config settings */ static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */ static char *LogName = NULL; /* the log socket name TODO: make configurable! */ @@ -128,8 +126,6 @@ solaris_readLog(int fd) uchar *pRcv = NULL; /* receive buffer */ char errStr[1024]; - assert(logfd >= 0); - iMaxLine = glbl.GetMaxLine(); /* we optimize performance: if iMaxLine is below 4K (which it is in almost all @@ -152,10 +148,10 @@ solaris_readLog(int fd) ret = getmsg(fd, &ctl, &data, &flags); if(ret < 0) { rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("imsolaris: getmsg() error on fd %d: %s.\n", fd, errStr); + DBGPRINTF("imsolaris: getmsg() error on fd %d: %s.\n", fd, errStr); } - dbgprintf("imsolaris: getmsg() returns %d\n", ret); - dbgprintf("imsolaris: message from log socket: #%d: %s\n", fd, pRcv); + DBGPRINTF("imsolaris: getmsg() returns %d\n", ret); + DBGPRINTF("imsolaris: message from log socket: #%d: %s\n", fd, pRcv); if (1) {//iRcvd > 0) { CHKiRet(msgConstruct(&pMsg)); //MsgSetFlowControlType(pMsg, eFLOWCTL_FULL_DELAY); @@ -170,7 +166,7 @@ solaris_readLog(int fd) } else if (iRcvd < 0 && errno != EINTR) { int en = errno; rs_strerror_r(en, errStr, sizeof(errStr)); - dbgprintf("imsolaris: stream error: %d = %s.\n", errno, errStr); + DBGPRINTF("imsolaris: stream error: %d = %s.\n", errno, errStr); errmsg.LogError(en, NO_ERRCODE, "imsolaris: stream input error: %s", errStr); } @@ -182,6 +178,117 @@ finalize_it: } +/* we try to recover a failed file by closing and re-opening + * it. We loop until the re-open works, but wait between each + * failure. If the open succeeds, we assume all is well. If it is + * not, we will run into the retry process with the next + * iteration. + * rgerhards, 2010-04-19 + */ +static inline void +tryRecover(void) +{ + int tryNum = 0; + int waitsecs; + int waitusecs; + rsRetVal iRet; + + close(sun_Pfd.fd); + sun_Pfd.fd = -1; + + while(1) { /* loop broken inside */ + iRet = sun_openklog((LogName == NULL) ? PATH_LOG : LogName); + if(iRet == RS_RET_OK) { + if(tryNum > 0) { + errmsg.LogError(0, iRet, "failure on system log socket recovered."); + } + break; + } + /* failure, so sleep a bit. We wait try*10 ms, with a max of 15 seconds */ + if(tryNum == 0) { + errmsg.LogError(0, iRet, "failure on system log socket, trying to recover..."); + waitusecs = tryNum * 10000; + waitsecs = waitusecs / 1000000; + if(waitsecs != 15) { + waitsecs = 15; + waitusecs = 0; + } else { + waitusecs = waitusecs % 1000000; + } + srSleep(waitsecs, waitusecs); + ++tryNum; + } + } +} + + +/* a function to replace the sun logerror() function. + * It generates an error message from the supplied string. The main + * reason for not calling logError directly is that sun_cddl.c does not + * know or has acces to rsyslog objects (namely errmsg) -- and we do not + * want to do this effort. -- rgerhards, 2010-04-19 + */ +void +imsolaris_logerror(int err, char *errStr) +{ + errmsg.LogError(err, RS_RET_ERR_DOOR, "%s", errStr); +} + + +/* once the system is fully initialized, we wait for new messages. + * We may think about replacing this with a read-loop, thus saving + * us the overhead of the poll. + * The timeout variable is the timeout to use for poll. During startup, + * it should be set to 0 (non-blocking) and later to -1 (infinit, blocking). + * This mimics the (strange) behaviour of the original syslogd. + * rgerhards, 2010-04-19 + */ +static inline rsRetVal +getMsgs(int timeout) +{ + DEFiRet; + int nfds; + char errStr[1024]; + + do { + DBGPRINTF("imsolaris: waiting for next message (timeout %d)...\n", timeout); + nfds = poll(&sun_Pfd, 1, timeout); /* wait without timeout */ + + /* v5-TODO: here we must check if we should terminante! */ + + if(nfds == 0) { + if(timeout == 0) { + DBGPRINTF("imsolaris: no more messages, getMsgs() terminates\n"); + FINALIZE; + } else { + continue; + } + } + + if(nfds < 0) { + if(errno != EINTR) { + int en = errno; + rs_strerror_r(en, errStr, sizeof(errStr)); + DBGPRINTF("imsolaris: poll error: %d = %s.\n", errno, errStr); + errmsg.LogError(en, NO_ERRCODE, "imsolaris: poll error: %s", errStr); + } + continue; + } + if(sun_Pfd.revents & POLLIN) { + solaris_readLog(sun_Pfd.fd); + } else if(sun_Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + tryRecover(); + } + + } while(1); + + /* Note: in v4, this code is never reached (our thread will be cancelled) */ + +finalize_it: + RETiRet; +} + + /* This function is called to gather input. */ BEGINrunInput CODESTARTrunInput @@ -190,19 +297,18 @@ CODESTARTrunInput * right into the sleep below. */ - dbgprintf("imsolaris: prepare_sys_poll()\n"); - prepare_sys_poll(); + DBGPRINTF("imsolaris: doing startup poll before openeing door()\n"); + CHKiRet(getMsgs(0)); /* note: sun's syslogd code claims that the door should only - * be opened when the log socket has been polled. So file header + * be opened when the log stream has been polled. So file header * comment of this file for more details. */ sun_open_door(); - dbgprintf("imsolaris: starting regular poll loop\n"); - while(1) { - sun_sys_poll(); - } + DBGPRINTF("imsolaris: starting regular poll loop\n"); + iRet = getMsgs(-1); /* this is the primary poll loop, infinite timeout */ +finalize_it: RETiRet; ENDrunInput @@ -214,8 +320,7 @@ CODESTARTwillRun CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imsolaris"), sizeof("imsolaris") - 1)); CHKiRet(prop.ConstructFinalize(pInputName)); - iRet = sun_openklog((LogName == NULL) ? PATH_LOG : LogName, &logfd); - dbgprintf("imsolaris opened system log socket as fd %d\n", logfd); + iRet = sun_openklog((LogName == NULL) ? PATH_LOG : LogName); if(iRet != RS_RET_OK) { errmsg.LogError(0, iRet, "error opening system log socket"); } @@ -245,7 +350,8 @@ CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES ENDqueryEtryPt -static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, + void __attribute__((unused)) *pVal) { return RS_RET_OK; } @@ -259,7 +365,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(prop, CORE_COMPONENT)); - dbgprintf("imsolaris version %s initializing\n", PACKAGE_VERSION); + DBGPRINTF("imsolaris version %s initializing\n", PACKAGE_VERSION); /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, diff --git a/plugins/imsolaris/imsolaris.h b/plugins/imsolaris/imsolaris.h index 9637220b..e73380fa 100644 --- a/plugins/imsolaris/imsolaris.h +++ b/plugins/imsolaris/imsolaris.h @@ -1 +1,2 @@ rsRetVal solaris_readLog(int fd); +void imsolaris_logerror(int err, char *errStr); diff --git a/plugins/imsolaris/sun_cddl.c b/plugins/imsolaris/sun_cddl.c index 69636df0..6d49c8bc 100644 --- a/plugins/imsolaris/sun_cddl.c +++ b/plugins/imsolaris/sun_cddl.c @@ -71,7 +71,14 @@ /* Buffer to allocate for error messages: */ #define ERRMSG_LEN 1024 -static struct pollfd Pfd; /* Pollfd for local the log device */ +/* Max number of door server threads for syslogd. Since door is used + * to check the health of syslogd, we don't need large number of + * server threads. + */ +#define MAX_DOOR_SERVER_THR 3 + + +struct pollfd sun_Pfd; /* Pollfd for local log device */ static int DoorFd = -1; static int DoorCreated = 0; @@ -82,14 +89,16 @@ static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER; static uint_t door_server_cnt = 0; static pthread_attr_t door_thr_attr; -/* - * the 'server' function that we export via the door. It does +/* the 'server' function that we export via the door. It does * nothing but return. */ /*ARGSUSED*/ static void -server(void __attribute__((unused)) *cookie, char __attribute__((unused)) *argp, size_t __attribute__((unused)) arg_size, - door_desc_t __attribute__((unused)) *dp, __attribute__((unused)) uint_t n) +server( void __attribute__((unused)) *cookie, + char __attribute__((unused)) *argp, + size_t __attribute__((unused)) arg_size, + door_desc_t __attribute__((unused)) *dp, + __attribute__((unused)) uint_t n ) { (void) door_return(NULL, 0, NULL, 0); /* NOTREACHED */ @@ -102,8 +111,7 @@ create_door_thr(void __attribute__((unused)) *arg) (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); (void) door_return(NULL, 0, NULL, 0); - /* - * If there is an error in door_return(), it will return here and + /* If there is an error in door_return(), it will return here and * the thread will exit. Hence we need to decrement door_server_cnt. */ (void) pthread_mutex_lock(&door_server_cnt_lock); @@ -112,13 +120,6 @@ create_door_thr(void __attribute__((unused)) *arg) return (NULL); } -/* - * Max number of door server threads for syslogd. Since door is used - * to check the health of syslogd, we don't need large number of - * server threads. - */ -#define MAX_DOOR_SERVER_THR 3 - /* * Manage door server thread pool. */ @@ -149,8 +150,7 @@ sun_delete_doorfiles(void) err = errno; (void) snprintf(line, sizeof (line), "unlink() of %s failed - fatal", DoorFileName); - errno = err; - DBGPRINTF("%s", line);//logerror(line); + imsolaris_logerror(err, line); DBGPRINTF("delete_doorfiles: error: %s, " "errno=%d\n", line, err); exit(1); @@ -171,7 +171,7 @@ sun_delete_doorfiles(void) errno = err; (void) strlcat(line, " - fatal", sizeof (line)); - //logerror(line); + imsolaris_logerror(err, line); DBGPRINTF("delete_doorfiles: " "error: %s, errno=%d\n", line, err); @@ -233,8 +233,7 @@ sun_open_door(void) info.di_target, getpid()); DBGPRINTF("open_door: error: " "%s\n", line); - errno = 0; - //logerror(line); + imsolaris_logerror(0, line); exit(1); } } @@ -256,8 +255,7 @@ sun_open_door(void) DBGPRINTF("open_door: error: %s, " "errno=%d\n", line, err); - errno = err; - //logerror(line); + imsolaris_logerror(err, line); sun_delete_doorfiles(); exit(1); } @@ -284,8 +282,7 @@ sun_open_door(void) OLD_DOORFILE); DBGPRINTF("open_door: error: " "%s\n", line); - errno = 0; - //logerror(line); + imsolaris_logerror(0, line); sun_delete_doorfiles(); exit(1); } @@ -306,8 +303,7 @@ sun_open_door(void) "errno=%d\n", line, err); (void) strcat(line, " - fatal"); - errno = err; - //logerror(line); + imsolaris_logerror(err, line); sun_delete_doorfiles(); exit(1); } @@ -333,9 +329,8 @@ sun_open_door(void) DBGPRINTF("open_door: error: %s, " "errno=%d\n", line, err); - errno = err; (void) strcat(line, " - fatal"); - //logerror(line); + imsolaris_logerror(err, line); sun_delete_doorfiles(); exit(1); } @@ -356,8 +351,7 @@ sun_open_door(void) (void) sprintf(line, "door_create() failed - fatal"); DBGPRINTF("open_door: error: %s, errno=%d\n", line, err); - errno = err; - //logerror(line); + imsolaris_logerror(err, line); sun_delete_doorfiles(); exit(1); } @@ -378,8 +372,7 @@ sun_open_door(void) " %d to %s failed - fatal", DoorFd, DoorFileName); DBGPRINTF("open_door: error: %s, errno=%d\n", line, err); - errno = err; - //logerror(line); + imsolaris_logerror(err, line); sun_delete_doorfiles(); exit(1); } @@ -394,15 +387,16 @@ sun_open_door(void) * and return a file descriptor. */ rsRetVal -sun_openklog(char *name, int *fd) +sun_openklog(char *name) { DEFiRet; + int fd; struct strioctl str; char errBuf[1024]; - if((*fd = open(name, O_RDONLY)) < 0) { + if((fd = open(name, O_RDONLY)) < 0) { rs_strerror_r(errno, errBuf, sizeof(errBuf)); - dbgprintf("imsolaris:openklog: cannot open %s: %s\n", + DBGPRINTF("imsolaris:openklog: cannot open %s: %s\n", name, errBuf); ABORT_FINALIZE(RS_RET_ERR_OPEN_KLOG); } @@ -410,87 +404,16 @@ sun_openklog(char *name, int *fd) str.ic_timout = 0; str.ic_len = 0; str.ic_dp = NULL; - if (ioctl(*fd, I_STR, &str) < 0) { + if (ioctl(fd, I_STR, &str) < 0) { rs_strerror_r(errno, errBuf, sizeof(errBuf)); - dbgprintf("imsolaris:openklog: cannot register to log " + DBGPRINTF("imsolaris:openklog: cannot register to log " "console messages: %s\n", errBuf); ABORT_FINALIZE(RS_RET_ERR_AQ_CONLOG); } - Pfd.fd = *fd; - Pfd.events = POLLIN; - dbgprintf("imsolaris/openklog: opened '%s' as fd %d.\n", name, *fd); + sun_Pfd.fd = fd; + sun_Pfd.events = POLLIN; + DBGPRINTF("imsolaris/openklog: opened '%s' as fd %d.\n", name, fd); finalize_it: RETiRet; } - - -/* this thread listens to the local stream log driver for log messages - * generated by this host, formats them, and queues them to the logger - * thread. - */ -/*ARGSUSED*/ -void -sun_sys_poll() -{ - int nfds; - - dbgprintf("imsolaris:sys_poll: sys_thread started\n"); - - for (;;) { - errno = 0; - - dbgprintf("imsolaris:sys_poll waiting for next message...\n"); - nfds = poll(&Pfd, 1, INFTIM); - - if (nfds == 0) - continue; - - if (nfds < 0) { - if (errno != EINTR) - dbgprintf("imsolaris:poll error"); - continue; - } - if (Pfd.revents & POLLIN) { - solaris_readLog(Pfd.fd); - } else { - /* TODO: shutdown, the rsyslog way (in v5!) -- check shutdown flag */ - if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - // TODO: trigger retry logic -/* logerror("kernel log driver poll error"); - (void) close(Pfd.fd); - Pfd.fd = -1; - */ - } - } - - } - /*NOTREACHED*/ -} - - -/* Open the log device, and pull up all pending messages. - */ -void -prepare_sys_poll() -{ - int nfds; - - Pfd.events = POLLIN; - - for (;;) { - dbgprintf("imsolaris:prepare_sys_poll waiting for next message...\n"); - nfds = poll(&Pfd, 1, 0); - if (nfds <= 0) { - break; - } - - if (Pfd.revents & POLLIN) { - solaris_readLog(Pfd.fd); - } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - //logerror("kernel log driver poll error"); - break; - } - } - -} diff --git a/plugins/imsolaris/sun_cddl.h b/plugins/imsolaris/sun_cddl.h index 0139b3d8..42e4b799 100644 --- a/plugins/imsolaris/sun_cddl.h +++ b/plugins/imsolaris/sun_cddl.h @@ -1,5 +1,7 @@ -rsRetVal sun_openklog(char *name, int *); +rsRetVal sun_openklog(char *name); void prepare_sys_poll(void); void sun_sys_poll(void); void sun_open_door(void); void sun_delete_doorfiles(void); + +extern struct pollfd sun_Pfd; /* Pollfd for local log device */ diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 173f15a8..09dc7ae6 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -362,6 +362,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_PEER_CLOSED_CONN = -2144, /**< remote peer closed connection (information, no error) */ RS_RET_ERR_OPEN_KLOG = -2145, /**< error opening the kernel log socket (primarily solaris) */ RS_RET_ERR_AQ_CONLOG = -2146, /**< error aquiring console log (on solaris) */ + RS_RET_ERR_DOOR = -2147, /**< some problems with handling the Solaris door functionality */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/runtime/stream.c b/runtime/stream.c index e8805a40..e6680adc 100644 --- a/runtime/stream.c +++ b/runtime/stream.c @@ -215,7 +215,8 @@ doPhysOpen(strm_t *pThis) } pThis->fd = open((char*)pThis->pszCurrFName, iFlags, pThis->tOpenMode); - DBGPRINTF("file '%s' opened as #%d with mode %d\n", pThis->pszCurrFName, pThis->fd, pThis->tOpenMode); + DBGPRINTF("file '%s' opened as #%d with mode %d\n", pThis->pszCurrFName, + pThis->fd, (int) pThis->tOpenMode); if(pThis->fd == -1) { char errStr[1024]; int err = errno; -- cgit From 1b282841f9f6a48cfefe472e1e42652d8b7cfb0c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 20 Apr 2010 14:56:23 +0200 Subject: finalized work on imsolaris Did a couple of clean-ups and made the module more robust. Among others, improved performance and structure, fixed the recovery handler (which did not correctly work before) and straightend out some minor issues. Doc and some platform tests are still missing, but other than that this version looks pretty good. --- plugins/imsolaris/imsolaris.c | 236 ++++++++++++++++++++++-------------------- 1 file changed, 126 insertions(+), 110 deletions(-) diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c index c8076d93..6b07ba2b 100644 --- a/plugins/imsolaris/imsolaris.c +++ b/plugins/imsolaris/imsolaris.c @@ -102,79 +102,16 @@ static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock static char *LogName = NULL; /* the log socket name TODO: make configurable! */ - -/* This function receives data from a socket indicated to be ready - * to receive and submits the message received for processing. - * rgerhards, 2007-12-20 - * Interface changed so that this function is passed the array index - * of the socket which is to be processed. This eases access to the - * growing number of properties. -- rgerhards, 2008-08-01 +/* a function to replace the sun logerror() function. + * It generates an error message from the supplied string. The main + * reason for not calling logError directly is that sun_cddl.c does not + * know or has acces to rsyslog objects (namely errmsg) -- and we do not + * want to do this effort. -- rgerhards, 2010-04-19 */ -rsRetVal -solaris_readLog(int fd) +void +imsolaris_logerror(int err, char *errStr) { - DEFiRet; - int iRcvd; - int iMaxLine; - struct strbuf data; - struct strbuf ctl; - struct log_ctl hdr; - int flags; - msg_t *pMsg; - int ret; - uchar bufRcv[4096+1]; - uchar *pRcv = NULL; /* receive buffer */ - char errStr[1024]; - - iMaxLine = glbl.GetMaxLine(); - - /* we optimize performance: if iMaxLine is below 4K (which it is in almost all - * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory - * is used. We could use alloca() to achive a similar aspect, but there are so - * many issues with alloca() that I do not want to take that route. - * rgerhards, 2008-09-02 - */ - if((size_t) iMaxLine < sizeof(bufRcv) - 1) { - pRcv = bufRcv; - } else { - CHKmalloc(pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))); - } - - data.buf = (char*)pRcv; - data.maxlen = iMaxLine; - ctl.maxlen = sizeof (struct log_ctl); - ctl.buf = (caddr_t)&hdr; - flags = 0; - ret = getmsg(fd, &ctl, &data, &flags); - if(ret < 0) { - rs_strerror_r(errno, errStr, sizeof(errStr)); - DBGPRINTF("imsolaris: getmsg() error on fd %d: %s.\n", fd, errStr); - } - DBGPRINTF("imsolaris: getmsg() returns %d\n", ret); - DBGPRINTF("imsolaris: message from log socket: #%d: %s\n", fd, pRcv); - if (1) {//iRcvd > 0) { - CHKiRet(msgConstruct(&pMsg)); - //MsgSetFlowControlType(pMsg, eFLOWCTL_FULL_DELAY); - MsgSetInputName(pMsg, pInputName); - MsgSetRawMsg(pMsg, (char*)pRcv, strlen((char*)pRcv)); - MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())); - pMsg->iFacility = LOG_FAC(hdr.pri); - pMsg->iSeverity = LOG_PRI(hdr.pri); - pMsg->bParseHOSTNAME = 0; - pMsg->msgFlags = NEEDS_PARSING | NO_PRI_IN_RAW; - CHKiRet(submitMsg(pMsg)); - } else if (iRcvd < 0 && errno != EINTR) { - int en = errno; - rs_strerror_r(en, errStr, sizeof(errStr)); - DBGPRINTF("imsolaris: stream error: %d = %s.\n", errno, errStr); - errmsg.LogError(en, NO_ERRCODE, "imsolaris: stream input error: %s", errStr); - } - -finalize_it: - if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) - free(pRcv); - - RETiRet; + errmsg.LogError(err, RS_RET_ERR_DOOR, "%s", errStr); } @@ -185,10 +122,10 @@ finalize_it: * iteration. * rgerhards, 2010-04-19 */ -static inline void +static void tryRecover(void) { - int tryNum = 0; + int tryNum = 1; int waitsecs; int waitusecs; rsRetVal iRet; @@ -199,17 +136,20 @@ tryRecover(void) while(1) { /* loop broken inside */ iRet = sun_openklog((LogName == NULL) ? PATH_LOG : LogName); if(iRet == RS_RET_OK) { - if(tryNum > 0) { + if(tryNum > 1) { errmsg.LogError(0, iRet, "failure on system log socket recovered."); } break; } /* failure, so sleep a bit. We wait try*10 ms, with a max of 15 seconds */ - if(tryNum == 0) { + if(tryNum == 1) { errmsg.LogError(0, iRet, "failure on system log socket, trying to recover..."); + } waitusecs = tryNum * 10000; waitsecs = waitusecs / 1000000; - if(waitsecs != 15) { + DBGPRINTF("imsolaris: try %d to recover system log socket in %d.%d seconds\n", + tryNum, waitsecs, waitusecs); + if(waitsecs > 15) { waitsecs = 15; waitusecs = 0; } else { @@ -217,21 +157,61 @@ tryRecover(void) } srSleep(waitsecs, waitusecs); ++tryNum; - } } } -/* a function to replace the sun logerror() function. - * It generates an error message from the supplied string. The main - * reason for not calling logError directly is that sun_cddl.c does not - * know or has acces to rsyslog objects (namely errmsg) -- and we do not - * want to do this effort. -- rgerhards, 2010-04-19 +/* This function receives data from a socket indicated to be ready + * to receive and submits the message received for processing. + * rgerhards, 2007-12-20 + * Interface changed so that this function is passed the array index + * of the socket which is to be processed. This eases access to the + * growing number of properties. -- rgerhards, 2008-08-01 */ -void -imsolaris_logerror(int err, char *errStr) +static rsRetVal +readLog(int fd, uchar *pRcv, int iMaxLine) { - errmsg.LogError(err, RS_RET_ERR_DOOR, "%s", errStr); + DEFiRet; + struct strbuf data; + struct strbuf ctl; + struct log_ctl hdr; + int flags; + msg_t *pMsg; + int ret; + char errStr[1024]; + + data.buf = (char*)pRcv; + data.maxlen = iMaxLine; + ctl.maxlen = sizeof (struct log_ctl); + ctl.buf = (caddr_t)&hdr; + flags = 0; + ret = getmsg(fd, &ctl, &data, &flags); + if(ret < 0) { + if(errno == EINTR) { + FINALIZE; + } else { + int en = errno; + rs_strerror_r(errno, errStr, sizeof(errStr)); + DBGPRINTF("imsolaris: stream input error on fd %d: %s.\n", fd, errStr); + errmsg.LogError(en, NO_ERRCODE, "imsolaris: stream input error: %s", errStr); + tryRecover(); + } + } else { + DBGPRINTF("imsolaris: message from log stream %d: %s\n", fd, pRcv); + pRcv[data.len] = '\0'; /* make sure it is a valid C-String */ + CHKiRet(msgConstruct(&pMsg)); + MsgSetInputName(pMsg, pInputName); + MsgSetRawMsg(pMsg, (char*)pRcv, strlen((char*)pRcv)); + MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())); + pMsg->iFacility = LOG_FAC(hdr.pri); + pMsg->iSeverity = LOG_PRI(hdr.pri); + pMsg->bParseHOSTNAME = 0; + pMsg->msgFlags = NEEDS_PARSING | NO_PRI_IN_RAW; + CHKiRet(submitMsg(pMsg)); + } + +finalize_it: + RETiRet; } @@ -248,43 +228,76 @@ getMsgs(int timeout) { DEFiRet; int nfds; + int iMaxLine; + uchar *pRcv = NULL; /* receive buffer */ + uchar bufRcv[4096+1]; char errStr[1024]; - do { - DBGPRINTF("imsolaris: waiting for next message (timeout %d)...\n", timeout); - nfds = poll(&sun_Pfd, 1, timeout); /* wait without timeout */ + iMaxLine = glbl.GetMaxLine(); - /* v5-TODO: here we must check if we should terminante! */ + /* we optimize performance: if iMaxLine is below 4K (which it is in almost all + * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory + * is used. We could use alloca() to achive a similar aspect, but there are so + * many issues with alloca() that I do not want to take that route. + * rgerhards, 2008-09-02 + */ + if((size_t) iMaxLine < sizeof(bufRcv) - 1) { + pRcv = bufRcv; + } else { + CHKmalloc(pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))); + } - if(nfds == 0) { - if(timeout == 0) { - DBGPRINTF("imsolaris: no more messages, getMsgs() terminates\n"); - FINALIZE; - } else { + do { + DBGPRINTF("imsolaris: waiting for next message (timeout %d)...\n", timeout); + if(timeout == 0) { + nfds = poll(&sun_Pfd, 1, timeout); /* wait without timeout */ + + /* v5-TODO: here we must check if we should terminante! */ + + if(nfds == 0) { + if(timeout == 0) { + DBGPRINTF("imsolaris: no more messages, getMsgs() terminates\n"); + FINALIZE; + } else { + continue; + } + } + + if(nfds < 0) { + if(errno != EINTR) { + int en = errno; + rs_strerror_r(en, errStr, sizeof(errStr)); + DBGPRINTF("imsolaris: poll error: %d = %s.\n", errno, errStr); + errmsg.LogError(en, NO_ERRCODE, "imsolaris: poll error: %s", + errStr); + } continue; - } - } - - if(nfds < 0) { - if(errno != EINTR) { - int en = errno; - rs_strerror_r(en, errStr, sizeof(errStr)); - DBGPRINTF("imsolaris: poll error: %d = %s.\n", errno, errStr); - errmsg.LogError(en, NO_ERRCODE, "imsolaris: poll error: %s", errStr); } - continue; - } - if(sun_Pfd.revents & POLLIN) { - solaris_readLog(sun_Pfd.fd); - } else if(sun_Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - tryRecover(); + if(sun_Pfd.revents & POLLIN) { + readLog(sun_Pfd.fd, pRcv, iMaxLine); + } else if(sun_Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + tryRecover(); + } + } else { + /* if we have an infinite wait, we do not use poll at all + * I'd consider this a waste of time. However, I do not totally + * remove the code, as it may be useful if we decide at some + * point to provide a capability to support multiple input streams + * at once (this may be useful for a jail). In that case, the poll() + * loop would be needed, and so it doesn't make much sense to change + * the code to not support it. -- rgerhards, 2010-04-20 + */ + readLog(sun_Pfd.fd, pRcv, iMaxLine); } - } while(1); + } while(1); /* TODO: in v5, we must check the termination predicate */ /* Note: in v4, this code is never reached (our thread will be cancelled) */ finalize_it: + if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) + free(pRcv); + RETiRet; } @@ -333,6 +346,7 @@ CODESTARTafterRun /* do cleanup here */ if(pInputName != NULL) prop.Destruct(&pInputName); + free(LogName); ENDafterRun @@ -370,6 +384,8 @@ CODEmodInit_QueryRegCFSLineHdlr /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"imsolarislogsocketname", 0, eCmdHdlrGetWord, + NULL, &LogName, STD_LOADABLE_MODULE_ID)); ENDmodInit /* vim:set ai: */ -- cgit From e52c7224ba92bc1126c584167124d04f717e48a2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 20 Apr 2010 15:37:28 +0200 Subject: testbench improvement: Java is no longer needed for testing tool creation --- ChangeLog | 1 + tests/Makefile.am | 10 ++-- tests/diag.sh | 6 +-- tests/diagtalker.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 tests/diagtalker.c diff --git a/ChangeLog b/ChangeLog index d0cab9e8..d279009e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ Version 4.7.1 [v4-devel] (rgerhards), 2010-04-?? Solaris is no longer supported in imklog, but rather there is a new plugin imsolaris, which is used to pull local log sources on a Solaris machine. +- testbench improvement: Java is no longer needed for testing tool creation --------------------------------------------------------------------------- Version 4.7.0 [v4-devel] (rgerhards), 2010-04-14 - new: support for Solaris added (but not yet the Solaris door API) diff --git a/tests/Makefile.am b/tests/Makefile.am index a43f305e..8ec72d4f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ if ENABLE_TESTBENCH TESTRUNS = rt_init rscript -check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen +check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker TESTS = $(TESTRUNS) cfg.sh \ validation-run.sh \ imtcp-multiport.sh \ @@ -45,12 +45,10 @@ if ENABLE_EXTENDED_TESTS TESTS += random.sh endif -check_JAVA = DiagTalker.java - endif # if ENABLE_TESTBENCH TESTS_ENVIRONMENT = RSYSLOG_MODDIR='$(abs_top_builddir)'/runtime/.libs/ -DISTCLEANFILES=rsyslog.pid '$(abs_top_builddir)'/DiagTalker.class +DISTCLEANFILES=rsyslog.pid test_files = testbench.h runtime-dummy.c EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ @@ -204,7 +202,6 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ execonlyonce.sh \ testsuites/execonlyonce.conf \ testsuites/execonlyonce.data \ - DiagTalker.java \ cfg.sh ourtail_SOURCES = ourtail.c @@ -214,6 +211,9 @@ chkseq_SOURCES = chkseq.c tcpflood_SOURCES = tcpflood.c tcpflood_LDADD = $(SOL_LIBS) +diagtalker_SOURCES = diagtalker.c +diagtalker_LDADD = $(SOL_LIBS) + randomgen_SOURCES = randomgen.c randomgen_LDADD = $(SOL_LIBS) diff --git a/tests/diag.sh b/tests/diag.sh index 54232a37..83d5b561 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -51,9 +51,9 @@ case $1 in 'wait-queueempty') # wait for main message queue to be empty. $2 is the instance. if [ "$2" == "2" ] then - echo WaitMainQueueEmpty | java -classpath $abs_top_builddir DiagTalker + echo WaitMainQueueEmpty | ./diagtalker else - echo WaitMainQueueEmpty | java -classpath $abs_top_builddir DiagTalker 13501 + echo WaitMainQueueEmpty | ./diagtalker fi ;; 'shutdown-when-empty') # shut rsyslogd down when main queue is empty. $2 is the instance. @@ -75,7 +75,7 @@ case $1 in ;; 'injectmsg') # inject messages via our inject interface (imdiag) echo injecting $3 messages - echo injectmsg $2 $3 $4 $5 | java -classpath $abs_top_builddir DiagTalker + echo injectmsg $2 $3 $4 $5 | ./diagtalker # TODO: some return state checking? (does it really make sense here?) ;; 'check-mainq-spool') # check if mainqueue spool files exist, if not abort (we just check .qi). diff --git a/tests/diagtalker.c b/tests/diagtalker.c new file mode 100644 index 00000000..f5fd1c40 --- /dev/null +++ b/tests/diagtalker.c @@ -0,0 +1,156 @@ +/* A yet very simple tool to talk to imdiag (this replaces the + * previous Java implementation in order to get fewer dependencies). + * + * Copyright 2010 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include + + +static char *targetIP = "127.0.0.1"; +static int targetPort = 13500; + + +/* open a single tcp connection + */ +int openConn(int *fd) +{ + int sock; + struct sockaddr_in addr; + int port; + int retries = 0; + + if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) { + perror("socket()"); + exit(1); + } + + port = targetPort; + memset((char *) &addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if(inet_aton(targetIP, &addr.sin_addr)==0) { + fprintf(stderr, "inet_aton() failed\n"); + exit(1); + } + while(1) { /* loop broken inside */ + if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == 0) { + break; + } else { + if(retries++ == 50) { + perror("connect()"); + fprintf(stderr, "connect() failed\n"); + exit(1); + } else { + usleep(100000); /* ms = 1000 us! */ + } + } + } + + *fd = sock; + return 0; +} + + +/* send a string + */ +static void +sendCmd(int fd, char *buf, int len) +{ + int lenSend; + + lenSend = send(fd, buf, len, 0); + if(lenSend != len) { + perror("sending string"); + exit(1); + } +} + + +/* wait for a response from remote system + */ +static void +waitRsp(int fd, char *buf, int len) +{ + int ret; + + ret = recv(fd, buf, len - 1, 0); + if(ret < 0) { + perror("receiving response"); + exit(1); + } + /* we assume the message was complete, it may be better to wait + * for a LF... + */ + buf[ret] = '\0'; +} + + +/* do the actual processing + */ +static void +doProcessing() +{ + int fd; + int len; + char line[2048]; + + openConn(&fd); + while(!feof(stdin)) { + if(fgets(line, sizeof(line) - 1, stdin) == NULL) + break; + len = strlen(line); + sendCmd(fd, line, len); + waitRsp(fd, line, sizeof(line)); + printf("imdiag: %s", line); + } +} + + +/* Run the test. + * rgerhards, 2009-04-03 + */ +int main(int argc, char *argv[]) +{ + int ret = 0; + int opt; + + while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:n:M:rB")) != -1) { + switch (opt) { + case 't': targetIP = optarg; + break; + case 'p': targetPort = atoi(optarg); + break; + default: printf("invalid option '%c' or value missing - terminating...\n", opt); + exit (1); + break; + } + } + + doProcessing(); + + exit(ret); +} -- cgit From 881d5e8c27a921e7add15bbbaf8a9fc1820843e1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 20 Apr 2010 15:39:29 +0200 Subject: saved old copy of Java DiagTalker tool --- tests/DiagTalker.java | 73 --------------------------------------- tests/historical/DiagTalker.java | 74 ++++++++++++++++++++++++++++++++++++++++ tests/historical/README | 2 ++ 3 files changed, 76 insertions(+), 73 deletions(-) delete mode 100644 tests/DiagTalker.java create mode 100644 tests/historical/DiagTalker.java create mode 100644 tests/historical/README diff --git a/tests/DiagTalker.java b/tests/DiagTalker.java deleted file mode 100644 index 5a6f7dd5..00000000 --- a/tests/DiagTalker.java +++ /dev/null @@ -1,73 +0,0 @@ -/* A yet very simple tool to talk to imdiag. - * - * 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 . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -//package com.rsyslog.diag; -import java.io.*; -import java.net.*; - -public class DiagTalker { - public static void main(String[] args) throws IOException { - - Socket diagSocket = null; - PrintWriter out = null; - BufferedReader in = null; - final String host = "127.0.0.1"; - int port = 13500; - if(args.length > 1) { - port = Integer.parseInt(args[1]); - } - - try { - diagSocket = new Socket(host, port); - diagSocket.setSoTimeout(0); /* wait for lenghty operations */ - out = new PrintWriter(diagSocket.getOutputStream(), true); - in = new BufferedReader(new InputStreamReader( - diagSocket.getInputStream())); - } catch (UnknownHostException e) { - System.err.println("can not resolve " + host + "!"); - System.exit(1); - } catch (IOException e) { - System.err.println("Couldn't get I/O for " - + "the connection to: " + host + "."); - System.exit(1); - } - - BufferedReader stdIn = new BufferedReader( - new InputStreamReader(System.in)); - String userInput; - - try { - while ((userInput = stdIn.readLine()) != null) { - out.println(userInput); - System.out.println("imdiag returns: " + in.readLine()); - } - } catch (SocketException e) { - System.err.println("We had a socket exception and consider this to be OK: " - + e.getMessage()); - } - - out.close(); - in.close(); - stdIn.close(); - diagSocket.close(); - } -} - diff --git a/tests/historical/DiagTalker.java b/tests/historical/DiagTalker.java new file mode 100644 index 00000000..147cec34 --- /dev/null +++ b/tests/historical/DiagTalker.java @@ -0,0 +1,74 @@ +This tool has been replaced by ./tests/diagtalker.c in release 4.7.1 +/* A yet very simple tool to talk to imdiag. + * + * 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +//package com.rsyslog.diag; +import java.io.*; +import java.net.*; + +public class DiagTalker { + public static void main(String[] args) throws IOException { + + Socket diagSocket = null; + PrintWriter out = null; + BufferedReader in = null; + final String host = "127.0.0.1"; + int port = 13500; + if(args.length > 1) { + port = Integer.parseInt(args[1]); + } + + try { + diagSocket = new Socket(host, port); + diagSocket.setSoTimeout(0); /* wait for lenghty operations */ + out = new PrintWriter(diagSocket.getOutputStream(), true); + in = new BufferedReader(new InputStreamReader( + diagSocket.getInputStream())); + } catch (UnknownHostException e) { + System.err.println("can not resolve " + host + "!"); + System.exit(1); + } catch (IOException e) { + System.err.println("Couldn't get I/O for " + + "the connection to: " + host + "."); + System.exit(1); + } + + BufferedReader stdIn = new BufferedReader( + new InputStreamReader(System.in)); + String userInput; + + try { + while ((userInput = stdIn.readLine()) != null) { + out.println(userInput); + System.out.println("imdiag returns: " + in.readLine()); + } + } catch (SocketException e) { + System.err.println("We had a socket exception and consider this to be OK: " + + e.getMessage()); + } + + out.close(); + in.close(); + stdIn.close(); + diagSocket.close(); + } +} + diff --git a/tests/historical/README b/tests/historical/README new file mode 100644 index 00000000..5f10ecef --- /dev/null +++ b/tests/historical/README @@ -0,0 +1,2 @@ +This directory contains tools that are currently not being used, but are +kept because they may be used again in the future. -- cgit From 74000ea71eb47c19653e0cd7bbffb83d913c3923 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 20 Apr 2010 15:49:58 +0200 Subject: doc for imsolaris added --- doc/Makefile.am | 1 + doc/imsolaris.html | 47 +++++++++++++++++++++++++++++++++++++++++++ doc/rsyslog_conf_modules.html | 1 + 3 files changed, 49 insertions(+) create mode 100644 doc/imsolaris.html diff --git a/doc/Makefile.am b/doc/Makefile.am index a1f192ee..9ca0afe6 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -39,6 +39,7 @@ html_files = \ imtcp.html \ imgssapi.html \ imrelp.html \ + imsolaris.html \ imuxsock.html \ imklog.html \ professional_support.html \ diff --git a/doc/imsolaris.html b/doc/imsolaris.html new file mode 100644 index 00000000..ce0e7e84 --- /dev/null +++ b/doc/imsolaris.html @@ -0,0 +1,47 @@ + + + +Solaris Input Module (imsolaris) + + + +back + +

    Solaris Input Module

    +

    Module Name:    imsolaris

    +

    Author: Rainer Gerhards +<rgerhards@adiscon.com>

    +

    Description:

    +

    Reads local Solaris log messages including the kernel log.

    +

    This module is specifically tailored for Solaris. Under Solaris, there +is no special kernel input device. Instead, both kernel messages as well as +messages emitted via syslog() are received from a single source. +

    This module obeys the Solaris door() mechanism to detect a running syslogd +instance. As such, only one can be active at one time. If it detects another +active intance at startup, the module disables itself, but rsyslog will +continue to run. +

    Configuration Directives:

    +
      +
    • $IMSolarisLogSocketName <name>
      +This is the name of the log socket (stream) to read. If not given, /dev/log +is read. +
    • +
    +Caveats/Known Bugs: +

    None currently known. For obvious reasons, works on Solaris, only (and compilation +will most probably fail on any other platform). +

    Sample:

    +

    The following sample pulls messages from the default log source +
    +

    + +

    [rsyslog.conf overview] +[manual index] [rsyslog site]

    +

    This documentation is part of the +rsyslog +project.
    +Copyright © 2010 by Rainer Gerhards and +Adiscon. +Released under the GNU GPL version 3 or higher.

    + diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html index 675b8bb3..c36b8c6d 100644 --- a/doc/rsyslog_conf_modules.html +++ b/doc/rsyslog_conf_modules.html @@ -32,6 +32,7 @@ to message generators.
  • immark - support for mark messages
  • imklog - kernel logging
  • imuxsock - unix sockets, including the system log socket
  • +
  • imsolaris - input for the Sun Solaris system log source
  • im3195 - accepts syslog messages via RFC 3195
  • -- cgit From b526e3d92f214aa2a3d0e3c2746884e9a9dba411 Mon Sep 17 00:00:00 2001 From: Super-User Date: Wed, 21 Apr 2010 17:36:03 +0100 Subject: bugfix: some race condition in testbench on Solaris/Sparc --- tests/diag.sh | 3 +++ tests/diagtalker.c | 1 + tests/threadingmqaq.sh | 3 +++ 3 files changed, 7 insertions(+) diff --git a/tests/diag.sh b/tests/diag.sh index 83d5b561..1caf529f 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -37,6 +37,9 @@ case $1 in $srcdir/diag.sh wait-startup $3 ;; 'wait-startup') # wait for rsyslogd startup ($2 is the instance) + while test ! -f rsyslog$2.pid; do + ./msleep 100 # wait 100 milliseconds + done while test ! -f rsyslogd$2.started; do ./msleep 100 # wait 100 milliseconds done diff --git a/tests/diagtalker.c b/tests/diagtalker.c index f5fd1c40..6a721e47 100644 --- a/tests/diagtalker.c +++ b/tests/diagtalker.c @@ -65,6 +65,7 @@ int openConn(int *fd) fprintf(stderr, "connect() failed\n"); exit(1); } else { + fprintf(stderr, "connect failed, retrying...\n"); usleep(100000); /* ms = 1000 us! */ } } diff --git a/tests/threadingmqaq.sh b/tests/threadingmqaq.sh index b7764821..0104be00 100755 --- a/tests/threadingmqaq.sh +++ b/tests/threadingmqaq.sh @@ -12,6 +12,9 @@ source $srcdir/diag.sh startup threadingmqaq.conf #source $srcdir/diag.sh tcpflood -c2 -m100000 #source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages source $srcdir/diag.sh injectmsg 0 100000 +# we need to sleep a bit on some environments, as imdiag can not correctly +# diagnose when the action queues are empty... +sleep 3 source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages source $srcdir/diag.sh wait-shutdown source $srcdir/diag.sh seq-check 0 99999 -- cgit From f902c9ca4891dcd65fd1f4b8bba0d23c75451dcd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 21 Apr 2010 18:25:17 +0100 Subject: removed some complier warnings --- runtime/rsyslog.h | 14 ++++++++++++-- runtime/wtp.c | 6 ++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 09dc7ae6..acc31a99 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -60,6 +60,11 @@ #endif +/* under Solaris (actually only SPARC), we need to redefine some types + * to be void, so that we get void* pointers. Otherwise, we will see +* alignment errors. +*/ + /* define some base data types */ typedef unsigned char uchar;/* get rid of the unhandy "unsigned char" */ typedef struct thrdInfo thrdInfo_t; @@ -78,8 +83,13 @@ typedef struct nsd_gsspi_s nsd_gsspi_t; typedef struct nsd_nss_s nsd_nss_t; typedef struct nsdsel_ptcp_s nsdsel_ptcp_t; typedef struct nsdsel_gtls_s nsdsel_gtls_t; -typedef obj_t nsd_t; -typedef obj_t nsdsel_t; +#ifdef OS_SOLARIS + typedef void nsd_t; + typedef void nsdsel_t; +#else + typedef obj_t nsd_t; + typedef obj_t nsdsel_t; +#endif typedef struct msg msg_t; typedef struct prop_s prop_t; typedef struct interface_s interface_t; diff --git a/runtime/wtp.c b/runtime/wtp.c index 0c66dd11..271c6f0d 100644 --- a/runtime/wtp.c +++ b/runtime/wtp.c @@ -421,13 +421,15 @@ wtpWrkrExecCancelCleanup(void *arg) static void * wtpWorker(void *arg) /* the arg is actually a wti object, even though we are in wtp! */ { - uchar *pszDbgHdr; - uchar thrdName[32] = "rs:"; DEFiRet; DEFVARS_mutexProtection; wti_t *pWti = (wti_t*) arg; wtp_t *pThis; sigset_t sigSet; +# if HAVE_PRCTL && defined PR_SET_NAME + uchar *pszDbgHdr; + uchar thrdName[32] = "rs:"; +# endif ISOBJ_TYPE_assert(pWti, wti); pThis = pWti->pWtp; -- cgit From 3a12d05433153d5c7c84f85af6b5039fbcdd1d09 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 22 Apr 2010 14:38:12 +0100 Subject: solved alignment errors on Solaris Sparc --- action.c | 20 ++++++++++---------- action.h | 3 ++- plugins/omstdout/omstdout.c | 2 +- runtime/msg.c | 2 +- runtime/net.c | 8 ++++---- runtime/rsyslog.h | 28 ++++++++++++++++------------ 6 files changed, 34 insertions(+), 29 deletions(-) diff --git a/action.c b/action.c index 724dea4b..5451ef13 100644 --- a/action.c +++ b/action.c @@ -200,7 +200,7 @@ rsRetVal actionDestruct(action_t *pThis) /* message ptr cleanup */ for(i = 0 ; i < pThis->iNumTpls ; ++i) { - if(pThis->ppMsgs[i] != NULL) { + if(((uchar**)pThis->ppMsgs)[i] != NULL) { switch(pThis->eParamPassing) { case ACT_ARRAY_PASSING: #if 0 /* later! */ @@ -214,7 +214,7 @@ rsRetVal actionDestruct(action_t *pThis) #endif break; case ACT_STRING_PASSING: - d_free(pThis->ppMsgs[i]); + d_free(((uchar**)pThis->ppMsgs)[i]); break; default: assert(0); @@ -475,10 +475,10 @@ actionCallDoAction(action_t *pAction, msg_t *pMsg) for(i = 0 ; i < pAction->iNumTpls ; ++i) { switch(pAction->eParamPassing) { case ACT_STRING_PASSING: - CHKiRet(tplToString(pAction->ppTpl[i], pMsg, &(pAction->ppMsgs[i]), &(pAction->lenMsgs[i]))); + CHKiRet(tplToString(pAction->ppTpl[i], pMsg, &(((uchar**)pAction->ppMsgs)[i]), &(pAction->lenMsgs[i]))); break; case ACT_ARRAY_PASSING: - CHKiRet(tplToArray(pAction->ppTpl[i], pMsg, (uchar***) &(pAction->ppMsgs[i]))); + CHKiRet(tplToArray(pAction->ppTpl[i], pMsg, (uchar***) &(((uchar**)pAction->ppMsgs)[i]))); break; default:assert(0); /* software bug if this happens! */ } @@ -526,16 +526,16 @@ actionCallDoAction(action_t *pAction, msg_t *pMsg) finalize_it: /* cleanup */ for(i = 0 ; i < pAction->iNumTpls ; ++i) { - if(pAction->ppMsgs[i] != NULL) { + if(((uchar**)pAction->ppMsgs)[i] != NULL) { switch(pAction->eParamPassing) { case ACT_ARRAY_PASSING: iArr = 0; - while(((char **)pAction->ppMsgs[i])[iArr] != NULL) { - d_free(((char **)pAction->ppMsgs[i])[iArr++]); - ((char **)pAction->ppMsgs[i])[iArr++] = NULL; + while((((uchar***)pAction->ppMsgs)[i][iArr]) != NULL) { + d_free(((uchar ***)pAction->ppMsgs)[i][iArr++]); + ((uchar ***)pAction->ppMsgs)[i][iArr++] = NULL; } - d_free(pAction->ppMsgs[i]); - pAction->ppMsgs[i] = NULL; + d_free(((uchar**)pAction->ppMsgs)[i]); + ((uchar**)pAction->ppMsgs)[i] = NULL; break; case ACT_STRING_PASSING: break; diff --git a/action.h b/action.h index 579a1215..c4ef94bb 100644 --- a/action.h +++ b/action.h @@ -74,7 +74,8 @@ struct action_s { SYNC_OBJ_TOOL; /* required for mutex support */ pthread_mutex_t mutActExec; /* mutex to guard actual execution of doAction for single-threaded modules */ uchar *pszName; /* action name (for documentation) */ - uchar **ppMsgs; /* pointer to action-calling parameters (kept in structure to save alloc() time!) */ + //uchar **ppMsgs; /* pointer to action-calling parameters (kept in structure to save alloc() time!) */ + void *ppMsgs; /* pointer to action-calling parameters (kept in structure to save alloc() time!) */ size_t *lenMsgs; /* length of message in ppMsgs */ }; typedef struct action_s action_t; diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c index b3ec6287..929de703 100644 --- a/plugins/omstdout/omstdout.c +++ b/plugins/omstdout/omstdout.c @@ -103,7 +103,7 @@ CODESTARTdoAction * So this code here is also more or less an example of how to do that. * rgerhards, 2009-04-03 */ - szParams = (char**) (ppString[0]); + szParams = (char**)(void*) (ppString[0]); /* In array-passing mode, ppString[] contains a NULL-terminated array * of char *pointers. */ diff --git a/runtime/msg.c b/runtime/msg.c index 91057f97..6d7e6a89 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -3048,7 +3048,7 @@ static rsRetVal msgConstructFinalizer(msg_t *pThis) * rgerhards, 2008-01-14 */ static rsRetVal -MsgGetSeverity(obj_t *pThis, int *piSeverity) +MsgGetSeverity(obj_t_ptr pThis, int *piSeverity) { ISOBJ_TYPE_assert(pThis, msg); assert(piSeverity != NULL); diff --git a/runtime/net.c b/runtime/net.c index fe6eef5b..4eb5a3bb 100644 --- a/runtime/net.c +++ b/runtime/net.c @@ -502,8 +502,8 @@ static inline void MaskIP4 (struct in_addr *addr, uint8_t bits) { addr->s_addr &= htonl(0xffffffff << (32 - bits)); } -#define SIN(sa) ((struct sockaddr_in *)(sa)) -#define SIN6(sa) ((struct sockaddr_in6 *)(sa)) +#define SIN(sa) ((struct sockaddr_in *)(void*)(sa)) +#define SIN6(sa) ((struct sockaddr_in6 *)(void*)(sa)) /* This is a cancel-safe getnameinfo() version, because we learned @@ -1165,12 +1165,12 @@ void debugListenInfo(int fd, char *type) switch(sa.sa_family) { case PF_INET: szFamily = "IPv4"; - ipv4 = (struct sockaddr_in*) &sa; + ipv4 = (struct sockaddr_in*)(void*) &sa; port = ntohs(ipv4->sin_port); break; case PF_INET6: szFamily = "IPv6"; - ipv6 = (struct sockaddr_in6*) &sa; + ipv6 = (struct sockaddr_in6*)(void*) &sa; port = ntohs(ipv6->sin6_port); break; default: diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index acc31a99..b7117029 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -60,12 +60,8 @@ #endif -/* under Solaris (actually only SPARC), we need to redefine some types - * to be void, so that we get void* pointers. Otherwise, we will see -* alignment errors. -*/ - /* define some base data types */ + typedef unsigned char uchar;/* get rid of the unhandy "unsigned char" */ typedef struct thrdInfo thrdInfo_t; typedef struct obj_s obj_t; @@ -83,13 +79,6 @@ typedef struct nsd_gsspi_s nsd_gsspi_t; typedef struct nsd_nss_s nsd_nss_t; typedef struct nsdsel_ptcp_s nsdsel_ptcp_t; typedef struct nsdsel_gtls_s nsdsel_gtls_t; -#ifdef OS_SOLARIS - typedef void nsd_t; - typedef void nsdsel_t; -#else - typedef obj_t nsd_t; - typedef obj_t nsdsel_t; -#endif typedef struct msg msg_t; typedef struct prop_s prop_t; typedef struct interface_s interface_t; @@ -108,6 +97,21 @@ typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript f typedef struct tcpLstnPortList_s tcpLstnPortList_t; // TODO: rename? typedef struct strmLstnPortList_s strmLstnPortList_t; // TODO: rename? +/* under Solaris (actually only SPARC), we need to redefine some types + * to be void, so that we get void* pointers. Otherwise, we will see + * alignment errors. + */ +#ifdef OS_SOLARIS + typedef void * obj_t_ptr; + typedef void nsd_t; + typedef void nsdsel_t; +#else + typedef obj_t obj_t_ptr; + typedef obj_t nsd_t; + typedef obj_t nsdsel_t; +#endif + + /* some universal 64 bit define... */ typedef long long int64; typedef long long unsigned uint64; -- cgit From afe45bbbe250c2ba73858ca37e4a2a6cb18f6f8e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 22 Apr 2010 15:09:40 +0200 Subject: fixed typo ... that caused compilation to fail on non-Solaris --- runtime/rsyslog.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index b7117029..a6dfc9ed 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -106,7 +106,7 @@ typedef struct strmLstnPortList_s strmLstnPortList_t; // TODO: rename? typedef void nsd_t; typedef void nsdsel_t; #else - typedef obj_t obj_t_ptr; + typedef obj_t *obj_t_ptr; typedef obj_t nsd_t; typedef obj_t nsdsel_t; #endif -- cgit From 9ba148cca62620d0bc9357b46393f9b5e2d6ede0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 22 Apr 2010 15:32:15 +0200 Subject: preparing for 4.7.1 release --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index d279009e..7a1ad2ee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 4.7.1 [v4-devel] (rgerhards), 2010-04-?? +Version 4.7.1 [v4-devel] (rgerhards), 2010-04-22 - Solaris support much improved -- was not truely usable in 4.7.0 Solaris is no longer supported in imklog, but rather there is a new plugin imsolaris, which is used to pull local log sources on a Solaris diff --git a/configure.ac b/configure.ac index 287534cd..6a4d2817 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[4.7.0],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[4.7.1],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([ChangeLog]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/manual.html b/doc/manual.html index 3d9a2f2d..a5f12a56 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@ rsyslog support available directly from the source!

    Please visit the rsyslog sponsor's page to honor the project sponsors or become one yourself! We are very grateful for any help towards the project goals.

    -

    This documentation is for version 4.7.0 (v4-devel branch) of rsyslog. +

    If you like rsyslog, you might -- cgit From 57eb123abe8aa4c169a5a155247f036b703cd8cf Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 23 Apr 2010 12:59:11 +0100 Subject: minor fix: invalid duplicated include of config.h --- runtime/atomic.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/runtime/atomic.h b/runtime/atomic.h index ea3be37a..271e825e 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -31,8 +31,6 @@ * A copy of the GPL can be found in the file "COPYING" in this distribution. * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. */ -#include "config.h" /* autotools! */ - #ifndef INCLUDED_ATOMIC_H #define INCLUDED_ATOMIC_H -- cgit From bbde403b46bd94cb8900562d8cfd3e0540913730 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 23 Apr 2010 13:00:21 +0100 Subject: cosmetic: prepared ChangeLog for next release --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 7a1ad2ee..447f22fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ --------------------------------------------------------------------------- +Version 4.7.2 [v4-devel] (rgerhards), 2010-04-?? +--------------------------------------------------------------------------- Version 4.7.1 [v4-devel] (rgerhards), 2010-04-22 - Solaris support much improved -- was not truely usable in 4.7.0 Solaris is no longer supported in imklog, but rather there is a new -- cgit From d19806431653e6575a002ab48206c16d3041e465 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 26 Apr 2010 12:08:00 +0200 Subject: added new $Sleep directive to hold processing for a couple of seconds during startup --- ChangeLog | 2 ++ doc/rsyslog_conf_global.html | 5 ++++- tools/syslogd.c | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 447f22fb..80779457 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ --------------------------------------------------------------------------- Version 4.7.2 [v4-devel] (rgerhards), 2010-04-?? +- added new $Sleep directive to hold processing for a couple of seconds + during startup --------------------------------------------------------------------------- Version 4.7.1 [v4-devel] (rgerhards), 2010-04-22 - Solaris support much improved -- was not truely usable in 4.7.0 diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html index 8137bcba..8c1cc9a7 100644 --- a/doc/rsyslog_conf_global.html +++ b/doc/rsyslog_conf_global.html @@ -273,6 +273,9 @@ the value, the less precise the timestamp.

  • $PrivDropToGroupID
  • $PrivDropToUser
  • $PrivDropToUserID
  • +
  • $Sleep <seconds> - puts the rsyslog main thread to sleep for the specified +number of seconds immediately when the directive is encountered. You should have a +good reason for using this directive!
  • $UMASK
  • Where <size_nbr> is specified above, @@ -291,7 +294,7 @@ point of view, "1,,0.0.,.,0" also has the value 1000.

    [rsyslog site]

    This documentation is part of the rsyslog project.
    -Copyright © 2008, 2009 by Rainer Gerhards and +Copyright © 2008-2010 by Rainer Gerhards and Adiscon. Released under the GNU GPL version 3 or higher.

    diff --git a/tools/syslogd.c b/tools/syslogd.c index e318fd8e..98bfd3b2 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -2460,6 +2460,25 @@ finalize_it: } + +/* Put the rsyslog main thread to sleep for n seconds. This was introduced as + * a quick and dirty workaround for a privilege drop race in regard to listener + * startup, which itself was a result of the not-yet-done proper coding of + * privilege drop code (quite some effort). It may be useful for other occasions, too. + * is specified). + * rgerhards, 2009-06-12 + */ +static rsRetVal +putToSleep(void __attribute__((unused)) *pVal, int iNewVal) +{ + DEFiRet; + DBGPRINTF("rsyslog main thread put to sleep via $sleep %d directive...\n", iNewVal); + srSleep(iNewVal, 0); + DBGPRINTF("rsyslog main thread continues after $sleep %d\n", iNewVal); + RETiRet; +} + + /* Switch to either an already existing rule set or start a new one. The * named rule set becomes the new "current" rule set (what means that new * actions are added to it). @@ -2713,6 +2732,7 @@ static rsRetVal loadBuildInModules(void) CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeretrycount", 0, eCmdHdlrInt, NULL, &glbliActionResumeRetryCount, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, setCurrRuleset, NULL, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrInt, putToSleep, NULL, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQHighWtrMark, NULL)); -- cgit From cbe2e3d44496ec7c6418e7e74ce917f2086a2947 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 27 Apr 2010 17:31:28 +0200 Subject: bugfix: problems with atomic operations emulation replaced atomic operation emulation with new code. The previous code seemed to have some issue and also limited concurrency severely. The whole atomic operation emulation has been rewritten. --- ChangeLog | 4 + runtime/Makefile.am | 1 - runtime/atomic-posix-sem.c | 70 ---------------- runtime/atomic.h | 200 ++++++++++++++++----------------------------- runtime/debug.c | 2 +- runtime/msg.c | 13 ++- runtime/msg.h | 1 + runtime/prop.c | 6 +- runtime/prop.h | 2 + runtime/queue.c | 10 ++- runtime/queue.h | 1 + runtime/rsyslog.c | 12 --- runtime/wti.c | 11 +-- runtime/wti.h | 1 + runtime/wtp.c | 18 +++- runtime/wtp.h | 3 + 16 files changed, 129 insertions(+), 226 deletions(-) delete mode 100644 runtime/atomic-posix-sem.c diff --git a/ChangeLog b/ChangeLog index 80779457..f7b838d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ --------------------------------------------------------------------------- Version 4.7.2 [v4-devel] (rgerhards), 2010-04-?? +- bugfix: problems with atomic operations emulaton + replaced atomic operation emulation with new code. The previous code + seemed to have some issue and also limited concurrency severely. The + whole atomic operation emulation has been rewritten. - added new $Sleep directive to hold processing for a couple of seconds during startup --------------------------------------------------------------------------- diff --git a/runtime/Makefile.am b/runtime/Makefile.am index ac006bca..c1a15198 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -9,7 +9,6 @@ librsyslog_la_SOURCES = \ rsyslog.h \ unicode-helper.h \ atomic.h \ - atomic-posix-sem.c \ syslogd-types.h \ module-template.h \ obj-types.h \ diff --git a/runtime/atomic-posix-sem.c b/runtime/atomic-posix-sem.c deleted file mode 100644 index 979fae02..00000000 --- a/runtime/atomic-posix-sem.c +++ /dev/null @@ -1,70 +0,0 @@ -/* atomic_posix_sem.c: This file supplies an emulation for atomic operations using - * POSIX semaphores. - * - * Copyright 2010 DResearch Digital Media Systems GmbH - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime library 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#ifndef HAVE_ATOMIC_BUILTINS -#ifdef HAVE_SEMAPHORE_H -#include -#include - -#include "atomic.h" -#include "rsyslog.h" -#include "srUtils.h" - -sem_t atomicSem; - -rsRetVal -atomicSemInit(void) -{ - DEFiRet; - - dbgprintf("init posix semaphore for atomics emulation\n"); - if(sem_init(&atomicSem, 0, 1) == -1) - { - char errStr[1024]; - rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("init posix semaphore for atomics emulation failed: %s\n", errStr); - iRet = RS_RET_SYS_ERR; /* the right error code ??? */ - } - - RETiRet; -} - -void -atomicSemExit(void) -{ - dbgprintf("destroy posix semaphore for atomics emulation\n"); - if(sem_destroy(&atomicSem) == -1) - { - char errStr[1024]; - rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("destroy posix semaphore for atomics emulation failed: %s\n", errStr); - } -} - -#endif /* HAVE_SEMAPHORE_H */ -#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ - -/* vim:set ai: - */ diff --git a/runtime/atomic.h b/runtime/atomic.h index 271e825e..fc3e0b2d 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -39,134 +39,29 @@ * They simply came in too late. -- rgerhards, 2008-04-02 */ #ifdef HAVE_ATOMIC_BUILTINS -# define ATOMIC_INC(data) ((void) __sync_fetch_and_add(&(data), 1)) +# define ATOMIC_INC(data, phlpmut) ((void) __sync_fetch_and_add(data, 1)) # define ATOMIC_INC_AND_FETCH(data) __sync_fetch_and_add(&(data), 1) -# define ATOMIC_DEC(data) ((void) __sync_sub_and_fetch(&(data), 1)) -# define ATOMIC_DEC_AND_FETCH(data) __sync_sub_and_fetch(&(data), 1) +# define ATOMIC_DEC(data, phlpmut) ((void) __sync_sub_and_fetch(data, 1)) +# define ATOMIC_DEC_AND_FETCH(data, phlpmut) __sync_sub_and_fetch(data, 1) # define ATOMIC_FETCH_32BIT(data) ((unsigned) __sync_fetch_and_and(&(data), 0xffffffff)) # define ATOMIC_STORE_1_TO_32BIT(data) __sync_lock_test_and_set(&(data), 1) -# define ATOMIC_STORE_0_TO_INT(data) __sync_fetch_and_and(&(data), 0) -# define ATOMIC_STORE_1_TO_INT(data) __sync_fetch_and_or(&(data), 1) +# define ATOMIC_STORE_0_TO_INT(data, phlpmut) __sync_fetch_and_and(data, 0) +# define ATOMIC_STORE_1_TO_INT(data, phlpmut) __sync_fetch_and_or(data, 1) # define ATOMIC_STORE_INT_TO_INT(data, val) __sync_fetch_and_or(&(data), (val)) # define ATOMIC_CAS(data, oldVal, newVal) __sync_bool_compare_and_swap(&(data), (oldVal), (newVal)); -# define ATOMIC_CAS_VAL(data, oldVal, newVal) __sync_val_compare_and_swap(&(data), (oldVal), (newVal)); -#else -#ifdef HAVE_SEMAPHORE_H - /* we use POSIX semaphores instead */ - -#include "rsyslog.h" -#include - -extern sem_t atomicSem; -rsRetVal atomicSemInit(void); -void atomicSemExit(void); - -#if HAVE_TYPEOF -#define my_typeof(x) typeof(x) -#else /* sorry, can't determine types, using 'int' */ -#define my_typeof(x) int -#endif - -# define ATOMIC_SUB(data, val) \ -({ \ - my_typeof(data) tmp; \ - sem_wait(&atomicSem); \ - tmp = data; \ - data -= val; \ - sem_post(&atomicSem); \ - tmp; \ -}) - -# define ATOMIC_ADD(data, val) \ -({ \ - my_typeof(data) tmp; \ - sem_wait(&atomicSem); \ - tmp = data; \ - data += val; \ - sem_post(&atomicSem); \ - tmp; \ -}) - -# define ATOMIC_INC_AND_FETCH(data) \ -({ \ - my_typeof(data) tmp; \ - sem_wait(&atomicSem); \ - tmp = data; \ - data += 1; \ - sem_post(&atomicSem); \ - tmp; \ -}) - -# define ATOMIC_INC(data) ((void) ATOMIC_INC_AND_FETCH(data)) - -# define ATOMIC_DEC_AND_FETCH(data) \ -({ \ - sem_wait(&atomicSem); \ - data -= 1; \ - sem_post(&atomicSem); \ - data; \ -}) +# define ATOMIC_CAS_VAL(data, oldVal, newVal, phlpmut) __sync_val_compare_and_swap(data, (oldVal), (newVal)); -# define ATOMIC_DEC(data) ((void) ATOMIC_DEC_AND_FETCH(data)) + /* functions below are not needed if we have atomics */ +# define DEF_ATOMIC_HELPER_MUT(x) +# define INIT_ATOMIC_HELPER_MUT(x) +# define DESTROY_ATOMIC_HELPER_MUT(x) -# define ATOMIC_FETCH_32BIT(data) ((unsigned) ATOMIC_ADD((data), 0xffffffff)) - -# define ATOMIC_STORE_1_TO_32BIT(data) \ -({ \ - my_typeof(data) tmp; \ - sem_wait(&atomicSem); \ - tmp = data; \ - data = 1; \ - sem_post(&atomicSem); \ - tmp; \ -}) - -# define ATOMIC_STORE_0_TO_INT(data) \ -({ \ - my_typeof(data) tmp; \ - sem_wait(&atomicSem); \ - tmp = data; \ - data = 0; \ - sem_post(&atomicSem); \ - tmp; \ -}) - -# define ATOMIC_STORE_1_TO_INT(data) \ -({ \ - my_typeof(data) tmp; \ - sem_wait(&atomicSem); \ - tmp = data; \ - data = 1; \ - sem_post(&atomicSem); \ - tmp; \ -}) - -# define ATOMIC_CAS(data, oldVal, newVal) \ -({ \ - int ret; \ - sem_wait(&atomicSem); \ - if(data != oldVal) ret = 0; \ - else \ - { \ - data = newVal; \ - ret = 1; \ - } \ - sem_post(&atomicSem); \ - ret; \ -}) - -# define ATOMIC_CAS_VAL(data, oldVal, newVal) \ -({ \ - sem_wait(&atomicSem); \ - if(data == oldVal) \ - { \ - data = newVal; \ - } \ - sem_post(&atomicSem); \ - data; \ -}) - -#else /* not HAVE_SEMAPHORE_H */ + /* the following operations should preferrably be done atomic, but it is + * not fatal if not -- that means we can live with some missed updates. So be + * sure to use these macros only if that really does not matter! + */ +# define PREFER_ATOMIC_INC(data) ((void) __sync_fetch_and_add(&(data), 1)) +#else /* note that we gained parctical proof that theoretical problems DO occur * if we do not properly address them. See this blog post for details: * http://blog.gerhards.net/2009/01/rsyslog-data-race-analysis.html @@ -174,16 +69,63 @@ void atomicSemExit(void); * simply go ahead and do without them - use mutexes or other things. The * code needs to be checked against all those cases. -- rgerhards, 2009-01-30 */ + #include +# define ATOMIC_INC(data, phlpmut) { \ + pthread_mutex_lock(phlpmut); \ + ++(*(data)); \ + pthread_mutex_unlock(phlpmut); \ + } + +# define ATOMIC_STORE_0_TO_INT(data, hlpmut) { \ + pthread_mutex_lock(&hlpmut); \ + *(data) = 0; \ + pthread_mutex_unlock(&hlpmut); \ + } + +# define ATOMIC_STORE_1_TO_INT(data, hlpmut) { \ + pthread_mutex_lock(&hlpmut); \ + *(data) = 1; \ + pthread_mutex_unlock(&hlpmut); \ + } + + static inline int + ATOMIC_CAS_VAL(int *data, int oldVal, int newVal, pthread_mutex_t *phlpmut) { + int val; + pthread_mutex_lock(phlpmut); + if(*data == oldVal) { + *data = newVal; + } + val = *data; + pthread_mutex_unlock(phlpmut); + return(val); + } + +# define ATOMIC_DEC(data, phlpmut) { \ + pthread_mutex_lock(phlpmut); \ + --(*(data)); \ + pthread_mutex_unlock(phlpmut); \ + } + + static inline int + ATOMIC_DEC_AND_FETCH(int *data, pthread_mutex_t *phlpmut) { + int val; + pthread_mutex_lock(phlpmut); + val = --(*data); + pthread_mutex_unlock(phlpmut); + return(val); + } +#if 0 # warning "atomic builtins not available, using nul operations - rsyslogd will probably be racy!" -# define ATOMIC_INC(data) (++(data)) -# define ATOMIC_DEC(data) (--(data)) -# define ATOMIC_DEC_AND_FETCH(data) (--(data)) -# define ATOMIC_FETCH_32BIT(data) (data) -# define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1 -# define ATOMIC_STORE_1_TO_INT(data) (data) = 1 -# define ATOMIC_STORE_0_TO_INT(data) (data) = 0 -# define ATOMIC_CAS_VAL(data, oldVal, newVal) (data) = (newVal) +# define ATOMIC_INC_AND_FETCH(data) (++(data)) +# define ATOMIC_FETCH_32BIT(data) (data) // TODO: del +# define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1 // TODO: del #endif +# define DEF_ATOMIC_HELPER_MUT(x) pthread_mutex_t x +# define INIT_ATOMIC_HELPER_MUT(x) pthread_mutex_init(&(x), NULL) +# define DESTROY_ATOMIC_HELPER_MUT(x) pthread_mutex_init(&(x), NULL) + +# define PREFER_ATOMIC_INC(data) ((void) ++data) + #endif #endif /* #ifndef INCLUDED_ATOMIC_H */ diff --git a/runtime/debug.c b/runtime/debug.c index da471609..0ada909b 100644 --- a/runtime/debug.c +++ b/runtime/debug.c @@ -1073,7 +1073,7 @@ int dbgEntrFunc(dbgFuncDB_t **ppFuncDB, const char *file, const char *func, int } /* when we reach this point, we have a fully-initialized FuncDB! */ - ATOMIC_INC(pFuncDB->nTimesCalled); + PREFER_ATOMIC_INC(pFuncDB->nTimesCalled); if(bLogFuncFlow && dbgPrintNameIsInList((const uchar*)pFuncDB->file, printNameFileRoot)) dbgprintf("%s:%d: %s: enter\n", pFuncDB->file, pFuncDB->line, pFuncDB->func); if(pThrd->stackPtr >= (int) (sizeof(pThrd->callStack) / sizeof(dbgFuncDB_t*))) { diff --git a/runtime/msg.c b/runtime/msg.c index 6d7e6a89..57291def 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -748,7 +748,7 @@ BEGINobjDestruct(msg) /* be sure to specify the object type also in END and CODE CODESTARTobjDestruct(msg) /* DEV Debugging only ! dbgprintf("msgDestruct\t0x%lx, Ref now: %d\n", (unsigned long)pThis, pThis->iRefCount - 1); */ # ifdef HAVE_ATOMIC_BUILTINS - currRefCount = ATOMIC_DEC_AND_FETCH(pThis->iRefCount); + currRefCount = ATOMIC_DEC_AND_FETCH(&pThis->iRefCount, NULL); # else MsgLock(pThis); currRefCount = --pThis->iRefCount; @@ -800,9 +800,18 @@ CODESTARTobjDestruct(msg) * that we trim too often when the counter wraps. */ static unsigned iTrimCtr = 1; +# ifdef HAVE_ATOMICS if(ATOMIC_INC_AND_FETCH(iTrimCtr) % 100000 == 0) { malloc_trim(128*1024); } +# else +static pthread_mutex_t mutTrimCtr = PTHREAD_MUTEX_INITIALIZER; + d_pthread_mutex_lock(&mutTrimCtr); + if(iTrimCtr++ % 100000 == 0) { + malloc_trim(128*1024); + } + d_pthread_mutex_unlock(&mutTrimCtr); +# endif } # endif } else { @@ -1002,7 +1011,7 @@ msg_t *MsgAddRef(msg_t *pM) { assert(pM != NULL); # ifdef HAVE_ATOMIC_BUILTINS - ATOMIC_INC(pM->iRefCount); + ATOMIC_INC(&pM->iRefCount, NULL); # else MsgLock(pM); pM->iRefCount++; diff --git a/runtime/msg.h b/runtime/msg.h index 0d3314b7..cda206fc 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -32,6 +32,7 @@ #include "obj.h" #include "syslogd-types.h" #include "template.h" +#include "atomic.h" /* rgerhards 2004-11-08: The following structure represents a diff --git a/runtime/prop.c b/runtime/prop.c index d188b2ed..7f2a56ff 100644 --- a/runtime/prop.c +++ b/runtime/prop.c @@ -53,6 +53,7 @@ DEFobjStaticHelpers */ BEGINobjConstruct(prop) /* be sure to specify the object type also in END macro! */ pThis->iRefCount = 1; + INIT_ATOMIC_HELPER_MUT(pThis->mutRefCount); ENDobjConstruct(prop) @@ -60,11 +61,12 @@ ENDobjConstruct(prop) BEGINobjDestruct(prop) /* be sure to specify the object type also in END and CODESTART macros! */ int currRefCount; CODESTARTobjDestruct(prop) - currRefCount = ATOMIC_DEC_AND_FETCH(pThis->iRefCount); + currRefCount = ATOMIC_DEC_AND_FETCH(&pThis->iRefCount, &pThis->mutRefCount); if(currRefCount == 0) { /* (only) in this case we need to actually destruct the object */ if(pThis->len >= CONF_PROP_BUFSIZE) free(pThis->szVal.psz); + DESTROY_ATOMIC_HELPER_MUT(pThis->mutRefCount); } else { pThis = NULL; /* tell framework NOT to destructing the object! */ } @@ -132,7 +134,7 @@ propConstructFinalize(prop_t __attribute__((unused)) *pThis) */ static rsRetVal AddRef(prop_t *pThis) { - ATOMIC_INC(pThis->iRefCount); + ATOMIC_INC(&pThis->iRefCount, &pThis->mutRefCount); return RS_RET_OK; } diff --git a/runtime/prop.h b/runtime/prop.h index e3519664..07b2ab7e 100644 --- a/runtime/prop.h +++ b/runtime/prop.h @@ -24,6 +24,7 @@ */ #ifndef INCLUDED_PROP_H #define INCLUDED_PROP_H +#include "atomic.h" /* the prop object */ struct prop_s { @@ -34,6 +35,7 @@ struct prop_s { uchar sz[CONF_PROP_BUFSIZE]; } szVal; int len; /* we use int intentionally, otherwise we may get some troubles... */ + DEF_ATOMIC_HELPER_MUT(mutRefCount); }; /* interfaces */ diff --git a/runtime/queue.c b/runtime/queue.c index 9d7a9058..bedefb77 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -110,7 +110,7 @@ static inline void queueDrain(qqueue_t *pThis) ASSERT(pThis != NULL); /* iQueueSize is not decremented by qDel(), so we need to do it ourselves */ - while(ATOMIC_DEC_AND_FETCH(pThis->iQueueSize) > 0) { + while(ATOMIC_DEC_AND_FETCH(&pThis->iQueueSize, &pThis->mutQueueSize) > 0) { pThis->qDel(pThis, &pUsr); if(pUsr != NULL) { objDestruct(pUsr); @@ -1028,7 +1028,7 @@ qqueueAdd(qqueue_t *pThis, void *pUsr) CHKiRet(pThis->qAdd(pThis, pUsr)); if(pThis->qType != QUEUETYPE_DIRECT) { - ATOMIC_INC(pThis->iQueueSize); + ATOMIC_INC(&pThis->iQueueSize, &pThis->mutQueueSize); dbgoprint((obj_t*) pThis, "entry added, size now %d entries\n", pThis->iQueueSize); } @@ -1057,7 +1057,7 @@ qqueueDel(qqueue_t *pThis, void *pUsr) iRet = qqueueGetUngottenObj(pThis, (obj_t**) pUsr); } else { iRet = pThis->qDel(pThis, pUsr); - ATOMIC_DEC(pThis->iQueueSize); + ATOMIC_DEC(&pThis->iQueueSize, &pThis->mutQueueSize); } dbgoprint((obj_t*) pThis, "entry deleted, state %d, size now %d entries\n", @@ -1345,6 +1345,8 @@ rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThread break; } + INIT_ATOMIC_HELPER_MUT(pThis->mutQueueSize); + finalize_it: OBJCONSTRUCT_CHECK_SUCCESS_AND_CLEANUP RETiRet; @@ -2065,6 +2067,8 @@ CODESTARTobjDestruct(qqueue) pthread_cond_destroy(&pThis->belowFullDlyWtrMrk); pthread_cond_destroy(&pThis->belowLightDlyWtrMrk); + DESTROY_ATOMIC_HELPER_MUT(pThis->mutQueueSize); + /* type-specific destructor */ iRet = pThis->qDestruct(pThis); diff --git a/runtime/queue.h b/runtime/queue.h index 1d82d8d9..aafdaa45 100644 --- a/runtime/queue.h +++ b/runtime/queue.h @@ -160,6 +160,7 @@ typedef struct queue_s { strm_t *pRead; /* current file to be read */ } disk; } tVars; + DEF_ATOMIC_HELPER_MUT(mutQueueSize); } qqueue_t; /* some symbolic constants for easier reference */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 5750ca76..c209ae30 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -140,12 +140,6 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(objClassInit(NULL)); /* *THIS* *MUST* always be the first class initilizer being called! */ CHKiRet(objGetObjInterface(pObjIF)); /* this provides the root pointer for all other queries */ -#ifndef HAVE_ATOMIC_BUILTINS -#ifdef HAVE_SEMAPHORE_H - CHKiRet(atomicSemInit()); -#endif /* HAVE_SEMAPHORE_H */ -#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ - /* initialize core classes. We must be very careful with the order of events. Some * classes use others and if we do not initialize them in the right order, we may end * up with an invalid call. The most important thing that can happen is that an error @@ -223,12 +217,6 @@ rsrtExit(void) rulesetClassExit(); ruleClassExit(); -#ifndef HAVE_ATOMIC_BUILTINS -#ifdef HAVE_SEMAPHORE_H - atomicSemExit(); -#endif /* HAVE_SEMAPHORE_H */ -#endif /* !defined(HAVE_ATOMIC_BUILTINS) */ - objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */ } diff --git a/runtime/wti.c b/runtime/wti.c index abdf4add..90bb14ed 100644 --- a/runtime/wti.c +++ b/runtime/wti.c @@ -146,7 +146,7 @@ wtiSetState(wti_t *pThis, qWrkCmd_t tCmd, int bActiveOnly, int bLockMutex) break; } /* apply the new state */ - unsigned val = ATOMIC_CAS_VAL(pThis->tCurrCmd, tCurrCmd, tCmd); + unsigned val = ATOMIC_CAS_VAL((int*)&pThis->tCurrCmd, tCurrCmd, tCmd, &pThis->mutCurrCmd); if(val != tCurrCmd) { DBGPRINTF("wtiSetState PROBLEM, tCurrCmd %d overwritten with %d, wanted to set %d\n", tCurrCmd, val, tCmd); } @@ -178,7 +178,7 @@ wtiCancelThrd(wti_t *pThis) dbgoprint((obj_t*) pThis, "canceling worker thread, curr stat %d\n", pThis->tCurrCmd); pthread_cancel(pThis->thrdID); wtiSetState(pThis, eWRKTHRD_TERMINATING, 0, MUTEX_ALREADY_LOCKED); - ATOMIC_STORE_1_TO_INT(pThis->pWtp->bThrdStateChanged); /* indicate change, so harverster will be called */ + wtpSetThrdStateChanged(pThis->pWtp, 1); /* indicate change, so harverster will be called */ } d_pthread_mutex_unlock(&pThis->mut); @@ -209,6 +209,7 @@ CODESTARTobjDestruct(wti) /* actual destruction */ pthread_cond_destroy(&pThis->condExitDone); pthread_mutex_destroy(&pThis->mut); + DESTROY_ATOMIC_HELPER_MUT(pThis->mutCurrCmd); free(pThis->pszDbgHdr); ENDobjDestruct(wti) @@ -219,6 +220,7 @@ ENDobjDestruct(wti) BEGINobjConstruct(wti) /* be sure to specify the object type also in END macro! */ pthread_cond_init(&pThis->condExitDone, NULL); pthread_mutex_init(&pThis->mut, NULL); + INIT_ATOMIC_HELPER_MUT(pThis->mutCurrCmd); ENDobjConstruct(wti) @@ -326,8 +328,7 @@ wtiWorkerCancelCleanup(void *arg) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &iCancelStateSave); d_pthread_mutex_lock(&pWtp->mut); wtiSetState(pThis, eWRKTHRD_TERMINATING, 0, MUTEX_ALREADY_LOCKED); - /* TODO: sync access? I currently think it is NOT needed -- rgerhards, 2008-01-28 */ - ATOMIC_STORE_1_TO_INT(pWtp->bThrdStateChanged); /* indicate change, so harverster will be called */ + wtpSetThrdStateChanged(pWtp, 1); /* indicate change, so harverster will be called */ d_pthread_mutex_unlock(&pWtp->mut); pthread_setcancelstate(iCancelStateSave, NULL); @@ -414,7 +415,7 @@ wtiWorker(wti_t *pThis) pWtp->pfOnWorkerShutdown(pWtp->pUsr); wtiSetState(pThis, eWRKTHRD_TERMINATING, 0, MUTEX_ALREADY_LOCKED); - ATOMIC_STORE_1_TO_INT(pWtp->bThrdStateChanged); /* indicate change, so harverster will be called */ + wtpSetThrdStateChanged(pWtp, 1); /* indicate change, so harverster will be called */ d_pthread_mutex_unlock(&pThis->mut); pthread_setcancelstate(iCancelStateSave, NULL); diff --git a/runtime/wti.h b/runtime/wti.h index 72653b15..d81672f3 100644 --- a/runtime/wti.h +++ b/runtime/wti.h @@ -39,6 +39,7 @@ typedef struct wti_s { pthread_mutex_t mut; bool bShutdownRqtd; /* shutdown for this thread requested? 0 - no , 1 - yes */ uchar *pszDbgHdr; /* header string for debug messages */ + DEF_ATOMIC_HELPER_MUT(mutCurrCmd); } wti_t; /* some symbolic constants for easier reference */ diff --git a/runtime/wtp.c b/runtime/wtp.c index 271c6f0d..fff37c2f 100644 --- a/runtime/wtp.c +++ b/runtime/wtp.c @@ -97,6 +97,7 @@ BEGINobjConstruct(wtp) /* be sure to specify the object type also in END macro! pThis->pfOnWorkerCancel = NotImplementedDummy; pThis->pfOnWorkerStartup = NotImplementedDummy; pThis->pfOnWorkerShutdown = NotImplementedDummy; + INIT_ATOMIC_HELPER_MUT(pThis->mutThrdStateChanged); ENDobjConstruct(wtp) @@ -153,6 +154,7 @@ CODESTARTobjDestruct(wtp) pthread_cond_destroy(&pThis->condThrdTrm); pthread_mutex_destroy(&pThis->mut); pthread_mutex_destroy(&pThis->mutThrdShutdwn); + DESTROY_ATOMIC_HELPER_MUT(pThis->mutThrdStateChanged); free(pThis->pszDbgHdr); ENDobjDestruct(wtp) @@ -186,6 +188,20 @@ wtpWakeupAllWrkr(wtp_t *pThis) } +/* set the bThrdStateChanged in an atomic way. Note that + * val may only be 0 or 1. + */ +void +wtpSetThrdStateChanged(wtp_t *pThis, int val) +{ + if(val == 0) { + ATOMIC_STORE_0_TO_INT(&pThis->bThrdStateChanged, pThis->mutThrdStateChanged); + } else { + ATOMIC_STORE_1_TO_INT(&pThis->bThrdStateChanged, pThis->mutThrdStateChanged); + } +} + + /* check if we had any worker thread changes and, if so, act * on them. At a minimum, terminated threads are harvested (joined). * This function MUST NEVER block on the queue mutex! @@ -216,7 +232,7 @@ wtpProcessThrdChanges(wtp_t *pThis) */ do { /* reset the change marker */ - ATOMIC_STORE_0_TO_INT(pThis->bThrdStateChanged); + wtpSetThrdStateChanged(pThis, 0); /* go through all threads */ for(i = 0 ; i < pThis->iNumWorkerThreads ; ++i) { wtiProcessThrdChanges(pThis->pWrkr[i], LOCK_MUTEX); diff --git a/runtime/wtp.h b/runtime/wtp.h index 1ce171cc..640c3320 100644 --- a/runtime/wtp.h +++ b/runtime/wtp.h @@ -26,6 +26,7 @@ #include #include "obj.h" +#include "atomic.h" /* commands and states for worker threads. */ typedef enum { @@ -79,6 +80,7 @@ typedef struct wtp_s { rsRetVal (*pfOnWorkerShutdown)(void *pUsr); /* end user objects */ uchar *pszDbgHdr; /* header string for debug messages */ + DEF_ATOMIC_HELPER_MUT(mutThrdStateChanged); } wtp_t; /* some symbolic constants for easier reference */ @@ -100,6 +102,7 @@ rsRetVal wtpSetDbgHdr(wtp_t *pThis, uchar *pszMsg, size_t lenMsg); rsRetVal wtpSignalWrkrTermination(wtp_t *pWtp); rsRetVal wtpShutdownAll(wtp_t *pThis, wtpState_t tShutdownCmd, struct timespec *ptTimeout); int wtpGetCurNumWrkr(wtp_t *pThis, int bLockMutex); +void wtpSetThrdStateChanged(wtp_t *pThis, int val); PROTOTYPEObjClassInit(wtp); PROTOTYPEpropSetMethFP(wtp, pfChkStopWrkr, rsRetVal(*pVal)(void*, int)); PROTOTYPEpropSetMethFP(wtp, pfRateLimiter, rsRetVal(*pVal)(void*)); -- cgit From 1ab2bb26d20eaffc36999cb2bb1d7c9be3994c56 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 3 May 2010 12:52:38 +0200 Subject: preparing for 4.7.2 --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index f7b838d8..3d6f74e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 4.7.2 [v4-devel] (rgerhards), 2010-04-?? +Version 4.7.2 [v4-devel] (rgerhards), 2010-05-03 - bugfix: problems with atomic operations emulaton replaced atomic operation emulation with new code. The previous code seemed to have some issue and also limited concurrency severely. The diff --git a/configure.ac b/configure.ac index 6a4d2817..07ccabf5 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[4.7.1],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[4.7.2],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([ChangeLog]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/manual.html b/doc/manual.html index a5f12a56..1d81a5f8 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@ rsyslog support available directly from the source!

    Please visit the rsyslog sponsor's page to honor the project sponsors or become one yourself! We are very grateful for any help towards the project goals.

    -

    This documentation is for version 4.7.1 (v4-devel branch) of rsyslog. +

    This documentation is for version 4.7.2 (v4-devel branch) of rsyslog. Visit the rsyslog status page to obtain current version information and project status.

    If you like rsyslog, you might -- cgit From 80ff634c841d692c1d9f335b88e225d6ce7317f7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 6 Aug 2010 17:25:38 +0200 Subject: added omuxsock, which permits to write message to local Unix sockets this is the counterpart to imuxsock, enabling fast local forwarding --- ChangeLog | 4 + Makefile.am | 7 +- configure.ac | 16 ++ doc/Makefile.am | 1 + doc/imuxsock.html | 2 +- doc/omuxsock.html | 43 +++++ doc/rsyslog_conf_modules.html | 1 + plugins/omuxsock/Makefile.am | 8 + plugins/omuxsock/omuxsock.c | 315 ++++++++++++++++++++++++++++++++++++ runtime/rsyslog.h | 1 + tests/Makefile.am | 8 +- tests/testsuites/uxsock_simple.conf | 10 ++ tests/uxsock_simple.sh | 31 ++++ tests/uxsockrcvr.c | 157 ++++++++++++++++++ 14 files changed, 600 insertions(+), 4 deletions(-) create mode 100644 doc/omuxsock.html create mode 100644 plugins/omuxsock/Makefile.am create mode 100644 plugins/omuxsock/omuxsock.c create mode 100644 tests/testsuites/uxsock_simple.conf create mode 100755 tests/uxsock_simple.sh create mode 100644 tests/uxsockrcvr.c diff --git a/ChangeLog b/ChangeLog index df0e77f1..1d5e05a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ --------------------------------------------------------------------------- +Version 4.7.3 [v4-devel] (rgerhards), 2010-??-?? +- added omuxsock, which permits to write message to local Unix sockets + this is the counterpart to imuxsock, enabling fast local forwarding +--------------------------------------------------------------------------- Version 4.7.2 [v4-devel] (rgerhards), 2010-05-03 - bugfix: problems with atomic operations emulaton replaced atomic operation emulation with new code. The previous code diff --git a/Makefile.am b/Makefile.am index 8401606a..1a090abb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -99,6 +99,10 @@ if ENABLE_OMSTDOUT SUBDIRS += plugins/omstdout endif +if ENABLE_OMUXSOCK +SUBDIRS += plugins/omuxsock +endif + if ENABLE_OMTEMPLATE SUBDIRS += plugins/omtemplate endif @@ -138,5 +142,6 @@ SUBDIRS += tests # 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 # 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 --enable-omprog --enable-imdiag --enable-shave --enable-extended-tests +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 --enable-imdiag --enable-shave --enable-extended-tests \ + --enable-omuxsock ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 07ccabf5..ffbefa60 100644 --- a/configure.ac +++ b/configure.ac @@ -785,6 +785,20 @@ AC_ARG_ENABLE(omstdout, ) AM_CONDITIONAL(ENABLE_OMSTDOUT, test x$enable_omstdout = xyes) + +# settings for omuxsock +AC_ARG_ENABLE(omuxsock, + [AS_HELP_STRING([--enable-omuxsock],[Compiles stdout module @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_omuxsock="yes" ;; + no) enable_omuxsock="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-omuxsock) ;; + esac], + [enable_omuxsock=no] +) +AM_CONDITIONAL(ENABLE_OMUXSOCK, test x$enable_omuxsock = xyes) + + # This provides a vehicle to integrate custom modules, that are not # part of rsyslog, into the build process. It is named cust1, so that # additional such modules can easily be added. @@ -860,6 +874,7 @@ AC_CONFIG_FILES([Makefile \ plugins/omtemplate/Makefile \ plugins/omprog/Makefile \ plugins/omstdout/Makefile \ + plugins/omuxsock/Makefile \ plugins/imfile/Makefile \ plugins/imsolaris/Makefile \ plugins/imrelp/Makefile \ @@ -901,6 +916,7 @@ echo "---{ output plugins }---" echo " Mail support enabled: $enable_mail" echo " omprog module will be compiled: $enable_omprog" echo " omstdout module will be compiled: $enable_omstdout" +echo " omuxsock module will be compiled: $enable_omuxsock" echo " output template module will be compiled: $enable_omtemplate" echo echo "---{ database support }---" diff --git a/doc/Makefile.am b/doc/Makefile.am index 5beebf0e..24a0ea74 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -100,6 +100,7 @@ html_files = \ gssapi.html \ licensing.html \ ommail.html \ + omuxsock.html \ omrelp.html \ syslog_parsing.html \ troubleshoot.html \ diff --git a/doc/imuxsock.html b/doc/imuxsock.html index 15c365a6..381374d2 100644 --- a/doc/imuxsock.html +++ b/doc/imuxsock.html @@ -100,7 +100,7 @@ $InputUnixListenSocketHostName /var/run/sshd/dev/log

    This documentation is part of the rsyslog project.
    -Copyright © 2008 by Rainer +Copyright © 2008-2010 by Rainer Gerhards and Adiscon. Released under the GNU GPL version 3 or higher.

    diff --git a/doc/omuxsock.html b/doc/omuxsock.html new file mode 100644 index 00000000..4ffc53eb --- /dev/null +++ b/doc/omuxsock.html @@ -0,0 +1,43 @@ + +Unix sockets output module (omuxsock) - sending syslog messages to local socket +back + + +

    Mail Output Module (omuxsock)

    +

    Module Name:    omuxsock

    +

    Available since:    4.7.3, 5.5.7

    +

    Author: Rainer Gerhards <rgerhards@adiscon.com>

    +

    Description:

    +

    This module supports sending syslog messages to local Unix sockets. +Thus it provided a fast message-passing interface between different rsyslog +instances. The counterpart to omuxsock is imuxsock. +Note that the template used together with omuxsock must be suitable to be +processed by the receiver. +

    Configuration Directives:

    +
      +
    • $OMUxSockSocket
      +Name of the socket to send data to. This has no default and must +be set. +
    • +
    • $OMUxSockDefaultTemplate
      +This can be used to override the default template to be used together +with omuxsock. This is primarily useful if there are many forwarding +actions and each of them should use the same template.
    • +
    +Caveats/Known Bugs: +

    Currently, only datagram sockets are supported. +

    Sample:

    +

    The following sample writes all messages to the "/tmp/socksample" socket. +

    + +[manual index] [rsyslog site]

    +

    This documentation is part of the rsyslog +project.
    +Copyright © 2010 by Rainer Gerhards and +Adiscon. +Released under the GNU GPL version 3 or higher.

    + + diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html index c36b8c6d..a6555c1a 100644 --- a/doc/rsyslog_conf_modules.html +++ b/doc/rsyslog_conf_modules.html @@ -52,6 +52,7 @@ SQLLite, Ingres, Oracle, mSQL)
  • ommail - permits rsyslog to alert folks by mail if something important happens
  • omoracle - output module for Oracle (native OCI interface)
  • +
  • omuxsock - output module Unix domain sockets
  • Library Modules

    diff --git a/plugins/omuxsock/Makefile.am b/plugins/omuxsock/Makefile.am new file mode 100644 index 00000000..997232d9 --- /dev/null +++ b/plugins/omuxsock/Makefile.am @@ -0,0 +1,8 @@ +pkglib_LTLIBRARIES = omuxsock.la + +omuxsock_la_SOURCES = omuxsock.c +omuxsock_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) +omuxsock_la_LDFLAGS = -module -avoid-version +omuxsock_la_LIBADD = + +EXTRA_DIST = diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c new file mode 100644 index 00000000..c66e63aa --- /dev/null +++ b/plugins/omuxsock/omuxsock.c @@ -0,0 +1,315 @@ +/* omuxsock.c + * This is the implementation of datgram unix domain socket forwarding. + * + * NOTE: read comments in module-template.h to understand how this file + * works! + * + * 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 2010 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "conf.h" +#include "srUtils.h" +#include "template.h" +#include "msg.h" +#include "cfsysline.h" +#include "module-template.h" +#include "glbl.h" +#include "errmsg.h" +#include "unicode-helper.h" + +MODULE_TYPE_OUTPUT + +/* internal structures + */ +DEF_OMOD_STATIC_DATA +DEFobjCurrIf(errmsg) +DEFobjCurrIf(glbl) + +#define INVLD_SOCK -1 + +typedef struct _instanceData { + permittedPeers_t *pPermPeers; + uchar *sockName; + int sock; + int bIsConnected; /* are we connected to remote host? 0 - no, 1 - yes, UDP means addr resolved */ + struct sockaddr_un addr; +} instanceData; + +/* config data */ +static uchar *tplName = NULL; /* name of the default template to use */ +static uchar *sockName = NULL; /* name of the default template to use */ + +static rsRetVal doTryResume(instanceData *pData); + +/* Close socket. + */ +static inline rsRetVal +closeSocket(instanceData *pData) +{ + DEFiRet; + if(pData->sock != INVLD_SOCK) { + close(pData->sock); + pData->sock = INVLD_SOCK; + } +pData->bIsConnected = 0; // TODO: remove this variable altogether + RETiRet; +} + + + +BEGINcreateInstance +CODESTARTcreateInstance + pData->sock = INVLD_SOCK; +ENDcreateInstance + + +BEGINisCompatibleWithFeature +CODESTARTisCompatibleWithFeature + if(eFeat == sFEATURERepeatedMsgReduction) + iRet = RS_RET_OK; +ENDisCompatibleWithFeature + + +BEGINfreeInstance +CODESTARTfreeInstance + /* final cleanup */ + closeSocket(pData); + free(pData->sockName); +ENDfreeInstance + + +BEGINdbgPrintInstInfo +CODESTARTdbgPrintInstInfo + DBGPRINTF("%s", pData->sockName); +ENDdbgPrintInstInfo + + +/* Send a message via UDP + * rgehards, 2007-12-20 + */ +static rsRetVal sendMsg(instanceData *pData, char *msg, size_t len) +{ + DEFiRet; + unsigned lenSent = 0; + + if(pData->sock == INVLD_SOCK) { + CHKiRet(doTryResume(pData)); + } + + if(pData->sock != INVLD_SOCK) { + /* we need to track if we have success sending to the remote + * peer. Success is indicated by at least one sendto() call + * succeeding. We track this be bSendSuccess. We can not simply + * rely on lsent, as a call might initially work, but a later + * call fails. Then, lsent has the error status, even though + * the sendto() succeeded. -- rgerhards, 2007-06-22 + */ + lenSent = sendto(pData->sock, msg, len, 0, &pData->addr, sizeof(pData->addr)); + if(lenSent == len) { + int eno = errno; + char errStr[1024]; + DBGPRINTF("omuxsock suspending: sendto(), socket %d, error: %d = %s.\n", + pData->sock, eno, rs_strerror_r(eno, errStr, sizeof(errStr))); + } + } + +finalize_it: + RETiRet; +} + + +/* open socket to remote system + */ +static inline rsRetVal +openSocket(instanceData *pData) +{ + DEFiRet; + assert(pData->sock == INVLD_SOCK); + + if((pData->sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { + char errStr[1024]; + int eno = errno; + DBGPRINTF("error %d creating AF_UNIX/SOCK_DGRAM: %s.\n", + eno, rs_strerror_r(eno, errStr, sizeof(errStr))); + pData->sock = INVLD_SOCK; + ABORT_FINALIZE(RS_RET_NO_SOCKET); + + } + + /* set up server address structure */ + memset(&pData->addr, 0, sizeof(pData->addr)); + pData->addr.sun_family = AF_UNIX; + strcpy(pData->addr.sun_path, (char*)pData->sockName); + +finalize_it: + if(iRet != RS_RET_OK) { + closeSocket(pData); + } + RETiRet; +} + + + +/* try to resume connection if it is not ready + */ +static rsRetVal doTryResume(instanceData *pData) +{ + DEFiRet; + + DBGPRINTF("omuxsock trying to resume\n"); + closeSocket(pData); + iRet = openSocket(pData); + + if(iRet != RS_RET_OK) { + iRet = RS_RET_SUSPENDED; + } + + RETiRet; +} + + +BEGINtryResume +CODESTARTtryResume + iRet = doTryResume(pData); +ENDtryResume + +BEGINdoAction + char *psz = NULL; /* temporary buffering */ + register unsigned l; + int iMaxLine; +CODESTARTdoAction + CHKiRet(doTryResume(pData)); + + iMaxLine = glbl.GetMaxLine(); + + DBGPRINTF(" omuxsock:%s\n", pData->sockName); + + psz = (char*) ppString[0]; + l = strlen((char*) psz); + if((int) l > iMaxLine) + l = iMaxLine; + + CHKiRet(sendMsg(pData, psz, l)); + +finalize_it: +ENDdoAction + + +BEGINparseSelectorAct +CODESTARTparseSelectorAct +CODE_STD_STRING_REQUESTparseSelectorAct(1) + + /* first check if this config line is actually for us */ + if(strncmp((char*) p, ":omuxsock:", sizeof(":omuxsock:") - 1)) { + ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); + } + + /* ok, if we reach this point, we have something for us */ + p += sizeof(":omuxsock:") - 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, tplName == NULL ? UCHAR_CONSTANT("RSYSLOG_TraditionalForwardFormat") + : tplName )); + + if(sockName == NULL) { + errmsg.LogError(0, RS_RET_NO_SOCK_CONFIGURED, "No output socket configured for omuxsock\n"); + ABORT_FINALIZE(RS_RET_NO_SOCK_CONFIGURED); + } + + pData->sockName = sockName; + sockName = NULL; /* pData is now owner and will fee it */ + +CODE_STD_FINALIZERparseSelectorAct +ENDparseSelectorAct + + +/* a common function to free our configuration variables - used both on exit + * and on $ResetConfig processing. -- rgerhards, 2008-05-16 + */ +static inline void +freeConfigVars(void) +{ + free(tplName); + tplName = NULL; + free(sockName); + sockName = NULL; +} + + +BEGINmodExit +CODESTARTmodExit + /* release what we no longer need */ + objRelease(errmsg, CORE_COMPONENT); + objRelease(glbl, CORE_COMPONENT); + + freeConfigVars(); +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_OMOD_QUERIES +ENDqueryEtryPt + + +/* Reset config variables for this module to default values. + * rgerhards, 2008-03-28 + */ +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + freeConfigVars(); + return RS_RET_OK; +} + + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ +CODEmodInit_QueryRegCFSLineHdlr + CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + + CHKiRet(regCfSysLineHdlr((uchar *)"omuxsockdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &tplName, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"omuxsocksocket", 0, eCmdHdlrGetWord, NULL, &sockName, NULL)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); +ENDmodInit + +/* vim:set ai: + */ diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index a6dfc9ed..04a57e43 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -377,6 +377,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_ERR_OPEN_KLOG = -2145, /**< error opening the kernel log socket (primarily solaris) */ RS_RET_ERR_AQ_CONLOG = -2146, /**< error aquiring console log (on solaris) */ RS_RET_ERR_DOOR = -2147, /**< some problems with handling the Solaris door functionality */ + RS_RET_NO_SOCK_CONFIGURED = -2148, /**< no socket (name) was configured where one is required */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 8ec72d4f..201fbed6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ if ENABLE_TESTBENCH TESTRUNS = rt_init rscript -check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker +check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker uxsockrcvr TESTS = $(TESTRUNS) cfg.sh \ validation-run.sh \ imtcp-multiport.sh \ @@ -26,7 +26,8 @@ TESTS = $(TESTRUNS) cfg.sh \ dynfile_invalid2.sh \ complex1.sh \ queue-persist.sh \ - pipeaction.sh + pipeaction.sh \ + uxsock_simple.sh \ execonlyonce.sh \ queue-persist.sh @@ -162,6 +163,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/sndrcv_gzip_rcvr.conf \ pipeaction.sh \ testsuites/pipeaction.conf \ + uxsock_simple.sh \ + testsuites/uxsock_simple.conf \ asynwr_simple.sh \ testsuites/asynwr_simple.conf \ asynwr_timeout.sh \ @@ -204,6 +207,7 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/execonlyonce.data \ cfg.sh +uxsockrcvr_SOURCES = uxsockrcvr.c ourtail_SOURCES = ourtail.c msleep_SOURCES = msleep.c chkseq_SOURCES = chkseq.c diff --git a/tests/testsuites/uxsock_simple.conf b/tests/testsuites/uxsock_simple.conf new file mode 100644 index 00000000..efffdd90 --- /dev/null +++ b/tests/testsuites/uxsock_simple.conf @@ -0,0 +1,10 @@ +# Test for pipe output action (see .sh file for details) +# rgerhards, 2009-11-05 +$IncludeConfig diag-common.conf + +$MainMsgQueueTimeoutShutdown 10000 + +$ModLoad ../plugins/omuxsock/.libs/omuxsock +$template outfmt,"%msg:F,58:2%\n" +$OMUXSockSocket rsyslog-testbench-dgram-uxsock +:msg, contains, "msgnum:" :omuxsock:;outfmt diff --git a/tests/uxsock_simple.sh b/tests/uxsock_simple.sh new file mode 100755 index 00000000..7f00f4bc --- /dev/null +++ b/tests/uxsock_simple.sh @@ -0,0 +1,31 @@ +# This tests basic omuxsock functionality. A socket receiver is started which sends +# all data to an output file, then a rsyslog instance is started which generates +# messages and sends them to the unix socket. Datagram sockets are being used. +# added 2010-08-06 by Rgerhards +echo =============================================================================== +echo \[uxsock_simple.sh\]: simple tests for omuxsock functionality + +# create the pipe and start a background process that copies data from +# it to the "regular" work file +source $srcdir/diag.sh init +./uxsockrcvr -srsyslog-testbench-dgram-uxsock -orsyslog.out.log & +BGPROCESS=$! +echo background uxsockrcvr process id is $BGPROCESS + +# now do the usual run +source $srcdir/diag.sh startup uxsock_simple.conf +# 10000 messages should be enough +source $srcdir/diag.sh injectmsg 0 10000 +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown + +# wait for the cp process to finish, do pipe-specific cleanup +echo shutting down uxsockrcvr... +# TODO: we should do this more reliable in the long run! (message counter? timeout?) +kill $BGPROCESS +wait $BGPROCESS +echo background process has terminated, continue test... + +# and continue the usual checks +source $srcdir/diag.sh seq-check 0 9999 +source $srcdir/diag.sh exit diff --git a/tests/uxsockrcvr.c b/tests/uxsockrcvr.c new file mode 100644 index 00000000..551f0ef3 --- /dev/null +++ b/tests/uxsockrcvr.c @@ -0,0 +1,157 @@ +/* receives messages from a specified unix sockets and writes + * output to specfied file. + * + * Command line options: + * -s name of socket (required) + * -o name of output file (stdout if not given) + * -l add newline after each message received (default: do not add anything) + * + * Part of the testbench for rsyslog. + * + * Copyright 2010 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include + +char *sockName = NULL; +int sock; +int addNL = 0; + + +/* called to clean up on exit + */ +void +cleanup(void) +{ + unlink(sockName); + close(sock); +} + + +void +doTerm(int __attribute__((unused)) signum) +{ + exit(1); +} + + +void +usage(void) +{ + fprintf(stderr, "usage: uxsockrcvr -s /socket/name -o /output/file -l\n" + "-l adds newline after each message received\n" + "-s MUST be specified\n" + "if -o ist not specified, stdout is used\n"); + exit(1); +} + + +int +main(int argc, char *argv[]) +{ + int opt; + int rlen; + FILE *fp = stdout; + unsigned char data[128*1024]; + struct sockaddr_un addr; /* address of server */ + struct sockaddr from; + socklen_t fromlen; + + if(argc < 2) { + fprintf(stderr, "error: too few arguments!\n"); + usage(); + } + + while((opt = getopt(argc, argv, "s:o:l")) != EOF) { + switch((char)opt) { + case 'l': + addNL = 1; + break; + case 's': + sockName = optarg; + break; + case 'o': + if((fp = fopen(optarg, "w")) == NULL) { + perror(optarg); + exit(1); + } + break; + default:usage(); + } + } + + if(sockName == NULL) { + fprintf(stderr, "error: -s /socket/name must be specified!\n"); + exit(1); + } + + if(signal(SIGTERM, doTerm) == SIG_ERR) { + perror("signal(SIGTERM, ...)"); + exit(1); + } + if(signal(SIGINT, doTerm) == SIG_ERR) { + perror("signal(SIGINT, ...)"); + exit(1); + } + + /* Create a UNIX datagram socket for server */ + if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { + perror("server: socket"); + exit(1); + } + + atexit(cleanup); + + /* Set up address structure for server socket */ + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sockName); + + if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) < 0) { + close(sock); + perror("server: bind"); + exit(1); + } + + /* we now run in an endless loop. We do not check who sends us + * data. This should be no problem for our testbench use. + */ + while(1) { + fromlen = sizeof(from); + rlen = recvfrom(sock, data, 2000, 0, &from, &fromlen); + if(rlen == -1) { + perror("uxsockrcvr : recv\n"); + exit(1); + } else { + fwrite(data, 1, rlen, fp); + if(addNL) + fputc('\n', fp); + } + } + + return 0; +} -- cgit From c8ee85614bb78c590deb9ac4a1904d124d06bef5 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 6 Aug 2010 17:43:01 +0200 Subject: solving an error ID collision with v5 build --- runtime/rsyslog.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 04a57e43..8917d12b 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -377,7 +377,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_ERR_OPEN_KLOG = -2145, /**< error opening the kernel log socket (primarily solaris) */ RS_RET_ERR_AQ_CONLOG = -2146, /**< error aquiring console log (on solaris) */ RS_RET_ERR_DOOR = -2147, /**< some problems with handling the Solaris door functionality */ - RS_RET_NO_SOCK_CONFIGURED = -2148, /**< no socket (name) was configured where one is required */ + RS_RET_NO_SOCK_CONFIGURED = -2166, /**< no socket (name) was configured where one is required */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ -- cgit From 89f7dddf36d57c9261464560e3b2c0fb8ea88fd2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 Aug 2010 08:09:15 +0200 Subject: doc nit: wrong title in omuxsock page thanks to David Lang for finding this issue --- doc/omuxsock.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/omuxsock.html b/doc/omuxsock.html index 4ffc53eb..5fa569eb 100644 --- a/doc/omuxsock.html +++ b/doc/omuxsock.html @@ -3,7 +3,7 @@ back -

    Mail Output Module (omuxsock)

    +

    Unix sockets Output Module (omuxsock)

    Module Name:    omuxsock

    Available since:    4.7.3, 5.5.7

    Author: Rainer Gerhards <rgerhards@adiscon.com>

    -- cgit From 55256ac96815d6e13fc9df7206d50ef7dcaca4fe Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 10 Aug 2010 14:51:43 +0200 Subject: added imptcp imptcp is a simplified, Linux-specific and potentielly fast syslog plain tcp input plugin (NOT supporting TLS!) --- ChangeLog | 2 + Makefile.am | 7 +- configure.ac | 15 + doc/Makefile.am | 1 + doc/imptcp.html | 84 +++ doc/rsyslog_conf_modules.html | 3 +- plugins/imptcp/Makefile.am | 6 + plugins/imptcp/imptcp.c | 1146 +++++++++++++++++++++++++++++++++++++++++ runtime/rsyslog.h | 4 + tools/syslogd.c | 2 +- 10 files changed, 1267 insertions(+), 3 deletions(-) create mode 100644 doc/imptcp.html create mode 100644 plugins/imptcp/Makefile.am create mode 100644 plugins/imptcp/imptcp.c diff --git a/ChangeLog b/ChangeLog index df29694c..b8cbdb42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +- added imptcp, a simplified, Linux-specific and potentielly fast + syslog plain tcp input plugin (NOT supporting TLS!) --------------------------------------------------------------------------- Version 4.6.4 [v4-stable] (rgerhards), 2010-08.05 - bugfix: zero-sized (empty) messages were processed by imtcp diff --git a/Makefile.am b/Makefile.am index f5f9a6ed..439cb417 100644 --- a/Makefile.am +++ b/Makefile.am @@ -103,6 +103,10 @@ if ENABLE_IMFILE SUBDIRS += plugins/imfile endif +if ENABLE_IMPTCP +SUBDIRS += plugins/imptcp +endif + if ENABLE_IMDIAG SUBDIRS += plugins/imdiag endif @@ -134,5 +138,6 @@ SUBDIRS += tests # 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 # 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 --enable-omprog --enable-imdiag --enable-shave --enable-extended-tests +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 --enable-imdiag --enable-shave --enable-extended-tests \ + --enable-imptcp ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index bc3965d5..ce34e53d 100644 --- a/configure.ac +++ b/configure.ac @@ -727,6 +727,19 @@ AC_ARG_ENABLE(imfile, AM_CONDITIONAL(ENABLE_IMFILE, test x$enable_imfile = xyes) +# settings for the ptcp input module +AC_ARG_ENABLE(imptcp, + [AS_HELP_STRING([--enable-imptcp],[plain tcp input module enabled @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_imptcp="yes" ;; + no) enable_imptcp="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-imptcp) ;; + esac], + [enable_imptcp=no] +) +AM_CONDITIONAL(ENABLE_IMPTCP, test x$enable_imptcp = xyes) + + # settings for the omprog output module AC_ARG_ENABLE(omprog, [AS_HELP_STRING([--enable-omprog],[Compiles omprog module @<:@default=no@:>@])], @@ -828,6 +841,7 @@ AC_CONFIG_FILES([Makefile \ plugins/omprog/Makefile \ plugins/omstdout/Makefile \ plugins/imfile/Makefile \ + plugins/imptcp/Makefile \ plugins/imrelp/Makefile \ plugins/imdiag/Makefile \ plugins/omtesting/Makefile \ @@ -857,6 +871,7 @@ echo " custom module 1 will be built: $enable_cust1" echo echo "---{ input plugins }---" echo " Klog functionality enabled: $enable_klog ($os_type)" +echo " plain tcp input module enabled: $enable_imptcp" echo " imdiag enabled: $enable_imdiag" echo " file input module enabled: $enable_imfile" echo " input template module will be compiled: $enable_imtemplate" diff --git a/doc/Makefile.am b/doc/Makefile.am index ca2ee71c..7ba86ad4 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -37,6 +37,7 @@ html_files = \ omlibdbi.html \ imfile.html \ imtcp.html \ + imptcp.html \ imgssapi.html \ imrelp.html \ imuxsock.html \ diff --git a/doc/imptcp.html b/doc/imptcp.html new file mode 100644 index 00000000..913563a5 --- /dev/null +++ b/doc/imptcp.html @@ -0,0 +1,84 @@ + + + +Plain TCP Syslog Input Module (imptcp) + +back + +

    Plain TCP Syslog Input Module

    +

    Module Name:    imptcp

    +

    Available since: 4.7.3+, 5.5.8+? +

    Author: Rainer Gerhards +<rgerhards@adiscon.com>

    +

    Description:

    +

    Provides the ability to receive syslog messages via plain TCP syslog. +This is a specialised input plugin tailored for high performance on Linux. It will +probably not run on any other platform. Also, it does no provide TLS services. +Encryption can be provided by using stunnel. +

    This module has no limit on the number of listeners and sessions that can be used. +

    Multiple receivers may be configured by +specifying $InputPTCPServerRun multiple times. +

    +

    Configuration Directives:

    +

    This plugin has config directives similar named as imtcp, but they all have PTCP in +their name instead of just TCP. Note that only a subset of the parameters are supported. +

      +
    • $InputPTCPServerAddtlFrameDelimiter <Delimiter>
      +CURRENTLY DISABLED
      +This directive permits to specify an additional frame delimiter for plain tcp syslog. +The industry-standard specifies using the LF character as frame delimiter. Some vendors, +notable Juniper in their NetScreen products, use an invalid frame delimiter, in Juniper's +case the NUL character. This directive permits to specify the ASCII value of the delimiter +in question. Please note that this does not guarantee that all wrong implementations can +be cured with this directive. It is not even a sure fix with all versions of NetScreen, +as I suggest the NUL character is the effect of a (common) coding error and thus will +probably go away at some time in the future. But for the time being, the value 0 can +probably be used to make rsyslog handle NetScreen's invalid syslog/tcp framing. +For additional information, see this +forum thread. +
      If this doesn't work for you, please do not blame the rsyslog team. Instead file +a bug report with Juniper! +
      Note that a similar, but worse, issue exists with Cisco's IOS implementation. They do +not use any framing at all. This is confirmed from Cisco's side, but there seems to be +very limited interest in fixing this issue. This directive can not fix the Cisco bug. +That would require much more code changes, which I was unable to do so far. Full details +can be found at the Cisco tcp syslog anomaly +page. +
    • $InputPTCPServerNotifyOnConnectionClose [on/off]
      +CURRENTLY DISABLED
      +instructs imptcp to emit a message if the remote peer closes a connection.
      +Important: This directive is global to all listeners and must be given right +after loading imptcp, otherwise it may have no effect.
    • +
    • $InputPTCPServerRun <port>
      +Starts a TCP server on selected port
    • +
    • $InputPTCPServerInputName <name>
      +Sets a name for the inputname property. If no name is set "imptcp" is used by default. Setting a +name is not strictly necessary, but can be useful to apply filtering based on which input +the message was received from. +
    • $InputPTCPServerBindRuleset <name>
      +Binds specified ruleset to next server defined. +
    • $InputPTCPServerListenIP <name>
      +On multi-homed machines, specifies to which local address the next listerner should +be bound. +
    +Caveats/Known Bugs: +
      +
    • module always binds to all interfaces
    • +
    +

    Sample:

    +

    This sets up a TCP server on port 514:
    +

    + +

    [rsyslog.conf overview] +[manual index] [rsyslog site]

    +

    This documentation is part of the +rsyslog +project.
    +Copyright © 2010 by Rainer +Gerhards and +Adiscon. +Released under the GNU GPL version 3 or higher.

    + diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html index 675b8bb3..19f69da6 100644 --- a/doc/rsyslog_conf_modules.html +++ b/doc/rsyslog_conf_modules.html @@ -27,7 +27,8 @@ to message generators.
  • imfile -  input module for text files
  • imrelp - RELP input module
  • imudp - udp syslog message input
  • -
  • imtcp - input plugin for plain tcp syslog
  • +
  • imtcp - input plugin for tcp syslog
  • +
  • imptcp - input plugin for plain tcp syslog (no TLS but faster)
  • imgssapi - input plugin for plain tcp and GSS-enabled syslog
  • immark - support for mark messages
  • imklog - kernel logging
  • diff --git a/plugins/imptcp/Makefile.am b/plugins/imptcp/Makefile.am new file mode 100644 index 00000000..bfacc884 --- /dev/null +++ b/plugins/imptcp/Makefile.am @@ -0,0 +1,6 @@ +pkglib_LTLIBRARIES = imptcp.la + +imptcp_la_SOURCES = imptcp.c +imptcp_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) +imptcp_la_LDFLAGS = -module -avoid-version +imptcp_la_LIBADD = diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c new file mode 100644 index 00000000..5aeb0192 --- /dev/null +++ b/plugins/imptcp/imptcp.c @@ -0,0 +1,1146 @@ +/* imptcp.c + * This is a native implementation of plain tcp. It is intentionally + * duplicate work (imtcp). The intent is to gain very fast and simple + * native ptcp support, utilizing the best interfaces Linux (no cross- + * platform intended!) has to offer. + * + * Note that in this module we try out some new naming conventions, + * so it may look a bit "different" from the other modules. We are + * investigating if removing prefixes can help make code more readable. + * + * File begun on 2010-08-10 by RGerhards + * + * Copyright 2007-2010 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 . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if HAVE_FCNTL_H +#include +#endif +#include "rsyslog.h" +#include "cfsysline.h" +#include "prop.h" +#include "dirty.h" +#include "module-template.h" +#include "unicode-helper.h" +#include "glbl.h" +#include "prop.h" +#include "errmsg.h" +#include "srUtils.h" +#include "datetime.h" +#include "ruleset.h" +#include "msg.h" +#include "net.h" /* for permittedPeers, may be removed when this is removed */ +//#include "tcpsrv.h" /* NOTE: we use some defines from this module -- TODO: re-think! */ + +MODULE_TYPE_INPUT + +/* static data */ +DEF_IMOD_STATIC_DATA +DEFobjCurrIf(glbl) +DEFobjCurrIf(net) +DEFobjCurrIf(prop) +DEFobjCurrIf(datetime) +DEFobjCurrIf(errmsg) +DEFobjCurrIf(ruleset) + + + +/* config settings */ +typedef struct configSettings_s { + int bEmitMsgOnClose; /* emit an informational message on close by remote peer */ + int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */ + uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */ + uchar *lstnIP; /* which IP we should listen on? */ + ruleset_t *pRuleset; /* ruleset to bind listener to (use system default if unspecified) */ +} configSettings_t; + +static configSettings_t cs; + +/* data elements describing our running config */ +typedef struct ptcpsrv_s ptcpsrv_t; +typedef struct ptcplstn_s ptcplstn_t; +typedef struct ptcpsess_s ptcpsess_t; +typedef struct epolld_s epolld_t; + +/* the ptcp server (listener) object + * Note that the object contains support for forming a linked list + * of them. It does not make sense to do this seperately. + */ +struct ptcpsrv_s { + ptcpsrv_t *pNext; /* linked list maintenance */ + uchar *port; /* Port to listen to */ + uchar *lstnIP; /* which IP we should listen on? */ + int bEmitMsgOnClose; + int iAddtlFrameDelim; + uchar *pszInputName; + prop_t *pInputName; /* InputName in (fast to process) property format */ + ruleset_t *pRuleset; + ptcplstn_t *pLstn; /* root of our listeners */ + ptcpsess_t *pSess; /* root of our sessions */ +}; + +/* the ptcp session object. Describes a single active session. + * includes support for doubly-linked list. + */ +struct ptcpsess_s { + ptcpsrv_t *pSrv; /* our server */ + ptcpsess_t *prev, *next; + int sock; + epolld_t *epd; +//--- from tcps_sess.h + int iMsg; /* index of next char to store in msg */ + int bAtStrtOfFram; /* are we at the very beginning of a new frame? */ + enum { + eAtStrtFram, + eInOctetCnt, + eInMsg + } inputState; /* our current state */ + int iOctetsRemain; /* Number of Octets remaining in message */ + TCPFRAMINGMODE eFraming; + uchar *pMsg; /* message (fragment) received */ + prop_t *peerName; /* host name we received messages from */ + prop_t *peerIP; +//--- END from tcps_sess.h +}; + + +/* the ptcp listener object. Describes a single active listener. + */ +struct ptcplstn_s { + ptcpsrv_t *pSrv; /* our server */ + ptcplstn_t *prev, *next; + int sock; + epolld_t *epd; +}; + + +/* type of object stored in epoll descriptor */ +typedef enum { + epolld_lstn, + epolld_sess +} epolld_type_t; + +/* an epoll descriptor. contains all information necessary to process + * the result of epoll. + */ +struct epolld_s { + epolld_type_t typ; + void *ptr; + struct epoll_event ev; +}; + + +/* global data */ +//static permittedPeers_t *pPermPeersRoot = NULL; +static ptcpsrv_t *pSrvRoot = NULL; +static int epollfd = -1; /* (sole) descriptor for epoll */ +static int iMaxLine; /* maximum size of a single message */ + +/* forward definitions */ +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); +static rsRetVal addLstn(ptcpsrv_t *pSrv, int sock); + + +/* some simple constructors/destructors */ +static void +destructSess(ptcpsess_t *pSess) +{ + free(pSess->pMsg); + free(pSess->epd); + prop.Destruct(&pSess->peerName); + prop.Destruct(&pSess->peerIP); + /* TODO: make these inits compile-time switch depending: */ + pSess->pMsg = NULL; + pSess->epd = NULL; + free(pSess); +} + +static void +destructSrv(ptcpsrv_t *pSrv) +{ + prop.Destruct(&pSrv->pInputName); + free(pSrv->port); + free(pSrv); +} + +/****************************************** TCP SUPPORT FUNCTIONS ***********************************/ +/* We may later think about moving this into a helper library again. But the whole point + * so far was to keep everything related close togehter. -- rgerhards, 2010-08-10 + */ + + +/* Start up a server. That means all of its listeners are created. + * Does NOT yet accept/process any incoming data (but binds ports). Hint: this + * code is to be executed before dropping privileges. + */ +static rsRetVal +startupSrv(ptcpsrv_t *pSrv) +{ + DEFiRet; + int iSessMax = 200; /* TODO: Make configurable or remove? */ + int error, maxs, on = 1; + int sock = -1; + int numSocks; + int sockflags; + struct addrinfo hints, *res = NULL, *r; + uchar *lstnIP; + + lstnIP = pSrv->lstnIP == NULL ? UCHAR_CONSTANT("") : pSrv->lstnIP; + + dbgprintf("imptcp creating listen socket on server '%s', port %s\n", lstnIP, pSrv->port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = glbl.GetDefPFFamily(); + hints.ai_socktype = SOCK_STREAM; + + error = getaddrinfo((char*)pSrv->lstnIP, (char*) pSrv->port, &hints, &res); + if(error) { + dbgprintf("error %d querying server '%s', port '%s'\n", error, pSrv->lstnIP, pSrv->port); + ABORT_FINALIZE(RS_RET_INVALID_PORT); + } + + /* Count max number of sockets we may open */ + for(maxs = 0, r = res; r != NULL ; r = r->ai_next, maxs++) + /* EMPTY */; + + numSocks = 0; /* num of sockets counter at start of array */ + for(r = res; r != NULL ; r = r->ai_next) { + sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol); + if(sock < 0) { + if(!(r->ai_family == PF_INET6 && errno == EAFNOSUPPORT)) + dbgprintf("error %d creating tcp listen socket", errno); + /* it is debatable if PF_INET with EAFNOSUPPORT should + * also be ignored... + */ + continue; + } + +#ifdef IPV6_V6ONLY + if(r->ai_family == AF_INET6) { + int iOn = 1; + if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + (char *)&iOn, sizeof (iOn)) < 0) { + close(sock); + sock = -1; + continue; + } + } +#endif + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0 ) { + dbgprintf("error %d setting tcp socket option\n", errno); + close(sock); + sock = -1; + continue; + } + + /* We use non-blocking IO! */ + if((sockflags = fcntl(sock, F_GETFL)) != -1) { + sockflags |= O_NONBLOCK; + /* SETFL could fail too, so get it caught by the subsequent + * error check. + */ + sockflags = fcntl(sock, F_SETFL, sockflags); + } + if(sockflags == -1) { + dbgprintf("error %d setting fcntl(O_NONBLOCK) on tcp socket", errno); + close(sock); + sock = -1; + continue; + } + + + + /* We need to enable BSD compatibility. Otherwise an attacker + * could flood our log files by sending us tons of ICMP errors. + */ +#ifndef BSD + if(net.should_use_so_bsdcompat()) { + if (setsockopt(sock, SOL_SOCKET, SO_BSDCOMPAT, + (char *) &on, sizeof(on)) < 0) { + errmsg.LogError(errno, NO_ERRCODE, "TCP setsockopt(BSDCOMPAT)"); + close(sock); + sock = -1; + continue; + } + } +#endif + + if( (bind(sock, r->ai_addr, r->ai_addrlen) < 0) +#ifndef IPV6_V6ONLY + && (errno != EADDRINUSE) +#endif + ) { + /* TODO: check if *we* bound the socket - else we *have* an error! */ + dbgprintf("error %d while binding tcp socket", errno); + close(sock); + sock = -1; + continue; + } + + if(listen(sock, iSessMax / 10 + 5) < 0) { + /* If the listen fails, it most probably fails because we ask + * for a too-large backlog. So in this case we first set back + * to a fixed, reasonable, limit that should work. Only if + * that fails, too, we give up. + */ + dbgprintf("listen with a backlog of %d failed - retrying with default of 32.", + iSessMax / 10 + 5); + if(listen(sock, 32) < 0) { + dbgprintf("tcp listen error %d, suspending\n", errno); + close(sock); + sock = -1; + continue; + } + } + + /* if we reach this point, we were able to obtain a valid socket, so we can + * create our listener object. -- rgerhards, 2010-08-10 + */ + CHKiRet(addLstn(pSrv, sock)); + ++numSocks; + } + + if(numSocks != maxs) + dbgprintf("We could initialize %d TCP listen sockets out of %d we received " + "- this may or may not be an error indication.\n", numSocks, maxs); + + if(numSocks == 0) { + dbgprintf("No TCP listen sockets could successfully be initialized"); + ABORT_FINALIZE(RS_RET_COULD_NOT_BIND); + } + +finalize_it: + if(res != NULL) + freeaddrinfo(res); + + if(iRet != RS_RET_OK) { + if(sock != -1) + close(sock); + } + + RETiRet; +} + + +/* Set pRemHost based on the address provided. This is to be called upon accept()ing + * a connection request. It must be provided by the socket we received the + * message on as well as a NI_MAXHOST size large character buffer for the FQDN. + * Please see http://www.hmug.org/man/3/getnameinfo.php (under Caveats) + * for some explanation of the code found below. If we detect a malicious + * hostname, we return RS_RET_MALICIOUS_HNAME and let the caller decide + * on how to deal with that. + * rgerhards, 2008-03-31 + */ +static rsRetVal +getPeerNames(prop_t **peerName, prop_t **peerIP, struct sockaddr *pAddr) +{ + int error; + uchar szIP[NI_MAXHOST] = ""; + uchar szHname[NI_MAXHOST] = ""; + struct addrinfo hints, *res; + + DEFiRet; + + error = getnameinfo(pAddr, SALEN(pAddr), (char*)szIP, sizeof(szIP), NULL, 0, NI_NUMERICHOST); + + if(error) { + dbgprintf("Malformed from address %s\n", gai_strerror(error)); + strcpy((char*)szHname, "???"); + strcpy((char*)szIP, "???"); + ABORT_FINALIZE(RS_RET_INVALID_HNAME); + } + + if(!glbl.GetDisableDNS()) { + error = getnameinfo(pAddr, SALEN(pAddr), (char*)szHname, NI_MAXHOST, NULL, 0, NI_NAMEREQD); + if(error == 0) { + memset (&hints, 0, sizeof (struct addrinfo)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_socktype = SOCK_STREAM; + /* we now do a lookup once again. This one should fail, + * because we should not have obtained a non-numeric address. If + * we got a numeric one, someone messed with DNS! + */ + if(getaddrinfo((char*)szHname, NULL, &hints, &res) == 0) { + freeaddrinfo (res); + /* OK, we know we have evil, so let's indicate this to our caller */ + snprintf((char*)szHname, NI_MAXHOST, "[MALICIOUS:IP=%s]", szIP); + dbgprintf("Malicious PTR record, IP = \"%s\" HOST = \"%s\"", szIP, szHname); + iRet = RS_RET_MALICIOUS_HNAME; + } + } else { + strcpy((char*)szHname, (char*)szIP); + } + } else { + strcpy((char*)szHname, (char*)szIP); + } + + /* We now have the names, so now let's allocate memory and store them permanently. */ + CHKiRet(prop.Construct(peerName)); + CHKiRet(prop.SetString(*peerName, szHname, ustrlen(szHname))); + CHKiRet(prop.ConstructFinalize(*peerName)); + CHKiRet(prop.Construct(peerIP)); + CHKiRet(prop.SetString(*peerIP, szIP, ustrlen(szIP))); + CHKiRet(prop.ConstructFinalize(*peerIP)); + +finalize_it: + RETiRet; +} + + + +/* accept an incoming connection request + * rgerhards, 2008-04-22 + */ +static rsRetVal +AcceptConnReq(int sock, int *newSock, prop_t **peerName, prop_t **peerIP) +{ + int sockflags; + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + int iNewSock = -1; + + DEFiRet; + + iNewSock = accept(sock, (struct sockaddr*) &addr, &addrlen); + if(iNewSock < 0) { + ABORT_FINALIZE(RS_RET_ACCEPT_ERR); + } + + CHKiRet(getPeerNames(peerName, peerIP, (struct sockaddr*) &addr)); + + /* set the new socket to non-blocking IO */ + if((sockflags = fcntl(iNewSock, F_GETFL)) != -1) { + sockflags |= O_NONBLOCK; + /* SETFL could fail too, so get it caught by the subsequent + * error check. + */ + sockflags = fcntl(iNewSock, F_SETFL, sockflags); + } + if(sockflags == -1) { + dbgprintf("error %d setting fcntl(O_NONBLOCK) on tcp socket %d", errno, iNewSock); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + + *newSock = iNewSock; + +finalize_it: + if(iRet != RS_RET_OK) { + /* the close may be redundant, but that doesn't hurt... */ + close(iNewSock); + } + + RETiRet; +} + + +/* This is a helper for submitting the message to the rsyslog core. + * It does some common processing, including resetting the various + * state variables to a "processed" state. + * Note that this function is also called if we had a buffer overflow + * due to a too-long message. So far, there is no indication this + * happened and it may be worth thinking about different handling + * of this case (what obviously would require a change to this + * function or some related code). + * rgerhards, 2009-04-23 + * EXTRACT from tcps_sess.c + */ +static rsRetVal +doSubmitMsg(ptcpsess_t *pThis, struct syslogTime *stTime, time_t ttGenTime, multi_submit_t *pMultiSub) +{ + msg_t *pMsg; + DEFiRet; + + if(pThis->iMsg == 0) { + DBGPRINTF("discarding zero-sized message\n"); + FINALIZE; + } + + /* we now create our own message object and submit it to the queue */ + CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime)); + MsgSetRawMsg(pMsg, (char*)pThis->pMsg, pThis->iMsg); + MsgSetInputName(pMsg, pThis->pSrv->pInputName); + MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY); + pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME; + pMsg->bParseHOSTNAME = 1; + MsgSetRcvFrom(pMsg, pThis->peerName); + CHKiRet(MsgSetRcvFromIP(pMsg, pThis->peerIP)); + MsgSetRuleset(pMsg, pThis->pSrv->pRuleset); + + if(pMultiSub == NULL) { + CHKiRet(submitMsg(pMsg)); + } else { + pMultiSub->ppMsgs[pMultiSub->nElem++] = pMsg; + if(pMultiSub->nElem == pMultiSub->maxElem) + CHKiRet(multiSubmitMsg(pMultiSub)); + } + + +finalize_it: + /* reset status variables */ + pThis->bAtStrtOfFram = 1; + pThis->iMsg = 0; + + RETiRet; +} + + +/* process the data received. As TCP is stream based, we need to process the + * data inside a state machine. The actual data received is passed in byte-by-byte + * from DataRcvd, and this function here compiles messages from them and submits + * the end result to the queue. Introducing this function fixes a long-term bug ;) + * rgerhards, 2008-03-14 + * EXTRACT from tcps_sess.c + */ +static inline rsRetVal +processDataRcvd(ptcpsess_t *pThis, char c, struct syslogTime *stTime, time_t ttGenTime, multi_submit_t *pMultiSub) +{ + DEFiRet; + + if(pThis->inputState == eAtStrtFram) { + if(isdigit((int) c)) { + pThis->inputState = eInOctetCnt; + pThis->iOctetsRemain = 0; + pThis->eFraming = TCP_FRAMING_OCTET_COUNTING; + } else { + pThis->inputState = eInMsg; + pThis->eFraming = TCP_FRAMING_OCTET_STUFFING; + } + } + + if(pThis->inputState == eInOctetCnt) { + if(isdigit(c)) { + pThis->iOctetsRemain = pThis->iOctetsRemain * 10 + c - '0'; + } else { /* done with the octet count, so this must be the SP terminator */ + dbgprintf("TCP Message with octet-counter, size %d.\n", pThis->iOctetsRemain); + if(c != ' ') { + errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: " + "delimiter is not SP but has ASCII value %d.\n", c); + } + if(pThis->iOctetsRemain < 1) { + /* TODO: handle the case where the octet count is 0! */ + dbgprintf("Framing Error: invalid octet count\n"); + errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: " + "invalid octet count %d.\n", pThis->iOctetsRemain); + } else if(pThis->iOctetsRemain > iMaxLine) { + /* while we can not do anything against it, we can at least log an indication + * that something went wrong) -- rgerhards, 2008-03-14 + */ + dbgprintf("truncating message with %d octets - max msg size is %d\n", + pThis->iOctetsRemain, iMaxLine); + errmsg.LogError(0, NO_ERRCODE, "received oversize message: size is %d bytes, " + "max msg size is %d, truncating...\n", pThis->iOctetsRemain, iMaxLine); + } + pThis->inputState = eInMsg; + } + } else { + assert(pThis->inputState == eInMsg); + if(pThis->iMsg >= iMaxLine) { + /* emergency, we now need to flush, no matter if we are at end of message or not... */ + dbgprintf("error: message received is larger than max msg size, we split it\n"); + doSubmitMsg(pThis, stTime, ttGenTime, pMultiSub); + /* we might think if it is better to ignore the rest of the + * message than to treat it as a new one. Maybe this is a good + * candidate for a configuration parameter... + * rgerhards, 2006-12-04 + */ + } + + if(( (c == '\n') + //|| ((pThis->pSrv->addtlFrameDelim != TCPSRV_NO_ADDTL_DELIMITER) && (c == pThis->pSrv->addtlFrameDelim)) + ) && pThis->eFraming == TCP_FRAMING_OCTET_STUFFING) { /* record delimiter? */ + doSubmitMsg(pThis, stTime, ttGenTime, pMultiSub); + pThis->inputState = eAtStrtFram; + } else { + /* IMPORTANT: here we copy the actual frame content to the message - for BOTH framing modes! + * If we have a message that is larger than the max msg size, we truncate it. This is the best + * we can do in light of what the engine supports. -- rgerhards, 2008-03-14 + */ + if(pThis->iMsg < iMaxLine) { + *(pThis->pMsg + pThis->iMsg++) = c; + } + } + + if(pThis->eFraming == TCP_FRAMING_OCTET_COUNTING) { + /* do we need to find end-of-frame via octet counting? */ + pThis->iOctetsRemain--; + if(pThis->iOctetsRemain < 1) { + /* we have end of frame! */ + doSubmitMsg(pThis, stTime, ttGenTime, pMultiSub); + pThis->inputState = eAtStrtFram; + } + } + } + + RETiRet; +} + + +/* Processes the data received via a TCP session. If there + * is no other way to handle it, data is discarded. + * Input parameter data is the data received, iLen is its + * len as returned from recv(). iLen must be 1 or more (that + * is errors must be handled by caller!). iTCPSess must be + * the index of the TCP session that received the data. + * rgerhards 2005-07-04 + * And another change while generalizing. We now return either + * RS_RET_OK, which means the session should be kept open + * or anything else, which means it must be closed. + * rgerhards, 2008-03-01 + * As a performance optimization, we pick up the timestamp here. Acutally, + * this *is* the *correct* reception step for all the data we received, because + * we have just received a bunch of data! -- rgerhards, 2009-06-16 + * EXTRACT from tcps_sess.c + */ +#define NUM_MULTISUB 1024 +static rsRetVal +DataRcvd(ptcpsess_t *pThis, char *pData, size_t iLen) +{ + multi_submit_t multiSub; + msg_t *pMsgs[NUM_MULTISUB]; + struct syslogTime stTime; + time_t ttGenTime; + char *pEnd; + DEFiRet; + + assert(pData != NULL); + assert(iLen > 0); + + datetime.getCurrTime(&stTime, &ttGenTime); + multiSub.ppMsgs = pMsgs; + multiSub.maxElem = NUM_MULTISUB; + multiSub.nElem = 0; + + /* We now copy the message to the session buffer. */ + pEnd = pData + iLen; /* this is one off, which is intensional */ + + while(pData < pEnd) { + CHKiRet(processDataRcvd(pThis, *pData++, &stTime, ttGenTime, &multiSub)); + } + + if(multiSub.nElem > 0) { + /* submit anything that was not yet submitted */ + CHKiRet(multiSubmitMsg(&multiSub)); + } + +finalize_it: + RETiRet; +} +#undef NUM_MULTISUB + + +/****************************************** --END-- TCP SUPPORT FUNCTIONS ***********************************/ + + +static inline void +initConfigSettings(void) +{ + cs.bEmitMsgOnClose = 0; + //cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; + cs.pszInputName = NULL; + cs.pRuleset = NULL; + cs.lstnIP = NULL; +} + + +/* add socket to the epoll set + */ +static inline rsRetVal +addEPollSock(epolld_type_t typ, void *ptr, int sock, epolld_t **pEpd) +{ + DEFiRet; + epolld_t *epd = NULL; + + CHKmalloc(epd = malloc(sizeof(epolld_t))); + epd->typ = typ; + epd->ptr = ptr; + *pEpd = epd; + epd->ev.events = EPOLLIN|EPOLLET; + epd->ev.data.ptr = (void*) epd; + + if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &(epd->ev)) != 0) { + char errStr[1024]; + int eno = errno; + errmsg.LogError(0, RS_RET_EPOLL_CTL_FAILED, "os error (%d) during epoll ADD: %s", + eno, rs_strerror_r(eno, errStr, sizeof(errStr))); + ABORT_FINALIZE(RS_RET_EPOLL_CTL_FAILED); + } + + DBGPRINTF("imptcp: added socket %d to epoll[%d] set\n", sock, epollfd); + +finalize_it: + if(iRet != RS_RET_OK) { + free(epd); + } + RETiRet; +} + + +/* remove a socket from the epoll set. Note that the epd parameter + * is not really required -- it is used to satisfy older kernels where + * epoll_ctl() required a non-NULL pointer even though the ptr is never used. + * For simplicity, we supply the same pointer we had when we created the + * event (it's simple because we have it at hand). + */ +static inline rsRetVal +removeEPollSock(int sock, epolld_t *epd) +{ + DEFiRet; + + DBGPRINTF("imptcp: removing socket %d from epoll[%d] set\n", sock, epollfd); + + if(epoll_ctl(epollfd, EPOLL_CTL_DEL, sock, &(epd->ev)) != 0) { + char errStr[1024]; + int eno = errno; + errmsg.LogError(0, RS_RET_EPOLL_CTL_FAILED, "os error (%d) during epoll DEL: %s", + eno, rs_strerror_r(eno, errStr, sizeof(errStr))); + ABORT_FINALIZE(RS_RET_EPOLL_CTL_FAILED); + } + +finalize_it: + RETiRet; +} + + +/* add a listener to the server + */ +static rsRetVal +addLstn(ptcpsrv_t *pSrv, int sock) +{ + DEFiRet; + ptcplstn_t *pLstn; + + CHKmalloc(pLstn = malloc(sizeof(ptcplstn_t))); + pLstn->pSrv = pSrv; + pLstn->sock = sock; + + /* add to start of server's listener list */ + pLstn->prev = NULL; + pLstn->next = pSrv->pLstn; + pSrv->pLstn = pLstn; + + iRet = addEPollSock(epolld_lstn, pLstn, sock, &pLstn->epd); + +finalize_it: + RETiRet; +} + + +/* add a session to the server + */ +static rsRetVal +addSess(ptcpsrv_t *pSrv, int sock, prop_t *peerName, prop_t *peerIP) +{ + DEFiRet; + ptcpsess_t *pSess = NULL; + + CHKmalloc(pSess = malloc(sizeof(ptcpsess_t))); + CHKmalloc(pSess->pMsg = malloc(iMaxLine * sizeof(uchar))); + pSess->pSrv = pSrv; + pSess->sock = sock; + pSess->inputState = eAtStrtFram; + pSess->iMsg = 0; + pSess->bAtStrtOfFram = 1; + pSess->peerName = peerName; + pSess->peerIP = peerIP; + + /* add to start of server's listener list */ + pSess->prev = NULL; + pSess->next = pSrv->pSess; + pSrv->pSess = pSess; + + iRet = addEPollSock(epolld_sess, pSess, sock, &pSess->epd); + +finalize_it: + RETiRet; +} + + +/* close/remove a session + * NOTE: we must first remove the fd from the epoll set and then close it -- else we + * get an error "bad file descriptor" from epoll. + */ +static rsRetVal +closeSess(ptcpsess_t *pSess) +{ + int sock; + DEFiRet; + + sock = pSess->sock; + CHKiRet(removeEPollSock(sock, pSess->epd)); + close(sock); + + /* finally unlink session from structures */ + if(pSess->next != NULL) + pSess->next->prev = pSess->prev; + if(pSess->prev == NULL) { + /* need to update root! */ + pSess->pSrv->pSess = pSess->next; + } else { + pSess->prev->next = pSess->next; + } + + /* unlinked, now remove structure */ + destructSess(pSess); + +finalize_it: + DBGPRINTF("imtcp: session on socket %d closed with iRet %d.\n", sock, iRet); + RETiRet; +} + + +#if 0 +/* set permitted peer -- rgerhards, 2008-05-19 + */ +static rsRetVal +setPermittedPeer(void __attribute__((unused)) *pVal, uchar *pszID) +{ + DEFiRet; + CHKiRet(net.AddPermittedPeer(&pPermPeersRoot, pszID)); + free(pszID); /* no longer needed, but we need to free as of interface def */ +finalize_it: + RETiRet; +} +#endif + + +/* accept a new ruleset to bind. Checks if it exists and complains, if not */ +static rsRetVal setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) +{ + ruleset_t *pRuleset; + rsRetVal localRet; + DEFiRet; + + localRet = ruleset.GetRuleset(&pRuleset, pszName); + if(localRet == RS_RET_NOT_FOUND) { + errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName); + } + CHKiRet(localRet); + cs.pRuleset = pRuleset; + DBGPRINTF("imptcp current bind ruleset %p: '%s'\n", pRuleset, pszName); + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + + +static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVal) +{ + DEFiRet; + ptcpsrv_t *pSrv; + + CHKmalloc(pSrv = malloc(sizeof(ptcpsrv_t))); + pSrv->pSess = NULL; + pSrv->pLstn = NULL; + pSrv->bEmitMsgOnClose = cs.bEmitMsgOnClose; + pSrv->port = pNewVal; + //pSrv->iAddtlFrameDelim = cs.iAddtlFrameDelim; + cs.pszInputName = NULL; /* moved over to pSrv, we do not own */ + pSrv->lstnIP = cs.lstnIP; + cs.lstnIP = NULL; /* moved over to pSrv, we do not own */ + pSrv->pRuleset = cs.pRuleset; + pSrv->pszInputName = (cs.pszInputName == NULL) ? UCHAR_CONSTANT("imptcp") : cs.pszInputName; + CHKiRet(prop.Construct(&pSrv->pInputName)); + CHKiRet(prop.SetString(pSrv->pInputName, pSrv->pszInputName, ustrlen(pSrv->pszInputName))); + CHKiRet(prop.ConstructFinalize(pSrv->pInputName)); + + /* add to linked list */ + pSrv->pNext = pSrvRoot; + pSrvRoot = pSrv; + + /* all config vars are auto-reset -- this also is very useful with the + * new config format effort (v6). + */ + resetConfigVariables(NULL, NULL); + +finalize_it: + if(iRet != RS_RET_OK) { + errmsg.LogError(0, NO_ERRCODE, "error %d trying to add listener", iRet); + } + RETiRet; +} + + +/* start up all listeners + * This is a one-time stop once the module is set to start. + */ +static inline rsRetVal +startupServers() +{ + DEFiRet; + ptcpsrv_t *pSrv; + + pSrv = pSrvRoot; + while(pSrv != NULL) { + DBGPRINTF("Starting up ptcp server for port %s, name '%s'\n", pSrv->port, pSrv->pszInputName); + startupSrv(pSrv); + pSrv = pSrv->pNext; + } + + RETiRet; +} + + +/* process new activity on listener. This means we need to accept a new + * connection. + */ +static inline rsRetVal +lstnActivity(ptcplstn_t *pLstn) +{ + int newSock; + prop_t *peerName; + prop_t *peerIP; + DEFiRet; + + DBGPRINTF("imptcp: new connection on listen socket %d\n", pLstn->sock); + CHKiRet(AcceptConnReq(pLstn->sock, &newSock, &peerName, &peerIP)); + CHKiRet(addSess(pLstn->pSrv, newSock, peerName, peerIP)); + +finalize_it: + RETiRet; +} + + +/* process new activity on session. This means we need to accept data + * or close the session. + */ +static inline rsRetVal +sessActivity(ptcpsess_t *pSess) +{ + int lenRcv; + int lenBuf; + char rcvBuf[4096]; + DEFiRet; + + DBGPRINTF("imptcp: new activity on session socket %d\n", pSess->sock); + + lenBuf = sizeof(rcvBuf); + lenRcv = recv(pSess->sock, rcvBuf, lenBuf, 0); + + if(lenRcv > 0) { + /* have data, process it */ + DBGPRINTF("imtcp: data(%d) on socket %d: %s\n", lenBuf, pSess->sock, rcvBuf); + CHKiRet(DataRcvd(pSess, rcvBuf, lenRcv)); + } else if (lenRcv == 0) { + /* session was closed, do clean-up */ + CHKiRet(closeSess(pSess)); + } else { + DBGPRINTF("imtcp: error on session socket %d - closed.\n", pSess->sock); + closeSess(pSess); /* try clean-up by dropping session */ + } + +finalize_it: + RETiRet; +} + + +/* This function is called to gather input. + */ +BEGINrunInput + int i; + int nfds; + struct epoll_event events[1]; + epolld_t *epd; +CODESTARTrunInput + DBGPRINTF("imptcp now beginning to process input data\n"); + /* v5 TODO: consentual termination mode */ + while(1) { + DBGPRINTF("imptcp going on epoll_wait\n"); + nfds = epoll_wait(epollfd, events, sizeof(events)/sizeof(struct epoll_event), -1); + for(i = 0 ; i < nfds ; ++i) { /* support for larger batches (later, TODO) */ + epd = (epolld_t*) events[i].data.ptr; + switch(epd->typ) { + case epolld_lstn: + lstnActivity((ptcplstn_t *) epd->ptr); + break; + case epolld_sess: + sessActivity((ptcpsess_t *) epd->ptr); + break; + default: + errmsg.LogError(0, RS_RET_INTERNAL_ERROR, + "error: invalid epolld_type_t %d after epoll", epd->typ); + break; + } + } + } +ENDrunInput + + +/* initialize and return if will run or not */ +BEGINwillRun +CODESTARTwillRun + /* first apply some config settings */ + //net.PrintAllowedSenders(2); /* TCP */ + iMaxLine = glbl.GetMaxLine(); /* get maximum size we currently support */ + + if(pSrvRoot == NULL) { + errmsg.LogError(0, RS_RET_NO_LSTN_DEFINED, "error: no ptcp server defined, module can not run."); + ABORT_FINALIZE(RS_RET_NO_RUN); + } + + if((epollfd = epoll_create1(EPOLL_CLOEXEC)) < 0) { + errmsg.LogError(0, RS_RET_EPOLL_CR_FAILED, "error: epoll_create() failed"); + ABORT_FINALIZE(RS_RET_NO_RUN); + } + + /* start up servers, but do not yet read input data */ + CHKiRet(startupServers()); + DBGPRINTF("imptcp started up, but not yet receiving data\n"); +finalize_it: +ENDwillRun + + +/* completely shut down a server, that means closing all of its + * listeners and sessions. + */ +static inline void +shutdownSrv(ptcpsrv_t *pSrv) +{ + ptcplstn_t *pLstn, *lstnDel; + ptcpsess_t *pSess, *sessDel; + + /* listeners */ + pLstn = pSrv->pLstn; + while(pLstn != NULL) { + close(pLstn->sock); + lstnDel = pLstn; + pLstn = pLstn->next; + DBGPRINTF("imptcp shutdown listen socket %d\n", lstnDel->sock); + free(lstnDel->epd); + free(lstnDel); + } + + /* sessions */ + pSess = pSrv->pSess; + while(pSess != NULL) { + close(pSess->sock); + sessDel = pSess; + pSess = pSess->next; + DBGPRINTF("imptcp shutdown session socket %d\n", sessDel->sock); + destructSess(sessDel); + } +} + + +BEGINafterRun + ptcpsrv_t *pSrv, *srvDel; +CODESTARTafterRun + /* do cleanup here */ + //net.clearAllowedSenders(UCHAR_CONSTANT("TCP")); + /* we need to close everything that is still open */ + pSrv = pSrvRoot; + while(pSrv != NULL) { + srvDel = pSrv; + pSrv = pSrv->pNext; + shutdownSrv(srvDel); + destructSrv(srvDel); + } + + close(epollfd); +ENDafterRun + + +BEGINmodExit +CODESTARTmodExit +#if 0 + if(pPermPeersRoot != NULL) { + net.DestructPermittedPeers(&pPermPeersRoot); + } +#endif + + /* release objects we used */ + objRelease(glbl, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); + objRelease(net, LM_NET_FILENAME); + objRelease(datetime, CORE_COMPONENT); + objRelease(errmsg, CORE_COMPONENT); + objRelease(ruleset, CORE_COMPONENT); +ENDmodExit + + +static rsRetVal +resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + cs.bEmitMsgOnClose = 0; + //cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; + free(cs.pszInputName); + cs.pszInputName = NULL; + free(cs.lstnIP); + cs.lstnIP = NULL; + return RS_RET_OK; +} + + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_IMOD_QUERIES +ENDqueryEtryPt + + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ +CODEmodInit_QueryRegCFSLineHdlr + initConfigSettings(); + /* request objects we use */ + CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(prop, CORE_COMPONENT)); + CHKiRet(objUse(net, LM_NET_FILENAME)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(datetime, CORE_COMPONENT)); + CHKiRet(objUse(ruleset, CORE_COMPONENT)); + + /* register config file handlers */ + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverrun"), 0, eCmdHdlrGetWord, + addTCPListener, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpservernotifyonconnectionclose"), 0, + eCmdHdlrBinary, NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID)); + //CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverstreamdriverpermittedpeer"), 0, + //eCmdHdlrGetWord, setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserveraddtlframedelimiter"), 0, eCmdHdlrInt, + NULL, &cs.iAddtlFrameDelim, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverinputname"), 0, + eCmdHdlrGetWord, NULL, &cs.pszInputName, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverlistenip"), 0, + eCmdHdlrGetWord, NULL, &cs.lstnIP, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverbindruleset"), 0, + eCmdHdlrGetWord, setRuleset, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler, + resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); +ENDmodInit + + +/* vim:set ai: + */ diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 8979893a..907b9c1a 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -360,6 +360,10 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_VAR_NOT_FOUND = -2142, /**< variable not found */ RS_RET_EMPTY_MSG = -2143, /**< provided (raw) MSG is empty */ RS_RET_PEER_CLOSED_CONN = -2144, /**< remote peer closed connection (information, no error) */ + RS_RET_NO_LSTN_DEFINED = -2172, /**< no listener defined (e.g. inside an input module) */ + RS_RET_EPOLL_CR_FAILED = -2173, /**< epoll_create() failed */ + RS_RET_EPOLL_CTL_FAILED = -2174, /**< epoll_ctl() failed */ + RS_RET_INTERNAL_ERROR = -2175, /**< rsyslogd internal error, unexpected code path reached */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tools/syslogd.c b/tools/syslogd.c index a03dcf0e..18e0c98f 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -371,7 +371,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a /* hardcoded standard templates (used for defaults) */ -static uchar template_DebugFormat[] = "\"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%', HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\nrawmsg: '%rawmsg%'\n\n\""; +static uchar template_DebugFormat[] = "\"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%', HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\ninputname: %inputname% rawmsg: '%rawmsg%'\n\n\""; static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\""; static uchar template_TraditionalFileFormat[] = "\"%TIMESTAMP% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n\""; static uchar template_FileFormat[] = "\"%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n\""; -- cgit From ee4aed1713bb968afa6db992f9e2e6c00d6c9350 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 10 Aug 2010 16:18:21 +0200 Subject: added tests for imptcp and fixed some problems with it it now also works reliably in edge-triggered mode --- plugins/imptcp/imptcp.c | 59 ++++++++++++++++++++++++++------------ tests/Makefile.am | 6 ++++ tests/diag.sh | 2 +- tests/imptcp_large.sh | 14 +++++++++ tests/testsuites/imptcp_large.conf | 16 +++++++++++ 5 files changed, 78 insertions(+), 19 deletions(-) create mode 100755 tests/imptcp_large.sh create mode 100644 tests/testsuites/imptcp_large.conf diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 5aeb0192..80df959c 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -434,6 +434,8 @@ AcceptConnReq(int sock, int *newSock, prop_t **peerName, prop_t **peerIP) iNewSock = accept(sock, (struct sockaddr*) &addr, &addrlen); if(iNewSock < 0) { + if(errno == EAGAIN || errno == EWOULDBLOCK) + ABORT_FINALIZE(RS_RET_NO_MORE_DATA); ABORT_FINALIZE(RS_RET_ACCEPT_ERR); } @@ -747,6 +749,8 @@ addLstn(ptcpsrv_t *pSrv, int sock) /* add to start of server's listener list */ pLstn->prev = NULL; pLstn->next = pSrv->pLstn; + if(pSrv->pLstn != NULL) + pSrv->pLstn->prev = pLstn; pSrv->pLstn = pLstn; iRet = addEPollSock(epolld_lstn, pLstn, sock, &pLstn->epd); @@ -777,6 +781,8 @@ addSess(ptcpsrv_t *pSrv, int sock, prop_t *peerName, prop_t *peerIP) /* add to start of server's listener list */ pSess->prev = NULL; pSess->next = pSrv->pSess; + if(pSrv->pSess != NULL) + pSrv->pSess->prev = pSess; pSrv->pSess = pSess; iRet = addEPollSock(epolld_sess, pSess, sock, &pSess->epd); @@ -801,6 +807,9 @@ closeSess(ptcpsess_t *pSess) close(sock); /* finally unlink session from structures */ +//fprintf(stderr, "closing session %d next %p, prev %p\n", pSess->sock, pSess->next, pSess->prev); +//dbgprintf("imptcp: pSess->next %p\n", pSess->next); +//dbgprintf("imptcp: pSess->prev %p\n", pSess->prev); if(pSess->next != NULL) pSess->next->prev = pSess->prev; if(pSess->prev == NULL) { @@ -921,11 +930,19 @@ lstnActivity(ptcplstn_t *pLstn) int newSock; prop_t *peerName; prop_t *peerIP; + rsRetVal localRet; +int iac = 0; DEFiRet; DBGPRINTF("imptcp: new connection on listen socket %d\n", pLstn->sock); - CHKiRet(AcceptConnReq(pLstn->sock, &newSock, &peerName, &peerIP)); - CHKiRet(addSess(pLstn->pSrv, newSock, peerName, peerIP)); + while(1) { + localRet = AcceptConnReq(pLstn->sock, &newSock, &peerName, &peerIP); +//if(iac++ > 0) fprintf(stderr, "%d accepts in a row!\n", iac); + if(localRet == RS_RET_NO_MORE_DATA) + break; + CHKiRet(localRet); + CHKiRet(addSess(pLstn->pSrv, newSock, peerName, peerIP)); + } finalize_it: RETiRet; @@ -940,24 +957,32 @@ sessActivity(ptcpsess_t *pSess) { int lenRcv; int lenBuf; - char rcvBuf[4096]; + char rcvBuf[128*1024]; DEFiRet; +int iac = 0; DBGPRINTF("imptcp: new activity on session socket %d\n", pSess->sock); - lenBuf = sizeof(rcvBuf); - lenRcv = recv(pSess->sock, rcvBuf, lenBuf, 0); - - if(lenRcv > 0) { - /* have data, process it */ - DBGPRINTF("imtcp: data(%d) on socket %d: %s\n", lenBuf, pSess->sock, rcvBuf); - CHKiRet(DataRcvd(pSess, rcvBuf, lenRcv)); - } else if (lenRcv == 0) { - /* session was closed, do clean-up */ - CHKiRet(closeSess(pSess)); - } else { - DBGPRINTF("imtcp: error on session socket %d - closed.\n", pSess->sock); - closeSess(pSess); /* try clean-up by dropping session */ + while(1) { + lenBuf = sizeof(rcvBuf); + lenRcv = recv(pSess->sock, rcvBuf, lenBuf, 0); +//if(iac++ > 1) fprintf(stderr, "\n%d recv in a row!\n", iac-1); + + if(lenRcv > 0) { + /* have data, process it */ + DBGPRINTF("imtcp: data(%d) on socket %d: %s\n", lenBuf, pSess->sock, rcvBuf); + CHKiRet(DataRcvd(pSess, rcvBuf, lenRcv)); + } else if (lenRcv == 0) { + /* session was closed, do clean-up */ + CHKiRet(closeSess(pSess)); + break; + } else { + if(errno == EAGAIN || errno == EWOULDBLOCK) + break; + DBGPRINTF("imtcp: error on session socket %d - closed.\n", pSess->sock); + closeSess(pSess); /* try clean-up by dropping session */ + break; + } } finalize_it: @@ -1127,8 +1152,6 @@ CODEmodInit_QueryRegCFSLineHdlr addTCPListener, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpservernotifyonconnectionclose"), 0, eCmdHdlrBinary, NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID)); - //CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverstreamdriverpermittedpeer"), 0, - //eCmdHdlrGetWord, setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserveraddtlframedelimiter"), 0, eCmdHdlrInt, NULL, &cs.iAddtlFrameDelim, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverinputname"), 0, diff --git a/tests/Makefile.am b/tests/Makefile.am index 0045f00a..b9b1ede7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,6 +7,8 @@ TESTS = $(TESTRUNS) cfg.sh \ diskqueue.sh \ diskqueue-fsync.sh \ manytcp.sh \ + manyptcp.sh \ + imptcp_large.sh \ sndrcv.sh \ sndrcv_gzip.sh \ asynwr_simple.sh \ @@ -136,6 +138,10 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/imtcp-multiport.conf \ manytcp.sh \ testsuites/manytcp.conf \ + manyptcp.sh \ + testsuites/manyptcp.conf \ + imptcp_large.sh \ + testsuites/imptcp_large.conf \ inputname.sh \ testsuites/inputname_imtcp.conf \ testsuites/1.inputname_imtcp_12514 \ diff --git a/tests/diag.sh b/tests/diag.sh index 51ad5f6a..8659aa17 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -10,7 +10,7 @@ #valgrind="valgrind --tool=helgrind --log-fd=1" #valgrind="valgrind --tool=exp-ptrcheck --log-fd=1" #set -o xtrace -#export RSYSLOG_DEBUG="debug nostdout printmutexaction" +#export RSYSLOG_DEBUG="debug nostdout noprintmutexaction" #export RSYSLOG_DEBUGLOG="log" case $1 in 'init') $srcdir/killrsyslog.sh # kill rsyslogd if it runs for some reason diff --git a/tests/imptcp_large.sh b/tests/imptcp_large.sh new file mode 100755 index 00000000..f6eee895 --- /dev/null +++ b/tests/imptcp_large.sh @@ -0,0 +1,14 @@ +# Test imptcp with large messages +# added 2010-08-10 by Rgerhards +# +# This file is part of the rsyslog project, released under GPLv3 +cat rsyslog.action.1.include +source $srcdir/diag.sh init +source $srcdir/diag.sh startup imptcp_large.conf +# send 4000 messages of 10.000bytes plus header max, randomized +source $srcdir/diag.sh tcpflood -c5 -m20000 -r -d10000 -P129 +sleep 2 # due to large messages, we need this time for the tcp receiver to settle... +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown # and wait for it to terminate +source $srcdir/diag.sh seq-check 0 19999 -E +source $srcdir/diag.sh exit diff --git a/tests/testsuites/imptcp_large.conf b/tests/testsuites/imptcp_large.conf new file mode 100644 index 00000000..677e33f6 --- /dev/null +++ b/tests/testsuites/imptcp_large.conf @@ -0,0 +1,16 @@ +# simple async writing test +# rgerhards, 2010-03-09 +$MaxMessageSize 10k +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imptcp/.libs/imptcp +$MainMsgQueueTimeoutShutdown 10000 +$InputPTCPServerRun 13514 + +$template outfmt,"%msg:F,58:2%,%msg:F,58:3%,%msg:F,58:4%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +$OMFileFlushOnTXEnd off +$OMFileFlushInterval 2 +$OMFileIOBufferSize 256k +$IncludeConfig rsyslog.action.1.include +local0.* ?dynfile;outfmt -- cgit From 83948a07fd0a9a9a3ea7db8647a0c1d032f0bc2e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 10 Aug 2010 17:22:27 +0200 Subject: some cleanup and minor optimization --- plugins/imptcp/imptcp.c | 65 ++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 80df959c..732590a9 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -165,6 +165,16 @@ struct epolld_s { static ptcpsrv_t *pSrvRoot = NULL; static int epollfd = -1; /* (sole) descriptor for epoll */ static int iMaxLine; /* maximum size of a single message */ +/* we use a single static receive buffer, as this module is not multi-threaded. Keeping + * the buffer in the data segment is probably a little bit more efficient than on the stack + * (but at least I can't believe it will ever be less efficient ;) -- rgerhards, 2010-08-10 + * Note that we do NOT (yet?) provide a config setting to set the buffer size. For usual + * syslog traffic, it should be large enough. Also keep in mind that we run under a virtual + * memory system, so if we do not use large parts of the buffer, that's no issue at + * all -- it'll just use up address space. On the other hand, it would be silly to page in + * or page out some data just to get space for the IO buffer. + */ +static char rcvBuf[128*1024]; /* forward definitions */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); @@ -207,7 +217,6 @@ static rsRetVal startupSrv(ptcpsrv_t *pSrv) { DEFiRet; - int iSessMax = 200; /* TODO: Make configurable or remove? */ int error, maxs, on = 1; int sock = -1; int numSocks; @@ -217,7 +226,7 @@ startupSrv(ptcpsrv_t *pSrv) lstnIP = pSrv->lstnIP == NULL ? UCHAR_CONSTANT("") : pSrv->lstnIP; - dbgprintf("imptcp creating listen socket on server '%s', port %s\n", lstnIP, pSrv->port); + DBGPRINTF("imptcp creating listen socket on server '%s', port %s\n", lstnIP, pSrv->port); memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; @@ -226,7 +235,7 @@ startupSrv(ptcpsrv_t *pSrv) error = getaddrinfo((char*)pSrv->lstnIP, (char*) pSrv->port, &hints, &res); if(error) { - dbgprintf("error %d querying server '%s', port '%s'\n", error, pSrv->lstnIP, pSrv->port); + DBGPRINTF("error %d querying server '%s', port '%s'\n", error, pSrv->lstnIP, pSrv->port); ABORT_FINALIZE(RS_RET_INVALID_PORT); } @@ -239,7 +248,7 @@ startupSrv(ptcpsrv_t *pSrv) sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol); if(sock < 0) { if(!(r->ai_family == PF_INET6 && errno == EAFNOSUPPORT)) - dbgprintf("error %d creating tcp listen socket", errno); + DBGPRINTF("error %d creating tcp listen socket", errno); /* it is debatable if PF_INET with EAFNOSUPPORT should * also be ignored... */ @@ -258,7 +267,7 @@ startupSrv(ptcpsrv_t *pSrv) } #endif if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0 ) { - dbgprintf("error %d setting tcp socket option\n", errno); + DBGPRINTF("error %d setting tcp socket option\n", errno); close(sock); sock = -1; continue; @@ -273,7 +282,7 @@ startupSrv(ptcpsrv_t *pSrv) sockflags = fcntl(sock, F_SETFL, sockflags); } if(sockflags == -1) { - dbgprintf("error %d setting fcntl(O_NONBLOCK) on tcp socket", errno); + DBGPRINTF("error %d setting fcntl(O_NONBLOCK) on tcp socket", errno); close(sock); sock = -1; continue; @@ -302,26 +311,17 @@ startupSrv(ptcpsrv_t *pSrv) #endif ) { /* TODO: check if *we* bound the socket - else we *have* an error! */ - dbgprintf("error %d while binding tcp socket", errno); + DBGPRINTF("error %d while binding tcp socket", errno); close(sock); sock = -1; continue; } - if(listen(sock, iSessMax / 10 + 5) < 0) { - /* If the listen fails, it most probably fails because we ask - * for a too-large backlog. So in this case we first set back - * to a fixed, reasonable, limit that should work. Only if - * that fails, too, we give up. - */ - dbgprintf("listen with a backlog of %d failed - retrying with default of 32.", - iSessMax / 10 + 5); - if(listen(sock, 32) < 0) { - dbgprintf("tcp listen error %d, suspending\n", errno); - close(sock); - sock = -1; - continue; - } + if(listen(sock, 511) < 0) { + DBGPRINTF("tcp listen error %d, suspending\n", errno); + close(sock); + sock = -1; + continue; } /* if we reach this point, we were able to obtain a valid socket, so we can @@ -332,11 +332,11 @@ startupSrv(ptcpsrv_t *pSrv) } if(numSocks != maxs) - dbgprintf("We could initialize %d TCP listen sockets out of %d we received " + DBGPRINTF("We could initialize %d TCP listen sockets out of %d we received " "- this may or may not be an error indication.\n", numSocks, maxs); if(numSocks == 0) { - dbgprintf("No TCP listen sockets could successfully be initialized"); + DBGPRINTF("No TCP listen sockets could successfully be initialized"); ABORT_FINALIZE(RS_RET_COULD_NOT_BIND); } @@ -375,7 +375,7 @@ getPeerNames(prop_t **peerName, prop_t **peerIP, struct sockaddr *pAddr) error = getnameinfo(pAddr, SALEN(pAddr), (char*)szIP, sizeof(szIP), NULL, 0, NI_NUMERICHOST); if(error) { - dbgprintf("Malformed from address %s\n", gai_strerror(error)); + DBGPRINTF("Malformed from address %s\n", gai_strerror(error)); strcpy((char*)szHname, "???"); strcpy((char*)szIP, "???"); ABORT_FINALIZE(RS_RET_INVALID_HNAME); @@ -395,7 +395,7 @@ getPeerNames(prop_t **peerName, prop_t **peerIP, struct sockaddr *pAddr) freeaddrinfo (res); /* OK, we know we have evil, so let's indicate this to our caller */ snprintf((char*)szHname, NI_MAXHOST, "[MALICIOUS:IP=%s]", szIP); - dbgprintf("Malicious PTR record, IP = \"%s\" HOST = \"%s\"", szIP, szHname); + DBGPRINTF("Malicious PTR record, IP = \"%s\" HOST = \"%s\"", szIP, szHname); iRet = RS_RET_MALICIOUS_HNAME; } } else { @@ -450,7 +450,7 @@ AcceptConnReq(int sock, int *newSock, prop_t **peerName, prop_t **peerIP) sockflags = fcntl(iNewSock, F_SETFL, sockflags); } if(sockflags == -1) { - dbgprintf("error %d setting fcntl(O_NONBLOCK) on tcp socket %d", errno, iNewSock); + DBGPRINTF("error %d setting fcntl(O_NONBLOCK) on tcp socket %d", errno, iNewSock); ABORT_FINALIZE(RS_RET_IO_ERROR); } @@ -544,21 +544,21 @@ processDataRcvd(ptcpsess_t *pThis, char c, struct syslogTime *stTime, time_t ttG if(isdigit(c)) { pThis->iOctetsRemain = pThis->iOctetsRemain * 10 + c - '0'; } else { /* done with the octet count, so this must be the SP terminator */ - dbgprintf("TCP Message with octet-counter, size %d.\n", pThis->iOctetsRemain); + DBGPRINTF("TCP Message with octet-counter, size %d.\n", pThis->iOctetsRemain); if(c != ' ') { errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: " "delimiter is not SP but has ASCII value %d.\n", c); } if(pThis->iOctetsRemain < 1) { /* TODO: handle the case where the octet count is 0! */ - dbgprintf("Framing Error: invalid octet count\n"); + DBGPRINTF("Framing Error: invalid octet count\n"); errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: " "invalid octet count %d.\n", pThis->iOctetsRemain); } else if(pThis->iOctetsRemain > iMaxLine) { /* while we can not do anything against it, we can at least log an indication * that something went wrong) -- rgerhards, 2008-03-14 */ - dbgprintf("truncating message with %d octets - max msg size is %d\n", + DBGPRINTF("truncating message with %d octets - max msg size is %d\n", pThis->iOctetsRemain, iMaxLine); errmsg.LogError(0, NO_ERRCODE, "received oversize message: size is %d bytes, " "max msg size is %d, truncating...\n", pThis->iOctetsRemain, iMaxLine); @@ -569,7 +569,7 @@ processDataRcvd(ptcpsess_t *pThis, char c, struct syslogTime *stTime, time_t ttG assert(pThis->inputState == eInMsg); if(pThis->iMsg >= iMaxLine) { /* emergency, we now need to flush, no matter if we are at end of message or not... */ - dbgprintf("error: message received is larger than max msg size, we split it\n"); + DBGPRINTF("error: message received is larger than max msg size, we split it\n"); doSubmitMsg(pThis, stTime, ttGenTime, pMultiSub); /* we might think if it is better to ignore the rest of the * message than to treat it as a new one. Maybe this is a good @@ -808,8 +808,8 @@ closeSess(ptcpsess_t *pSess) /* finally unlink session from structures */ //fprintf(stderr, "closing session %d next %p, prev %p\n", pSess->sock, pSess->next, pSess->prev); -//dbgprintf("imptcp: pSess->next %p\n", pSess->next); -//dbgprintf("imptcp: pSess->prev %p\n", pSess->prev); +//DBGPRINTF("imptcp: pSess->next %p\n", pSess->next); +//DBGPRINTF("imptcp: pSess->prev %p\n", pSess->prev); if(pSess->next != NULL) pSess->next->prev = pSess->prev; if(pSess->prev == NULL) { @@ -957,7 +957,6 @@ sessActivity(ptcpsess_t *pSess) { int lenRcv; int lenBuf; - char rcvBuf[128*1024]; DEFiRet; int iac = 0; -- cgit From b5b4bd138949f09b3703e6f7f5caf46d361fa41c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 10 Aug 2010 18:29:22 +0200 Subject: small improvements to testbench --- tests/complex1.sh | 2 +- tests/imptcp_large.sh | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/complex1.sh b/tests/complex1.sh index 7f3cd994..954ddf6c 100755 --- a/tests/complex1.sh +++ b/tests/complex1.sh @@ -12,7 +12,7 @@ source $srcdir/diag.sh init source $srcdir/diag.sh startup complex1.conf # send 30,000 messages of 400 bytes plus header max, via three dest ports source $srcdir/diag.sh tcpflood -m40000 -rd400 -P129 -f5 -n3 -c15 -i1 -sleep 2 # due to large messages, we need this time for the tcp receiver to settle... +sleep 4 # due to large messages, we need this time for the tcp receiver to settle... source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages source $srcdir/diag.sh wait-shutdown # and wait for it to terminate ls rsyslog.out.*.log diff --git a/tests/imptcp_large.sh b/tests/imptcp_large.sh index f6eee895..b4d130bb 100755 --- a/tests/imptcp_large.sh +++ b/tests/imptcp_large.sh @@ -2,6 +2,8 @@ # added 2010-08-10 by Rgerhards # # This file is part of the rsyslog project, released under GPLv3 +echo ==================================================================================== +echo TEST: \[imptcp_large.sh\]: test imptcp with large-size messages cat rsyslog.action.1.include source $srcdir/diag.sh init source $srcdir/diag.sh startup imptcp_large.conf -- cgit From c664adfa1683763ae503f2da9e8d4d528d6634d1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 10 Aug 2010 19:34:42 +0200 Subject: more testbench improvements and new tests --- tests/Makefile.am | 6 +++ tests/imptcp_conndrop.sh | 16 ++++++ tests/imtcp_conndrop.sh | 16 ++++++ tests/tcpflood.c | 95 ++++++++++++++--------------------- tests/testsuites/imptcp_conndrop.conf | 16 ++++++ tests/testsuites/imtcp_conndrop.conf | 16 ++++++ 6 files changed, 107 insertions(+), 58 deletions(-) create mode 100755 tests/imptcp_conndrop.sh create mode 100755 tests/imtcp_conndrop.sh create mode 100644 tests/testsuites/imptcp_conndrop.conf create mode 100644 tests/testsuites/imtcp_conndrop.conf diff --git a/tests/Makefile.am b/tests/Makefile.am index b9b1ede7..b500bc85 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -9,6 +9,8 @@ TESTS = $(TESTRUNS) cfg.sh \ manytcp.sh \ manyptcp.sh \ imptcp_large.sh \ + imptcp_conndrop.sh \ + imtcp_conndrop.sh \ sndrcv.sh \ sndrcv_gzip.sh \ asynwr_simple.sh \ @@ -142,6 +144,10 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/manyptcp.conf \ imptcp_large.sh \ testsuites/imptcp_large.conf \ + imptcp_conndrop.sh \ + testsuites/imptcp_conndrop.conf \ + imtcp_conndrop.sh \ + testsuites/imtcp_conndrop.conf \ inputname.sh \ testsuites/inputname_imtcp.conf \ testsuites/1.inputname_imtcp_12514 \ diff --git a/tests/imptcp_conndrop.sh b/tests/imptcp_conndrop.sh new file mode 100755 index 00000000..684de6b5 --- /dev/null +++ b/tests/imptcp_conndrop.sh @@ -0,0 +1,16 @@ +# Test imptcp with many dropping connections +# added 2010-08-10 by Rgerhards +# +# This file is part of the rsyslog project, released under GPLv3 +echo ==================================================================================== +echo TEST: \[imptcp_conndrop.sh\]: test imptcp with random connection drops +cat rsyslog.action.1.include +source $srcdir/diag.sh init +source $srcdir/diag.sh startup imptcp_large.conf +# 100 byte messages to gain more practical data use +source $srcdir/diag.sh tcpflood -c20 -m50000 -r -d100 -P129 -D +sleep 4 # due to large messages, we need this time for the tcp receiver to settle... +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown # and wait for it to terminate +source $srcdir/diag.sh seq-check 0 49999 -E +source $srcdir/diag.sh exit diff --git a/tests/imtcp_conndrop.sh b/tests/imtcp_conndrop.sh new file mode 100755 index 00000000..2caa0ce2 --- /dev/null +++ b/tests/imtcp_conndrop.sh @@ -0,0 +1,16 @@ +# Test imtcp with many dropping connections +# added 2010-08-10 by Rgerhards +# +# This file is part of the rsyslog project, released under GPLv3 +echo ==================================================================================== +echo TEST: \[imtcp_conndrop.sh\]: test imtcp with random connection drops +cat rsyslog.action.1.include +source $srcdir/diag.sh init +source $srcdir/diag.sh startup imptcp_large.conf +# 100 byte messages to gain more practical data use +source $srcdir/diag.sh tcpflood -c20 -m50000 -r -d100 -P129 -D +sleep 4 # due to large messages, we need this time for the tcp receiver to settle... +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown # and wait for it to terminate +source $srcdir/diag.sh seq-check 0 49999 -E +source $srcdir/diag.sh exit diff --git a/tests/tcpflood.c b/tests/tcpflood.c index d8c3f038..ee43449e 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -28,6 +28,8 @@ * delemiters into account. * -C when input from a file is read, this file is transmitted -C times * (C like cycle, running out of meaningful option switches ;)) + * -D randomly drop and re-establish connections. Useful for stress-testing + * the TCP receiver. * * Part of the testbench for rsyslog. * @@ -82,11 +84,13 @@ static int numConnections = 1; /* number of connections to create */ static int *sockArray; /* array of sockets to use */ static int msgNum = 0; /* initial message number to start with */ static int bShowProgress = 1; /* show progress messages */ +static int bRandConnDrop = 0; /* randomly drop connections? */ static char *MsgToSend = NULL; /* if non-null, this is the actual message to send */ static int bBinaryFile = 0; /* is -I file binary */ static char *dataFile = NULL; /* name of data file, if NULL, generate own data */ static int numFileIterations = 1;/* how often is file data to be sent? */ FILE *dataFP = NULL; /* file pointer for data file, if used */ +static long nConnDrops = 0; /* counter: number of time connection was dropped (-D option) */ /* open a single tcp connection @@ -153,8 +157,6 @@ int openConnections(void) if(i % 10 == 0) { if(bShowProgress) printf("\r%5.5d", i); - //lenMsg = sprintf(msgBuf, "\r%5.5d", i); - //write(1, msgBuf, lenMsg); } if(openConn(&(sockArray[i])) != 0) { printf("error in trying to open connection i=%d\n", i); @@ -179,6 +181,7 @@ void closeConnections(void) { int i; size_t lenMsg; + struct linger ling; char msgBuf[128]; if(bShowProgress) @@ -190,7 +193,15 @@ void closeConnections(void) write(1, msgBuf, lenMsg); } } - close(sockArray[i]); + if(sockArray[i] != -1) { + /* we try to not overrun the receiver by trying to flush buffers + * *during* close(). -- rgerhards, 2010-08-10 + */ + ling.l_onoff = 1; + ling.l_linger = 1; + setsockopt(sockArray[i], SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); + close(sockArray[i]); + } } lenMsg = sprintf(msgBuf, "\r%5.5d close connections\n", i); write(1, msgBuf, lenMsg); @@ -287,12 +298,18 @@ int sendMessages(void) socknum = i - (numMsgsToSend - numConnections); else { int rnd = rand(); - //socknum = rand() % numConnections; socknum = rnd % numConnections; } genMsg(buf, sizeof(buf), &lenBuf); /* generate the message to send according to params */ if(lenBuf == 0) break; /* end of processing! */ + if(sockArray[socknum] == -1) { + /* connection was dropped, need to re-establish */ + if(openConn(&(sockArray[socknum])) != 0) { + printf("error in trying to re-open connection %d\n", socknum); + exit(1); + } + } lenSend = send(sockArray[socknum], buf, lenBuf, 0); if(lenSend != lenBuf) { printf("\r%5.5d\n", i); @@ -307,6 +324,16 @@ int sendMessages(void) if(bShowProgress) printf("\r%8.8d", i); } + if(bRandConnDrop) { + /* if we need to randomly drop connections, see if we + * are a victim + */ + if(rand() > (int) (RAND_MAX * 0.95)) { + ++nConnDrops; + close(sockArray[socknum]); + sockArray[socknum] = -1; + } + } ++msgNum; ++i; } @@ -316,59 +343,6 @@ int sendMessages(void) } -/* send a message via TCP - * We open the connection on the initial send, and never close it - * (let the OS do that). If a conneciton breaks, we do NOT try to - * recover, so all test after that one will fail (and the test - * driver probably hang. returns 0 if ok, something else otherwise. - * We use traditional framing '\n' at EOR for this tester. It may be - * worth considering additional framing modes. - * rgerhards, 2009-04-08 - */ -int -tcpSend(char *buf, int lenBuf) -{ - static int sock = INVALID_SOCKET; - struct sockaddr_in addr; - - if(sock == INVALID_SOCKET) { - /* first time, need to connect to target */ - if((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) { - perror("socket()"); - return(1); - } - - memset((char *) &addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(13514); - if(inet_aton("127.0.0.1", &addr.sin_addr)==0) { - fprintf(stderr, "inet_aton() failed\n"); - return(1); - } - if(connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) { - fprintf(stderr, "connect() failed\n"); - return(1); - } - } - - /* send test data */ - if(send(sock, buf, lenBuf, 0) != lenBuf) { - perror("send test data"); - fprintf(stderr, "send() failed\n"); - return(1); - } - - /* send record terminator */ - if(send(sock, "\n", 1, 0) != 1) { - perror("send record terminator"); - fprintf(stderr, "send() failed\n"); - return(1); - } - - return 0; -} - - /* Run the test. * rgerhards, 2009-04-03 */ @@ -394,7 +368,7 @@ int main(int argc, char *argv[]) if(!isatty(1)) bShowProgress = 0; - while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:n:M:rB")) != -1) { + while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:Dn:M:rB")) != -1) { switch (opt) { case 't': targetIP = optarg; break; @@ -419,6 +393,8 @@ int main(int argc, char *argv[]) exit(1); } break; + case 'D': bRandConnDrop = 1; + break; case 'r': bRandomizeExtraData = 1; break; case 'f': dynFileIDs = atoi(optarg); @@ -456,7 +432,10 @@ int main(int argc, char *argv[]) exit(1); } + if(nConnDrops > 0) + printf("-D option initiated %ld connection closures\n", nConnDrops); printf("End of tcpflood Run\n"); + closeConnections(); /* this is important so that we do not finish too early! */ exit(ret); } diff --git a/tests/testsuites/imptcp_conndrop.conf b/tests/testsuites/imptcp_conndrop.conf new file mode 100644 index 00000000..677e33f6 --- /dev/null +++ b/tests/testsuites/imptcp_conndrop.conf @@ -0,0 +1,16 @@ +# simple async writing test +# rgerhards, 2010-03-09 +$MaxMessageSize 10k +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imptcp/.libs/imptcp +$MainMsgQueueTimeoutShutdown 10000 +$InputPTCPServerRun 13514 + +$template outfmt,"%msg:F,58:2%,%msg:F,58:3%,%msg:F,58:4%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +$OMFileFlushOnTXEnd off +$OMFileFlushInterval 2 +$OMFileIOBufferSize 256k +$IncludeConfig rsyslog.action.1.include +local0.* ?dynfile;outfmt diff --git a/tests/testsuites/imtcp_conndrop.conf b/tests/testsuites/imtcp_conndrop.conf new file mode 100644 index 00000000..b64f132b --- /dev/null +++ b/tests/testsuites/imtcp_conndrop.conf @@ -0,0 +1,16 @@ +# simple async writing test +# rgerhards, 2010-03-09 +$MaxMessageSize 10k +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imtcp/.libs/imtcp +$MainMsgQueueTimeoutShutdown 10000 +$InputTCPServerRun 13514 + +$template outfmt,"%msg:F,58:2%,%msg:F,58:3%,%msg:F,58:4%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +$OMFileFlushOnTXEnd off +$OMFileFlushInterval 2 +$OMFileIOBufferSize 256k +$IncludeConfig rsyslog.action.1.include +local0.* ?dynfile;outfmt -- cgit From e7d4ec890b42ceb0ab9bb4ee5ecc9a9e489c7388 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 11 Aug 2010 14:38:21 +0200 Subject: imptcp: added $InputPTCPServerNotifyOnConnectionClose directive plus some minor cleanup --- doc/imptcp.html | 3 --- plugins/imptcp/imptcp.c | 13 ++++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/imptcp.html b/doc/imptcp.html index 913563a5..c63ddc34 100644 --- a/doc/imptcp.html +++ b/doc/imptcp.html @@ -45,10 +45,7 @@ That would require much more code changes, which I was unable to do so far. Full can be found at the Cisco tcp syslog anomaly page.
  • $InputPTCPServerNotifyOnConnectionClose [on/off]
    -CURRENTLY DISABLED
    instructs imptcp to emit a message if the remote peer closes a connection.
    -Important: This directive is global to all listeners and must be given right -after loading imptcp, otherwise it may have no effect.
  • $InputPTCPServerRun <port>
    Starts a TCP server on selected port
  • $InputPTCPServerInputName <name>
    diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 732590a9..2bceffad 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -60,7 +60,6 @@ #include "ruleset.h" #include "msg.h" #include "net.h" /* for permittedPeers, may be removed when this is removed */ -//#include "tcpsrv.h" /* NOTE: we use some defines from this module -- TODO: re-think! */ MODULE_TYPE_INPUT @@ -873,6 +872,7 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa pSrv->pSess = NULL; pSrv->pLstn = NULL; pSrv->bEmitMsgOnClose = cs.bEmitMsgOnClose; +dbgprintf("imptcp: add srv emitMsgOnClose: %d\n", pSrv->bEmitMsgOnClose); pSrv->port = pNewVal; //pSrv->iAddtlFrameDelim = cs.iAddtlFrameDelim; cs.pszInputName = NULL; /* moved over to pSrv, we do not own */ @@ -931,13 +931,11 @@ lstnActivity(ptcplstn_t *pLstn) prop_t *peerName; prop_t *peerIP; rsRetVal localRet; -int iac = 0; DEFiRet; DBGPRINTF("imptcp: new connection on listen socket %d\n", pLstn->sock); while(1) { localRet = AcceptConnReq(pLstn->sock, &newSock, &peerName, &peerIP); -//if(iac++ > 0) fprintf(stderr, "%d accepts in a row!\n", iac); if(localRet == RS_RET_NO_MORE_DATA) break; CHKiRet(localRet); @@ -958,14 +956,12 @@ sessActivity(ptcpsess_t *pSess) int lenRcv; int lenBuf; DEFiRet; -int iac = 0; DBGPRINTF("imptcp: new activity on session socket %d\n", pSess->sock); while(1) { lenBuf = sizeof(rcvBuf); lenRcv = recv(pSess->sock, rcvBuf, lenBuf, 0); -//if(iac++ > 1) fprintf(stderr, "\n%d recv in a row!\n", iac-1); if(lenRcv > 0) { /* have data, process it */ @@ -973,6 +969,13 @@ int iac = 0; CHKiRet(DataRcvd(pSess, rcvBuf, lenRcv)); } else if (lenRcv == 0) { /* session was closed, do clean-up */ + if(pSess->pSrv->bEmitMsgOnClose) { + uchar *peerName; + int lenPeer; + prop.GetString(pSess->peerName, &peerName, &lenPeer); + errmsg.LogError(0, RS_RET_PEER_CLOSED_CONN, "imptcp session %d closed by remote peer %s.\n", + pSess->sock, peerName); + } CHKiRet(closeSess(pSess)); break; } else { -- cgit From 4bf834bad6640b5670959ce0c21557bf5923bb2b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 11 Aug 2010 14:40:57 +0200 Subject: fixed minor issue: imptcp did a close(-1) on each accept --- plugins/imptcp/imptcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 2bceffad..975d3e89 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -458,7 +458,8 @@ AcceptConnReq(int sock, int *newSock, prop_t **peerName, prop_t **peerIP) finalize_it: if(iRet != RS_RET_OK) { /* the close may be redundant, but that doesn't hurt... */ - close(iNewSock); + if(iNewSock != -1) + close(iNewSock); } RETiRet; -- cgit From 809ed1768b83bc0c5392f943f4820523494e8285 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 11 Aug 2010 15:06:50 +0200 Subject: imptcp: added $InputPTCPServerAddtlFrameDelimiter directive also improved testbench --- doc/imptcp.html | 3 +-- plugins/imptcp/imptcp.c | 13 ++++++++----- tests/Makefile.am | 6 ++++++ tests/imptcp_addtlframedelim.sh | 14 ++++++++++++++ tests/imtcp_addtlframedelim.sh | 14 ++++++++++++++ tests/tcpflood.c | 14 +++++++++----- tests/testsuites/imptcp_addtlframedelim.conf | 13 +++++++++++++ tests/testsuites/imtcp_addtlframedelim.conf | 13 +++++++++++++ 8 files changed, 78 insertions(+), 12 deletions(-) create mode 100755 tests/imptcp_addtlframedelim.sh create mode 100755 tests/imtcp_addtlframedelim.sh create mode 100644 tests/testsuites/imptcp_addtlframedelim.conf create mode 100644 tests/testsuites/imtcp_addtlframedelim.conf diff --git a/doc/imptcp.html b/doc/imptcp.html index c63ddc34..d4228185 100644 --- a/doc/imptcp.html +++ b/doc/imptcp.html @@ -7,7 +7,7 @@

    Plain TCP Syslog Input Module

    Module Name:    imptcp

    -

    Available since: 4.7.3+, 5.5.8+? +

    Available since: 4.7.3+, 5.5.8+

    Author: Rainer Gerhards <rgerhards@adiscon.com>

    Description:

    @@ -24,7 +24,6 @@ specifying $InputPTCPServerRun multiple times. their name instead of just TCP. Note that only a subset of the parameters are supported.
    • $InputPTCPServerAddtlFrameDelimiter <Delimiter>
      -CURRENTLY DISABLED
      This directive permits to specify an additional frame delimiter for plain tcp syslog. The industry-standard specifies using the LF character as frame delimiter. Some vendors, notable Juniper in their NetScreen products, use an invalid frame delimiter, in Juniper's diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 975d3e89..93906ba0 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -61,6 +61,10 @@ #include "msg.h" #include "net.h" /* for permittedPeers, may be removed when this is removed */ +/* the define is from tcpsrv.h, we need to find a new (but easier!!!) abstraction layer some time ... */ +#define TCPSRV_NO_ADDTL_DELIMITER -1 /* specifies that no additional delimiter is to be used in TCP framing */ + + MODULE_TYPE_INPUT /* static data */ @@ -579,7 +583,7 @@ processDataRcvd(ptcpsess_t *pThis, char c, struct syslogTime *stTime, time_t ttG } if(( (c == '\n') - //|| ((pThis->pSrv->addtlFrameDelim != TCPSRV_NO_ADDTL_DELIMITER) && (c == pThis->pSrv->addtlFrameDelim)) + || ((pThis->pSrv->iAddtlFrameDelim != TCPSRV_NO_ADDTL_DELIMITER) && (c == pThis->pSrv->iAddtlFrameDelim)) ) && pThis->eFraming == TCP_FRAMING_OCTET_STUFFING) { /* record delimiter? */ doSubmitMsg(pThis, stTime, ttGenTime, pMultiSub); pThis->inputState = eAtStrtFram; @@ -668,7 +672,7 @@ static inline void initConfigSettings(void) { cs.bEmitMsgOnClose = 0; - //cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; + cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; cs.pszInputName = NULL; cs.pRuleset = NULL; cs.lstnIP = NULL; @@ -873,9 +877,8 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa pSrv->pSess = NULL; pSrv->pLstn = NULL; pSrv->bEmitMsgOnClose = cs.bEmitMsgOnClose; -dbgprintf("imptcp: add srv emitMsgOnClose: %d\n", pSrv->bEmitMsgOnClose); pSrv->port = pNewVal; - //pSrv->iAddtlFrameDelim = cs.iAddtlFrameDelim; + pSrv->iAddtlFrameDelim = cs.iAddtlFrameDelim; cs.pszInputName = NULL; /* moved over to pSrv, we do not own */ pSrv->lstnIP = cs.lstnIP; cs.lstnIP = NULL; /* moved over to pSrv, we do not own */ @@ -1121,7 +1124,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { cs.bEmitMsgOnClose = 0; - //cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; + cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; free(cs.pszInputName); cs.pszInputName = NULL; free(cs.lstnIP); diff --git a/tests/Makefile.am b/tests/Makefile.am index b500bc85..8b75a9f2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -9,8 +9,10 @@ TESTS = $(TESTRUNS) cfg.sh \ manytcp.sh \ manyptcp.sh \ imptcp_large.sh \ + imptcp_addtlframedelim.sh \ imptcp_conndrop.sh \ imtcp_conndrop.sh \ + imtcp_addtlframedelim.sh \ sndrcv.sh \ sndrcv_gzip.sh \ asynwr_simple.sh \ @@ -144,10 +146,14 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/manyptcp.conf \ imptcp_large.sh \ testsuites/imptcp_large.conf \ + imptcp_addtlframedelim.sh \ + testsuites/imptcp_addtlframedelim.conf \ imptcp_conndrop.sh \ testsuites/imptcp_conndrop.conf \ imtcp_conndrop.sh \ testsuites/imtcp_conndrop.conf \ + imtcp_addtlframedelim.sh \ + testsuites/imtcp_addtlframedelim.conf \ inputname.sh \ testsuites/inputname_imtcp.conf \ testsuites/1.inputname_imtcp_12514 \ diff --git a/tests/imptcp_addtlframedelim.sh b/tests/imptcp_addtlframedelim.sh new file mode 100755 index 00000000..b26fc85b --- /dev/null +++ b/tests/imptcp_addtlframedelim.sh @@ -0,0 +1,14 @@ +# added 2010-08-11 by Rgerhards +# +# This file is part of the rsyslog project, released under GPLv3 +echo ==================================================================================== +echo TEST: \[imptcp_addtlframedelim.sh\]: test imptcp additional frame delimiter +cat rsyslog.action.1.include +source $srcdir/diag.sh init +source $srcdir/diag.sh startup imptcp_addtlframedelim.conf +source $srcdir/diag.sh tcpflood -m20000 -F0 -P129 +#sleep 2 # due to large messages, we need this time for the tcp receiver to settle... +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown # and wait for it to terminate +source $srcdir/diag.sh seq-check 0 19999 +source $srcdir/diag.sh exit diff --git a/tests/imtcp_addtlframedelim.sh b/tests/imtcp_addtlframedelim.sh new file mode 100755 index 00000000..8de7ca58 --- /dev/null +++ b/tests/imtcp_addtlframedelim.sh @@ -0,0 +1,14 @@ +# added 2010-08-11 by Rgerhards +# +# This file is part of the rsyslog project, released under GPLv3 +echo ==================================================================================== +echo TEST: \[imtcp_addtlframedelim.sh\]: test imtcp additional frame delimiter +cat rsyslog.action.1.include +source $srcdir/diag.sh init +source $srcdir/diag.sh startup imtcp_addtlframedelim.conf +source $srcdir/diag.sh tcpflood -m20000 -F0 -P129 +#sleep 2 # due to large messages, we need this time for the tcp receiver to settle... +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown # and wait for it to terminate +source $srcdir/diag.sh seq-check 0 19999 +source $srcdir/diag.sh exit diff --git a/tests/tcpflood.c b/tests/tcpflood.c index ee43449e..f3aa4e7f 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -30,6 +30,7 @@ * (C like cycle, running out of meaningful option switches ;)) * -D randomly drop and re-establish connections. Useful for stress-testing * the TCP receiver. + * -F USASCII value for frame delimiter (in octet-stuffing mode), default LF * * Part of the testbench for rsyslog. * @@ -89,6 +90,7 @@ static char *MsgToSend = NULL; /* if non-null, this is the actual message to sen static int bBinaryFile = 0; /* is -I file binary */ static char *dataFile = NULL; /* name of data file, if NULL, generate own data */ static int numFileIterations = 1;/* how often is file data to be sent? */ +static char frameDelim = '\n'; /* default frame delimiter */ FILE *dataFP = NULL; /* file pointer for data file, if used */ static long nConnDrops = 0; /* counter: number of time connection was dropped (-D option) */ @@ -242,8 +244,8 @@ genMsg(char *buf, size_t maxBuf, int *pLenBuf) snprintf(dynFileIDBuf, maxBuf, "%d:", rand() % dynFileIDs); } if(extraDataLen == 0) { - *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:\n", - msgPRI, dynFileIDBuf, msgNum); + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%c", + msgPRI, dynFileIDBuf, msgNum, frameDelim); } else { if(bRandomizeExtraData) edLen = ((long) rand() + extraDataLen) % extraDataLen + 1; @@ -251,8 +253,8 @@ genMsg(char *buf, size_t maxBuf, int *pLenBuf) edLen = extraDataLen; memset(extraData, 'X', edLen); extraData[edLen] = '\0'; - *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s\n", - msgPRI, dynFileIDBuf, msgNum, edLen, extraData); + *pLenBuf = snprintf(buf, maxBuf, "<%s>Mar 1 01:00:00 172.20.245.8 tag msgnum:%s%8.8d:%d:%s%c", + msgPRI, dynFileIDBuf, msgNum, edLen, extraData, frameDelim); } } else { /* use fixed message format from command line */ @@ -368,7 +370,7 @@ int main(int argc, char *argv[]) if(!isatty(1)) bShowProgress = 0; - while((opt = getopt(argc, argv, "f:t:p:c:C:m:i:I:P:d:Dn:M:rB")) != -1) { + while((opt = getopt(argc, argv, "f:F:t:p:c:C:m:i:I:P:d:Dn:M:rB")) != -1) { switch (opt) { case 't': targetIP = optarg; break; @@ -399,6 +401,8 @@ int main(int argc, char *argv[]) break; case 'f': dynFileIDs = atoi(optarg); break; + case 'F': frameDelim = atoi(optarg); + break; case 'M': MsgToSend = optarg; break; case 'I': dataFile = optarg; diff --git a/tests/testsuites/imptcp_addtlframedelim.conf b/tests/testsuites/imptcp_addtlframedelim.conf new file mode 100644 index 00000000..eb7ed0c4 --- /dev/null +++ b/tests/testsuites/imptcp_addtlframedelim.conf @@ -0,0 +1,13 @@ +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imptcp/.libs/imptcp +$MainMsgQueueTimeoutShutdown 10000 +$InputPTCPServerAddtlFrameDelimiter 0 +$InputPTCPServerRun 13514 + +$template outfmt,"%msg:F,58:2%\n" +$OMFileFlushOnTXEnd off +$OMFileFlushInterval 2 +$OMFileIOBufferSize 256k +$IncludeConfig rsyslog.action.1.include +local0.* ./rsyslog.out.log;outfmt diff --git a/tests/testsuites/imtcp_addtlframedelim.conf b/tests/testsuites/imtcp_addtlframedelim.conf new file mode 100644 index 00000000..3b4759c5 --- /dev/null +++ b/tests/testsuites/imtcp_addtlframedelim.conf @@ -0,0 +1,13 @@ +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imtcp/.libs/imtcp +$MainMsgQueueTimeoutShutdown 10000 +$InputTCPServerAddtlFrameDelimiter 0 +$InputTCPServerRun 13514 + +$template outfmt,"%msg:F,58:2%\n" +$OMFileFlushOnTXEnd off +$OMFileFlushInterval 2 +$OMFileIOBufferSize 256k +$IncludeConfig rsyslog.action.1.include +local0.* ./rsyslog.out.log;outfmt -- cgit From ffd08f2a6caaaddb86ccbec4206bf560d34fcfd7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 24 Oct 2010 14:31:12 +0200 Subject: imfile improvements - added the $InputFilePersistStateInterval config directive to imfile - changed imfile so that the state file is never deleted (makes imfile more robust in regard to fatal failures) --- ChangeLog | 3 +++ doc/imfile.html | 10 ++++++++++ plugins/imfile/imfile.c | 35 +++++++++++++++++------------------ 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index a4ac46b9..acb0ef5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,9 @@ Version 4.7.3 [v4-devel] (rgerhards), 2010-??-?? - bugfix: imfile utilizes 32 bit to track offset. Most importantly, this problem can not experienced on Fedora 64 bit OS (which has 64 bit long's!) +- added the $InputFilePersistStateInterval config directive to imfile +- changed imfile so that the state file is never deleted (makes imfile + more robust in regard to fatal failures) --------------------------------------------------------------------------- Version 4.7.2 [v4-devel] (rgerhards), 2010-05-03 - bugfix: problems with atomic operations emulaton diff --git a/doc/imfile.html b/doc/imfile.html index af0413dd..3687302b 100644 --- a/doc/imfile.html +++ b/doc/imfile.html @@ -86,6 +86,16 @@ level may be needed. Even if you need quick response, 1 seconds should be well enough. Please note that imfile keeps reading files as long as there is any data in them. So a "polling sleep" will only happen when nothing is left to be processed.
    • +
    • $InputFilePollInterval [lines]
      +Available in 4.7.3+
      +Specifies how often the state file shall be written when processing the input +file. The default value is 0, which means a new state file is only written when +the monitored files is being closed (end of rsyslogd execution). Any other +value n means that the state file is written every time n file lines have +been processed. This setting can be used to guard against message duplication due +to fatal errors (like power fail). Note that this setting affects imfile +performance, especially when set to a low value. Frequently writing the state +file is very time consuming.
    Caveats/Known Bugs:

    So far, only 100 files can be monitored. If more are needed, diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 3981f9f7..91493bb1 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -67,15 +67,21 @@ typedef struct fileInfo_s { uchar *pszStateFile; /* file in which state between runs is to be stored */ int iFacility; int iSeverity; + int nRecords; /**< How many records did we process before persisting the stream? */ + int iPersistStateInterval; /**< how often should state be persisted? (0=on close only) */ strm_t *pStrm; /* its stream (NULL if not assigned) */ } fileInfo_t; +/* forward definitions */ +static rsRetVal persistStrmState(fileInfo_t *pInfo); + /* config variables */ static uchar *pszFileName = NULL; static uchar *pszFileTag = NULL; static uchar *pszStateFile = NULL; static int iPollInterval = 10; /* number of seconds to sleep when there was no file activity */ +static int iPersistStateInterval = 0; /* how often if state file to be persisted? (default 0->never) */ static int iFacility = 128; /* local0 */ static int iSeverity = 5; /* notice, as of rfc 3164 */ @@ -154,10 +160,9 @@ openFile(fileInfo_t *pThis) CHKiRet(strm.SeekCurrOffs(pThis->pStrm)); - /* OK, we could successfully read the file, so we now can request that it be deleted. - * If we need it again, it will be written on the next shutdown. + /* note: we do not delete the state file, so that the last position remains + * known even in the case that rsyslogd aborts for some reason (like powerfail) */ - psSF->bDeleteOnClose = 1; finalize_it: if(psSF != NULL) @@ -211,6 +216,10 @@ static rsRetVal pollFile(fileInfo_t *pThis, int *pbHadFileData) *pbHadFileData = 1; /* this is just a flag, so set it and forget it */ CHKiRet(enqLine(pThis, pCStr)); /* process line */ rsCStrDestruct(&pCStr); /* discard string (must be done by us!) */ + if(pThis->iPersistStateInterval > 0 && pThis->nRecords++ >= pThis->iPersistStateInterval) { + persistStrmState(pThis); + pThis->nRecords = 0; + } } finalize_it: @@ -244,27 +253,12 @@ finalize_it: * IMPORTANT: the calling interface of this function can NOT be modified. It actually is * called by pthreads. The provided argument is currently not being used. */ -/* ------------------------------------------------------------------------------------------ * - * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */ static void inputModuleCleanup(void __attribute__((unused)) *arg) { BEGINfunc -/* END no-touch zone * - * ------------------------------------------------------------------------------------------ */ - - - - /* so far not needed */ - - - -/* ------------------------------------------------------------------------------------------ * - * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */ ENDfunc } -/* END no-touch zone * - * ------------------------------------------------------------------------------------------ */ /* This function is called by the framework to gather the input. The module stays @@ -499,6 +493,9 @@ static rsRetVal addMonitor(void __attribute__((unused)) *pVal, uchar *pNewVal) pThis->iSeverity = iSeverity; pThis->iFacility = iFacility; + pThis->iPersistStateInterval = iPersistStateInterval; + pThis->nRecords = 0; + iPersistStateInterval = 0; } else { errmsg.LogError(0, RS_RET_OUT_OF_DESRIPTORS, "Too many file monitors configured - ignoring this one"); ABORT_FINALIZE(RS_RET_OUT_OF_DESRIPTORS); @@ -544,6 +541,8 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &iFacility, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepollinterval", 0, eCmdHdlrInt, NULL, &iPollInterval, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepersiststateinterval", 0, eCmdHdlrInt, + NULL, &iPersistStateInterval, STD_LOADABLE_MODULE_ID)); /* that command ads a new file! */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrunfilemonitor", 0, eCmdHdlrGetWord, addMonitor, NULL, STD_LOADABLE_MODULE_ID)); -- cgit From ab6e674b0bae88d3a91a30f4e32fbb857096964f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Oct 2010 16:32:33 +0200 Subject: doc/imfile: fixed small but important typo --- doc/imfile.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/imfile.html b/doc/imfile.html index 3687302b..89be3292 100644 --- a/doc/imfile.html +++ b/doc/imfile.html @@ -86,7 +86,7 @@ level may be needed. Even if you need quick response, 1 seconds should be well enough. Please note that imfile keeps reading files as long as there is any data in them. So a "polling sleep" will only happen when nothing is left to be processed.

  • -
  • $InputFilePollInterval [lines]
    +
  • $InputFilePersistStateInterval [lines]
    Available in 4.7.3+
    Specifies how often the state file shall be written when processing the input file. The default value is 0, which means a new state file is only written when -- cgit From 9e6ab1494d95da61095867db209674975b1b1a2b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Nov 2010 13:56:53 +0100 Subject: preparing for 4.7.3 --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0fe62c5f..a266aafd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 4.7.3 [v4-devel] (rgerhards), 2010-??-?? +Version 4.7.3 [v4-devel] (rgerhards), 2010-11-25 - bugfix(important): problem in TLS handling could cause rsyslog to loop in a tight loop, effectively disabling functionality and bearing the risk of unresponsiveness of the whole system. diff --git a/configure.ac b/configure.ac index f265727f..70ec65d3 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[4.7.2],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[4.7.3],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([ChangeLog]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/manual.html b/doc/manual.html index 0e4166d0..a95e8eec 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@ rsyslog support available directly from the source!

    Please visit the rsyslog sponsor's page to honor the project sponsors or become one yourself! We are very grateful for any help towards the project goals.

    -

    This documentation is for version 4.7.2 (v4-devel branch) of rsyslog. +

    This documentation is for version 4.7.3 (v4-devel branch) of rsyslog. Visit the rsyslog status page to obtain current version information and project status.

    If you like rsyslog, you might -- cgit From 91cf297043e20d2dae8b00c20efadcc388357a86 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Nov 2010 14:29:02 +0100 Subject: added forgotten testcase files --- tests/manyptcp.sh | 13 +++++++++++++ tests/testsuites/manyptcp.conf | 12 ++++++++++++ 2 files changed, 25 insertions(+) create mode 100755 tests/manyptcp.sh create mode 100644 tests/testsuites/manyptcp.conf diff --git a/tests/manyptcp.sh b/tests/manyptcp.sh new file mode 100755 index 00000000..3ed5493b --- /dev/null +++ b/tests/manyptcp.sh @@ -0,0 +1,13 @@ +# test many concurrent tcp connections +echo ==================================================================================== +echo TEST: \[manyptcp.sh\]: test imptcp with large connection count +source $srcdir/diag.sh init +source $srcdir/diag.sh startup manyptcp.conf +# the config file specifies exactly 1100 connections +source $srcdir/diag.sh tcpflood -c1000 -m40000 +# the sleep below is needed to prevent too-early termination of the tcp listener +sleep 1 +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown # we need to wait until rsyslogd is finished! +source $srcdir/diag.sh seq-check 0 39999 +source $srcdir/diag.sh exit diff --git a/tests/testsuites/manyptcp.conf b/tests/testsuites/manyptcp.conf new file mode 100644 index 00000000..4069f977 --- /dev/null +++ b/tests/testsuites/manyptcp.conf @@ -0,0 +1,12 @@ +# Test for tcp "flood" testing +# rgerhards, 2009-04-08 +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imptcp/.libs/imptcp +$MainMsgQueueTimeoutShutdown 10000 +$MaxOpenFiles 2000 +$InputPTCPServerRun 13514 + +$template outfmt,"%msg:F,58:2%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +:msg, contains, "msgnum:" ?dynfile;outfmt -- cgit From b9151f6a1708b2fb7e9518e73fcf42d86b0364a9 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Thu, 25 Nov 2010 15:44:49 +0100 Subject: bugfix: atomic increment for msg object may not work correct on all platforms. Signed-off-by: Rainer Gerhards --- ChangeLog | 4 ++++ runtime/msg.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a266aafd..bbf900fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ --------------------------------------------------------------------------- +Version 4.7.4 [v4-???] (rgerhards), 2010-11-?? +- bugfix: atomic increment for msg object may not work correct on all + platforms. Thanks to Chris Metcalf for the patch +--------------------------------------------------------------------------- Version 4.7.3 [v4-devel] (rgerhards), 2010-11-25 - bugfix(important): problem in TLS handling could cause rsyslog to loop in a tight loop, effectively disabling functionality and bearing the diff --git a/runtime/msg.h b/runtime/msg.h index cda206fc..a6923d52 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -60,9 +60,9 @@ struct msg { flowControl_t flowCtlType; /**< type of flow control we can apply, for enqueueing, needs not to be persisted because once data has entered the queue, this property is no longer needed. */ pthread_mutex_t mut; + int iRefCount; /* reference counter (0 = unused) */ bool bDoLock; /* use the mutex? */ bool bParseHOSTNAME; /* should the hostname be parsed from the message? */ - short iRefCount; /* reference counter (0 = unused) */ /* background: the hostname is not present on "regular" messages * received via UNIX domain sockets from the same machine. However, * it is available when we have a forwarder (e.g. rfc3195d) using local -- cgit From 0b18c17b2850152203ce9db648ce06212ab67157 Mon Sep 17 00:00:00 2001 From: Luis Fernando Muñoz Mejías Date: Tue, 30 Nov 2010 13:04:58 +0100 Subject: Fix a potential missing '\0' on too long strings. By implementing a trivial strlcpy it's much easier to detect string truncations and react to them. This also gives a noticeable speedup in buffer handling (can be HUGE), since strlcpy() doesn't clear all the buffer entry before writing data. Converted all uses of strncpy() into strlcpy(). Also, we don't need to check for some null pointers, as there are no malloc-like operations in the doAction loop. --- plugins/omoracle/omoracle.c | 19 +++++++++++++---- tests/cfg4.testin | 52 +++++++-------------------------------------- 2 files changed, 23 insertions(+), 48 deletions(-) diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index 48ee1fa4..30b5834b 100644 --- a/plugins/omoracle/omoracle.c +++ b/plugins/omoracle/omoracle.c @@ -127,6 +127,13 @@ typedef struct _instanceData { struct oracle_batch batch; } instanceData; +/* To be honest, strlcpy is faster than strncpy and makes very easy to + * detect if a message has been truncated. */ +#ifndef strlcpy +#define strlcpy(dst,src,sz) snprintf((dst), (sz), "%s", (src)) +#endif + + /** Database name, to be filled by the $OmoracleDB directive */ static char* db_name; /** Database user name, to be filled by the $OmoracleDBUser @@ -529,7 +536,7 @@ CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct BEGINdoAction - int i; + int i, sz; char **params = (char**) ppString[0]; CODESTARTdoAction @@ -540,9 +547,13 @@ CODESTARTdoAction for (i = 0; i < pData->batch.arguments && params[i]; i++) { dbgprintf("batch[%d][%d]=%s\n", i, pData->batch.n, params[i]); - strncpy(pData->batch.parameters[i][pData->batch.n], params[i], - pData->batch.param_size); - CHKmalloc(pData->batch.parameters[i][pData->batch.n]); + sz = strlcpy(pData->batch.parameters[i][pData->batch.n], + params[i], pData->batch.param_size); + if (sz >= pData->batch.param_size) + errmsg.LogError(0, NO_ERRCODE, + "Possibly truncated %d column of '%s' " + "statement: %s", i, + pData->txt_statement, params[i]); } pData->batch.n++; diff --git a/tests/cfg4.testin b/tests/cfg4.testin index a49c0fb6..2dc0e830 100644 --- a/tests/cfg4.testin +++ b/tests/cfg4.testin @@ -12,48 +12,6 @@ # If you do not load inputs, nothing happens! # You may need to set the module load path if modules are not found. -#$ModLoad immark # provides --MARK-- message capability -#$ModLoad imuxsock # provides support for local system logging (e.g. via logger command) -#$ModLoad imklog # kernel logging (formerly provided by rklogd) - -# Log all kernel messages to the console. -# Logging much else clutters up the screen. -#kern.* /dev/console - -# Log anything (except mail) of level info or higher. -# Don't log private authentication messages! -*.info;mail.none;authpriv.none;cron.none -/var/log/messages - -# The authpriv file has restricted access. -authpriv.* /var/log/secure - -# Log all the mail messages in one place. -mail.* -/var/log/maillog - - -# Log cron stuff -cron.* -/var/log/cron - -# Everybody gets emergency messages -*.emerg * - -# Save news errors of level crit and higher in a special file. -uucp,news.crit -/var/log/spooler - -# Save boot messages also to boot.log -local7.* /var/log/boot.log - -# Remote Logging (we use TCP for reliable delivery) -# An on-disk queue is created for this action. If the remote host is -# down, messages are spooled to disk and sent when it is up again. -#$WorkDirectory /rsyslog/spool # where to place spool files -#$ActionQueueFileName uniqName # unique name prefix for spool files -#$ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible) -#$ActionQueueSaveOnShutdown on # save messages to disk on shutdown -#$ActionQueueType LinkedList # run asynchronously -#$ActionResumeRetryCount -1 # infinite retries if host is down -# remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional -#*.* @@remote-host:514 # ######### Receiving Messages from Remote Hosts ########## @@ -63,5 +21,11 @@ local7.* /var/log/boot.log #$InputTCPServerRun 514 # start up TCP listener at port 514 # UDP Syslog Server: -#$ModLoad imudp.so # provides UDP syslog reception -#$UDPServerRun 514 # start a UDP syslog server at standard port 514 +$ModLoad imudp.so # provides UDP syslog reception +$ModLoad omoracle.so +$UDPServerRun 514 # start a UDP syslog server at standard port 514 + +$IncludeConfig /home/munoz/logging/rsyslog/20*conf +$IncludeConfig /home/munoz/logging/rsyslog/30*conf + +#*.* ~ -- cgit From c4c20c18aae7c95c1e69c10d2ea9efbc3c2c1913 Mon Sep 17 00:00:00 2001 From: Luis Fernando Muñoz Mejías Date: Tue, 30 Nov 2010 13:04:59 +0100 Subject: Fix the build system to build outisde CERN. It should build against Oracle 11, too. Depending on the user's installation, either a single ORACLE_HOME environment variable or ORACLE_LIB_PATH and ORACLE_INCLUDE_PATH environment variables will be needed. --- configure.ac | 52 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/configure.ac b/configure.ac index 70ec65d3..b5c2d1c2 100644 --- a/configure.ac +++ b/configure.ac @@ -487,7 +487,7 @@ AC_SUBST(PGSQL_LIBS) # oracle (OCI) support AC_ARG_ENABLE(oracle, - [AS_HELP_STRING([--enable-oracle],[Enable native Oracle database support @<:@default=no@:>@])], + [AS_HELP_STRING([--enable-oracle],[Enable native Oracle database support @<:@default=no@:>@]. (Check your ORACLE_HOME environment variable!))], [case "${enableval}" in yes) enable_oracle="yes" ;; no) enable_oracle="no" ;; @@ -496,23 +496,41 @@ AC_ARG_ENABLE(oracle, [enable_oracle=no] ) if test "x$enable_oracle" = "xyes"; then - AC_CHECK_PROG( - [HAVE_ORACLE_CONFIG], - [oracle-instantclient-config], - [yes],,, - ) - if test "x${HAVE_ORACLE_CONFIG}" != "xyes"; then - AC_MSG_FAILURE([oracle-instantclient-config not found in PATH]) + if test -d "$ORACLE_HOME" + then + AC_CHECK_LIB([occi], [OCIEnvCreate], + [ORACLE_CFLAGS=-I$ORACLE_HOME/rdbms/public] + [ORACLE_LIBS=-L$ORACLE_HOME/lib -locci], + [AC_MSG_FAILURE([Oracle (OCI) library is missing: wrong oracle home])], + [-I$ORACLE_HOME/rdbms/public/ -L$ORACLE_HOME/lib -locci -lclntsh ] + ) + elif test -d "$ORACLE_LIB_PATH" -a -d "$ORACLE_INCLUDE_PATH" + then + AC_CHECK_LIB([occi], [OCIEnvCreate], + [ORACLE_CFLAGS=-I$ORACLE_INCLUDE_PATH] + [ORACLE_LIBS=-L$ORACLE_LIB_PATH -locci], + [AC_MSG_FAILURE([Oracle (OCI) library is missing: wrong oracle directories])], + [-I$ORACLE_INCLUDE_PATH -L$ORACLE_LIB_PATH -locci -lclntsh ] + ) + else + AC_CHECK_PROG( + [HAVE_ORACLE_CONFIG], + [oracle-instantclient-config], + [yes],,, + ) + if test "x${HAVE_ORACLE_CONFIG}" != "xyes"; then + AC_MSG_FAILURE([oracle-instantclient-config not found in PATH]) + fi + AC_CHECK_LIB( + [occi], + [OCIEnvCreate], + [ORACLE_CFLAGS="`oracle-instantclient-config --cflags`" + ORACLE_LIBS="`oracle-instantclient-config --libs`" + ], + [AC_MSG_FAILURE([Oracle (OCI) libraray is missing])], + [`oracle-instantclient-config --libs --cflags`] + ) fi - AC_CHECK_LIB( - [occi], - [OCIEnvCreate], - [ORACLE_CFLAGS="`oracle-instantclient-config --cflags`" - ORACLE_LIBS="`oracle-instantclient-config --libs`" - ], - [AC_MSG_FAILURE([Oracle (OCI) libraray is missing])], - [`oracle-instantclient-config --libs --cflags`] - ) fi AM_CONDITIONAL(ENABLE_ORACLE, test x$enable_oracle = xyes) AC_SUBST(ORACLE_CFLAGS) -- cgit From 06bad730521dc476a7eabbbedf624a4cfbf65b18 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 16 Dec 2010 13:40:23 +0100 Subject: cleanup of cosmetic nit (result of clang static code analyser run) --- tools/syslogd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/syslogd.c b/tools/syslogd.c index fb1c6e0e..5f8d45a8 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -3290,7 +3290,7 @@ int realMain(int argc, char **argv) } } - if ((argc -= optind)) + if(argc - optind) usage(); DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s', cwd:%s\n", -- cgit From 699d0d933ab64941d40df17c69b2c377231924cf Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 16 Dec 2010 15:29:20 +0100 Subject: added $LocalHostName config directive & some bugfixing - added $LocalHostName config directive - bugfix: local hostname was pulled too-early, so that some config directives (namely FQDN settings) did not have any effect --- ChangeLog | 3 +++ doc/rsyslog_conf_global.html | 6 ++++++ runtime/cfsysline.c | 3 --- runtime/glbl.c | 27 +++++++++++++++++++-------- tests/testsuites/parse1.conf | 1 + tools/syslogd.c | 6 +++--- 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0982b77a..caa53b8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ --------------------------------------------------------------------------- Version 4.7.4 [v4-???] (rgerhards), 2010-11-?? +- added $LocalHostName config directive +- bugfix: local hostname was pulled too-early, so that some config + directives (namely FQDN settings) did not have any effect - bugfix: atomic increment for msg object may not work correct on all platforms. Thanks to Chris Metcalf for the patch --------------------------------------------------------------------------- diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html index 8c1cc9a7..b58ae9c2 100644 --- a/doc/rsyslog_conf_global.html +++ b/doc/rsyslog_conf_global.html @@ -150,6 +150,12 @@ Usually that should not be a big issue, as the restart-type HUP can easily be re something along the lines of "/etc/init.d/rsyslog restart".

  • $IncludeConfig
  • MainMsgQueueCheckpointInterval <number>
  • +
  • $LocalHostName [name] - this directive permits to overwrite the system +hostname with the one specified in the directive. If the directive is given +multiple times, all but the last one will be ignored. Please note that startup +error messages may be issued with the real hostname. This is by design and not +a bug (but one may argue if the design should be changed ;)). Available since +4.7.4+, 5.7.3+, 6.1.3+.
  • $LogRSyslogStatusMessages [on/off] - If set to on (the default), rsyslog emits message on startup and shutdown as well as when it is HUPed. This information might be needed by some log analyzers. If set to off, no such diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index 5ab73184..037e9f84 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -953,8 +953,6 @@ finalize_it: */ void dbgPrintCfSysLineHandlers(void) { - DEFiRet; - cslCmd_t *pCmd; cslCmdHdlr_t *pCmdHdlr; linkedListCookie_t llCookieCmd; @@ -976,7 +974,6 @@ void dbgPrintCfSysLineHandlers(void) } } dbgprintf("\n"); - ENDfunc } diff --git a/runtime/glbl.c b/runtime/glbl.c index 58558ed2..b396ed7c 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -64,6 +64,7 @@ static int option_DisallowWarning = 1; /* complain if message from disallowed se static int bDisableDNS = 0; /* don't look up IP addresses of remote messages */ static prop_t *propLocalHostName = NULL;/* our hostname as FQDN - read-only after startup */ static uchar *LocalHostName = NULL;/* our hostname - read-only after startup */ +static uchar *LocalHostNameOverride = NULL;/* user-overridden hostname - read-only after startup */ static uchar *LocalFQDNName = NULL;/* our hostname as FQDN - read-only after startup */ static uchar *LocalDomain; /* our local domain name - read-only after startup */ static char **StripDomains = NULL;/* these domains may be stripped before writing logs - r/o after s.u., never touched by init */ @@ -153,17 +154,21 @@ GenerateLocalHostNameProperty(void) uchar *pszName; if(propLocalHostName != NULL) - prop.Destruct(&propLocalHostName); CHKiRet(prop.Construct(&propLocalHostName)); - if(LocalHostName == NULL) - pszName = (uchar*) "[localhost]"; - else { - if(GetPreserveFQDN() == 1) - pszName = LocalFQDNName; - else - pszName = LocalHostName; + if(LocalHostNameOverride == NULL) { + if(LocalHostName == NULL) + pszName = (uchar*) "[localhost]"; + else { + if(GetPreserveFQDN() == 1) + pszName = LocalFQDNName; + else + pszName = LocalHostName; + } + } else { /* local hostname is overriden via config */ + pszName = LocalHostNameOverride; } + DBGPRINTF("GenerateLocalHostName uses '%s'\n", pszName); CHKiRet(prop.SetString(propLocalHostName, pszName, ustrlen(pszName))); CHKiRet(prop.ConstructFinalize(propLocalHostName)); @@ -296,6 +301,10 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a free(pszDfltNetstrmDrvrCertFile); pszDfltNetstrmDrvrCertFile = NULL; } + if(LocalHostNameOverride != NULL) { + free(LocalHostNameOverride); + LocalHostNameOverride = NULL; + } if(pszWorkDir != NULL) { free(pszWorkDir); pszWorkDir = NULL; @@ -327,6 +336,7 @@ BEGINAbstractObjClassInit(glbl, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercafile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCAF, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriverkeyfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrKeyFile, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercertfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCertFile, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"localhostname", 0, eCmdHdlrGetWord, NULL, &LocalHostNameOverride, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"optimizeforuniprocessor", 0, eCmdHdlrBinary, NULL, &bOptimizeUniProc, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"hupisrestart", 0, eCmdHdlrBinary, NULL, &bHUPisRestart, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"preservefqdn", 0, eCmdHdlrBinary, NULL, &bPreserveFQDN, NULL)); @@ -350,6 +360,7 @@ BEGINObjClassExit(glbl, OBJ_IS_CORE_MODULE) /* class, version */ free(pszWorkDir); if(LocalHostName != NULL) free(LocalHostName); + free(LocalHostNameOverride); if(LocalFQDNName != NULL) free(LocalFQDNName); objRelease(prop, CORE_COMPONENT); diff --git a/tests/testsuites/parse1.conf b/tests/testsuites/parse1.conf index 947a05a8..094cd762 100644 --- a/tests/testsuites/parse1.conf +++ b/tests/testsuites/parse1.conf @@ -2,6 +2,7 @@ $ModLoad ../plugins/omstdout/.libs/omstdout $IncludeConfig nettest.input.conf # This picks the to be tested input from the test driver! $ErrorMessagesToStderr off +$LocalHostName localhost # use a special format that we can easily parse in expect $template expect,"%PRI%,%syslogfacility-text%,%syslogseverity-text%,%timestamp%,%hostname%,%programname%,%syslogtag%,%msg%\n" diff --git a/tools/syslogd.c b/tools/syslogd.c index 5f8d45a8..058d75d8 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -2302,6 +2302,9 @@ init() legacyOptsHook(); + /* re-generate local host name property, as the config may have changed our FQDN settings */ + glbl.GenerateLocalHostNameProperty(); + /* we are now done with reading the configuration. This is the right time to * free some objects that were just needed for loading it. rgerhards 2005-10-19 */ @@ -3566,9 +3569,6 @@ int realMain(int argc, char **argv) if(!iConfigVerify) CHKiRet(doGlblProcessInit()); - /* re-generate local host name property, as the config may have changed our FQDN settings */ - glbl.GenerateLocalHostNameProperty(); - CHKiRet(mainThread()); /* do any de-init's that need to be done AFTER this comment */ -- cgit From cc8237736d11b54a3d6089d836da7ccb6972a29c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 17 Dec 2010 12:21:17 +0100 Subject: added $IMUDPSchedulingPolicy and $IMUDPSchedulingPriority config settings --- ChangeLog | 1 + plugins/imudp/imudp.c | 42 ++++++++++++++++++++++++++++++++++++++++++ runtime/glbl.c | 1 + 3 files changed, 44 insertions(+) diff --git a/ChangeLog b/ChangeLog index caa53b8c..740ed3c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ --------------------------------------------------------------------------- Version 4.7.4 [v4-???] (rgerhards), 2010-11-?? +- added $IMUDPSchedulingPolicy and $IMUDPSchedulingPriority config settings - added $LocalHostName config directive - bugfix: local hostname was pulled too-early, so that some config directives (namely FQDN settings) did not have any effect diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index d76f3544..fea789ec 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -72,6 +72,8 @@ static uchar *pRcvBuf = NULL; /* receive buffer (for a single packet). We use a * termination if we can not get it. -- rgerhards, 2007-12-27 */ static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */ +static uchar *pszSchedPolicy = NULL; /**< scheduling policy (string) */ +static int iSchedPrio = -1; /**< scheduling priority (must not be negative) */ // TODO: static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */ #define TIME_REQUERY_DFLT 2 static int iTimeRequery = TIME_REQUERY_DFLT;/* how often is time to be queried inside tight recv loop? 0=always */ @@ -357,6 +359,7 @@ ENDrunInput /* initialize and return if will run or not */ BEGINwillRun + struct sched_param sparam; CODESTARTwillRun /* we need to create the inputName property (only once during our lifetime) */ CHKiRet(prop.Construct(&pInputName)); @@ -364,6 +367,41 @@ CODESTARTwillRun CHKiRet(prop.ConstructFinalize(pInputName)); net.PrintAllowedSenders(1); /* UDP */ + + if(pszSchedPolicy == NULL) { + if(iSchedPrio != -1) { + errmsg.LogError(errno, NO_ERRCODE, "imudp: scheduling policy not set, but " + "priority - ignoring settings"); + } + } else { + if(iSchedPrio == -1) { + errmsg.LogError(errno, NO_ERRCODE, "imudp: scheduling policy set, but no " + "priority - ignoring settings"); + } + sparam.sched_priority = iSchedPrio; + dbgprintf("imudp trying to set sched policy to '%s', prio %d\n", + pszSchedPolicy, iSchedPrio); + if(0) { /* trick to use conditional compilation */ +# ifdef SCHED_FIFO + } else if(!strcasecmp((char*)pszSchedPolicy, "fifo")) { + pthread_setschedparam(pthread_self(), SCHED_FIFO, &sparam); +# endif +# ifdef SCHED_RR + } else if(!strcasecmp((char*)pszSchedPolicy, "rr")) { + pthread_setschedparam(pthread_self(), SCHED_RR, &sparam); +# endif +# ifdef SCHED_OTHER + } else if(!strcasecmp((char*)pszSchedPolicy, "other")) { + pthread_setschedparam(pthread_self(), SCHED_OTHER, &sparam); +# endif + } else { + errmsg.LogError(errno, NO_ERRCODE, "imudp: invliad scheduling policy '%s' " + "ignoring settings", pszSchedPolicy); + } + free(pszSchedPolicy); + pszSchedPolicy = NULL; + } + /* if we could not set up any listners, there is no point in running... */ if(udpLstnSocks == NULL) @@ -445,6 +483,10 @@ CODEmodInit_QueryRegCFSLineHdlr addListner, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserveraddress", 0, eCmdHdlrGetWord, NULL, &pszBindAddr, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpolicy", 0, eCmdHdlrGetWord, + NULL, &pszSchedPolicy, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpriority", 0, eCmdHdlrInt, + NULL, &iSchedPrio, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpservertimerequery", 0, eCmdHdlrInt, NULL, &iTimeRequery, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, diff --git a/runtime/glbl.c b/runtime/glbl.c index b396ed7c..59d1fb0f 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -154,6 +154,7 @@ GenerateLocalHostNameProperty(void) uchar *pszName; if(propLocalHostName != NULL) + prop.Destruct(&propLocalHostName); CHKiRet(prop.Construct(&propLocalHostName)); if(LocalHostNameOverride == NULL) { -- cgit From 8d862730d297cbf88d9301b7a4cbee47a3f8fb9e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 17 Dec 2010 14:59:44 +0100 Subject: added support for systems without epoll_create1() --- configure.ac | 2 +- plugins/imptcp/imptcp.c | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index b5c2d1c2..8e940e53 100644 --- a/configure.ac +++ b/configure.ac @@ -105,7 +105,7 @@ AC_TYPE_SIGNAL AC_FUNC_STAT AC_FUNC_STRERROR_R AC_FUNC_VPRINTF -AC_CHECK_FUNCS([flock basename alarm clock_gettime gethostbyname gethostname gettimeofday localtime_r memset mkdir regcomp select setid socket strcasecmp strchr strdup strerror strndup strnlen strrchr strstr strtol strtoul uname ttyname_r epoll_wait getline malloc_trim prctl fdatasync lseek64]) +AC_CHECK_FUNCS([flock basename alarm clock_gettime gethostbyname gethostname gettimeofday localtime_r memset mkdir regcomp select setid socket strcasecmp strchr strdup strerror strndup strnlen strrchr strstr strtol strtoul uname ttyname_r epoll_wait getline malloc_trim prctl epoll_create epoll_create1 fdatasync lseek64]) # Check for MAXHOSTNAMELEN AC_MSG_CHECKING(for MAXHOSTNAMELEN) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 93906ba0..2afb340f 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -30,6 +30,13 @@ * A copy of the GPL can be found in the file "COPYING" in this distribution. */ #include "config.h" +#if !defined(HAVE_EPOLL_CREATE) +# error imptcp requires OS support for epoll - can not build + /* imptcp gains speed by using modern Linux capabilities. As such, + * it can only be build on platforms supporting the epoll API. + */ +#endif + #include #include #include @@ -1040,7 +1047,18 @@ CODESTARTwillRun ABORT_FINALIZE(RS_RET_NO_RUN); } - if((epollfd = epoll_create1(EPOLL_CLOEXEC)) < 0) { +# if defined(EPOLL_CLOEXEC) && defined(HAVE_EPOLL_CREATE1) + DBGPRINTF("imptcp uses epoll_create1()\n"); + epollfd = epoll_create1(EPOLL_CLOEXEC); +# else + DBGPRINTF("imptcp uses epoll_create()\n"); + /* reading the docs, the number of epoll events passed to + * epoll_create() seems not to be used at all in kernels. So + * we just provide "a" number, happens to be 10. + */ + epollfd = epoll_create(10); +# endif + if(epollfd < 0) { errmsg.LogError(0, RS_RET_EPOLL_CR_FAILED, "error: epoll_create() failed"); ABORT_FINALIZE(RS_RET_NO_RUN); } -- cgit From dec726ed46a75750b30117ba772fc82e8660db1d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 10 Jan 2011 12:09:38 +0100 Subject: imudp: removing new scheduling priority setting code as it had too many implications. This will now be part of v5 only. --- ChangeLog | 1 - plugins/imudp/imudp.c | 42 ------------------------------------------ 2 files changed, 43 deletions(-) diff --git a/ChangeLog b/ChangeLog index 740ed3c8..caa53b8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,5 @@ --------------------------------------------------------------------------- Version 4.7.4 [v4-???] (rgerhards), 2010-11-?? -- added $IMUDPSchedulingPolicy and $IMUDPSchedulingPriority config settings - added $LocalHostName config directive - bugfix: local hostname was pulled too-early, so that some config directives (namely FQDN settings) did not have any effect diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index fea789ec..d76f3544 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -72,8 +72,6 @@ static uchar *pRcvBuf = NULL; /* receive buffer (for a single packet). We use a * termination if we can not get it. -- rgerhards, 2007-12-27 */ static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */ -static uchar *pszSchedPolicy = NULL; /**< scheduling policy (string) */ -static int iSchedPrio = -1; /**< scheduling priority (must not be negative) */ // TODO: static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */ #define TIME_REQUERY_DFLT 2 static int iTimeRequery = TIME_REQUERY_DFLT;/* how often is time to be queried inside tight recv loop? 0=always */ @@ -359,7 +357,6 @@ ENDrunInput /* initialize and return if will run or not */ BEGINwillRun - struct sched_param sparam; CODESTARTwillRun /* we need to create the inputName property (only once during our lifetime) */ CHKiRet(prop.Construct(&pInputName)); @@ -367,41 +364,6 @@ CODESTARTwillRun CHKiRet(prop.ConstructFinalize(pInputName)); net.PrintAllowedSenders(1); /* UDP */ - - if(pszSchedPolicy == NULL) { - if(iSchedPrio != -1) { - errmsg.LogError(errno, NO_ERRCODE, "imudp: scheduling policy not set, but " - "priority - ignoring settings"); - } - } else { - if(iSchedPrio == -1) { - errmsg.LogError(errno, NO_ERRCODE, "imudp: scheduling policy set, but no " - "priority - ignoring settings"); - } - sparam.sched_priority = iSchedPrio; - dbgprintf("imudp trying to set sched policy to '%s', prio %d\n", - pszSchedPolicy, iSchedPrio); - if(0) { /* trick to use conditional compilation */ -# ifdef SCHED_FIFO - } else if(!strcasecmp((char*)pszSchedPolicy, "fifo")) { - pthread_setschedparam(pthread_self(), SCHED_FIFO, &sparam); -# endif -# ifdef SCHED_RR - } else if(!strcasecmp((char*)pszSchedPolicy, "rr")) { - pthread_setschedparam(pthread_self(), SCHED_RR, &sparam); -# endif -# ifdef SCHED_OTHER - } else if(!strcasecmp((char*)pszSchedPolicy, "other")) { - pthread_setschedparam(pthread_self(), SCHED_OTHER, &sparam); -# endif - } else { - errmsg.LogError(errno, NO_ERRCODE, "imudp: invliad scheduling policy '%s' " - "ignoring settings", pszSchedPolicy); - } - free(pszSchedPolicy); - pszSchedPolicy = NULL; - } - /* if we could not set up any listners, there is no point in running... */ if(udpLstnSocks == NULL) @@ -483,10 +445,6 @@ CODEmodInit_QueryRegCFSLineHdlr addListner, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserveraddress", 0, eCmdHdlrGetWord, NULL, &pszBindAddr, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpolicy", 0, eCmdHdlrGetWord, - NULL, &pszSchedPolicy, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpriority", 0, eCmdHdlrInt, - NULL, &iSchedPrio, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpservertimerequery", 0, eCmdHdlrInt, NULL, &iTimeRequery, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, -- cgit From d4539663f685910db1e8d7816508298b940c8590 Mon Sep 17 00:00:00 2001 From: Corey Smith Date: Thu, 24 Mar 2011 17:16:59 +0100 Subject: bugfix: PRI was invalid on Solaris for message from local log socket Signed-off-by: root --- ChangeLog | 1 + runtime/parser.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index caa53b8c..0fb8334d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ --------------------------------------------------------------------------- Version 4.7.4 [v4-???] (rgerhards), 2010-11-?? +- bugfix: PRI was invalid on Solaris for message from local log socket - added $LocalHostName config directive - bugfix: local hostname was pulled too-early, so that some config directives (namely FQDN settings) did not have any effect diff --git a/runtime/parser.c b/runtime/parser.c index fdda9546..be9304d7 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -303,10 +303,10 @@ rsRetVal parseMsg(msg_t *pMsg) if(pri & ~(LOG_FACMASK|LOG_PRIMASK)) pri = DEFUPRI; } + pMsg->iFacility = LOG_FAC(pri); + pMsg->iSeverity = LOG_PRI(pri); + MsgSetAfterPRIOffs(pMsg, msg - pMsg->pszRawMsg); } - pMsg->iFacility = LOG_FAC(pri); - pMsg->iSeverity = LOG_PRI(pri); - MsgSetAfterPRIOffs(pMsg, msg - pMsg->pszRawMsg); /* rger 2005-11-24 (happy thanksgiving!): we now need to check if we have * a traditional syslog message or one formatted according to syslog-protocol. -- cgit From 579c61e579d9452682da51ec5e4b547684573807 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 2 May 2011 11:57:29 +0200 Subject: bugfix: a slightly more informative error message when a TCP connections is aborted --- ChangeLog | 2 ++ runtime/strmsrv.c | 6 ++++-- tcpsrv.c | 8 +++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0fb8334d..c838f6d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,8 @@ Version 4.7.4 [v4-???] (rgerhards), 2010-11-?? directives (namely FQDN settings) did not have any effect - bugfix: atomic increment for msg object may not work correct on all platforms. Thanks to Chris Metcalf for the patch +- bugfix: a slightly more informative error message when a TCP + connections is aborted --------------------------------------------------------------------------- Version 4.7.3 [v4-devel] (rgerhards), 2010-11-25 - bugfix(important): problem in TLS handling could cause rsyslog to loop diff --git a/runtime/strmsrv.c b/runtime/strmsrv.c index 3dc53a97..8cebf810 100644 --- a/runtime/strmsrv.c +++ b/runtime/strmsrv.c @@ -520,6 +520,7 @@ Run(strmsrv_t *pThis) strms_sess_t *pNewSess; nssel_t *pSel; ssize_t iRcvd; + rsRetVal localRet; ISOBJ_TYPE_assert(pThis, strmsrv); @@ -579,11 +580,12 @@ Run(strmsrv_t *pThis) break; case RS_RET_OK: /* valid data received, process it! */ - if(strms_sess.DataRcvd(pThis->pSessions[iSTRMSess], buf, iRcvd) != RS_RET_OK) { + localRet = strms_sess.DataRcvd(pThis->pSessions[iSTRMSess], buf, iRcvd); + if(localRet != RS_RET_OK) { /* in this case, something went awfully wrong. * We are instructed to terminate the session. */ - errmsg.LogError(0, NO_ERRCODE, "Tearing down STRM Session %d - see " + errmsg.LogError(0, localRet, "Tearing down STRM Session %d - see " "previous messages for reason(s)\n", iSTRMSess); pThis->pOnErrClose(pThis->pSessions[iSTRMSess]); strms_sess.Destruct(&pThis->pSessions[iSTRMSess]); diff --git a/tcpsrv.c b/tcpsrv.c index 0102bee7..5de805b2 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -471,6 +471,7 @@ static rsRetVal Run(tcpsrv_t *pThis) { DEFiRet; + rsRetVal localRet; int nfds; int i; int iTCPSess; @@ -545,12 +546,13 @@ Run(tcpsrv_t *pThis) break; case RS_RET_OK: /* valid data received, process it! */ - if(tcps_sess.DataRcvd(pThis->pSessions[iTCPSess], buf, iRcvd) != RS_RET_OK) { + localRet = tcps_sess.DataRcvd(pThis->pSessions[iTCPSess], buf, iRcvd); + if(localRet != RS_RET_OK) { /* in this case, something went awfully wrong. * We are instructed to terminate the session. */ - errmsg.LogError(0, NO_ERRCODE, "Tearing down TCP Session %d - see " - "previous messages for reason(s)\n", iTCPSess); + errmsg.LogError(0, localRet, "Tearing down TCP Session %d - see " + "previous messages for reason(s)", iTCPSess); pThis->pOnErrClose(pThis->pSessions[iTCPSess]); tcps_sess.Destruct(&pThis->pSessions[iTCPSess]); } -- cgit From f55eee74a3fca58f747857c9b7ec5040178a6f8b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 09:34:26 +0200 Subject: issue a warning message for old-style dynafile action --- doc/v4compatibility.html | 19 +++++++++++++++++++ runtime/rsyslog.h | 1 + tools/omfile.c | 9 ++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/doc/v4compatibility.html b/doc/v4compatibility.html index 5d877af1..72b0f5a9 100644 --- a/doc/v4compatibility.html +++ b/doc/v4compatibility.html @@ -74,4 +74,23 @@ So it is a good idea to become ready for the new version now and also enjoy some benefits of the "real restart", like the better error-reporting capability.

    Note that code complexity reduction (and thus performance improvement) needs the restart-type HUP code to be removed, so these changes can (and will) only happen in version 5. +

    outchannels

    +Note: as always documented, outchannels are an experimental feature that may be +removed and/or changed in the future. +There is one concrete change done starting with 4.6.7: let's assume an +outchannel "mychannel" was defined. Then, this channel could be used inside an + +*.* $mychannel + +This is still supported and will remain to be supported in v4. However, there is +a new variant which explicitely tells this is to be handled by omfile. This new +syntax is as follows: + +*.* :omfile:$mychannel + +Note that future versions, specifically starting with v6, the older syntax is no +longer supported. So users are strongly advised to switch to the new syntax. As an +aid to the conversion process, rsyslog 4.7.4 and above issue a warning message +if the old-style directive is seen -- but still accept the old syntax without +any problems. diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 9dd45b38..03f5120d 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -382,6 +382,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_EPOLL_CR_FAILED = -2173, /**< epoll_create() failed */ RS_RET_EPOLL_CTL_FAILED = -2174, /**< epoll_ctl() failed */ RS_RET_INTERNAL_ERROR = -2175, /**< rsyslogd internal error, unexpected code path reached */ + RS_RET_OUTDATED_STMT = -2184, /**< some outdated statement/functionality is being used in conf file */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tools/omfile.c b/tools/omfile.c index b7b94597..a58dfd5b 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -672,7 +672,14 @@ CODESTARTparseSelectorAct */ if(!strncmp((char*) p, ":omfile:", sizeof(":omfile:") - 1)) { p += sizeof(":omfile:") - 1; - } + } else { + if(*p == '$') { + errmsg.LogError(0, RS_RET_OUTDATED_STMT, + "action '%s' treated as ':omfile:%s' - please " + "change syntax, '%s' will not be supported in " + "rsyslog v6 and above.", p, p, p); + } + } if(!(*p == '$' || *p == '?' || *p == '/' || *p == '.' || *p == '-')) ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); -- cgit From f285420d1731555eb9eb6717fc9c875651ab7c91 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 09:47:28 +0200 Subject: preparing for 4.7.4 --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 10f37806..60735183 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 4.7.4 [v4-beta] (rgerhards), 2010-11-?? +Version 4.7.4 [v4-beta] (rgerhards), 2011-07-11 - added support for the ":omusrmsg:" syntax in configuring user messages - added support for the ":omfile:" syntax in configuring user messages - added $LocalHostName config directive diff --git a/configure.ac b/configure.ac index 979ba5af..956599fa 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[4.7.3],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[4.7.4],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([ChangeLog]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/manual.html b/doc/manual.html index a95e8eec..8c95cca4 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@ rsyslog support available directly from the source!

    Please visit the rsyslog sponsor's page to honor the project sponsors or become one yourself! We are very grateful for any help towards the project goals.

    -

    This documentation is for version 4.7.3 (v4-devel branch) of rsyslog. +

    This documentation is for version 4.7.4 (v4-devel branch) of rsyslog. Visit the rsyslog status page to obtain current version information and project status.

    If you like rsyslog, you might -- cgit From e4c44a77fd36539ff80f7d8b1257f70fd2e46ea5 Mon Sep 17 00:00:00 2001 From: Andre Lorbach Date: Thu, 11 Aug 2011 10:59:33 +0200 Subject: Added changelog entry --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index b0cafe88..73648ab3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ --------------------------------------------------------------------------- Version 4.7.5 [v4-beta] (al), 2011-??-?? - bugfix: potential misadressing in property replacer +- bugfix: The NUL-Byte for the syslogtag was not copied in MsgDup (msg.c) --------------------------------------------------------------------------- Version 4.7.4 [v4-beta] (rgerhards), 2011-07-11 - added support for the ":omusrmsg:" syntax in configuring user messages -- cgit From 156d3f64e7ce50a570c1f8f95f51406c4853aad8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 31 Aug 2011 12:27:32 +0200 Subject: preparing for 4.7.5 release --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 381d729a..cc2a9140 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 4.7.5 [v4-beta] (al), 2011-09-01 +Version 4.7.5 [v4-beta], 2011-09-01 - bugfix/security: off-by-two bug in legacy syslog parser, CVE-2011-3200 - bugfix: potential misadressing in property replacer - bugfix: The NUL-Byte for the syslogtag was not copied in MsgDup (msg.c) diff --git a/configure.ac b/configure.ac index 956599fa..da319d7e 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[4.7.4],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[4.7.5],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([ChangeLog]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/manual.html b/doc/manual.html index 8c95cca4..ff94b5bd 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@ rsyslog support available directly from the source!

    Please visit the rsyslog sponsor's page to honor the project sponsors or become one yourself! We are very grateful for any help towards the project goals.

    -

    This documentation is for version 4.7.4 (v4-devel branch) of rsyslog. +

    This documentation is for version 4.7.5 (v4-devel branch) of rsyslog. Visit the rsyslog status page to obtain current version information and project status.

    If you like rsyslog, you might -- cgit

  • This documentation is for version 4.7.1 (v4-devel branch) of rsyslog. Visit the rsyslog status page to obtain current version information and project status.