~ubuntu-branches/ubuntu/lucid/rsyslog/lucid

« back to all changes in this revision

Viewing changes to omfile.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2007-10-19 17:21:49 UTC
  • Revision ID: james.westby@ubuntu.com-20071019172149-ie6ej2xve33mxiu7
Tags: upstream-1.19.10
ImportĀ upstreamĀ versionĀ 1.19.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* omfile.c
 
2
 * This is the implementation of the build-in file output module.
 
3
 *
 
4
 * Handles: eTypeCONSOLE, eTypeTTY, eTypeFILE, eTypePIPE
 
5
 *
 
6
 * NOTE: read comments in module-template.h to understand how this file
 
7
 *       works!
 
8
 *
 
9
 * File begun on 2007-07-21 by RGerhards (extracted from syslogd.c)
 
10
 * This file is under development and has not yet arrived at being fully
 
11
 * self-contained and a real object. So far, it is mostly an excerpt
 
12
 * of the "old" message code without any modifications. However, it
 
13
 * helps to have things at the right place one we go to the meat of it.
 
14
 *
 
15
 * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
 
16
 *
 
17
 * This program is free software; you can redistribute it and/or
 
18
 * modify it under the terms of the GNU General Public License
 
19
 * as published by the Free Software Foundation; either version 2
 
20
 * of the License, or (at your option) any later version.
 
21
 *
 
22
 * This program is distributed in the hope that it will be useful,
 
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
25
 * GNU General Public License for more details.
 
26
 *
 
27
 * You should have received a copy of the GNU General Public License
 
28
 * along with this program; if not, write to the Free Software
 
29
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
30
 *
 
31
 * A copy of the GPL can be found in the file "COPYING" in this distribution.
 
32
 */
 
33
#include "config.h"
 
34
#include "rsyslog.h"
 
35
#include <stdio.h>
 
36
#include <stdarg.h>
 
37
#include <stdlib.h>
 
38
#include <string.h>
 
39
#include <time.h>
 
40
#include <assert.h>
 
41
#include <errno.h>
 
42
#include <ctype.h>
 
43
#include <unistd.h>
 
44
#include <sys/file.h>
 
45
 
 
46
#include "syslogd.h"
 
47
#include "syslogd-types.h"
 
48
#include "srUtils.h"
 
49
#include "template.h"
 
50
#include "outchannel.h"
 
51
#include "omfile.h"
 
52
#include "cfsysline.h"
 
53
#include "module-template.h"
 
54
 
 
55
/* internal structures
 
56
 */
 
57
DEF_OMOD_STATIC_DATA
 
58
 
 
59
/* The following structure is a dynafile name cache entry.
 
60
 */
 
61
struct s_dynaFileCacheEntry {
 
62
        uchar *pName;   /* name currently open, if dynamic name */
 
63
        short   fd;             /* name associated with file name in cache */
 
64
        time_t  lastUsed;       /* for LRU - last access */
 
65
};
 
66
typedef struct s_dynaFileCacheEntry dynaFileCacheEntry;
 
67
 
 
68
 
 
69
/* globals for default values */
 
70
static int iDynaFileCacheSize = 10; /* max cache for dynamic files */
 
71
static int fCreateMode = 0644; /* mode to use when creating files */
 
72
static int fDirCreateMode = 0644; /* mode to use when creating files */
 
73
static int      bFailOnChown;   /* fail if chown fails? */
 
74
static uid_t    fileUID;        /* UID to be used for newly created files */
 
75
static uid_t    fileGID;        /* GID to be used for newly created files */
 
76
static uid_t    dirUID;         /* UID to be used for newly created directories */
 
77
static uid_t    dirGID;         /* GID to be used for newly created directories */
 
78
static int      bCreateDirs;    /* auto-create directories for dynaFiles: 0 - no, 1 - yes */
 
79
/* end globals for default values */
 
80
 
 
81
typedef struct _instanceData {
 
82
        uchar   f_fname[MAXFNAME];/* file or template name (display only) */
 
83
        short   fd;               /* file descriptor for (current) file */
 
84
        enum {
 
85
                eTypeFILE,
 
86
                eTypeTTY,
 
87
                eTypeCONSOLE,
 
88
                eTypePIPE
 
89
        } fileType;     
 
90
        struct template *pTpl;  /* pointer to template object */
 
91
        char    bDynamicName;   /* 0 - static name, 1 - dynamic name (with properties) */
 
92
        int     fCreateMode;    /* file creation mode for open() */
 
93
        int     fDirCreateMode; /* creation mode for mkdir() */
 
94
        int     bCreateDirs;    /* auto-create directories? */
 
95
        int     bSyncFile;      /* should the file by sync()'ed? 1- yes, 0- no */
 
96
        uid_t   fileUID;        /* IDs for creation */
 
97
        uid_t   dirUID;
 
98
        gid_t   fileGID;
 
99
        gid_t   dirGID;
 
100
        int     bFailOnChown;   /* fail creation if chown fails? */
 
101
        int     iCurrElt;       /* currently active cache element (-1 = none) */
 
102
        int     iCurrCacheSize; /* currently cache size (1-based) */
 
103
        int     iDynaFileCacheSize; /* size of file handle cache */
 
104
        /* The cache is implemented as an array. An empty element is indicated
 
105
         * by a NULL pointer. Memory is allocated as needed. The following
 
106
         * pointer points to the overall structure.
 
107
         */
 
108
        dynaFileCacheEntry **dynCache;
 
109
        off_t   f_sizeLimit;            /* file size limit, 0 = no limit */
 
110
        char    *f_sizeLimitCmd;        /* command to carry out when size limit is reached */
 
111
} instanceData;
 
112
 
 
113
 
 
114
BEGINisCompatibleWithFeature
 
115
CODESTARTisCompatibleWithFeature
 
116
        if(eFeat == sFEATURERepeatedMsgReduction)
 
117
                iRet = RS_RET_OK;
 
118
ENDisCompatibleWithFeature
 
119
 
 
120
 
 
121
BEGINdbgPrintInstInfo
 
122
CODESTARTdbgPrintInstInfo
 
123
        if(pData->bDynamicName) {
 
124
                printf("[dynamic]\n\ttemplate='%s'"
 
125
                       "\tfile cache size=%d\n"
 
126
                       "\tcreate directories: %s\n"
 
127
                       "\tfile owner %d, group %d\n"
 
128
                       "\tdirectory owner %d, group %d\n"
 
129
                       "\tfail if owner/group can not be set: %s\n",
 
130
                        pData->f_fname,
 
131
                        pData->iDynaFileCacheSize,
 
132
                        pData->bCreateDirs ? "yes" : "no",
 
133
                        pData->fileUID, pData->fileGID,
 
134
                        pData->dirUID, pData->dirGID,
 
135
                        pData->bFailOnChown ? "yes" : "no"
 
136
                        );
 
137
        } else { /* regular file */
 
138
                printf("%s", pData->f_fname);
 
139
                if (pData->fd == -1)
 
140
                        printf(" (unused)");
 
141
        }
 
142
ENDdbgPrintInstInfo
 
143
 
 
144
 
 
145
/* set the dynaFile cache size. Does some limit checking.
 
146
 * rgerhards, 2007-07-31
 
147
 */
 
148
rsRetVal setDynaFileCacheSize(void __attribute__((unused)) *pVal, int iNewVal)
 
149
{
 
150
        DEFiRet;
 
151
        uchar errMsg[128];      /* for dynamic error messages */
 
152
 
 
153
        if(iNewVal < 1) {
 
154
                snprintf((char*) errMsg, sizeof(errMsg)/sizeof(uchar),
 
155
                         "DynaFileCacheSize must be greater 0 (%d given), changed to 1.", iNewVal);
 
156
                errno = 0;
 
157
                logerror((char*) errMsg);
 
158
                iRet = RS_RET_VAL_OUT_OF_RANGE;
 
159
                iNewVal = 1;
 
160
        } else if(iNewVal > 10000) {
 
161
                snprintf((char*) errMsg, sizeof(errMsg)/sizeof(uchar),
 
162
                         "DynaFileCacheSize maximum is 10,000 (%d given), changed to 10,000.", iNewVal);
 
163
                errno = 0;
 
164
                logerror((char*) errMsg);
 
165
                iRet = RS_RET_VAL_OUT_OF_RANGE;
 
166
                iNewVal = 10000;
 
167
        }
 
168
 
 
169
        iDynaFileCacheSize = iNewVal;
 
170
        dbgprintf("DynaFileCacheSize changed to %d.\n", iNewVal);
 
171
 
 
172
        return iRet;
 
173
}
 
174
 
 
175
 
 
176
/* Helper to cfline(). Parses a output channel name up until the first
 
177
 * comma and then looks for the template specifier. Tries
 
178
 * to find that template. Maps the output channel to the 
 
179
 * proper filed structure settings. Everything is stored in the
 
180
 * filed struct. Over time, the dependency on filed might be
 
181
 * removed.
 
182
 * rgerhards 2005-06-21
 
183
 */
 
184
static rsRetVal cflineParseOutchannel(instanceData *pData, uchar* p, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts)
 
185
{
 
186
        DEFiRet;
 
187
        size_t i;
 
188
        struct outchannel *pOch;
 
189
        char szBuf[128];        /* should be more than sufficient */
 
190
 
 
191
        /* this must always be a file, because we can not set a size limit
 
192
         * on a pipe...
 
193
         * rgerhards 2005-06-21: later, this will be a separate type, but let's
 
194
         * emulate things for the time being. When everything runs, we can
 
195
         * extend it...
 
196
         */
 
197
        pData->fileType = eTypeFILE;
 
198
 
 
199
        ++p; /* skip '$' */
 
200
        i = 0;
 
201
        /* get outchannel name */
 
202
        while(*p && *p != ';' && *p != ' ' &&
 
203
              i < sizeof(szBuf) / sizeof(char)) {
 
204
              szBuf[i++] = *p++;
 
205
        }
 
206
        szBuf[i] = '\0';
 
207
 
 
208
        /* got the name, now look up the channel... */
 
209
        pOch = ochFind(szBuf, i);
 
210
 
 
211
        if(pOch == NULL) {
 
212
                char errMsg[128];
 
213
                errno = 0;
 
214
                snprintf(errMsg, sizeof(errMsg)/sizeof(char),
 
215
                         "outchannel '%s' not found - ignoring action line",
 
216
                         szBuf);
 
217
                logerror(errMsg);
 
218
                return RS_RET_NOT_FOUND;
 
219
        }
 
220
 
 
221
        /* check if there is a file name in the outchannel... */
 
222
        if(pOch->pszFileTemplate == NULL) {
 
223
                char errMsg[128];
 
224
                errno = 0;
 
225
                snprintf(errMsg, sizeof(errMsg)/sizeof(char),
 
226
                         "outchannel '%s' has no file name template - ignoring action line",
 
227
                         szBuf);
 
228
                logerror(errMsg);
 
229
                return RS_RET_ERR;
 
230
        }
 
231
 
 
232
        /* OK, we finally got a correct template. So let's use it... */
 
233
        strncpy((char*) pData->f_fname, (char*) pOch->pszFileTemplate, MAXFNAME);
 
234
        pData->f_sizeLimit = pOch->uSizeLimit;
 
235
        /* WARNING: It is dangerous "just" to pass the pointer. As we
 
236
         * never rebuild the output channel description, this is acceptable here.
 
237
         */
 
238
        pData->f_sizeLimitCmd = (char*) pOch->cmdOnSizeLimit;
 
239
 
 
240
        iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, (uchar*) " TradFmt");
 
241
 
 
242
        return(iRet);
 
243
}
 
244
 
 
245
 
 
246
/* rgerhards 2005-06-21: Try to resolve a size limit
 
247
 * situation. This first runs the command, and then
 
248
 * checks if we are still above the treshold.
 
249
 * returns 0 if ok, 1 otherwise
 
250
 * TODO: consider moving the initial check in here, too
 
251
 */
 
252
int resolveFileSizeLimit(instanceData *pData)
 
253
{
 
254
        uchar *pParams;
 
255
        uchar *pCmd;
 
256
        uchar *p;
 
257
        off_t actualFileSize;
 
258
        assert(pData != NULL);
 
259
 
 
260
        if(pData->f_sizeLimitCmd == NULL)
 
261
                return 1; /* nothing we can do in this case... */
 
262
        
 
263
        /* the execProg() below is probably not great, but at least is is
 
264
         * fairly secure now. Once we change the way file size limits are
 
265
         * handled, we should also revisit how this command is run (and
 
266
         * with which parameters).   rgerhards, 2007-07-20
 
267
         */
 
268
        /* we first check if we have command line parameters. We assume this, 
 
269
         * when we have a space in the program name. If we find it, everything after
 
270
         * the space is treated as a single argument.
 
271
         */
 
272
        if((pCmd = (uchar*)strdup((char*)pData->f_sizeLimitCmd)) == NULL) {
 
273
                /* there is not much we can do - we make syslogd close the file in this case */
 
274
                glblHadMemShortage = 1;
 
275
                return 1;
 
276
                }
 
277
 
 
278
        for(p = pCmd ; *p && *p != ' ' ; ++p) {
 
279
                /* JUST SKIP */
 
280
        }
 
281
 
 
282
        if(*p == ' ') {
 
283
                *p = '\0'; /* pretend string-end */
 
284
                pParams = p+1;
 
285
        } else
 
286
                pParams = NULL;
 
287
 
 
288
        execProg(pCmd, 1, pParams);
 
289
 
 
290
        pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY,
 
291
                        pData->fCreateMode);
 
292
 
 
293
        actualFileSize = lseek(pData->fd, 0, SEEK_END);
 
294
        if(actualFileSize >= pData->f_sizeLimit) {
 
295
                /* OK, it didn't work out... */
 
296
                return 1;
 
297
                }
 
298
 
 
299
        return 0;
 
300
}
 
301
 
 
302
 
 
303
/* This function deletes an entry from the dynamic file name
 
304
 * cache. A pointer to the cache must be passed in as well
 
305
 * as the index of the to-be-deleted entry. This index may
 
306
 * point to an unallocated entry, in whcih case the
 
307
 * function immediately returns. Parameter bFreeEntry is 1
 
308
 * if the entry should be free()ed and 0 if not.
 
309
 */
 
310
static void dynaFileDelCacheEntry(dynaFileCacheEntry **pCache, int iEntry, int bFreeEntry)
 
311
{
 
312
        assert(pCache != NULL);
 
313
 
 
314
        if(pCache[iEntry] == NULL)
 
315
                return;
 
316
 
 
317
        dbgprintf("Removed entry %d for file '%s' from dynaCache.\n", iEntry,
 
318
                pCache[iEntry]->pName == NULL ? "[OPEN FAILED]" : (char*)pCache[iEntry]->pName);
 
319
        /* if the name is NULL, this is an improperly initilized entry which
 
320
         * needs to be discarded. In this case, neither the file is to be closed
 
321
         * not the name to be freed.
 
322
         */
 
323
        if(pCache[iEntry]->pName != NULL) {
 
324
                close(pCache[iEntry]->fd);
 
325
                free(pCache[iEntry]->pName);
 
326
                pCache[iEntry]->pName = NULL;
 
327
        }
 
328
 
 
329
        if(bFreeEntry) {
 
330
                free(pCache[iEntry]);
 
331
                pCache[iEntry] = NULL;
 
332
        }
 
333
}
 
334
 
 
335
 
 
336
/* This function frees the dynamic file name cache.
 
337
 */
 
338
static void dynaFileFreeCache(instanceData *pData)
 
339
{
 
340
        register int i;
 
341
        assert(pData != NULL);
 
342
 
 
343
        for(i = 0 ; i < pData->iCurrCacheSize ; ++i) {
 
344
                dynaFileDelCacheEntry(pData->dynCache, i, 1);
 
345
        }
 
346
 
 
347
        free(pData->dynCache);
 
348
}
 
349
 
 
350
 
 
351
/* This is a shared code for both static and dynamic files.
 
352
 */
 
353
static void prepareFile(instanceData *pData, uchar *newFileName)
 
354
{
 
355
        if(access((char*)newFileName, F_OK) == 0) {
 
356
                /* file already exists */
 
357
                pData->fd = open((char*) newFileName, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY,
 
358
                                pData->fCreateMode);
 
359
        } else {
 
360
                /* file does not exist, create it (and eventually parent directories */
 
361
                if(pData->bCreateDirs) {
 
362
                        /* we fist need to create parent dirs if they are missing
 
363
                         * We do not report any errors here ourselfs but let the code
 
364
                         * fall through to error handler below.
 
365
                         */
 
366
                        if(makeFileParentDirs(newFileName, strlen((char*)newFileName),
 
367
                             pData->fDirCreateMode, pData->dirUID,
 
368
                             pData->dirGID, pData->bFailOnChown) == 0) {
 
369
                                pData->fd = open((char*) newFileName, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY,
 
370
                                                pData->fCreateMode);
 
371
                                if(pData->fd != -1) {
 
372
                                        /* check and set uid/gid */
 
373
                                        if(pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) {
 
374
                                                /* we need to set owner/group */
 
375
                                                if(fchown(pData->fd, pData->fileUID,
 
376
                                                          pData->fileGID) != 0) {
 
377
                                                        if(pData->bFailOnChown) {
 
378
                                                                int eSave = errno;
 
379
                                                                close(pData->fd);
 
380
                                                                pData->fd = -1;
 
381
                                                                errno = eSave;
 
382
                                                        }
 
383
                                                        /* we will silently ignore the chown() failure
 
384
                                                         * if configured to do so.
 
385
                                                         */
 
386
                                                }
 
387
                                        }
 
388
                                }
 
389
                        }
 
390
                }
 
391
        }
 
392
}
 
393
 
 
394
 
 
395
/* This function handles dynamic file names. It checks if the
 
396
 * requested file name is already open and, if not, does everything
 
397
 * needed to switch to the it.
 
398
 * Function returns 0 if all went well and non-zero otherwise.
 
399
 * On successful return pData->fd must point to the correct file to
 
400
 * be written.
 
401
 * This is a helper to writeFile(). rgerhards, 2007-07-03
 
402
 */
 
403
static int prepareDynFile(instanceData *pData, uchar *newFileName, unsigned iMsgOpts)
 
404
{
 
405
        time_t ttOldest; /* timestamp of oldest element */
 
406
        int iOldest;
 
407
        int i;
 
408
        int iFirstFree;
 
409
        dynaFileCacheEntry **pCache;
 
410
 
 
411
        assert(pData != NULL);
 
412
        assert(newFileName != NULL);
 
413
 
 
414
        pCache = pData->dynCache;
 
415
 
 
416
        /* first check, if we still have the current file
 
417
         * I *hope* this will be a performance enhancement.
 
418
         */
 
419
        if(   (pData->iCurrElt != -1)
 
420
           && !strcmp((char*) newFileName, (char*) pCache[pData->iCurrElt]->pName)) {
 
421
                /* great, we are all set */
 
422
                pCache[pData->iCurrElt]->lastUsed = time(NULL); /* update timestamp for LRU */
 
423
                return 0;
 
424
        }
 
425
 
 
426
        /* ok, no luck. Now let's search the table if we find a matching spot.
 
427
         * While doing so, we also prepare for creation of a new one.
 
428
         */
 
429
        iFirstFree = -1; /* not yet found */
 
430
        iOldest = 0; /* we assume the first element to be the oldest - that will change as we loop */
 
431
        ttOldest = time(NULL) + 1; /* there must always be an older one */
 
432
        for(i = 0 ; i < pData->iCurrCacheSize ; ++i) {
 
433
                if(pCache[i] == NULL) {
 
434
                        if(iFirstFree == -1)
 
435
                                iFirstFree = i;
 
436
                } else { /* got an element, let's see if it matches */
 
437
                        if(!strcmp((char*) newFileName, (char*) pCache[i]->pName)) {
 
438
                                /* we found our element! */
 
439
                                pData->fd = pCache[i]->fd;
 
440
                                pData->iCurrElt = i;
 
441
                                pCache[i]->lastUsed = time(NULL); /* update timestamp for LRU */
 
442
                                return 0;
 
443
                        }
 
444
                        /* did not find it - so lets keep track of the counters for LRU */
 
445
                        if(pCache[i]->lastUsed < ttOldest) {
 
446
                                ttOldest = pCache[i]->lastUsed;
 
447
                                iOldest = i;
 
448
                                }
 
449
                }
 
450
        }
 
451
 
 
452
        /* we have not found an entry */
 
453
        if(iFirstFree == -1 && (pData->iCurrCacheSize < pData->iDynaFileCacheSize)) {
 
454
                /* there is space left, so set it to that index */
 
455
                iFirstFree = pData->iCurrCacheSize++;
 
456
        }
 
457
 
 
458
        if(iFirstFree == -1) {
 
459
                dynaFileDelCacheEntry(pCache, iOldest, 0);
 
460
                iFirstFree = iOldest; /* this one *is* now free ;) */
 
461
        } else {
 
462
                /* we need to allocate memory for the cache structure */
 
463
                pCache[iFirstFree] = (dynaFileCacheEntry*) calloc(1, sizeof(dynaFileCacheEntry));
 
464
                if(pCache[iFirstFree] == NULL) {
 
465
                        glblHadMemShortage = TRUE;
 
466
                        dbgprintf("prepareDynfile(): could not alloc mem, discarding this request\n");
 
467
                        return -1;
 
468
                }
 
469
        }
 
470
 
 
471
        /* Ok, we finally can open the file */
 
472
        prepareFile(pData, newFileName);
 
473
 
 
474
        /* file is either open now or an error state set */
 
475
        if(pData->fd == -1) {
 
476
                /* do not report anything if the message is an internally-generated
 
477
                 * message. Otherwise, we could run into a never-ending loop. The bad
 
478
                 * news is that we also lose errors on startup messages, but so it is.
 
479
                 */
 
480
                if(iMsgOpts & INTERNAL_MSG)
 
481
                        dbgprintf("Could not open dynaFile, discarding message\n");
 
482
                else
 
483
                        logerrorSz("Could not open dynamic file '%s' - discarding message", (char*)newFileName);
 
484
                dynaFileDelCacheEntry(pCache, iFirstFree, 1);
 
485
                pData->iCurrElt = -1;
 
486
                return -1;
 
487
        }
 
488
 
 
489
        pCache[iFirstFree]->fd = pData->fd;
 
490
        pCache[iFirstFree]->pName = (uchar*)strdup((char*)newFileName); /* TODO: check for NULL (very unlikely) */
 
491
        pCache[iFirstFree]->lastUsed = time(NULL);
 
492
        pData->iCurrElt = iFirstFree;
 
493
        dbgprintf("Added new entry %d for file cache, file '%s'.\n",
 
494
                iFirstFree, newFileName);
 
495
 
 
496
        return 0;
 
497
}
 
498
 
 
499
 
 
500
/* rgerhards 2004-11-11: write to a file output. This
 
501
 * will be called for all outputs using file semantics,
 
502
 * for example also for pipes.
 
503
 */
 
504
static rsRetVal writeFile(uchar **ppString, unsigned iMsgOpts, instanceData *pData)
 
505
{
 
506
        off_t actualFileSize;
 
507
        DEFiRet;
 
508
 
 
509
        assert(pData != NULL);
 
510
 
 
511
        /* first check if we have a dynamic file name and, if so,
 
512
         * check if it still is ok or a new file needs to be created
 
513
         */
 
514
        if(pData->bDynamicName) {
 
515
                if(prepareDynFile(pData, ppString[1], iMsgOpts) != 0)
 
516
                        return RS_RET_ERR;
 
517
        }
 
518
 
 
519
        /* create the message based on format specified */
 
520
again:
 
521
        /* check if we have a file size limit and, if so,
 
522
         * obey to it.
 
523
         */
 
524
        if(pData->f_sizeLimit != 0) {
 
525
                actualFileSize = lseek(pData->fd, 0, SEEK_END);
 
526
                if(actualFileSize >= pData->f_sizeLimit) {
 
527
                        char errMsg[256];
 
528
                        /* for now, we simply disable a file once it is
 
529
                         * beyond the maximum size. This is better than having
 
530
                         * us aborted by the OS... rgerhards 2005-06-21
 
531
                         */
 
532
                        (void) close(pData->fd);
 
533
                        /* try to resolve the situation */
 
534
                        if(resolveFileSizeLimit(pData) != 0) {
 
535
                                /* didn't work out, so disable... */
 
536
                                snprintf(errMsg, sizeof(errMsg),
 
537
                                         "no longer writing to file %s; grown beyond configured file size of %lld bytes, actual size %lld - configured command did not resolve situation",
 
538
                                         pData->f_fname, (long long) pData->f_sizeLimit, (long long) actualFileSize);
 
539
                                errno = 0;
 
540
                                logerror(errMsg);
 
541
                                return RS_RET_DISABLE_ACTION;
 
542
                        } else {
 
543
                                snprintf(errMsg, sizeof(errMsg),
 
544
                                         "file %s had grown beyond configured file size of %lld bytes, actual size was %lld - configured command resolved situation",
 
545
                                         pData->f_fname, (long long) pData->f_sizeLimit, (long long) actualFileSize);
 
546
                                errno = 0;
 
547
                                logerror(errMsg);
 
548
                        }
 
549
                }
 
550
        }
 
551
 
 
552
        if (write(pData->fd, ppString[0], strlen((char*)ppString[0])) < 0) {
 
553
                int e = errno;
 
554
 
 
555
                /* If a named pipe is full, just ignore it for now
 
556
                   - mrn 24 May 96 */
 
557
                if (pData->fileType == eTypePIPE && e == EAGAIN)
 
558
                        return RS_RET_OK;
 
559
 
 
560
                /* If the filesystem is filled up, just ignore
 
561
                 * it for now and continue writing when possible
 
562
                 * based on patch for sysklogd by Martin Schulze on 2007-05-24
 
563
                 */
 
564
                if (pData->fileType == eTypeFILE && e == ENOSPC)
 
565
                        return RS_RET_OK;
 
566
 
 
567
                (void) close(pData->fd);
 
568
                /*
 
569
                 * Check for EBADF on TTY's due to vhangup()
 
570
                 * Linux uses EIO instead (mrn 12 May 96)
 
571
                 */
 
572
                if ((pData->fileType == eTypeTTY || pData->fileType == eTypeCONSOLE)
 
573
#ifdef linux
 
574
                        && e == EIO) {
 
575
#else
 
576
                        && e == EBADF) {
 
577
#endif
 
578
                        pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_NOCTTY);
 
579
                        if (pData->fd < 0) {
 
580
                                iRet = RS_RET_DISABLE_ACTION;
 
581
                                logerror((char*) pData->f_fname);
 
582
                        } else {
 
583
                                untty();
 
584
                                goto again;
 
585
                        }
 
586
                } else {
 
587
                        iRet = RS_RET_DISABLE_ACTION;
 
588
                        errno = e;
 
589
                        logerror((char*) pData->f_fname);
 
590
                }
 
591
        } else if (pData->bSyncFile)
 
592
                fsync(pData->fd);
 
593
        return(iRet);
 
594
}
 
595
 
 
596
 
 
597
BEGINcreateInstance
 
598
CODESTARTcreateInstance
 
599
ENDcreateInstance
 
600
 
 
601
 
 
602
BEGINfreeInstance
 
603
CODESTARTfreeInstance
 
604
        if(pData->bDynamicName) {
 
605
                dynaFileFreeCache(pData);
 
606
        } else 
 
607
                close(pData->fd);
 
608
ENDfreeInstance
 
609
 
 
610
 
 
611
BEGINonSelectReadyWrite
 
612
CODESTARTonSelectReadyWrite
 
613
ENDonSelectReadyWrite
 
614
 
 
615
 
 
616
BEGINneedUDPSocket
 
617
CODESTARTneedUDPSocket
 
618
ENDneedUDPSocket
 
619
 
 
620
 
 
621
BEGINgetWriteFDForSelect
 
622
CODESTARTgetWriteFDForSelect
 
623
ENDgetWriteFDForSelect
 
624
 
 
625
 
 
626
BEGINtryResume
 
627
CODESTARTtryResume
 
628
ENDtryResume
 
629
 
 
630
BEGINdoAction
 
631
CODESTARTdoAction
 
632
        dbgprintf(" (%s)\n", pData->f_fname);
 
633
        /* pData->fd == -1 is an indicator that the we couldn't
 
634
         * open the file at startup. For dynaFiles, this is ok,
 
635
         * all others are doomed.
 
636
         */
 
637
        if(pData->bDynamicName || (pData->fd != -1))
 
638
                iRet = writeFile(ppString, iMsgOpts, pData);
 
639
ENDdoAction
 
640
 
 
641
 
 
642
BEGINparseSelectorAct
 
643
CODESTARTparseSelectorAct
 
644
        /* yes, the if below is redundant, but I need it now. Will go away as
 
645
         * the code further changes.  -- rgerhards, 2007-07-25
 
646
         */
 
647
        if(*p == '$' || *p == '?' || *p == '|' || *p == '/' || *p == '-') {
 
648
                if((iRet = createInstance(&pData)) != RS_RET_OK)
 
649
                        return iRet;
 
650
        } else {
 
651
                /* this is not clean, but we need it for the time being
 
652
                 * TODO: remove when cleaning up modularization 
 
653
                 */
 
654
                return RS_RET_CONFLINE_UNPROCESSED;
 
655
        }
 
656
 
 
657
        if (*p == '-') {
 
658
                pData->bSyncFile = 0;
 
659
                p++;
 
660
        } else
 
661
                pData->bSyncFile = 1;
 
662
 
 
663
        pData->f_sizeLimit = 0; /* default value, use outchannels to configure! */
 
664
 
 
665
        switch (*p)
 
666
        {
 
667
        case '$':
 
668
                CODE_STD_STRING_REQUESTparseSelectorAct(1)
 
669
                /* rgerhards 2005-06-21: this is a special setting for output-channel
 
670
                 * definitions. In the long term, this setting will probably replace
 
671
                 * anything else, but for the time being we must co-exist with the
 
672
                 * traditional mode lines.
 
673
                 * rgerhards, 2007-07-24: output-channels will go away. We keep them
 
674
                 * for compatibility reasons, but seems to have been a bad idea.
 
675
                 */
 
676
                if((iRet = cflineParseOutchannel(pData, p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS)) == RS_RET_OK) {
 
677
                        pData->bDynamicName = 0;
 
678
                        pData->fCreateMode = fCreateMode; /* preserve current setting */
 
679
                        pData->fDirCreateMode = fDirCreateMode; /* preserve current setting */
 
680
                        pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY,
 
681
                                         pData->fCreateMode);
 
682
                }
 
683
                break;
 
684
 
 
685
        case '?': /* This is much like a regular file handle, but we need to obtain
 
686
                   * a template name. rgerhards, 2007-07-03
 
687
                   */
 
688
                CODE_STD_STRING_REQUESTparseSelectorAct(2)
 
689
                ++p; /* eat '?' */
 
690
                if((iRet = cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS))
 
691
                   != RS_RET_OK)
 
692
                        break;
 
693
                /* "filename" is actually a template name, we need this as string 1. So let's add it
 
694
                 * to the pOMSR. -- rgerhards, 2007-07-27
 
695
                 */
 
696
                if((iRet = OMSRsetEntry(*ppOMSR, 1, (uchar*)strdup((char*) pData->f_fname), OMSR_NO_RQD_TPL_OPTS)) != RS_RET_OK)
 
697
                        break;
 
698
 
 
699
                pData->bDynamicName = 1;
 
700
                pData->iCurrElt = -1;             /* no current element */
 
701
                pData->fCreateMode = fCreateMode; /* freeze current setting */
 
702
                pData->fDirCreateMode = fDirCreateMode; /* preserve current setting */
 
703
                pData->bCreateDirs = bCreateDirs;
 
704
                pData->bFailOnChown = bFailOnChown;
 
705
                pData->fileUID = fileUID;
 
706
                pData->fileGID = fileGID;
 
707
                pData->dirUID = dirUID;
 
708
                pData->dirGID = dirGID;
 
709
                pData->iDynaFileCacheSize = iDynaFileCacheSize; /* freeze current setting */
 
710
                /* we now allocate the cache table. We use calloc() intentionally, as we 
 
711
                 * need all pointers to be initialized to NULL pointers.
 
712
                 */
 
713
                if((pData->dynCache = (dynaFileCacheEntry**)
 
714
                    calloc(iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))) == NULL) {
 
715
                        iRet = RS_RET_OUT_OF_MEMORY;
 
716
                        dbgprintf("Could not allocate memory for dynaFileCache - selector disabled.\n");
 
717
                }
 
718
                break;
 
719
 
 
720
        case '|':
 
721
        case '/':
 
722
                CODE_STD_STRING_REQUESTparseSelectorAct(1)
 
723
                /* rgerhards, 2007-0726: first check if file or pipe */
 
724
                if(*p == '|') {
 
725
                        pData->fileType = eTypePIPE;
 
726
                        ++p;
 
727
                } else {
 
728
                        pData->fileType = eTypeFILE;
 
729
                }
 
730
                /* rgerhards 2004-11-17: from now, we need to have different
 
731
                 * processing, because after the first comma, the template name
 
732
                 * to use is specified. So we need to scan for the first coma first
 
733
                 * and then look at the rest of the line.
 
734
                 */
 
735
                if((iRet = cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS))
 
736
                   != RS_RET_OK)
 
737
                        break;
 
738
 
 
739
                pData->bDynamicName = 0;
 
740
                pData->fCreateMode = fCreateMode; /* preserve current setting */
 
741
                pData->fDirCreateMode = fDirCreateMode;
 
742
                pData->bCreateDirs = bCreateDirs;
 
743
                pData->bFailOnChown = bFailOnChown;
 
744
                pData->fileUID = fileUID;
 
745
                pData->fileGID = fileGID;
 
746
                pData->dirUID = dirUID;
 
747
                pData->dirGID = dirGID;
 
748
 
 
749
                if(pData->fileType == eTypePIPE) {
 
750
                        pData->fd = open((char*) pData->f_fname, O_RDWR|O_NONBLOCK);
 
751
                } else {
 
752
                        prepareFile(pData, pData->f_fname);
 
753
                }
 
754
                        
 
755
                if ( pData->fd < 0 ){
 
756
                        pData->fd = -1;
 
757
                        dbgprintf("Error opening log file: %s\n", pData->f_fname);
 
758
                        logerror((char*) pData->f_fname);
 
759
                        break;
 
760
                }
 
761
                if (isatty(pData->fd)) {
 
762
                        pData->fileType = eTypeTTY;
 
763
                        untty();
 
764
                }
 
765
                if (strcmp((char*) p, ctty) == 0)
 
766
                        pData->fileType = eTypeCONSOLE;
 
767
                break;
 
768
        default:
 
769
                iRet = RS_RET_CONFLINE_UNPROCESSED;
 
770
                break;
 
771
        }
 
772
CODE_STD_FINALIZERparseSelectorAct
 
773
ENDparseSelectorAct
 
774
 
 
775
 
 
776
/* Reset config variables for this module to default values.
 
777
 * rgerhards, 2007-07-17
 
778
 */
 
779
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
 
780
{
 
781
        fileUID = -1;
 
782
        fileGID = -1;
 
783
        dirUID = -1;
 
784
        dirGID = -1;
 
785
        bFailOnChown = 1;
 
786
        iDynaFileCacheSize = 10;
 
787
        fCreateMode = 0644;
 
788
        fDirCreateMode = 0644;
 
789
        bCreateDirs = 1;
 
790
 
 
791
        return RS_RET_OK;
 
792
}
 
793
 
 
794
 
 
795
BEGINqueryEtryPt
 
796
CODESTARTqueryEtryPt
 
797
CODEqueryEtryPt_STD_OMOD_QUERIES
 
798
ENDqueryEtryPt
 
799
 
 
800
 
 
801
BEGINmodInit(File)
 
802
CODESTARTmodInit
 
803
        *ipIFVersProvided = 1; /* so far, we only support the initial definition */
 
804
CODEmodInit_QueryRegCFSLineHdlr
 
805
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"dynafilecachesize", 0, eCmdHdlrInt, (void*) setDynaFileCacheSize, NULL));
 
806
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"dirowner", 0, eCmdHdlrUID, NULL, &dirUID));
 
807
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"dirgroup", 0, eCmdHdlrGID, NULL, &dirGID));
 
808
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"fileowner", 0, eCmdHdlrUID, NULL, &fileUID));
 
809
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"filegroup", 0, eCmdHdlrGID, NULL, &fileGID));
 
810
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"dircreatemode", 0, eCmdHdlrFileCreateMode, NULL, &fDirCreateMode));
 
811
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"filecreatemode", 0, eCmdHdlrFileCreateMode, NULL, &fCreateMode));
 
812
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"createdirs", 0, eCmdHdlrBinary, NULL, &bCreateDirs));
 
813
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &bFailOnChown));
 
814
        CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL));
 
815
ENDmodInit
 
816
 
 
817
/*
 
818
 * vi:set ai:
 
819
 */