2
* This is the implementation of the build-in file output module.
4
* Handles: eTypeCONSOLE, eTypeTTY, eTypeFILE, eTypePIPE
6
* NOTE: read comments in module-template.h to understand how this file
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.
15
* Copyright 2007 Rainer Gerhards and Adiscon GmbH.
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.
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.
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.
31
* A copy of the GPL can be found in the file "COPYING" in this distribution.
47
#include "syslogd-types.h"
50
#include "outchannel.h"
52
#include "cfsysline.h"
53
#include "module-template.h"
55
/* internal structures
59
/* The following structure is a dynafile name cache entry.
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 */
66
typedef struct s_dynaFileCacheEntry dynaFileCacheEntry;
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 */
81
typedef struct _instanceData {
82
uchar f_fname[MAXFNAME];/* file or template name (display only) */
83
short fd; /* file descriptor for (current) file */
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 */
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.
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 */
114
BEGINisCompatibleWithFeature
115
CODESTARTisCompatibleWithFeature
116
if(eFeat == sFEATURERepeatedMsgReduction)
118
ENDisCompatibleWithFeature
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",
131
pData->iDynaFileCacheSize,
132
pData->bCreateDirs ? "yes" : "no",
133
pData->fileUID, pData->fileGID,
134
pData->dirUID, pData->dirGID,
135
pData->bFailOnChown ? "yes" : "no"
137
} else { /* regular file */
138
printf("%s", pData->f_fname);
145
/* set the dynaFile cache size. Does some limit checking.
146
* rgerhards, 2007-07-31
148
rsRetVal setDynaFileCacheSize(void __attribute__((unused)) *pVal, int iNewVal)
151
uchar errMsg[128]; /* for dynamic error messages */
154
snprintf((char*) errMsg, sizeof(errMsg)/sizeof(uchar),
155
"DynaFileCacheSize must be greater 0 (%d given), changed to 1.", iNewVal);
157
logerror((char*) errMsg);
158
iRet = RS_RET_VAL_OUT_OF_RANGE;
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);
164
logerror((char*) errMsg);
165
iRet = RS_RET_VAL_OUT_OF_RANGE;
169
iDynaFileCacheSize = iNewVal;
170
dbgprintf("DynaFileCacheSize changed to %d.\n", iNewVal);
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
182
* rgerhards 2005-06-21
184
static rsRetVal cflineParseOutchannel(instanceData *pData, uchar* p, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts)
188
struct outchannel *pOch;
189
char szBuf[128]; /* should be more than sufficient */
191
/* this must always be a file, because we can not set a size limit
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
197
pData->fileType = eTypeFILE;
201
/* get outchannel name */
202
while(*p && *p != ';' && *p != ' ' &&
203
i < sizeof(szBuf) / sizeof(char)) {
208
/* got the name, now look up the channel... */
209
pOch = ochFind(szBuf, i);
214
snprintf(errMsg, sizeof(errMsg)/sizeof(char),
215
"outchannel '%s' not found - ignoring action line",
218
return RS_RET_NOT_FOUND;
221
/* check if there is a file name in the outchannel... */
222
if(pOch->pszFileTemplate == NULL) {
225
snprintf(errMsg, sizeof(errMsg)/sizeof(char),
226
"outchannel '%s' has no file name template - ignoring action line",
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.
238
pData->f_sizeLimitCmd = (char*) pOch->cmdOnSizeLimit;
240
iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, (uchar*) " TradFmt");
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
252
int resolveFileSizeLimit(instanceData *pData)
257
off_t actualFileSize;
258
assert(pData != NULL);
260
if(pData->f_sizeLimitCmd == NULL)
261
return 1; /* nothing we can do in this case... */
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
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.
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;
278
for(p = pCmd ; *p && *p != ' ' ; ++p) {
283
*p = '\0'; /* pretend string-end */
288
execProg(pCmd, 1, pParams);
290
pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY,
293
actualFileSize = lseek(pData->fd, 0, SEEK_END);
294
if(actualFileSize >= pData->f_sizeLimit) {
295
/* OK, it didn't work out... */
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.
310
static void dynaFileDelCacheEntry(dynaFileCacheEntry **pCache, int iEntry, int bFreeEntry)
312
assert(pCache != NULL);
314
if(pCache[iEntry] == NULL)
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.
323
if(pCache[iEntry]->pName != NULL) {
324
close(pCache[iEntry]->fd);
325
free(pCache[iEntry]->pName);
326
pCache[iEntry]->pName = NULL;
330
free(pCache[iEntry]);
331
pCache[iEntry] = NULL;
336
/* This function frees the dynamic file name cache.
338
static void dynaFileFreeCache(instanceData *pData)
341
assert(pData != NULL);
343
for(i = 0 ; i < pData->iCurrCacheSize ; ++i) {
344
dynaFileDelCacheEntry(pData->dynCache, i, 1);
347
free(pData->dynCache);
351
/* This is a shared code for both static and dynamic files.
353
static void prepareFile(instanceData *pData, uchar *newFileName)
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,
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.
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,
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) {
383
/* we will silently ignore the chown() failure
384
* if configured to do so.
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
401
* This is a helper to writeFile(). rgerhards, 2007-07-03
403
static int prepareDynFile(instanceData *pData, uchar *newFileName, unsigned iMsgOpts)
405
time_t ttOldest; /* timestamp of oldest element */
409
dynaFileCacheEntry **pCache;
411
assert(pData != NULL);
412
assert(newFileName != NULL);
414
pCache = pData->dynCache;
416
/* first check, if we still have the current file
417
* I *hope* this will be a performance enhancement.
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 */
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.
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) {
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;
441
pCache[i]->lastUsed = time(NULL); /* update timestamp for LRU */
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;
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++;
458
if(iFirstFree == -1) {
459
dynaFileDelCacheEntry(pCache, iOldest, 0);
460
iFirstFree = iOldest; /* this one *is* now free ;) */
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");
471
/* Ok, we finally can open the file */
472
prepareFile(pData, newFileName);
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.
480
if(iMsgOpts & INTERNAL_MSG)
481
dbgprintf("Could not open dynaFile, discarding message\n");
483
logerrorSz("Could not open dynamic file '%s' - discarding message", (char*)newFileName);
484
dynaFileDelCacheEntry(pCache, iFirstFree, 1);
485
pData->iCurrElt = -1;
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);
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.
504
static rsRetVal writeFile(uchar **ppString, unsigned iMsgOpts, instanceData *pData)
506
off_t actualFileSize;
509
assert(pData != NULL);
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
514
if(pData->bDynamicName) {
515
if(prepareDynFile(pData, ppString[1], iMsgOpts) != 0)
519
/* create the message based on format specified */
521
/* check if we have a file size limit and, if so,
524
if(pData->f_sizeLimit != 0) {
525
actualFileSize = lseek(pData->fd, 0, SEEK_END);
526
if(actualFileSize >= pData->f_sizeLimit) {
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
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);
541
return RS_RET_DISABLE_ACTION;
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);
552
if (write(pData->fd, ppString[0], strlen((char*)ppString[0])) < 0) {
555
/* If a named pipe is full, just ignore it for now
557
if (pData->fileType == eTypePIPE && e == EAGAIN)
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
564
if (pData->fileType == eTypeFILE && e == ENOSPC)
567
(void) close(pData->fd);
569
* Check for EBADF on TTY's due to vhangup()
570
* Linux uses EIO instead (mrn 12 May 96)
572
if ((pData->fileType == eTypeTTY || pData->fileType == eTypeCONSOLE)
578
pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_NOCTTY);
580
iRet = RS_RET_DISABLE_ACTION;
581
logerror((char*) pData->f_fname);
587
iRet = RS_RET_DISABLE_ACTION;
589
logerror((char*) pData->f_fname);
591
} else if (pData->bSyncFile)
598
CODESTARTcreateInstance
603
CODESTARTfreeInstance
604
if(pData->bDynamicName) {
605
dynaFileFreeCache(pData);
611
BEGINonSelectReadyWrite
612
CODESTARTonSelectReadyWrite
613
ENDonSelectReadyWrite
617
CODESTARTneedUDPSocket
621
BEGINgetWriteFDForSelect
622
CODESTARTgetWriteFDForSelect
623
ENDgetWriteFDForSelect
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.
637
if(pData->bDynamicName || (pData->fd != -1))
638
iRet = writeFile(ppString, iMsgOpts, pData);
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
647
if(*p == '$' || *p == '?' || *p == '|' || *p == '/' || *p == '-') {
648
if((iRet = createInstance(&pData)) != RS_RET_OK)
651
/* this is not clean, but we need it for the time being
652
* TODO: remove when cleaning up modularization
654
return RS_RET_CONFLINE_UNPROCESSED;
658
pData->bSyncFile = 0;
661
pData->bSyncFile = 1;
663
pData->f_sizeLimit = 0; /* default value, use outchannels to configure! */
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.
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,
685
case '?': /* This is much like a regular file handle, but we need to obtain
686
* a template name. rgerhards, 2007-07-03
688
CODE_STD_STRING_REQUESTparseSelectorAct(2)
690
if((iRet = cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS))
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
696
if((iRet = OMSRsetEntry(*ppOMSR, 1, (uchar*)strdup((char*) pData->f_fname), OMSR_NO_RQD_TPL_OPTS)) != RS_RET_OK)
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.
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");
722
CODE_STD_STRING_REQUESTparseSelectorAct(1)
723
/* rgerhards, 2007-0726: first check if file or pipe */
725
pData->fileType = eTypePIPE;
728
pData->fileType = eTypeFILE;
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.
735
if((iRet = cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS))
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;
749
if(pData->fileType == eTypePIPE) {
750
pData->fd = open((char*) pData->f_fname, O_RDWR|O_NONBLOCK);
752
prepareFile(pData, pData->f_fname);
755
if ( pData->fd < 0 ){
757
dbgprintf("Error opening log file: %s\n", pData->f_fname);
758
logerror((char*) pData->f_fname);
761
if (isatty(pData->fd)) {
762
pData->fileType = eTypeTTY;
765
if (strcmp((char*) p, ctty) == 0)
766
pData->fileType = eTypeCONSOLE;
769
iRet = RS_RET_CONFLINE_UNPROCESSED;
772
CODE_STD_FINALIZERparseSelectorAct
776
/* Reset config variables for this module to default values.
777
* rgerhards, 2007-07-17
779
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
786
iDynaFileCacheSize = 10;
788
fDirCreateMode = 0644;
797
CODEqueryEtryPt_STD_OMOD_QUERIES
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));