249
256
legacyOptsLL_t *pLegacyOptsLL = NULL;
251
258
/* global variables for config file state */
252
static int bDropTrailingLF = 1; /* drop trailing LF's on reception? */
259
int bDropTrailingLF = 1; /* drop trailing LF's on reception? */
253
260
int iCompatibilityMode = 0; /* version we should be compatible with; 0 means sysklogd. It is
254
261
the default, so if no -c<n> option is given, we make ourselvs
255
262
as compatible to sysklogd as possible. */
256
263
static int bDebugPrintTemplateList = 1;/* output template list in debug mode? */
257
264
static int bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list in debug mode? */
258
265
static int bDebugPrintModuleList = 1;/* output module list in debug mode? */
259
static uchar cCCEscapeChar = '\\';/* character to be used to start an escape sequence for control chars */
260
static int bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */
266
uchar cCCEscapeChar = '\\';/* character to be used to start an escape sequence for control chars */
267
int bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */
261
268
static int bErrMsgToStderr = 1; /* print error messages to stderr (in addition to everything else)? */
262
269
int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */
263
270
int bActExecWhenPrevSusp; /* execute action only when previous one was suspended? */
582
593
* Interface change: added new parameter "InputName", permits the input to provide
583
594
* a string that identifies it. May be NULL, but must be a valid char* pointer if
597
* rgerhards, 2008-10-06:
598
* Interface change: added new parameter "stTime", which enables the caller to provide
599
* a timestamp that is to be used as timegenerated instead of the current system time.
600
* This is meant to facilitate performance optimization. Some inputs support such modes.
601
* If stTime is NULL, the current system time is used.
603
* rgerhards, 2008-10-09:
604
* interface change: bParseHostname removed, now in flags
586
rsRetVal printline(uchar *hname, uchar *hnameIP, uchar *msg, int bParseHost, int flags, flowControl_t flowCtlType,
606
static inline rsRetVal printline(uchar *hname, uchar *hnameIP, uchar *msg, int flags, flowControl_t flowCtlType,
607
uchar *pszInputName, struct syslogTime *stTime, time_t ttGenTime)
590
610
register uchar *p;
685
708
* Interface change: added new parameter "InputName", permits the input to provide
686
709
* a string that identifies it. May be NULL, but must be a valid char* pointer if
712
* rgerhards, 2008-10-06:
713
* Interface change: added new parameter "stTime", which enables the caller to provide
714
* a timestamp that is to be used as timegenerated instead of the current system time.
715
* This is meant to facilitate performance optimization. Some inputs support such modes.
716
* If stTime is NULL, the current system time is used.
718
* rgerhards, 2008-10-09:
719
* interface change: bParseHostname removed, now in flags
690
parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int bParseHost, int flags, flowControl_t flowCtlType,
722
parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlType,
723
uchar *pszInputName, struct syslogTime *stTime, time_t ttGenTime)
694
726
register int iMsg;
1252
1291
if(*p2parse != '[')
1253
1292
return 1; /* this is NOT structured data! */
1256
if(*p2parse == '\0') {
1257
iRet = 1; /* this is not valid! */
1259
} else if(*p2parse == '\\' && *(p2parse+1) == ']') {
1260
/* this is escaped, need to copy both */
1261
*pResult++ = *p2parse++;
1262
*pResult++ = *p2parse++;
1263
} else if(*p2parse == ']' && *(p2parse+1) == ' ') {
1264
/* found end, just need to copy the ] and eat the SP */
1265
*pResult++ = *p2parse;
1269
*pResult++ = *p2parse++;
1294
if(*p2parse == '-') { /* empty structured data? */
1299
if(*p2parse == '\0') {
1300
iRet = 1; /* this is not valid! */
1302
} else if(*p2parse == '\\' && *(p2parse+1) == ']') {
1303
/* this is escaped, need to copy both */
1304
*pResult++ = *p2parse++;
1305
*pResult++ = *p2parse++;
1306
} else if(*p2parse == ']' && *(p2parse+1) == ' ') {
1307
/* found end, just need to copy the ] and eat the SP */
1308
*pResult++ = *p2parse;
1312
*pResult++ = *p2parse++;
2092
/* drop to specified group
2093
* if something goes wrong, the function never returns
2094
* Note that such an abort can cause damage to on-disk structures, so we should
2095
* re-design the "interface" in the long term. -- rgerhards, 2008-11-26
2097
static void doDropPrivGid(int iGid)
2102
res = setgroups(0, NULL); /* remove all supplementary group IDs */
2104
perror("could not remove supplemental group IDs");
2107
DBGPRINTF("setgroups(0, NULL): %d\n", res);
2110
/* if we can not set the userid, this is fatal, so let's unconditionally abort */
2111
perror("could not set requested group id");
2114
DBGPRINTF("setgid(%d): %d\n", iGid, res);
2115
snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's groupid changed to %d", iGid);
2116
logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
2120
/* drop to specified user
2121
* if something goes wrong, the function never returns
2122
* Note that such an abort can cause damage to on-disk structures, so we should
2123
* re-design the "interface" in the long term. -- rgerhards, 2008-11-19
2125
static void doDropPrivUid(int iUid)
2132
/* if we can not set the userid, this is fatal, so let's unconditionally abort */
2133
perror("could not set requested userid");
2136
DBGPRINTF("setuid(%d): %d\n", iUid, res);
2137
snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's userid changed to %d", iUid);
2138
logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
2046
2142
/* helper to freeSelectors(), used with llExecFunc() to flush
2047
2143
* pending output. -- rgerhards, 2007-08-02
2048
2144
* We do not need to lock the action object here as the processing
2174
2270
cCCEscapeChar);
2176
2272
dbgprintf("Main queue size %d messages.\n", iMainMsgQueueSize);
2177
dbgprintf("Main queue worker threads: %d, Perists every %d updates.\n",
2178
iMainMsgQueueNumWorkers, iMainMsgQPersistUpdCnt);
2273
dbgprintf("Main queue worker threads: %d, wThread shutdown: %d, Perists every %d updates.\n",
2274
iMainMsgQueueNumWorkers, iMainMsgQtoWrkShutdown, iMainMsgQPersistUpdCnt);
2179
2275
dbgprintf("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n",
2180
2276
iMainMsgQtoQShutdown, iMainMsgQtoActShutdown, iMainMsgQtoEnq);
2181
2277
dbgprintf("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n",
2186
2282
iActionRetryCount = 0;
2187
2283
iActionRetryInterval = 30000;
2188
static int iMainMsgQtoWrkShutdown = 60000;
2189
2284
static int iMainMsgQtoWrkMinMsgs = 100;
2190
2285
static int iMainMsgQbSaveOnShutdown = 1;
2191
2286
iMainMsgQueMaxDiskSpace = 0;
2192
setQPROP(queueSettoWrkShutdown, "$MainMsgQueueTimeoutWorkerThreadShutdown", 5000);
2193
setQPROP(queueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100);
2194
setQPROP(queueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1);
2287
setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100);
2288
setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1);
2196
2290
dbgprintf("Work Directory: '%s'.\n", glbl.GetWorkDir());
2288
2383
if(localRet != RS_RET_OK) {
2289
2384
errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", ConfFile);
2290
2386
} else if(iNbrActions == 0) {
2291
2387
errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will "
2292
2388
"run, but no output whatsoever is created.");
2295
if(localRet != RS_RET_OK || iNbrActions == 0) {
2392
if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) {
2296
2393
/* rgerhards: this code is executed to set defaults when the
2297
2394
* config file could not be opened. We might think about
2298
2395
* abandoning the run in this case - but this, too, is not
2355
2452
/* we are done checking the config - now validate if we should actually run or not.
2356
2453
* If not, terminate. -- rgerhards, 2008-07-25
2457
/* a bit dirty, but useful... */
2359
2460
ABORT_FINALIZE(RS_RET_VALIDATION_RUN);
2361
2463
/* switch the message object to threaded operation, if necessary */
2464
/* TODO:XXX: I think we must do this also if we have action queues! -- rgerhards, 2009-01-26 */
2362
2465
if(MainMsgQueType == QUEUETYPE_DIRECT || iMainMsgQueueNumWorkers > 1) {
2363
2466
MsgEnableThreadSafety();
2366
2469
/* create message queue */
2367
CHKiRet_Hdlr(queueConstruct(&pMsgQueue, MainMsgQueType, iMainMsgQueueNumWorkers, iMainMsgQueueSize, msgConsumer)) {
2470
CHKiRet_Hdlr(qqueueConstruct(&pMsgQueue, MainMsgQueType, iMainMsgQueueNumWorkers, iMainMsgQueueSize, msgConsumer)) {
2368
2471
/* no queue is fatal, we need to give up in that case... */
2369
2472
fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet);
2382
2485
errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \
2385
setQPROP(queueSetMaxFileSize, "$MainMsgQueueFileSize", iMainMsgQueMaxFileSize);
2386
setQPROP(queueSetsizeOnDiskMax, "$MainMsgQueueMaxDiskSpace", iMainMsgQueMaxDiskSpace);
2387
setQPROPstr(queueSetFilePrefix, "$MainMsgQueueFileName", pszMainMsgQFName);
2388
setQPROP(queueSetiPersistUpdCnt, "$MainMsgQueueCheckpointInterval", iMainMsgQPersistUpdCnt);
2389
setQPROP(queueSettoQShutdown, "$MainMsgQueueTimeoutShutdown", iMainMsgQtoQShutdown );
2390
setQPROP(queueSettoActShutdown, "$MainMsgQueueTimeoutActionCompletion", iMainMsgQtoActShutdown);
2391
setQPROP(queueSettoWrkShutdown, "$MainMsgQueueWorkerTimeoutThreadShutdown", iMainMsgQtoWrkShutdown);
2392
setQPROP(queueSettoEnq, "$MainMsgQueueTimeoutEnqueue", iMainMsgQtoEnq);
2393
setQPROP(queueSetiHighWtrMrk, "$MainMsgQueueHighWaterMark", iMainMsgQHighWtrMark);
2394
setQPROP(queueSetiLowWtrMrk, "$MainMsgQueueLowWaterMark", iMainMsgQLowWtrMark);
2395
setQPROP(queueSetiDiscardMrk, "$MainMsgQueueDiscardMark", iMainMsgQDiscardMark);
2396
setQPROP(queueSetiDiscardSeverity, "$MainMsgQueueDiscardSeverity", iMainMsgQDiscardSeverity);
2397
setQPROP(queueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", iMainMsgQWrkMinMsgs);
2398
setQPROP(queueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", bMainMsgQSaveOnShutdown);
2399
setQPROP(queueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", iMainMsgQDeqSlowdown);
2400
setQPROP(queueSetiDeqtWinFromHr, "$MainMsgQueueDequeueTimeBegin", iMainMsgQueueDeqtWinFromHr);
2401
setQPROP(queueSetiDeqtWinToHr, "$MainMsgQueueDequeueTimeEnd", iMainMsgQueueDeqtWinToHr);
2488
setQPROP(qqueueSetMaxFileSize, "$MainMsgQueueFileSize", iMainMsgQueMaxFileSize);
2489
setQPROP(qqueueSetsizeOnDiskMax, "$MainMsgQueueMaxDiskSpace", iMainMsgQueMaxDiskSpace);
2490
setQPROPstr(qqueueSetFilePrefix, "$MainMsgQueueFileName", pszMainMsgQFName);
2491
setQPROP(qqueueSetiPersistUpdCnt, "$MainMsgQueueCheckpointInterval", iMainMsgQPersistUpdCnt);
2492
setQPROP(qqueueSettoQShutdown, "$MainMsgQueueTimeoutShutdown", iMainMsgQtoQShutdown );
2493
setQPROP(qqueueSettoActShutdown, "$MainMsgQueueTimeoutActionCompletion", iMainMsgQtoActShutdown);
2494
setQPROP(qqueueSettoWrkShutdown, "$MainMsgQueueWorkerTimeoutThreadShutdown", iMainMsgQtoWrkShutdown);
2495
setQPROP(qqueueSettoEnq, "$MainMsgQueueTimeoutEnqueue", iMainMsgQtoEnq);
2496
setQPROP(qqueueSetiHighWtrMrk, "$MainMsgQueueHighWaterMark", iMainMsgQHighWtrMark);
2497
setQPROP(qqueueSetiLowWtrMrk, "$MainMsgQueueLowWaterMark", iMainMsgQLowWtrMark);
2498
setQPROP(qqueueSetiDiscardMrk, "$MainMsgQueueDiscardMark", iMainMsgQDiscardMark);
2499
setQPROP(qqueueSetiDiscardSeverity, "$MainMsgQueueDiscardSeverity", iMainMsgQDiscardSeverity);
2500
setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", iMainMsgQWrkMinMsgs);
2501
setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", bMainMsgQSaveOnShutdown);
2502
setQPROP(qqueueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", iMainMsgQDeqSlowdown);
2503
setQPROP(qqueueSetiDeqtWinFromHr, "$MainMsgQueueDequeueTimeBegin", iMainMsgQueueDeqtWinFromHr);
2504
setQPROP(qqueueSetiDeqtWinToHr, "$MainMsgQueueDequeueTimeEnd", iMainMsgQueueDeqtWinToHr);
2403
2506
# undef setQPROP
2404
2507
# undef setQPROPstr
2406
2509
/* ... and finally start the queue! */
2407
CHKiRet_Hdlr(queueStart(pMsgQueue)) {
2510
CHKiRet_Hdlr(qqueueStart(pMsgQueue)) {
2408
2511
/* no queue is fatal, we need to give up in that case... */
2409
2512
fprintf(stderr, "fatal error %d: could not start message queue - rsyslogd can not run!\n", iRet);
2664
/* helper to doHUP(), this "HUPs" each action. The necessary locking
2665
* is done inside the action class and nothing we need to take care of.
2666
* rgerhards, 2008-10-22
2668
DEFFUNC_llExecFunc(doHUPActions)
2671
actionCallHUPHdlr((action_t*) pData);
2673
return RS_RET_OK; /* we ignore errors, we can not do anything either way */
2677
/* This function processes a HUP after one has been detected. Note that this
2678
* is *NOT* the sighup handler. The signal is recorded by the handler, that record
2679
* detected inside the mainloop and then this function is called to do the
2680
* real work. -- rgerhards, 2008-10-22
2688
snprintf(buf, sizeof(buf) / sizeof(char),
2689
" [origin software=\"rsyslogd\" " "swVersion=\"" VERSION
2690
"\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed, type '%s'.",
2691
(int) myPid, glbl.GetHUPisRestart() ? "restart" : "lightweight");
2693
logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0);
2695
if(glbl.GetHUPisRestart()) {
2696
DBGPRINTF("Received SIGHUP, configured to be restart, reloading rsyslogd.\n");
2697
init(); /* main queue is stopped as part of init() */
2699
DBGPRINTF("Received SIGHUP, configured to be a non-restart type of HUP - notifying actions.\n");
2700
for(f = Files; f != NULL ; f = f->f_next) {
2701
llExecFunc(&f->llActList, doHUPActions, NULL);
2563
2707
/* This is the main processing loop. It is called after successful initialization.
2564
2708
* When it returns, the syslogd terminates.
2565
2709
* Its sole function is to provide some housekeeping things. The real work is done
2750
2892
CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
2751
2893
CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &bErrMsgToStderr, NULL));
2752
2894
CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL));
2895
CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID, NULL, &uidDropPriv, NULL));
2896
CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt, NULL, &uidDropPriv, NULL));
2897
CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL));
2898
CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroupid", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL));
2754
2900
/* now add other modules handlers (we should work on that to be able to do it in ClassInit(), but so far
2755
2901
* that is not possible). -- rgerhards, 2008-01-28
2849
2995
/* Send a signal to the parent so it can terminate.
2852
kill (ppid, SIGTERM);
2998
kill(ppid, SIGTERM);
3001
/* If instructed to do so, we now drop privileges. Note that this is not 100% secure,
3002
* because inputs and outputs are already running at this time. However, we can implement
3003
* dropping of privileges rather quickly and it will work in many cases. While it is not
3004
* the ultimate solution, the current one is still much better than not being able to
3005
* drop privileges at all. Doing it correctly, requires a change in architecture, which
3006
* we should do over time. TODO -- rgerhards, 2008-11-19
3008
if(gidDropPriv != 0) {
3009
doDropPrivGid(gidDropPriv);
3010
glbl.SetHUPisRestart(0); /* we can not do restart-type HUPs with dropped privs */
3013
if(uidDropPriv != 0) {
3014
doDropPrivUid(uidDropPriv);
3015
glbl.SetHUPisRestart(0); /* we can not do restart-type HUPs with dropped privs */
2854
3019
/* END OF INTIALIZATION
2855
3020
* ... but keep in mind that we might do a restart and thus init() might
3468
3655
/* process compatibility mode settings */
3469
if(iCompatibilityMode < 3) {
3656
if(iCompatibilityMode < 4) {
3470
3657
errmsg.LogError(0, NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically "
3471
3658
"generated config directives may interfer with your rsyslog.conf settings. "
3472
"We suggest upgrading your config and adding -c3 as the first "
3659
"We suggest upgrading your config and adding -c4 as the first "
3473
3660
"rsyslogd option.");
3663
if(iCompatibilityMode < 3) {
3474
3664
if(MarkInterval > 0) {
3475
3665
legacyOptsEnq((uchar *) "ModLoad immark");
3476
3666
snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "MarkMessagePeriod %d", MarkInterval);