From df4d27d7532268a278668983fe11c7f1d384227e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 19 Nov 2004 11:09:55 +0000 Subject: fixing upload error - template parser also ok --- liblogging-stub.h | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ syslogd.c | 206 +++++++++++++++++++----------------- template.c | 6 +- template.h | 4 +- 4 files changed, 423 insertions(+), 103 deletions(-) create mode 100755 liblogging-stub.h diff --git a/liblogging-stub.h b/liblogging-stub.h new file mode 100755 index 00000000..f618a967 --- /dev/null +++ b/liblogging-stub.h @@ -0,0 +1,310 @@ +/*! \file liblogging.h + * \brief global objects and defines + * + * THIS IS A STUB MODULE TAKEN FROM LIBLOGGING. It will be replaced + * once liblogging is fully integrated in rsyslog. rgerhards 2004-11-17. + * + * Include this header in your application! + * + * \author Rainer Gerhards + * \date 2003-08-04 + * 0.1 version created. + * + * Copyright 2002-2003 + * Rainer Gerhards and Adiscon GmbH. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Adiscon GmbH or Rainer Gerhards + * nor the names of its contributors may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __LIB3195_LIBLOGGING_H_INCLUDED__ +#define __LIB3195_LIBLOGGING_H_INCLUDED__ 1 +#include /* debug only */ + +#ifdef __cplusplus +extern "C" { +#endif + + +enum srRetVal_ /** return value. All methods return this if not specified otherwise */ +{ + SR_RET_ERR = -1, /**< error occured, call error handler for details */ + SR_RET_REMAIN_WIN_TOO_SMALL = -2, /**< can't send, because not enough octets left in RFC3081 window --> wait for SEQ */ + SR_RET_INVALID_HANDLE = -3, /**< caller provided an invalid handle, e.g. NULL pointer or pointer to wrong object. + * This is only checked on the API layer. Internally, all functions check this via + * assert(), so protection is only available during debugging. This is a performance + * decision. + */ + SR_RET_INVALID_DESTRUCTOR = -4, /**< used, when the caller must provide a pointer to a destructor function but does not */ + SR_RET_NOT_FOUND = - 5, /**< a requested element was not found. May not be an error depending on what operation was + ** to be carried out... */ + SR_RET_OUT_OF_MEMORY = -6, /**< memory allocation failed */ + SR_RET_XML_INVALID_PARAMTAG = -7, /**< malformed tag parameter, most probably quotes are missing before value or intervening space */ + SR_RET_XML_INVALID_TERMINATOR = -8, /**< missing terminator sequence, e.g. a "param='no_terminator" - notice the missing closing quote */ + SR_RET_XML_MALFORMED = -9, /**< the XML is malformed (no specific reason given) */ + SR_RET_MISSING_CLOSE_BRACE = -10, /**< closing brace in missing */ + SR_RET_XML_MISSING_CLOSETAG = -11, /**< close tag is missing or syntax invalid ... */ + SR_RET_XML_MISSING_OPENTAG = -12, /**< open tag is missing, e.g othertag> */ + SR_RET_XML_TAG_MISMATCH = -13, /**< start and close tag name do not match (...) */ + SR_RET_XML_INVALID_CDATA_HDR = -14, /**< invalid start of CDATA, e.g. " (one ] missing) */ + SR_RET_PEER_NONOK_RESPONSE = -15, /**< was waiting for a BEEP peer to respond "ok", but received other response */ + SR_RET_PEER_INVALID_PROFILE = -16, /**< BEEP Peer did either not support the profile or did not return the correct on in response to a start message */ + SR_RET_PEER_NO_URI = -17, /**< BEEP peer did not inclulde a mandatory URI element in its xml response */ + SR_RET_PEER_NO_PROFILE = -18,/**< BEEP peer did not include a mandatory PROFILE element in its XML reponse */ + SR_RET_PEER_NO_GREETING = -19, /**< BEEP peer did not send a (correctly formatted) greeting message */ + SR_RET_PEER_DOESNT_SUPPORT_PROFILE = -20, /**< the reqeusted profile is not part of the peers profile set (from greeting message) */ + SR_RET_INVALID_FRAME_STATE = -21, /**< a frame object has an invalid frame state (pFram->iState) */ + SR_RET_PROFILE_ALREADY_SET = -22, /**< a profile should be assgined to a channel which already has one */ + SR_RET_INVALID_CHAN_STATE = -23, /**< a channel object has an invalid or unexpected (at this point) channel state */ + SR_RET_INVALID_GREETING = -24, /**< greeting message is (somehow) invalid, e.g. does not start with RPY) */ + SR_RET_INVALID_CHAN0_MESG = -25, /**< channel 0 received an invalid or out-of-sequence message */ + SR_RET_START_MISSING_NUMBER = -26, /**< a start message is missing the "number=" parameter */ + SR_RET_START_INVALID_NUMBER = -27, /**< a start message's "number=" parameter specifies an invalid number */ + SR_RET_START_EXISTING_NUMBER = -28, /**< a start message's "number=" parameter specifies a channel number which already exisits! */ + SR_RET_NO_VALUE = -29, /**< a linked list was asked to provide an uValue, but there was none. Not necessarily an error, depends on caller's needs. */ + SR_RET_START_EVEN_NUMBER = -30, /**< an initiator sent a even-numbered start number, which is invalid as of rfc 3080 2.3.1.2 */ + SR_RET_NO_PROFILE_RQSTD = -31, /**< no profile at all was requested in a start message (may be caused by invalid format) */ + SR_RET_WARNING_START_NO_PROFMATCH = -32,/**< WARNING only (no error) - during a start, no matching profile was found and the beep peer has been sent such an ERR frame */ + SR_RET_ERR_EVENT_HANDLER_MISSING = -33,/**< a required (profile) event handler is missing */ + SR_RET_ACKNO_ZERO = -34, /**< caller-provided ackno is zero. This can not be by design. */ + SR_RET_CHAN_DOESNT_EXIST = -35, /**< a chanel specified does not exist */ + SR_RET_ALREADY_LISTENING = -36, /**< caller tried to start an listener on the API object, but it is already one running */ + SR_RET_INVALID_OPTVAL = -37, /**< invalid option value was provided to srAPISetOption() (param 2) */ + SR_RET_INVALID_LIB_OPTION = -38, /**< invalid option was provided to srAPISetOption() (param 1) */ + SR_RET_NULL_POINTER_PROVIDED = -39, /**< the caller has provided a NULL-Pointer where none were expected/allowed */ + SR_RET_PROPERTY_NOT_AVAILABLE = -40,/**< a property asked for is not available, e.g. the TIMESTAMP in a not-wellformed message */ + SR_RET_UNSUPPORTED_FORMAT = -41, /**< a non-supported format was requested by the caller */ + SR_RET_UNALLOCATABLE_BUFFER = -42, /**< the operation can not be completed because a buffer that is under user control would need to be deallocated */ + SR_RET_PRIO_OUT_OF_RANGE = -43, /**< a priority value is outside the allowed range */ + SR_RET_FACIL_OUT_OF_RANGE = -44, /**< a facility value is outside the allowed range */ + SR_RET_INVALID_TAG = -45, /**< a syslog TAG value (string) provided was invalid, e.g. over 32 chars or included invalid chars */ + SR_RET_NULL_MSG_PROVIDED = -46, /**< caller provided a NULL pointer where a pointer to a MSG was expected */ + SR_RET_ERR_RECEIVE = -47, /**< an error occured during message receive. no more detail is available */ + SR_RET_UNEXPECTED_HDRCMD = -48, /**< an invalid HDR Command was received (e.g. an "MSG" in response to another "MSG") */ + SR_RET_PEER_INDICATED_ERROR = -49, /**< the PEER send an error response */ + SR_RET_PROVIDED_BUFFER_TOO_SMALL = -50,/**< the caller provided a buffer, but the called function sees the size of this buffer is too small - operation not carried out */ + SR_RET_INVALID_PARAM = -51, /**< an invalid parameter was provided to a method */ + + /* socket error codes */ + SR_RET_SOCKET_ERR = -1001, /**< generic error generated by socket subsystem */ + SR_RET_CANT_BIND_SOCKET = -1002, /**< socket bind() operation failed */ + SR_RET_INVALID_SOCKET = -1003, /**< invalid socket */ + SR_RET_CONNECTION_CLOSED = -1004, /**< the remote peer closed the connection */ + SR_RET_INVALID_OS_SOCKETS_VERSION = -1005,/**< the operating system socket subsystem version is inappropriate (this error will most probably occur under Win32, only) */ + SR_RET_CAN_NOT_INIT_SOCKET = -1006, /**< socket() failed for whatever reason... */ + SR_RET_UXDOMSOCK_CHMOD_ERR = -1007, /**< chmod() failed on Unix Domain Socket */ + + /* BEEP frame format & other errors */ + SR_RET_INVALID_HDRCMD = -2001, /**< invalid HDRCMD (e.g. "MSG", "RPY",...) */ + SR_RET_INVALID_WAITING_SP_CHAN = -2002, /**< invalid SP before channo */ + SR_RET_INVALID_CHANNO = -2003, /**< invalid channo */ + SR_RET_INVALID_WAITING_SP_MSGNO = -2004,/**< now the space before the next header */ + SR_RET_INVALID_IN_MSGNO = -2005, /**< and the next (numeric) header */ + SR_RET_INVALID_WAITING_SP_MORE = -2006, /**< now the space before the next header */ + SR_RET_INVALID_IN_MORE = -2007, /**< and the next (char) header */ + SR_RET_INVALID_WAITING_SP_SEQNO = -2008,/**< now the space before the next header */ + SR_RET_INVALID_IN_SEQNO = -2009, /**< and the next (numeric) header */ + SR_RET_INVALID_WAITING_SP_SIZE = -2010, /**< now the space before the next header */ + SR_RET_INVALID_IN_SIZE = -2011, /**< and the next (numeric) header */ + SR_RET_INVALID_WAITING_SP_ANSNO = -2012,/**< now the space before the next header */ + SR_RET_INVALID_IN_ANSNO = -2013, /**< and the next (numeric) header */ + SR_RET_INVALID_WAITING_HDRCR = -2014, /**< awaiting the HDR's CR */ + SR_RET_INVALID_WAITING_HDRLF = -2015, /**< awaiting the HDR's LF */ + SR_RET_INVALID_IN_PAYLOAD = -2016, /**< reading payload area */ + SR_RET_INVALID_WAITING_END1 = -2017, /**< waiting for the 1st HDR character */ + SR_RET_INVALID_WAITING_END2 = -2018, /**< waiting for the 2nd HDR character */ + SR_RET_INVALID_WAITING_END3 = -2019, /**< waiting for the 3rd HDR character */ + SR_RET_INVALID_WAITING_END4 = -2020, /**< waiting for the 4th HDR character */ + SR_RET_INVALID_WAITING_END5 = -2021, /**< waiting for the 5th HDR character */ + SR_RET_INVALID_WAITING_SP_ACKNO = -2022,/**< now the space before the next header */ + SR_RET_INVALID_WAITING_SP_WINDOW = -2023,/**< now the space before the next header */ + SR_RET_INAPROPRIATE_HDRCMD = -2024, /**< the beep header was syntactically correct, but could not be used semantically */ + SR_RET_OVERSIZED_FRAME = -2025, /**< the frame's "size" field specifies a size that does not fit into the current windows. Eventually malicous. */ + + /* and finally the OK state... */ + SR_RET_OK = 0 /**< operation successful */ +}; +/** friendly type for global return value */ +typedef enum srRetVal_ srRetVal; + + +typedef unsigned SBchannel; /**< our own type for channel numbers */ +typedef unsigned SBseqno; /**< our own type for sequence numbers */ +typedef unsigned SBansno; /**< our own type for answer numbers */ +typedef unsigned SBsize; /**< our own type for frame size */ +typedef unsigned SBmsgno; /**< our own type for message numbers */ +typedef unsigned SBackno; /**< our own type for acknowledgment numbers */ +typedef unsigned SBwindow; /**< our own type for window sizes*/ + + +/** Object ID. These are for internal checking. Each + * object is assigned a specific ID. This is contained in + * all Object structs (just like C++ RTTI). We can use + * this field to see if we have been passed a correct ID. + * Other than that, there is currently no other use for + * the object id. + */ +enum srObjectID +{ + OID_Freed = -1, /**< assigned, when an object is freed. If this + * is seen during a method call, this is an + * invalid object pointer! + */ + OID_Invalid = 0, /**< value created by calloc(), so do not use ;) */ + /* The 0xCDAB is a debug aid. It helps us find object IDs in memory + * dumps (on X86, this is ABCD in the dump ;) + * If you are on an embedded device and you would like to save space + * make them 1 byte only. + */ + OIDsbFram = 0xCDAB0001, + OIDsbChan = 0xCDAB0002, + OIDsbMesg = 0xCDAB0003, + OIDsbSess = 0xCDAB0004, + OIDsbSock = 0xCDAB0005, + OIDsbProf = 0xCDAB0006, + OIDsrAPI = 0xCDAB0007, + OIDsrSLMG = 0xCDAB0008, + OIDsbNVTR = 0xCDAB0009, + OIDsbNVTE = 0xCDAB000A, + OIDsbStrB = 0xCDAB000B, + OIDsbLstn = 0xCDAB000C, + OIDsbPSSR = 0xCDAB000D, + OIDsbPSRC = 0xCDAB000E +}; +typedef enum srObjectID srObjID; + + +/** + * Allowed options for 3195 client profile + * selection. + */ +enum srOPTION3195Profiles_ +{ + USE_3195_PROFILE_ANY = 1, + USE_3195_PROFILE_RAW_ONLY = 2, + USE_3195_PROFILE_COOKED_ONLY = 3 +}; +typedef enum srOPTION3195Profiles_ srOPTION3195Profiles; + +/** + * Library options. Modify library behaviour. + * Currently, no options are defined. + */ +enum srOPTION +{ + srOPTION_INVALID = 0, /**< invalid option, if seen, caller made an error */ + /** + * This option tells the library if it should instruct the + * socket parts of it to call the OS socket initialiser. + * Under Win32, for example, this is only allowed once per + * process. So if the lib is integrated into a process that + * already uses sockets, the sockets initializer (WSAStartup() + * in this case) should not be called. + * This is a global setting that NEEDS TO BE SET BEFORE the API + * object is created!!!! + */ + srOPTION_CALL_OS_SOCKET_INITIALIZER = 1, + /** + * This option tells the library which RFC 3195 Profile + * should be used when talking to the remote peer. This + * option so far is only used in the client parts of + * liblogging. See \ref srOPTION3195Profiles for + * allowed values. + */ + srOPTION_3195_ALLOWED_CLIENT_PROFILES = 2, + /** + * This options tells the lib if a UDP listener should + * be started. Option value must be TRUE or FALSE. + */ + srOPTION_LISTEN_UDP = 3, + /** + * Sets the UDP listener port. Is only used if the + * UDP listener is activated. + */ + srOPTION_UPD_LISTENPORT = 4, + /** + * This option tells the lib if a UNIX domain socket + * listener should be started. Supported values are + * TRUE and FALSE. + */ + srOPTION_LISTEN_UXDOMSOCK = 5, + /** + * Provides a pointer to the UNIX domain socket that + * should be listened to (if listening is enabled). + */ + srOPTION_UXDOMSOCK_LISTENAME = 6, + /** + * This option tells the lib if a BEEP + * listener should be started. Supported values are + * TRUE and FALSE. + */ + srOPTION_LISTEN_BEEP = 7, + /** + * Sets the BEEP listener port. Is only used if the + * UDP listener is activated. + */ + srOPTION_BEEP_LISTENPORT = 8 +}; +typedef enum srOPTION SRoption; + +/** + * This macro should be used to free objects. + * Microsoft VC automatically sets _DEBUG if compiling + * with debug settings. For other environments, you may + * want to add this to a debug makefile. + */ +#if DEBUGLEVEL > 0 +#define SRFREEOBJ(x) {(x)->OID = OID_Freed; free(x);} +#else +#define SRFREEOBJ(x) free(x) +#endif + +/** + * Integer values for the various supported + * BEEP headers. + */ +enum BEEPHdrID_ +{ + BEEPHDR_UNKNOWN = 0, + BEEPHDR_ANS, + BEEPHDR_ERR, + BEEPHDR_MSG, + BEEPHDR_NUL, + BEEPHDR_RPY, + BEEPHDR_SEQ +}; +typedef enum BEEPHdrID_ BEEPHdrID; + +#ifdef __cplusplus +} +#endif + +/* from liblogging config.h */ +#define STRINGBUF_ALLOC_INCREMENT 128 +#endif diff --git a/syslogd.c b/syslogd.c index 252974ec..5fca2657 100644 --- a/syslogd.c +++ b/syslogd.c @@ -2,6 +2,7 @@ * TODO: * - check if syslogd really needs to be shut down totally if * "syslog" service from etc/services can not be found + * - check if MsgGetProp() can be used for MySQL, too * * \brief This is what will become the rsyslogd daemon. * @@ -787,6 +788,7 @@ struct filed { short f_file; /* file descriptor */ #ifdef WITH_DB MYSQL f_hmysql; /* handle to MySQL */ + /* TODO: optimize memory layout / consumption; rgerhards 2004-11-19 */ char f_dbsrv[MAXHOSTNAMELEN+1]; /* IP or hostname of DB server*/ char f_dbname[_DB_MAXDBLEN+1]; /* DB name */ char f_dbuid[_DB_MAXUNAMELEN+1]; /* DB user */ @@ -809,6 +811,8 @@ struct filed { int f_prevcount; /* repetition cnt of prevline */ int f_repeatcount; /* number of "repeated" msgs */ int f_flags; /* store some additional flags */ + struct template *f_pTpl; /* pointer to template to use */ + struct iovec *f_iov; /* dyn allocated depinding on template */ struct msg* f_pMsg; /* pointer to the message (this wil * replace the other vars with msg * content later). This is preserved after @@ -1312,29 +1316,14 @@ struct msg* MsgConstruct() { struct msg *pM; - if((pM = malloc(sizeof(struct msg))) != NULL) - { /* initialize members */ + if((pM = calloc(1, sizeof(struct msg))) != NULL) + { /* initialize members that are non-zero */ pM->iRefCount = 1; - pM->iMsgSource = 0; pM->iSyslogVers = -1; pM->iSeverity = -1; pM->iFacility = -1; - pM->pszRcvdAt3164 = NULL; - pM->pszRawMsg = NULL; - pM->pszUxTradMsg = NULL; - pM->pszTAG = NULL; - pM->pszHOSTNAME = NULL; - pM->pszRcvFrom = NULL; - pM->pszMSG = NULL; - pM->iLenMSG = 0; - pM->iLenRawMsg = 0; - pM->iLenHOSTNAME = 0; - pM->iLenRcvFrom = 0; - pM->iLenTAG = 0; - pM->iLenUxTradMsg = 0; getCurrTime(&(pM->tRcvdAt)); /* TODO: we can set the time HERE! */ - pM->tTIMESTAMP.timeType = 0; } dprintf("MsgConstruct\t0x%x\n", (int)pM); @@ -1635,6 +1624,7 @@ char *MsgGetProp(struct msg *pMsg, char *pName) pRes = "INVALID PROPERTY NAME"; /* NULL;*/ } + dprintf("MsgGetProp(\"%s\"): \"%s\"\n", pName, pRes); return(pRes); } @@ -2427,6 +2417,8 @@ void logmsgInternal(pri, msg, from, flags) int flags; { struct msg *pMsg; + char buf[16]; + char szMsg[1024]; if((pMsg = MsgConstruct()) == NULL){ /* rgerhards 2004-11-09: calling panic might not be the @@ -2438,7 +2430,6 @@ void logmsgInternal(pri, msg, from, flags) } if(MsgSetMSG(pMsg, msg) != 0) return; - if(MsgSetUxTradMsg(pMsg, msg) != 0) return; if(MsgSetRawMsg(pMsg, msg) != 0) return; if(MsgSetHOSTNAME(pMsg, from) != 0) return; pMsg->iFacility = LOG_FAC(pri); @@ -2446,6 +2437,13 @@ void logmsgInternal(pri, msg, from, flags) pMsg->iMsgSource = SOURCE_INTERNAL; getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */ + /* generate traditional Unix message... */ + formatTimestamp3164(&pMsg->tTIMESTAMP, buf, sizeof(buf) / sizeof(char)); + + snprintf(szMsg, sizeof(szMsg) / sizeof(char), "%s %s %s", + buf, from, msg); + if(MsgSetUxTradMsg(pMsg, szMsg) != 0) return; + logmsg(pri, pMsg, flags); MsgDestruct(pMsg); } @@ -2655,19 +2653,14 @@ void logmsg(pri, pMsg, flags) */ void writeFile(struct filed *f) { - struct iovec *iov; register struct iovec *v; int iIOVused; - /*char szTIMESTAMP[40];*/ struct template *pTpl; struct templateEntry *pTpe; struct msg *pMsg; assert(f != NULL); - /* f->f_file == -1 is an indicator that the we couldn't - open the file at startup. */ - if (f->f_file == -1) - return; /* TODO: eventually do this check in caller! */ + /* Now generate the message. This can eventually be moved to * a generic subroutine (need to think about this....). * for now, this is a quick and dirty dummy. We need to have the @@ -2675,17 +2668,9 @@ void writeFile(struct filed *f) * code this part of the function. rgerhards 2004-11-11 */ - pMsg = f->f_pMsg; - - /*if((pTpl = tplFind("TraditionalFormat", strlen("TraditionalFormat"))) == NULL) {*/ - if((pTpl = tplFind("precise", strlen("precise"))) == NULL) { - dprintf("Could not find template '%s'\n", "precise"); - return; - } - - /* TODO: allocate iov in struct filed! */ - iov = calloc(tplGetEntryCount(pTpl), sizeof(struct iovec)); - v = iov; + pMsg = f->f_pMsg; + pTpl = f->f_pTpl; + v = f->f_iov; iIOVused = 0; pTpe = pTpl->pEntryRoot; @@ -2696,7 +2681,7 @@ void writeFile(struct filed *f) ++v; ++iIOVused; } else if(pTpe->eEntryType == FIELD) { - v->iov_base = MsgGetProp(pMsg, pTpe->data.pPropRepl); + v->iov_base = MsgGetProp(pMsg, pTpe->data.field.pPropRepl); v->iov_len = strlen(v->iov_base); /* TODO: performance optimize - can we obtain the length? */ ++v; @@ -2720,7 +2705,7 @@ void writeFile(struct filed *f) #endif again: - if (writev(f->f_file, iov, iIOVused) < 0) { + if (writev(f->f_file, f->f_iov, iIOVused) < 0) { int e = errno; /* If a named pipe is full, just ignore it for now @@ -2794,7 +2779,7 @@ void fprintlog(f, flags) v->iov_len = 1; v++; v->iov_base = f->f_prevhost; - v->iov_len = strlen(v->iov_base); + v->iov_len = f->f_prevhost == 0 ? 0 : strlen(v->iov_base); v++; v->iov_base = " "; v->iov_len = 1; @@ -2925,58 +2910,10 @@ void fprintlog(f, flags) case F_TTY: case F_FILE: case F_PIPE: - writeFile(f); -#if 0 - f->f_time = now; - dprintf(" %s\n", f->f_un.f_fname); - if (f->f_type == F_TTY || f->f_type == F_CONSOLE) { - v->iov_base = "\r\n"; - v->iov_len = 2; - } else { - v->iov_base = "\n"; - v->iov_len = 1; - } - again: /* f->f_file == -1 is an indicator that the we couldn't open the file at startup. */ - if (f->f_file == -1) - break; - - if (writev(f->f_file, iov, 6) < 0) { - int e = errno; - - /* If a named pipe is full, just ignore it for now - - mrn 24 May 96 */ - if (f->f_type == F_PIPE && e == EAGAIN) - break; - - (void) close(f->f_file); - /* - * Check for EBADF on TTY's due to vhangup() XXX - * Linux uses EIO instead (mrn 12 May 96) - */ - if ((f->f_type == F_TTY || f->f_type == F_CONSOLE) -#ifdef linux - && e == EIO) { -#else - && e == EBADF) { -#endif - f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND|O_NOCTTY); - if (f->f_file < 0) { - f->f_type = F_UNUSED; - logerror(f->f_un.f_fname); - } else { - untty(); - goto again; - } - } else { - f->f_type = F_UNUSED; - errno = e; - logerror(f->f_un.f_fname); - } - } else if (f->f_flags & SYNC_FILE) - (void) fsync(f->f_file); -#endif + if (f->f_file != -1) + writeFile(f); break; case F_USERS: @@ -3428,6 +3365,10 @@ void init() */ fprintlog(f, 0); + /* free iovec if it was allocated */ + if(f->f_iov != NULL) + free(f->f_iov); + switch (f->f_type) { case F_FILE: case F_PIPE: @@ -3646,6 +3587,72 @@ void init() }}} /* balance parentheses for emacs */ #endif +/* Helper to cfline(). Parses a file name up until the first + * comma and then looks for the template specifier. Tries + * to find that template. Everything is stored in the + * filed struct. + * rgerhards 2004-11-18 + */ +void cflineParseFileName(struct filed *f, register char* p) +{ + register char *pName; + int i; + char szTemplateName[128]; /* should be more than sufficient */ + + if(*p == '|') { + f->f_type = F_PIPE; + ++p; + } else { + f->f_type = F_FILE; + } + + pName = f->f_un.f_fname; + i = 0; + while(*p && *p != ',' && i < MAXFNAME - 1) { + *pName++ = *p++; + ++i; + } + *pName = '\0'; + + /* got the file name - now let's look for the template to use + * Just as a general precaution, we skip whitespace. + */ + while(*p && isspace(*p)) + ++p; + if(*p == ',') + ++p; /* eat it */ + while(*p && isspace(*p)) + ++p; + + pName = szTemplateName; + i = 0; + while(*p && i < sizeof(szTemplateName) / sizeof(char) - 1) { + *pName++ = *p++; + ++i; + } + *pName = '\0'; + + /* Ok, we got everything, so it now is time to look up the + * template (Hint: templates MUST be defined before they are + * used!) and initialize the pointer to it PLUS the iov + * pointer. We do the later because the template tells us + * how many elements iov must have - and this can never change. + */ + if((f->f_pTpl = tplFind(szTemplateName, i)) == NULL) { + dprintf("Could not find template '%s'\n", szTemplateName); + f->f_type = F_UNUSED; + } else { + if((f->f_iov = calloc(tplGetEntryCount(f->f_pTpl), + sizeof(struct iovec))) == NULL) { + dprintf("Could not allocate iovec memory for file '%s'\n", f->f_un.f_fname); + f->f_type = F_UNUSED; + } + } + + dprintf("filename: '%s', template: '%s'\n", f->f_un.f_fname, szTemplateName); +} + + /* * Crack a configuration file line * rgerhards 2004-11-17: well, I somewhat changed this function. It now does NOT @@ -3654,10 +3661,9 @@ void init() * with "$" have been filtered out by the caller and are passed to another function. * Please note, however, that I needed to make changes in the line syntax to support * assignment of format definitions to a file. So it is not (yet) 100% transparent. - * Eventually, we can overcome this limitation by prfexing the actual acton indicator + * Eventually, we can overcome this limitation by prefixing the actual action indicator * (e.g. "/file..") by something (e.g. "$/file..") - but for now, we just modify it... */ - void cfline(line, f) char *line; register struct filed *f; @@ -3854,23 +3860,25 @@ void cfline(line, f) case '|': case '/': - (void) strcpy(f->f_un.f_fname, p); - dprintf ("filename: %s\n", p); /*ASP*/ + /* rgerhards 2004-11-17: from now, we need to have different + * processing, because after the first comma, the template name + * to use is specified. So we need to scan for the first coma first + * and then look at the rest of the line. + */ + cflineParseFileName(f, p); if (syncfile) f->f_flags |= SYNC_FILE; - if ( *p == '|' ) { - f->f_file = open(++p, O_RDWR|O_NONBLOCK); - f->f_type = F_PIPE; + if (f->f_type == F_PIPE) { + f->f_file = open(f->f_un.f_fname, O_RDWR|O_NONBLOCK); } else { - f->f_file = open(p, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, + f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, 0644); - f->f_type = F_FILE; } if ( f->f_file < 0 ){ f->f_file = -1; - dprintf("Error opening log file: %s\n", p); - logerror(p); + dprintf("Error opening log file: %s\n", f->f_un.f_fname); + logerror(f->f_un.f_fname); break; } if (isatty(f->f_file)) { diff --git a/template.c b/template.c index b3c5853a..3b0f3d16 100644 --- a/template.c +++ b/template.c @@ -167,7 +167,7 @@ static int do_Parameter(char **pp, struct template *pTpl) return 1; } pTpe->eEntryType = FIELD; - pTpe->data.pPropRepl = sbStrBFinish(pStrB); + pTpe->data.field.pPropRepl = sbStrBFinish(pStrB); *pp = p; return 0; @@ -292,7 +292,7 @@ void tplPrintList(void) dprintf("Template: Name='%s'\n", pTpl->pszName == NULL? "NULL" : pTpl->pszName); pTpe = pTpl->pEntryRoot; while(pTpe != NULL) { - dprintf("\tEntry: type %d, ", pTpe->eEntryType); + dprintf("\tEntry(%x): type %d, ", (unsigned) pTpe, pTpe->eEntryType); switch(pTpe->eEntryType) { case UNDEFINED: dprintf("(UNDEFINED)\n"); @@ -302,7 +302,7 @@ void tplPrintList(void) pTpe->data.constant.pConstant); break; case FIELD: - dprintf("(FIELD), value: '%s'\n", pTpe->data.pPropRepl); + dprintf("(FIELD), value: '%s'\n", pTpe->data.field.pPropRepl); break; } pTpe = pTpe->pNext; diff --git a/template.h b/template.h index a3019828..604c317b 100644 --- a/template.h +++ b/template.h @@ -23,7 +23,9 @@ struct templateEntry { char *pConstant; /* pointer to constant value */ int iLenConstant; /* its length */ } constant; - char *pPropRepl; /* pointer to property replacer string */ + struct { + char *pPropRepl; /* pointer to property replacer string */ + } field; } data; }; -- cgit v1.2.3