/* This is the output channel processing code of rsyslog.
* Output channels - in the long term - will define how
* messages will be sent to whatever file or other medium.
* Currently, they mainly provide a way to store some file-related
* information (most importantly the maximum file size allowed).
* Please see syslogd.c for license information.
* This code is placed under the GPL.
* begun 2005-06-21 rgerhards
*
* Copyright (C) 2005 by 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 "stringbuf.h"
#include "outchannel.h"
#include "dirty.h"
static struct outchannel *ochRoot = NULL; /* the root of the outchannel list */
static struct outchannel *ochLast = NULL; /* points to the last element of the outchannel list */
/* Constructs a outchannel list object. Returns pointer to it
* or NULL (if it fails).
*/
struct outchannel* ochConstruct(void)
{
struct outchannel *pOch;
if((pOch = calloc(1, sizeof(struct outchannel))) == NULL)
return NULL;
/* basic initialisaion is done via calloc() - need to
* initialize only values != 0. */
if(ochLast == NULL)
{ /* we are the first element! */
ochRoot = ochLast = pOch;
}
else
{
ochLast->pNext = pOch;
ochLast = pOch;
}
return(pOch);
}
/* skips the next comma and any whitespace
* in front and after it.
*/
static void skip_Comma(char **pp)
{
register char *p;
assert(pp != NULL);
assert(*pp != NULL);
p = *pp;
while(isspace((int)*p))
++p;
if(*p == ',')
++p;
while(isspace((int)*p))
++p;
*pp = p;
}
/* helper to ochAddLine. Parses a comma-delimited field
* The field is delimited by SP or comma. Leading whitespace
* is "eaten" and does not become part of the field content.
*/
static rsRetVal get_Field(uchar **pp, uchar **pField)
{
DEFiRet;
register uchar *p;
cstr_t *pStrB = NULL;
assert(pp != NULL);
assert(*pp != NULL);
assert(pField != NULL);
skip_Comma((char**)pp);
p = *pp;
CHKiRet(rsCStrConstruct(&pStrB));
rsCStrSetAllocIncrement(pStrB, 32);
/* copy the field */
while(*p && *p != ' ' && *p != ',') {
CHKiRet(rsCStrAppendChar(pStrB, *p++));
}
*pp = p;
CHKiRet(rsCStrFinish(pStrB));
CHKiRet(rsCStrConvSzStrAndDestruct(pStrB, pField, 0));
finalize_it:
if(iRet != RS_RET_OK) {
if(pStrB != NULL)
rsCStrDestruct(&pStrB);
}
RETiRet;
}
/* helper to ochAddLine. Parses a off_t type from the
* input line.
* returns: 0 - ok, 1 - failure
*/
static int get_off_t(uchar **pp, off_t *pOff_t)
{
register uchar *p;
off_t val;
assert(pp != NULL);
assert(*pp != NULL);
assert(pOff_t != NULL);
skip_Comma((char**)pp);
p = *pp;
val = 0;
while(*p && isdigit((int)*p)) {
val = val * 10 + (*p - '0');
++p;
}
*pp = p;
*pOff_t = val;
return 0;
}
/* helper to ochAddLine. Parses everything from the
* current position to the end of line and returns it
* to the caller. Leading white space is removed, but
* not trailing.
*/
static inline rsRetVal get_restOfLine(uchar **pp, uchar **pBuf)
{
DEFiRet;
register uchar *p;
cstr_t *pStrB = NULL;
assert(pp != NULL);
assert(*pp != NULL);
assert(pBuf != NULL);
skip_Comma((char**)pp);
p = *pp;
CHKiRet(rsCStrConstruct(&pStrB));
rsCStrSetAllocIncrement(pStrB, 32);
/* copy the field */
while(*p) {
CHKiRet(rsCStrAppendChar(pStrB, *p++));
}
*pp = p;
CHKiRet(rsCStrFinish(pStrB));
CHKiRet(rsCStrConvSzStrAndDestruct(pStrB, pBuf, 0));
finalize_it:
if(iRet != RS_RET_OK) {
if(pStrB != NULL)
rsCStrDestruct(&pStrB);
}
RETiRet;
}
/* Add a new outchannel line
* returns pointer to new object if it succeeds, NULL otherwise.
* An outchannel line is primarily a set of fields delemited by commas.
* There might be some whitespace between the field (but not within)
* and the commas. This can be removed.
*/
struct outchannel *ochAddLine(char* pName, uchar** ppRestOfConfLine)
{
struct outchannel *pOch;
uchar *p;
assert(pName != NULL);
assert(ppRestOfConfLine != NULL);
if((pOch = ochConstruct()) == NULL)
return NULL;
pOch->iLenName = strlen(pName);
pOch->pszName = (char*) malloc(sizeof(char) * (pOch->iLenName + 1));
if(pOch->pszName == NULL) {
dbgprintf("ochAddLine could not alloc memory for outchannel name!");
pOch->iLenName = 0;
return NULL;
/* I know - we create a memory leak here - but I deem
* it acceptable as it is a) a very small leak b) very
* unlikely to happen. rgerhards 2004-11-17
*/
}
memcpy(pOch->pszName, pName, pOch->iLenName + 1);
/* now actually parse the line */
p = *ppRestOfConfLine;
assert(p != NULL);
/* get params */
get_Field(&p, &pOch->pszFileTemplate);
if(*p) get_off_t(&p, &pOch->uSizeLimit);
if(*p) get_restOfLine(&p, &pOch->cmdOnSizeLimit);
*ppRestOfConfLine = p;
return(pOch);
}
/* Find a outchannel object based on name. Search
* currently is case-senstive (should we change?).
* returns pointer to outchannel object if found and
* NULL otherwise.
* rgerhards 2004-11-17
*/
struct outchannel *ochFind(char *pName, int iLenName)
{
struct outchannel *pOch;
assert(pName != NULL);
pOch = ochRoot;
while(pOch != NULL &&
!(pOch->iLenName == iLenName &&
!strcmp(pOch->pszName, pName)
))
{
pOch = pOch->pNext;
}
return(pOch);
}
/* Destroy the outchannel structure. This is for de-initialization
* at program end. Everything is deleted.
* rgerhards 2005-02-22
*/
void ochDeleteAll(void)
{
struct outchannel *pOch, *pOchDel;
pOch = ochRoot;
while(pOch != NULL) {
dbgprintf("Delete Outchannel: Name='%s'\n ", pOch->pszName == NULL? "NULL" : pOch->pszName);
pOchDel = pOch;
pOch = pOch->pNext;
if(pOchDel->pszName != NULL)
free(pOchDel->pszName);
free(pOchDel);
}
}
/* Print the outchannel structure. This is more or less a
* debug or test aid, but anyhow I think it's worth it...
*/
void ochPrintList(void)
{
struct outchannel *pOch;
pOch = ochRoot;
while(pOch != NULL) {
dbgprintf("Outchannel: Name='%s'\n", pOch->pszName == NULL? "NULL" : pOch->pszName);
dbgprintf("\tFile Template: '%s'\n", pOch->pszFileTemplate == NULL ? "NULL" : (char*) pOch->pszFileTemplate);
dbgprintf("\tMax Size.....: %lu\n", (long unsigned) pOch->uSizeLimit);
dbgprintf("\tOnSizeLimtCmd: '%s'\n", pOch->cmdOnSizeLimit == NULL ? "NULL" : (char*) pOch->cmdOnSizeLimit);
pOch = pOch->pNext; /* done, go next */
}
}
/* vi:set ai:
*/