diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/imgssapi/imgssapi.c | 16 | ||||
-rw-r--r-- | plugins/imklog/solaris.c | 184 | ||||
-rw-r--r-- | plugins/imklog/solaris_cddl.c | 293 | ||||
-rw-r--r-- | plugins/imklog/solaris_cddl.h | 2 | ||||
-rw-r--r-- | plugins/imsolaris/Makefile.am | 6 | ||||
-rw-r--r-- | plugins/imsolaris/imsolaris.c | 391 | ||||
-rw-r--r-- | plugins/imsolaris/imsolaris.h | 2 | ||||
-rw-r--r-- | plugins/imsolaris/sun_cddl.c | 419 | ||||
-rw-r--r-- | plugins/imsolaris/sun_cddl.h | 7 | ||||
-rw-r--r-- | plugins/imudp/imudp.c | 20 | ||||
-rw-r--r-- | plugins/imuxsock/imuxsock.c | 47 | ||||
-rw-r--r-- | plugins/omoracle/omoracle.c | 64 | ||||
-rw-r--r-- | plugins/omprog/omprog.c | 3 | ||||
-rw-r--r-- | plugins/omstdout/omstdout.c | 2 |
14 files changed, 1427 insertions, 29 deletions
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/imklog/solaris.c b/plugins/imklog/solaris.c new file mode 100644 index 00000000..8a6d5af1 --- /dev/null +++ b/plugins/imklog/solaris.c @@ -0,0 +1,184 @@ +/* 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <sys/socket.h> + + + +#include "rsyslog.h" +#include "imklog.h" +#include "srUtils.h" +#include "unicode-helper.h" +#include "solaris_cddl.h" + +/* globals */ +static int fklog; // TODO: remove +#ifndef _PATH_KLOG +# define _PATH_KLOG "/dev/log" +#endif + + +static uchar *GetPath(void) +{ + return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); +} + +/* open the kernel log - will be called inside the willRun() imklog + * entry point. -- rgerhards, 2008-04-09 + */ +rsRetVal +klogWillRun(void) +{ + DEFiRet; + + fklog = sun_openklog((char*) GetPath(), O_RDONLY); + if (fklog < 0) { + char errStr[1024]; + int err = errno; + rs_strerror_r(err, errStr, sizeof(errStr)); + DBGPRINTF("error %s opening log socket: %s\n", + errStr, GetPath()); + iRet = RS_RET_ERR; // TODO: better error code + } + + RETiRet; +} + + +#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 + * a single file, it really doesn't matter if we wait inside a 1-file + * select or the read() directly. + */ +static void +readklog(void) +{ + 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 + */ + if((size_t) iMaxLine < sizeof(bufRcv) - 1) { + pRcv = bufRcv; + } else { + if((pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))) == NULL) + iMaxLine = sizeof(bufRcv) - 1; /* better this than noting */ + } + + 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); + + if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) + free(pRcv); +} +#endif + + +/* to be called in the module's AfterRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogAfterRun(void) +{ + DEFiRet; + if(fklog != -1) + close(fklog); + RETiRet; +} + + + +/* to be called in the module's WillRun entry point, this is the main + * "message pull" mechanism. + * rgerhards, 2008-04-09 + */ +rsRetVal klogLogKMsg(void) +{ + DEFiRet; + sun_sys_poll(); + RETiRet; +} + + +/* provide the (system-specific) default facility for internal messages + * rgerhards, 2008-04-14 + */ +int +klogFacilIntMsg(void) +{ + return LOG_SYSLOG; +} + diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c new file mode 100644 index 00000000..7e86c68c --- /dev/null +++ b/plugins/imklog/solaris_cddl.c @@ -0,0 +1,293 @@ +/* + * 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" +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <pthread.h> +#include <sys/poll.h> +#include <pthread.h> +#include <fcntl.h> +#include <stropts.h> +#include <assert.h> +#include <sys/strlog.h> + +#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 */ + + +/* 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 + */ +size_t +findnl_bkwd(const char *buf, const size_t len) +{ + const char *p; + size_t mb_cur_max; + + 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("klog:findnl_bkwd: Invalid MB sequence\n"); + /* + * 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; + + if ((fd = open(name, mode)) < 0) { + dbgprintf("klog:openklog: cannot open %s (%d)\n", + 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) { + dbgprintf("klog:openklog: cannot register to log " + "console messages (%d)\n", errno); + return (-1); + } + Pfd.fd = fd; + Pfd.events = POLLIN; + return (fd); +} + + +/* + * Pull up one message from log driver. + */ +void +sun_getkmsg() +{ + 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("klog: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'; + + Syslog(LOG_INFO, (uchar*) buf); + + 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("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)); + Syslog(LOG_INFO, (uchar*) buf); + } else if (i < 0 && errno != EINTR) { + if(1){ /* V5-TODO: rsyslog-like termination! (!shutting_down) { */ + dbgprintf("klog:kernel log driver read error"); + } + // TODO trigger retry logic + //(void) close(Pfd.fd); + //Pfd.fd = -1; + } +} + + +/* 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("klog:sys_poll: sys_thread started\n"); + + for (;;) { + errno = 0; + + nfds = poll(&Pfd, 1, INFTIM); + + if (nfds == 0) + continue; + + if (nfds < 0) { + if (errno != EINTR) + dbgprintf("klog:poll error"); + continue; + } + if (Pfd.revents & POLLIN) { + sun_getkmsg(); + } 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*/ + return (NULL); +} diff --git a/plugins/imklog/solaris_cddl.h b/plugins/imklog/solaris_cddl.h new file mode 100644 index 00000000..d48ef628 --- /dev/null +++ b/plugins/imklog/solaris_cddl.h @@ -0,0 +1,2 @@ +void *sun_sys_poll(); +int sun_openklog(char *name, int mode); diff --git a/plugins/imsolaris/Makefile.am b/plugins/imsolaris/Makefile.am new file mode 100644 index 00000000..b4ee1c29 --- /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.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..6b07ba2b --- /dev/null +++ b/plugins/imsolaris/imsolaris.c @@ -0,0 +1,391 @@ +/* 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <assert.h> +#include <string.h> +#include <stropts.h> +#include <sys/strlog.h> +#include <errno.h> +#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) + + +/* 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! */ + + +/* 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); +} + + +/* 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 void +tryRecover(void) +{ + int tryNum = 1; + 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 > 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 == 1) { + errmsg.LogError(0, iRet, "failure on system log socket, trying to recover..."); + } + waitusecs = tryNum * 10000; + waitsecs = waitusecs / 1000000; + 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 { + waitusecs = waitusecs % 1000000; + } + srSleep(waitsecs, waitusecs); + ++tryNum; + } +} + + +/* 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 +readLog(int fd, uchar *pRcv, int iMaxLine) +{ + 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; +} + + +/* 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; + int iMaxLine; + uchar *pRcv = NULL; /* receive buffer */ + uchar bufRcv[4096+1]; + 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))); + } + + 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(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); /* 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; +} + + +/* 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: 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 stream has been polled. So file header + * comment of this file for more details. + */ + sun_open_door(); + DBGPRINTF("imsolaris: starting regular poll loop\n"); + iRet = getMsgs(-1); /* this is the primary poll loop, infinite timeout */ + +finalize_it: + 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); + 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); + free(LogName); +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)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"imsolarislogsocketname", 0, eCmdHdlrGetWord, + NULL, &LogName, STD_LOADABLE_MODULE_ID)); +ENDmodInit +/* vim:set ai: + */ diff --git a/plugins/imsolaris/imsolaris.h b/plugins/imsolaris/imsolaris.h new file mode 100644 index 00000000..e73380fa --- /dev/null +++ b/plugins/imsolaris/imsolaris.h @@ -0,0 +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 new file mode 100644 index 00000000..6d49c8bc --- /dev/null +++ b/plugins/imsolaris/sun_cddl.c @@ -0,0 +1,419 @@ +/* + * 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 <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <pthread.h> +#include <fcntl.h> +#include <stropts.h> +#include <assert.h> + +#include <sys/param.h> +#include <sys/strlog.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/poll.h> +#include <door.h> +#include <sys/door.h> + +#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 + +/* 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; +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); +} + +/* + * 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) +{ + struct stat sb; + int err; + char line[ERRMSG_LEN+1]; + + 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); + imsolaris_logerror(err, line); + DBGPRINTF("delete_doorfiles: error: %s, " + "errno=%d\n", line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles: deleted %s\n", 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: %s\n", line); + + if (err != EROFS) { + errno = err; + (void) strlcat(line, " - fatal", + sizeof (line)); + imsolaris_logerror(err, line); + DBGPRINTF("delete_doorfiles: " + "error: %s, errno=%d\n", + line, err); + exit(1); + } + + DBGPRINTF("delete_doorfiles: unlink() " + "failure OK on RO file system\n"); + } + + DBGPRINTF("delete_doorfiles: deleted %s\n", + OLD_DOORFILE); + } + } + + if (DoorFd != -1) { + (void) door_revoke(DoorFd); + } + + DBGPRINTF("delete_doorfiles: revoked door: DoorFd=%d\n", + 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[ERRMSG_LEN+1]; + int err; + + /* 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) { + int door; + + if ((door = open(DoorFileName, O_RDONLY)) >= 0) { + DBGPRINTF("open_door: %s opened " + "successfully\n", DoorFileName); + + if (door_info(door, &info) >= 0) { + DBGPRINTF("open_door: " + "door_info:info.di_target = %ld\n", + 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: error: " + "%s\n", line); + imsolaris_logerror(0, line); + exit(1); + } + } + + (void) close(door); + } else { + if (lstat(DoorFileName, &buf) < 0) { + err = errno; + + DBGPRINTF("open_door: lstat() of %s " + "failed, errno=%d\n", + DoorFileName, err); + + if ((door = creat(DoorFileName, 0644)) < 0) { + err = errno; + (void) snprintf(line, sizeof (line), + "creat() of %s failed - fatal", + DoorFileName); + DBGPRINTF("open_door: error: %s, " + "errno=%d\n", line, + err); + imsolaris_logerror(err, line); + sun_delete_doorfiles(); + exit(1); + } + + (void) fchmod(door, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + + DBGPRINTF("open_door: creat() of %s " + "succeeded\n", + DoorFileName); + + (void) close(door); + } + } + + if (strcmp(DoorFileName, DOORFILE) == 0) { + if (lstat(OLD_DOORFILE, &buf) == 0) { + 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: error: " + "%s\n", line); + imsolaris_logerror(0, line); + sun_delete_doorfiles(); + exit(1); + } + + 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: %s\n", + line); + + if (err != EROFS) { + DBGPRINTF("open_door: " + "error: %s, " + "errno=%d\n", + line, err); + (void) strcat(line, " - fatal"); + imsolaris_logerror(err, line); + sun_delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door: unlink " + "failure OK on RO file " + "system\n"); + } + } else { + DBGPRINTF("open_door: file %s doesn't " + "exist\n", 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: %s\n", + line); + + if (err != EROFS) { + DBGPRINTF("open_door: error: %s, " + "errno=%d\n", line, + err); + (void) strcat(line, " - fatal"); + imsolaris_logerror(err, line); + sun_delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door: symlink failure OK " + "on RO file system\n"); + } else { + DBGPRINTF("open_door: symlink %s -> %s " + "succeeded\n", + 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: error: %s, errno=%d\n", + line, err); + imsolaris_logerror(err, line); + sun_delete_doorfiles(); + exit(1); + } + //???? (void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0); + DBGPRINTF("open_door: door_create() succeeded, " + "DoorFd=%d\n", 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: error: %s, errno=%d\n", + line, err); + imsolaris_logerror(err, line); + sun_delete_doorfiles(); + exit(1); + } + + DBGPRINTF("open_door: attached server() to %s\n", + DoorFileName); + +} + + +/* Attempts to open the local log device + * and return a file descriptor. + */ +rsRetVal +sun_openklog(char *name) +{ + DEFiRet; + int fd; + 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); + } + sun_Pfd.fd = fd; + sun_Pfd.events = POLLIN; + DBGPRINTF("imsolaris/openklog: opened '%s' as fd %d.\n", name, fd); + +finalize_it: + RETiRet; +} diff --git a/plugins/imsolaris/sun_cddl.h b/plugins/imsolaris/sun_cddl.h new file mode 100644 index 00000000..42e4b799 --- /dev/null +++ b/plugins/imsolaris/sun_cddl.h @@ -0,0 +1,7 @@ +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/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index f8555f00..d76f3544 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -45,6 +45,7 @@ #include "datetime.h" #include "prop.h" #include "unicode-helper.h" +#include "unlimited_select.h" MODULE_TYPE_INPUT @@ -287,12 +288,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. @@ -311,30 +318,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 */ @@ -343,6 +350,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 5567a405..daa3bb47 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -45,6 +45,7 @@ #include "glbl.h" #include "msg.h" #include "prop.h" +#include "unlimited_select.h" MODULE_TYPE_INPUT @@ -77,6 +78,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 +91,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 +136,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 +170,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 +182,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 || @@ -249,7 +257,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, @@ -263,11 +277,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]; } } @@ -275,22 +289,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 @@ -300,13 +315,22 @@ 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; /* 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]); } @@ -329,7 +353,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 */ @@ -376,6 +400,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 +434,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, diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index 331b7dd4..48ee1fa4 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 @@ -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_WITH_INFO; case OCI_NEED_DATA: errmsg.LogError(0, NO_ERRCODE, "OCI NEEDS MORE DATA\n"); break; @@ -180,6 +183,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"); @@ -332,6 +338,48 @@ 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) +{ + 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, "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); + 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); +} + + /* Inserts all stored statements into the database, releasing any * allocated memory. */ static int insert_to_db(instanceData* pData) @@ -346,6 +394,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 ? 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... */ 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. */ |