Merge branch 'v5-stable-elasticsearch' into v5-devel-tmp
[rsyslog.git] / outchannel.c
1 /* This is the output channel processing code of rsyslog.
2  * Output channels - in the long term - will define how
3  * messages will be sent to whatever file or other medium.
4  * Currently, they mainly provide a way to store some file-related
5  * information (most importantly the maximum file size allowed).
6  * Please see syslogd.c for license information.
7  * begun 2005-06-21 rgerhards
8  *
9  * Copyright (C) 2005-2012 Adiscon GmbH
10  *
11  * This file is part of rsyslog.
12  *
13  * Licensed under the Apache License, Version 2.0 (the "License");
14  * you may not use this file except in compliance with the License.
15  * You may obtain a copy of the License at
16  * 
17  *       http://www.apache.org/licenses/LICENSE-2.0
18  *       -or-
19  *       see COPYING.ASL20 in the source distribution
20  * 
21  * Unless required by applicable law or agreed to in writing, software
22  * distributed under the License is distributed on an "AS IS" BASIS,
23  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24  * See the License for the specific language governing permissions and
25  * limitations under the License.
26  */
27 #include "config.h"
28
29 #include "rsyslog.h"
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <assert.h>
36 #include "stringbuf.h"
37 #include "outchannel.h"
38 #include "dirty.h"
39 #include "debug.h"
40
41 static struct outchannel *ochRoot = NULL;       /* the root of the outchannel list */
42 static struct outchannel *ochLast = NULL;       /* points to the last element of the outchannel list */
43
44 /* Constructs a outchannel list object. Returns pointer to it
45  * or NULL (if it fails).
46  */
47 struct outchannel* ochConstruct(void)
48 {
49         struct outchannel *pOch;
50         if((pOch = calloc(1, sizeof(struct outchannel))) == NULL)
51                 return NULL;
52         
53         /* basic initialisaion is done via calloc() - need to
54          * initialize only values != 0. */
55
56         if(ochLast == NULL)
57         { /* we are the first element! */
58                 ochRoot = ochLast = pOch;
59         }
60         else
61         {
62                 ochLast->pNext = pOch;
63                 ochLast = pOch;
64         }
65
66         return(pOch);
67 }
68
69
70 /* skips the next comma and any whitespace
71  * in front and after it.
72  */
73 static void skip_Comma(char **pp)
74 {
75         register char *p;
76
77         assert(pp != NULL);
78         assert(*pp != NULL);
79
80         p = *pp;
81         while(isspace((int)*p))
82                 ++p;
83         if(*p == ',')
84                 ++p;
85         while(isspace((int)*p))
86                 ++p;
87         *pp = p;
88 }
89
90 /* helper to ochAddLine. Parses a comma-delimited field
91  * The field is delimited by SP or comma. Leading whitespace
92  * is "eaten" and does not become part of the field content.
93  */
94 static rsRetVal get_Field(uchar **pp, uchar **pField)
95 {
96         DEFiRet;
97         register uchar *p;
98         cstr_t *pStrB = NULL;
99
100         assert(pp != NULL);
101         assert(*pp != NULL);
102         assert(pField != NULL);
103
104         skip_Comma((char**)pp);
105         p = *pp;
106
107         CHKiRet(cstrConstruct(&pStrB));
108
109         /* copy the field */
110         while(*p && *p != ' ' && *p != ',') {
111                 CHKiRet(cstrAppendChar(pStrB, *p++));
112         }
113
114         *pp = p;
115         CHKiRet(cstrFinalize(pStrB));
116         CHKiRet(cstrConvSzStrAndDestruct(pStrB, pField, 0));
117
118 finalize_it:
119         if(iRet != RS_RET_OK) {
120                 if(pStrB != NULL)
121                         cstrDestruct(&pStrB);
122         }
123
124         RETiRet;
125 }
126
127
128 /* helper to ochAddLine. Parses a off_t type from the
129  * input line.
130  * returns: 0 - ok, 1 - failure
131  */
132 static int get_off_t(uchar **pp, off_t *pOff_t)
133 {
134         register uchar *p;
135         off_t val;
136
137         assert(pp != NULL);
138         assert(*pp != NULL);
139         assert(pOff_t != NULL);
140
141         skip_Comma((char**)pp);
142         p = *pp;
143
144         val = 0;
145         while(*p && isdigit((int)*p)) {
146                 val = val * 10 + (*p - '0');
147                 ++p;
148         }
149
150         *pp = p;
151         *pOff_t = val;
152
153         return 0;
154 }
155
156
157 /* helper to ochAddLine. Parses everything from the
158  * current position to the end of line and returns it
159  * to the caller. Leading white space is removed, but
160  * not trailing.
161  */
162 static inline rsRetVal get_restOfLine(uchar **pp, uchar **pBuf)
163 {
164         DEFiRet;
165         register uchar *p;
166         cstr_t *pStrB = NULL;
167
168         assert(pp != NULL);
169         assert(*pp != NULL);
170         assert(pBuf != NULL);
171
172         skip_Comma((char**)pp);
173         p = *pp;
174
175         CHKiRet(cstrConstruct(&pStrB));
176
177         /* copy the field */
178         while(*p) {
179                 CHKiRet(cstrAppendChar(pStrB, *p++));
180         }
181
182         *pp = p;
183         CHKiRet(cstrFinalize(pStrB));
184         CHKiRet(cstrConvSzStrAndDestruct(pStrB, pBuf, 0));
185
186 finalize_it:
187         if(iRet != RS_RET_OK) {
188                 if(pStrB != NULL)
189                         cstrDestruct(&pStrB);
190         }
191
192         RETiRet;
193 }
194
195
196 /* Add a new outchannel line
197  * returns pointer to new object if it succeeds, NULL otherwise.
198  * An outchannel line is primarily a set of fields delemited by commas.
199  * There might be some whitespace between the field (but not within)
200  * and the commas. This can be removed.
201  */
202 struct outchannel *ochAddLine(char* pName, uchar** ppRestOfConfLine)
203 {
204         struct outchannel *pOch;
205         uchar *p;
206
207         assert(pName != NULL);
208         assert(ppRestOfConfLine != NULL);
209
210         if((pOch = ochConstruct()) == NULL)
211                 return NULL;
212         
213         pOch->iLenName = strlen(pName);
214         pOch->pszName = (char*) MALLOC(sizeof(char) * (pOch->iLenName + 1));
215         if(pOch->pszName == NULL) {
216                 dbgprintf("ochAddLine could not alloc memory for outchannel name!");
217                 pOch->iLenName = 0;
218                 return NULL;
219                 /* I know - we create a memory leak here - but I deem
220                  * it acceptable as it is a) a very small leak b) very
221                  * unlikely to happen. rgerhards 2004-11-17
222                  */
223         }
224         memcpy(pOch->pszName, pName, pOch->iLenName + 1);
225
226         /* now actually parse the line */
227         p = *ppRestOfConfLine;
228         assert(p != NULL);
229
230         /* get params */
231         get_Field(&p, &pOch->pszFileTemplate);
232         if(*p) get_off_t(&p, &pOch->uSizeLimit);
233         if(*p) get_restOfLine(&p, &pOch->cmdOnSizeLimit);
234
235         *ppRestOfConfLine = p;
236         return(pOch);
237 }
238
239
240 /* Find a outchannel object based on name. Search
241  * currently is case-senstive (should we change?).
242  * returns pointer to outchannel object if found and
243  * NULL otherwise.
244  * rgerhards 2004-11-17
245  */
246 struct outchannel *ochFind(char *pName, int iLenName)
247 {
248         struct outchannel *pOch;
249
250         assert(pName != NULL);
251
252         pOch = ochRoot;
253         while(pOch != NULL &&
254               !(pOch->iLenName == iLenName &&
255                 !strcmp(pOch->pszName, pName)
256                 ))
257                 {
258                         pOch = pOch->pNext;
259                 }
260         return(pOch);
261 }
262
263 /* Destroy the outchannel structure. This is for de-initialization
264  * at program end. Everything is deleted.
265  * rgerhards 2005-02-22
266  */
267 void ochDeleteAll(void)
268 {
269         struct outchannel *pOch, *pOchDel;
270
271         pOch = ochRoot;
272         while(pOch != NULL) {
273                 dbgprintf("Delete Outchannel: Name='%s'\n ", pOch->pszName == NULL? "NULL" : pOch->pszName);
274                 pOchDel = pOch;
275                 pOch = pOch->pNext;
276                 if(pOchDel->pszName != NULL)
277                         free(pOchDel->pszName);
278                 free(pOchDel);
279         }
280 }
281
282
283 /* Print the outchannel structure. This is more or less a 
284  * debug or test aid, but anyhow I think it's worth it...
285  */
286 void ochPrintList(void)
287 {
288         struct outchannel *pOch;
289
290         pOch = ochRoot;
291         while(pOch != NULL) {
292                 dbgprintf("Outchannel: Name='%s'\n", pOch->pszName == NULL? "NULL" : pOch->pszName);
293                 dbgprintf("\tFile Template: '%s'\n", pOch->pszFileTemplate == NULL ? "NULL" : (char*) pOch->pszFileTemplate);
294                 dbgprintf("\tMax Size.....: %lu\n", (long unsigned) pOch->uSizeLimit);
295                 dbgprintf("\tOnSizeLimtCmd: '%s'\n", pOch->cmdOnSizeLimit == NULL ? "NULL" : (char*) pOch->cmdOnSizeLimit);
296                 pOch = pOch->pNext; /* done, go next */
297         }
298 }
299 /* vi:set ai:
300  */