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

« back to all changes in this revision

Viewing changes to tools/syslogd.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2009-06-23 12:12:43 UTC
  • mfrom: (1.1.11 upstream) (3.2.8 sid)
  • Revision ID: james.westby@ubuntu.com-20090623121243-d2fejarzidywnn17
Tags: 4.2.0-1
* New upstream release of the now stable v4 branch.
  - Fix warnings when /etc/rsyslog.d/ is empty. Closes: #530228
* debian/patches/imudp_multiple_udp_sockets.patch
  - Removed, merged upstream.
* debian/rsyslog.default
  - Set default compat mode to '4'.
* debian/rsyslog.logcheck.ignore.server
  - Update logcheck rules files to also ignore rsyslogd and imklog stop
    messages.
* debian/control
  - Bump Standards-Version to 3.8.2. No further changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
72
72
#include <stdarg.h>
73
73
#include <time.h>
74
74
#include <assert.h>
75
 
#include <libgen.h>
76
75
 
77
 
#ifdef  __sun
 
76
#ifdef OS_SOLARIS
78
77
#       include <errno.h>
 
78
#       include <fcntl.h>
 
79
#       include <stropts.h>
 
80
#       include <sys/termios.h>
 
81
#       include <sys/types.h>
79
82
#else
 
83
#       include <libgen.h>
80
84
#       include <sys/errno.h>
81
85
#endif
 
86
 
82
87
#include <sys/ioctl.h>
83
88
#include <sys/wait.h>
84
89
#include <sys/file.h>
 
90
#include <grp.h>
85
91
 
86
92
#if HAVE_SYS_TIMESPEC_H
87
93
# include <sys/timespec.h>
128
134
#include "vm.h"
129
135
#include "errmsg.h"
130
136
#include "datetime.h"
 
137
#include "parser.h"
131
138
#include "sysvar.h"
132
139
 
133
140
/* definitions for objects we access */
219
226
 
220
227
static pid_t myPid;     /* our pid for use in self-generated messages, e.g. on startup */
221
228
/* mypid is read-only after the initial fork() */
222
 
static int restart = 0; /* do restart (config read) - multithread safe */
 
229
static int bHadHUP = 0; /* did we have a HUP? */
223
230
 
224
231
static int bParseHOSTNAMEandTAG = 1; /* global config var: should the hostname and tag be
225
232
                                      * parsed inside message - rgerhards, 2006-03-13 */
249
256
legacyOptsLL_t *pLegacyOptsLL = NULL;
250
257
 
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? */
271
278
                                 * If the main queue is either not yet ready or not running in 
272
279
                                 * queueing mode (mode DIRECT!), then this is set to 0.
273
280
                                 */
 
281
static int uidDropPriv = 0;     /* user-id to which priveleges should be dropped to (AFTER init()!) */
 
282
static int gidDropPriv = 0;     /* group-id to which priveleges should be dropped to (AFTER init()!) */
274
283
 
275
284
extern  int errno;
276
285
 
277
286
/* main message queue and its configuration parameters */
278
 
static queue_t *pMsgQueue = NULL;                               /* the main message queue */
 
287
static qqueue_t *pMsgQueue = NULL;                              /* the main message queue */
279
288
static int iMainMsgQueueSize = 10000;                           /* size of the main message queue above */
280
289
static int iMainMsgQHighWtrMark = 8000;                         /* high water mark for disk-assisted queues */
281
290
static int iMainMsgQLowWtrMark = 2000;                          /* low water mark for disk-assisted queues */
420
429
                        rsCStrDestruct(&pThis->f_filterData.prop.pCSPropName);
421
430
                if(pThis->f_filterData.prop.pCSCompValue != NULL)
422
431
                        rsCStrDestruct(&pThis->f_filterData.prop.pCSCompValue);
 
432
                if(pThis->f_filterData.prop.regex_cache != NULL)
 
433
                        rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache);
423
434
        } else if(pThis->f_filter_type == FILTER_EXPR) {
424
435
                if(pThis->f_filterData.f_expr != NULL)
425
436
                        expr.Destruct(&pThis->f_filterData.f_expr);
540
551
        int i;
541
552
 
542
553
        if ( !Debug ) {
543
 
                i = open(_PATH_TTY, O_RDWR);
 
554
                i = open(_PATH_TTY, O_RDWR|O_CLOEXEC);
544
555
                if (i >= 0) {
545
556
#                       if !defined(__hpux)
546
557
                                (void) ioctl(i, (int) TIOCNOTTY, (char *)0);
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
584
595
 * non-NULL.
 
596
 *
 
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.
 
602
 *
 
603
 * rgerhards, 2008-10-09:
 
604
 * interface change: bParseHostname removed, now in flags
585
605
 */
586
 
rsRetVal printline(uchar *hname, uchar *hnameIP, uchar *msg, int bParseHost, int flags, flowControl_t flowCtlType,
587
 
        uchar *pszInputName)
 
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)
588
608
{
589
609
        DEFiRet;
590
610
        register uchar *p;
592
612
        msg_t *pMsg;
593
613
 
594
614
        /* Now it is time to create the message object (rgerhards) */
595
 
        CHKiRet(msgConstruct(&pMsg));
 
615
        if(stTime == NULL) {
 
616
                CHKiRet(msgConstruct(&pMsg));
 
617
        } else {
 
618
                CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime));
 
619
        }
596
620
        if(pszInputName != NULL)
597
621
                MsgSetInputName(pMsg, (char*) pszInputName);
598
622
        MsgSetFlowControlType(pMsg, flowCtlType);
599
623
        MsgSetRawMsg(pMsg, (char*)msg);
600
624
        
601
 
        pMsg->bParseHOSTNAME  = bParseHost;
602
625
        /* test for special codes */
603
626
        pri = DEFUPRI;
604
627
        p = msg;
623
646
         * the message was received from (that, for obvious reasons,
624
647
         * being the local host).  rgerhards 2004-11-16
625
648
         */
626
 
        if(bParseHost == 0)
 
649
        if((pMsg->msgFlags & PARSE_HOSTNAME) == 0)
627
650
                MsgSetHOSTNAME(pMsg, (char*)hname);
628
651
        MsgSetRcvFrom(pMsg, (char*)hname);
629
652
        CHKiRet(MsgSetRcvFromIP(pMsg, hnameIP));
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
687
710
 * non-NULL.
 
711
 *
 
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.
 
717
 *
 
718
 * rgerhards, 2008-10-09:
 
719
 * interface change: bParseHostname removed, now in flags
688
720
 */
689
721
rsRetVal
690
 
parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int bParseHost, int flags, flowControl_t flowCtlType,
691
 
        uchar *pszInputName)
 
722
parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlType,
 
723
        uchar *pszInputName, struct syslogTime *stTime, time_t ttGenTime)
692
724
{
693
725
        DEFiRet;
694
726
        register int iMsg;
715
747
         * TODO: optimize buffer handling */
716
748
        iMaxLine = glbl.GetMaxLine();
717
749
        CHKmalloc(tmpline = malloc(sizeof(uchar) * (iMaxLine + 1)));
718
 
#       ifdef USE_NETZIP
719
 
        CHKmalloc(deflateBuf = malloc(sizeof(uchar) * (iMaxLine + 1)));
720
 
#       endif
721
750
 
722
751
        /* we first check if we have a NUL character at the very end of the
723
752
         * message. This seems to be a frequent problem with a number of senders.
763
792
                 */
764
793
                int ret;
765
794
                iLenDefBuf = iMaxLine;
 
795
                CHKmalloc(deflateBuf = malloc(sizeof(uchar) * (iMaxLine + 1)));
766
796
                ret = uncompress((uchar *) deflateBuf, &iLenDefBuf, (uchar *) msg+1, len-1);
767
797
                dbgprintf("Compressed message uncompressed with status %d, length: new %ld, old %d.\n",
768
798
                        ret, (long) iLenDefBuf, len-1);
801
831
                         */
802
832
                        if(iMsg == iMaxLine) {
803
833
                                *(pMsg + iMsg) = '\0'; /* space *is* reserved for this! */
804
 
                                printline(hname, hnameIP, tmpline, bParseHost, flags, flowCtlType, pszInputName);
 
834
                                printline(hname, hnameIP, tmpline, flags, flowCtlType, pszInputName, stTime, ttGenTime);
805
835
                        } else {
806
836
                                /* This case in theory never can happen. If it happens, we have
807
837
                                 * a logic error. I am checking for it, because if I would not,
853
883
        *(pMsg + iMsg) = '\0'; /* space *is* reserved for this! */
854
884
 
855
885
        /* typically, we should end up here! */
856
 
        printline(hname, hnameIP, tmpline, bParseHost, flags, flowCtlType, pszInputName);
 
886
        printline(hname, hnameIP, tmpline, flags, flowCtlType, pszInputName, stTime, ttGenTime);
857
887
 
858
888
finalize_it:
859
889
        if(tmpline != NULL)
903
933
        MsgSetRcvFrom(pMsg, (char*)glbl.GetLocalHostName());
904
934
        MsgSetRcvFromIP(pMsg, (uchar*)"127.0.0.1");
905
935
        /* check if we have an error code associated and, if so,
906
 
         * adjust the tag. -- r5gerhards, 2008-06-27
 
936
         * adjust the tag. -- rgerhards, 2008-06-27
907
937
         */
908
938
        if(iErr == NO_ERRCODE) {
909
939
                MsgSetTAG(pMsg, "rsyslogd:");
925
955
         * permits us to process unmodified config files which otherwise contain a
926
956
         * supressor statement.
927
957
         */
928
 
        if(bErrMsgToStderr || iConfigVerify) {
929
 
                fprintf(stderr, "rsyslogd: %s\n", msg);
 
958
        if(((Debug || NoFork) && bErrMsgToStderr) || iConfigVerify) {
 
959
                if(LOG_PRI(pri) == LOG_ERR)
 
960
                        fprintf(stderr, "rsyslogd: %s\n", msg);
930
961
        }
931
962
 
932
963
        if(bHaveMainQueue == 0) { /* not yet in queued mode */
1048
1079
                        break;
1049
1080
                case FIOP_REGEX:
1050
1081
                        if(rsCStrSzStrMatchRegex(f->f_filterData.prop.pCSCompValue,
1051
 
                                          (unsigned char*) pszPropVal) == 0)
 
1082
                                        (unsigned char*) pszPropVal, 0, &f->f_filterData.prop.regex_cache) == RS_RET_OK)
 
1083
                                bRet = 1;
 
1084
                        break;
 
1085
                case FIOP_EREREGEX:
 
1086
                        if(rsCStrSzStrMatchRegex(f->f_filterData.prop.pCSCompValue,
 
1087
                                          (unsigned char*) pszPropVal, 1, &f->f_filterData.prop.regex_cache) == RS_RET_OK)
1052
1088
                                bRet = 1;
1053
1089
                        break;
1054
1090
                default:
1177
1213
 
1178
1214
        assert(pMsg != NULL);
1179
1215
 
 
1216
        if((pMsg->msgFlags & NEEDS_PARSING) != 0) {
 
1217
                parseMsg(pMsg);
 
1218
        }
1180
1219
        processMsg(pMsg);
1181
1220
        msgDestruct(&pMsg);
1182
1221
 
1252
1291
        if(*p2parse != '[')
1253
1292
                return 1; /* this is NOT structured data! */
1254
1293
 
1255
 
        while(bCont) {
1256
 
                if(*p2parse == '\0') {
1257
 
                        iRet = 1; /* this is not valid! */
1258
 
                        bCont = 0;
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;
1266
 
                        p2parse += 2;
1267
 
                        bCont = 0;
1268
 
                } else {
1269
 
                        *pResult++ = *p2parse++;
 
1294
        if(*p2parse == '-') { /* empty structured data? */
 
1295
                *pResult++ = '-';
 
1296
                ++p2parse;
 
1297
        } else {
 
1298
                while(bCont) {
 
1299
                        if(*p2parse == '\0') {
 
1300
                                iRet = 1; /* this is not valid! */
 
1301
                                bCont = 0;
 
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;
 
1309
                                p2parse += 2;
 
1310
                                bCont = 0;
 
1311
                        } else {
 
1312
                                *pResult++ = *p2parse++;
 
1313
                        }
1270
1314
                }
1271
1315
        }
1272
1316
 
1298
1342
 *
1299
1343
 * rger, 2005-11-24
1300
1344
 */
1301
 
static int parseRFCSyslogMsg(msg_t *pMsg, int flags)
 
1345
int parseRFCSyslogMsg(msg_t *pMsg, int flags)
1302
1346
{
1303
1347
        char *p2parse;
1304
1348
        char *pBuf;
1305
1349
        int bContParse = 1;
1306
1350
 
 
1351
        BEGINfunc
1307
1352
        assert(pMsg != NULL);
1308
1353
        assert(pMsg->pszUxTradMsg != NULL);
1309
1354
        p2parse = (char*) pMsg->pszUxTradMsg;
1377
1422
        MsgSetMSG(pMsg, p2parse);
1378
1423
 
1379
1424
        free(pBuf);
 
1425
        ENDfunc
1380
1426
        return 0; /* all ok */
1381
1427
}
1382
1428
 
1394
1440
 * but I thought I log it in this comment.
1395
1441
 * rgerhards, 2006-01-10
1396
1442
 */
1397
 
static int parseLegacySyslogMsg(msg_t *pMsg, int flags)
 
1443
int parseLegacySyslogMsg(msg_t *pMsg, int flags)
1398
1444
{
1399
1445
        char *p2parse;
1400
1446
        char *pBuf;
1456
1502
                 * the fields. I think this logic shall work with any type of syslog message.
1457
1503
                 */
1458
1504
                bTAGCharDetected = 0;
1459
 
                if(pMsg->bParseHOSTNAME) {
 
1505
                if(flags & PARSE_HOSTNAME) {
1460
1506
                        /* TODO: quick and dirty memory allocation */
1461
1507
                        /* the memory allocated is far too much in most cases. But on the plus side,
1462
1508
                         * it is quite fast... - rgerhards, 2007-09-20
1589
1635
        ISOBJ_TYPE_assert(pMsg, msg);
1590
1636
        
1591
1637
        MsgPrepareEnqueue(pMsg);
1592
 
        queueEnqObj(pMsgQueue, pMsg->flowCtlType, (void*) pMsg);
 
1638
        qqueueEnqObj(pMsgQueue, pMsg->flowCtlType, (void*) pMsg);
1593
1639
 
1594
1640
        RETiRet;
1595
1641
}
1650
1696
        /* now submit the message to the main queue - then we are done */
1651
1697
        pMsg->msgFlags = flags;
1652
1698
        MsgPrepareEnqueue(pMsg);
1653
 
        queueEnqObj(pMsgQueue, pMsg->flowCtlType, (void*) pMsg);
 
1699
        qqueueEnqObj(pMsgQueue, pMsg->flowCtlType, (void*) pMsg);
1654
1700
        ENDfunc
1655
1701
}
1656
1702
 
1877
1923
#       define MSG1 "DoDie called.\n"
1878
1924
#       define MSG2 "DoDie called 5 times - unconditional exit\n"
1879
1925
        static int iRetries = 0; /* debug aid */
1880
 
        if(Debug || NoFork)
 
1926
        if(Debug)
1881
1927
                write(1, MSG1, sizeof(MSG1) - 1);
1882
1928
        if(iRetries++ == 4) {
1883
 
                if(Debug || NoFork)
 
1929
                if(Debug)
1884
1930
                        write(1, MSG2, sizeof(MSG2) - 1);
1885
1931
                abort();
1886
1932
        }
1934
1980
 
1935
1981
        /* close the inputs */
1936
1982
        dbgprintf("Terminating input threads...\n");
1937
 
        thrdTerminateAll(); /* TODO: inputs only, please */
 
1983
        thrdTerminateAll();
1938
1984
 
1939
1985
        /* and THEN send the termination log message (see long comment above) */
1940
1986
        if (sig) {
1948
1994
        
1949
1995
        /* drain queue (if configured so) and stop main queue worker thread pool */
1950
1996
        dbgprintf("Terminating main queue...\n");
1951
 
        queueDestruct(&pMsgQueue);
 
1997
        qqueueDestruct(&pMsgQueue);
1952
1998
        pMsgQueue = NULL;
1953
1999
 
1954
2000
        /* Free ressources and close connections. This includes flushing any remaining
2043
2089
}
2044
2090
 
2045
2091
 
 
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
 
2096
 */
 
2097
static void doDropPrivGid(int iGid)
 
2098
{
 
2099
        int res;
 
2100
        uchar szBuf[1024];
 
2101
 
 
2102
        res = setgroups(0, NULL); /* remove all supplementary group IDs */
 
2103
        if(res) {
 
2104
                perror("could not remove supplemental group IDs");
 
2105
                exit(1);
 
2106
        }
 
2107
        DBGPRINTF("setgroups(0, NULL): %d\n", res);
 
2108
        res = setgid(iGid);
 
2109
        if(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");
 
2112
                exit(1);
 
2113
        }
 
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);
 
2117
}
 
2118
 
 
2119
 
 
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
 
2124
 */
 
2125
static void doDropPrivUid(int iUid)
 
2126
{
 
2127
        int res;
 
2128
        uchar szBuf[1024];
 
2129
 
 
2130
        res = setuid(iUid);
 
2131
        if(res) {
 
2132
                /* if we can not set the userid, this is fatal, so let's unconditionally abort */
 
2133
                perror("could not set requested userid");
 
2134
                exit(1);
 
2135
        }
 
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);
 
2139
}
 
2140
 
 
2141
 
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);
2175
2271
 
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",
2185
2281
        /* TODO: add
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);
2195
2289
         */
2196
2290
        dbgprintf("Work Directory: '%s'.\n", glbl.GetWorkDir());
2197
2291
}
2237
2331
        DEFiRet;
2238
2332
        rsRetVal localRet;
2239
2333
        int iNbrActions;
 
2334
        int bHadConfigErr = 0;
2240
2335
        char cbuf[BUFSIZ];
2241
2336
        char bufStartUpMsg[512];
2242
2337
        struct sigaction sigAct;
2253
2348
        /* delete the message queue, which also flushes all messages left over */
2254
2349
        if(pMsgQueue != NULL) {
2255
2350
                dbgprintf("deleting main message queue\n");
2256
 
                queueDestruct(&pMsgQueue); /* delete pThis here! */
 
2351
                qqueueDestruct(&pMsgQueue); /* delete pThis here! */
2257
2352
                pMsgQueue = NULL;
2258
2353
        }
2259
2354
 
2287
2382
 
2288
2383
        if(localRet != RS_RET_OK) {
2289
2384
                errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", ConfFile);
 
2385
                bHadConfigErr = 1;
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.");
 
2389
                bHadConfigErr = 1;
2293
2390
        }
2294
2391
 
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
2357
2454
         */
2358
 
        if(iConfigVerify)
 
2455
        if(iConfigVerify) {
 
2456
                if(bHadConfigErr) {
 
2457
                        /* a bit dirty, but useful... */
 
2458
                        exit(1);
 
2459
                }
2359
2460
                ABORT_FINALIZE(RS_RET_VALIDATION_RUN);
 
2461
        }
2360
2462
 
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();
2364
2467
        }
2365
2468
 
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);
2370
2473
                exit(1);
2382
2485
                errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \
2383
2486
        }
2384
2487
 
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);
2402
2505
 
2403
2506
#       undef setQPROP
2404
2507
#       undef setQPROPstr
2405
2508
 
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);
2410
2513
                exit(1);
2429
2532
         */
2430
2533
        snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char), 
2431
2534
                 " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \
2432
 
                 "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] restart",
 
2535
                 "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] (re)start",
2433
2536
                 (int) myPid);
2434
2537
        logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)bufStartUpMsg, 0);
2435
2538
 
2525
2628
 * The following function is resposible for handling a SIGHUP signal.  Since
2526
2629
 * we are now doing mallocs/free as part of init we had better not being
2527
2630
 * doing this during a signal handler.  Instead this function simply sets
2528
 
 * a flag variable which will tell the main loop to go through a restart.
 
2631
 * a flag variable which will tells the main loop to do "the right thing".
2529
2632
 */
2530
2633
void sighup_handler()
2531
2634
{
2532
2635
        struct sigaction sigAct;
2533
2636
        
2534
 
        restart = 1;
 
2637
        bHadHUP = 1;
2535
2638
 
2536
2639
        memset(&sigAct, 0, sizeof (sigAct));
2537
2640
        sigemptyset(&sigAct.sa_mask);
2538
2641
        sigAct.sa_handler = sighup_handler;
2539
2642
        sigaction(SIGHUP, &sigAct, NULL);
2540
 
 
2541
 
        return;
2542
2643
}
2543
2644
 
2544
2645
 
2560
2661
}
2561
2662
 
2562
2663
 
 
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
 
2667
 */
 
2668
DEFFUNC_llExecFunc(doHUPActions)
 
2669
{
 
2670
        BEGINfunc
 
2671
        actionCallHUPHdlr((action_t*) pData);
 
2672
        ENDfunc
 
2673
        return RS_RET_OK; /* we ignore errors, we can not do anything either way */
 
2674
}
 
2675
 
 
2676
 
 
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
 
2681
 */
 
2682
static inline void
 
2683
doHUP(void)
 
2684
{
 
2685
        selector_t *f;
 
2686
        char buf[512];
 
2687
 
 
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");
 
2692
                errno = 0;
 
2693
        logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0);
 
2694
 
 
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() */
 
2698
        } else {
 
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);
 
2702
                }
 
2703
        }
 
2704
}
 
2705
 
 
2706
 
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
2616
2760
                if(bReduceRepeatMsgs == 1)
2617
2761
                        doFlushRptdMsgs();
2618
2762
 
2619
 
                if(restart) {
2620
 
                        dbgprintf("\nReceived SIGHUP, reloading rsyslogd.\n");
2621
 
                        /* main queue is stopped as part of init() */
2622
 
                        init();
2623
 
                        restart = 0;
 
2763
                if(bHadHUP) {
 
2764
                        doHUP();
 
2765
                        bHadHUP = 0;
2624
2766
                        continue;
2625
2767
                }
2626
2768
        }
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));
2753
2899
 
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
2848
2994
        }
2849
2995
        /* Send a signal to the parent so it can terminate.
2850
2996
         */
2851
 
        if (myPid != ppid)
2852
 
                kill (ppid, SIGTERM);
 
2997
        if(myPid != ppid)
 
2998
                kill(ppid, SIGTERM);
 
2999
 
 
3000
 
 
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
 
3007
         */
 
3008
        if(gidDropPriv != 0) {
 
3009
                doDropPrivGid(gidDropPriv);
 
3010
                glbl.SetHUPisRestart(0); /* we can not do restart-type HUPs with dropped privs */
 
3011
        }
 
3012
 
 
3013
        if(uidDropPriv != 0) {
 
3014
                doDropPrivUid(uidDropPriv);
 
3015
                glbl.SetHUPisRestart(0); /* we can not do restart-type HUPs with dropped privs */
 
3016
        }
 
3017
 
2853
3018
 
2854
3019
        /* END OF INTIALIZATION
2855
3020
         * ... but keep in mind that we might do a restart and thus init() might
2904
3069
        CHKiRet(actionClassInit());
2905
3070
        pErrObj = "template";
2906
3071
        CHKiRet(templateInit());
 
3072
        pErrObj = "parser";
 
3073
        CHKiRet(parserClassInit());
2907
3074
 
2908
3075
        /* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */
2909
3076
        pErrObj = "net";
2949
3116
        CHKiRet(strmClassInit(NULL));
2950
3117
        CHKiRet(wtiClassInit(NULL));
2951
3118
        CHKiRet(wtpClassInit(NULL));
2952
 
        CHKiRet(queueClassInit(NULL));
 
3119
        CHKiRet(qqueueClassInit(NULL));
2953
3120
        CHKiRet(vmstkClassInit(NULL));
2954
3121
        CHKiRet(sysvarClassInit(NULL));
2955
3122
        CHKiRet(vmClassInit(NULL));
3083
3250
                                exit(1); /* "good" exit - after forking, not diasabling anything */
3084
3251
                        }
3085
3252
                        num_fds = getdtablesize();
3086
 
                        for (i= 0; i < num_fds; i++)
 
3253
                        close(0);
 
3254
                        /* we keep stdout and stderr open in case we have to emit something */
 
3255
                        for (i = 3; i < num_fds; i++)
3087
3256
                                (void) close(i);
3088
3257
                        untty();
3089
3258
                }
3157
3326
        uchar legacyConfLine[80];
3158
3327
        uchar *LocalHostName;
3159
3328
        uchar *LocalDomain;
 
3329
        uchar *LocalFQDNName;
3160
3330
 
3161
3331
        /* first, parse the command line options. We do not carry out any actual work, just
3162
3332
         * see what we should do. This relieves us from certain anomalies and we can process
3172
3342
         * only when actually neeeded. 
3173
3343
         * rgerhards, 2008-04-04
3174
3344
         */
3175
 
        while((ch = getopt(argc, argv, "46a:Ac:def:g:hi:l:m:M:nN:op:qQr::s:t:u:vwx")) != EOF) {
 
3345
        while((ch = getopt(argc, argv, "46a:Ac:def:g:hi:l:m:M:nN:op:qQr::s:t:T:u:vwx")) != EOF) {
3176
3346
                switch((char)ch) {
3177
3347
                case '4':
3178
3348
                case '6':
3190
3360
                case 'q': /* add hostname if DNS resolving has failed */
3191
3361
                case 'Q': /* dont resolve hostnames in ACL to IPs */
3192
3362
                case 's':
 
3363
                case 'T': /* chroot on startup (primarily for testing) */
3193
3364
                case 'u': /* misc user settings */
3194
3365
                case 'w': /* disable disallowed host warnings */
3195
3366
                case 'x': /* disable dns for remote messages */
3261
3432
        /* get our host and domain names - we need to do this early as we may emit
3262
3433
         * error log messages, which need the correct hostname. -- rgerhards, 2008-04-04
3263
3434
         */
3264
 
        net.getLocalHostname(&LocalHostName);
 
3435
        net.getLocalHostname(&LocalFQDNName);
 
3436
        CHKmalloc(LocalHostName = (uchar*) strdup((char*)LocalFQDNName));
 
3437
        glbl.SetLocalFQDNName(LocalFQDNName); /* set the FQDN before we modify it */
3265
3438
        if((p = (uchar*)strchr((char*)LocalHostName, '.'))) {
3266
3439
                *p++ = '\0';
3267
3440
                LocalDomain = p;
3321
3494
        /* END core initializations - we now come back to carrying out command line options*/
3322
3495
 
3323
3496
        while((iRet = bufOptRemove(&ch, &arg)) == RS_RET_OK) {
3324
 
                dbgprintf("deque option %c, optarg '%s'\n", ch, arg);
 
3497
                dbgprintf("deque option %c, optarg '%s'\n", ch, (arg == NULL) ? "" : arg);
3325
3498
                switch((char)ch) {
3326
3499
                case '4':
3327
3500
                        glbl.SetDefPFFamily(PF_INET);
3432
3605
                        } else
3433
3606
                                fprintf(stderr, "-t option only supported in compatibility modes 0 to 2 - ignored\n");
3434
3607
                        break;
 
3608
                case 'T':/* chroot() immediately at program startup, but only for testing, NOT security yet */
 
3609
{
 
3610
char buf[1024];
 
3611
getcwd(buf, 1024);
 
3612
printf("pwd: '%s'\n", buf);
 
3613
printf("chroot to '%s'\n", arg);
 
3614
                        if(chroot(arg) != 0) {
 
3615
                                perror("chroot");
 
3616
                                exit(1);
 
3617
                        }
 
3618
getcwd(buf, 1024);
 
3619
printf("pwd: '%s'\n", buf);
 
3620
}
 
3621
                        break;
3435
3622
                case 'u':               /* misc user settings */
3436
3623
                        iHelperUOpt = atoi(arg);
3437
3624
                        if(iHelperUOpt & 0x01)
3466
3653
 
3467
3654
 
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.");
 
3661
        }
 
3662
 
 
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);
3522
3712
        dbgClassInit();
3523
3713
        return realMain(argc, argv);
3524
3714
}
3525
 
 
3526
3715
/* vim:set ai:
3527
3716
 */