add elasticsearch output module
[rsyslog.git] / tools / syslogd.c
1 /**
2  * \brief This is the main file of the rsyslogd daemon.
3  *
4  * Please visit the rsyslog project at
5  *
6  * http://www.rsyslog.com
7  *
8  * to learn more about it and discuss any questions you may have.
9  *
10  * rsyslog had initially been forked from the sysklogd project.
11  * I would like to express my thanks to the developers of the sysklogd
12  * package - without it, I would have had a much harder start...
13  *
14  * Please note that while rsyslog started from the sysklogd code base,
15  * it nowadays has almost nothing left in common with it. Allmost all
16  * parts of the code have been rewritten.
17  *
18  * This Project was intiated and is maintained by
19  * Rainer Gerhards <rgerhards@hq.adiscon.com>.
20  *
21  * For further information, please see http://www.rsyslog.com
22  *
23  * rsyslog - An Enhanced syslogd Replacement.
24  * Copyright 2003-2009 Rainer Gerhards and Adiscon GmbH.
25  *
26  * This file is part of rsyslog.
27  *
28  * Rsyslog is free software: you can redistribute it and/or modify
29  * it under the terms of the GNU General Public License as published by
30  * the Free Software Foundation, either version 3 of the License, or
31  * (at your option) any later version.
32  *
33  * Rsyslog is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with Rsyslog.  If not, see <http://www.gnu.org/licenses/>.
40  *
41  * A copy of the GPL can be found in the file "COPYING" in this distribution.
42  */
43 #include "config.h"
44 #include "rsyslog.h"
45
46 #define DEFUPRI         (LOG_USER|LOG_NOTICE)
47 #define TIMERINTVL      30              /* interval for checking flush, mark */
48
49 #include <unistd.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <stddef.h>
53 #include <ctype.h>
54 #include <limits.h>
55 #define GNU_SOURCE
56 #include <string.h>
57 #include <stdarg.h>
58 #include <time.h>
59 #include <assert.h>
60
61 #ifdef OS_SOLARIS
62 #       include <errno.h>
63 #       include <fcntl.h>
64 #       include <stropts.h>
65 #       include <sys/termios.h>
66 #       include <sys/types.h>
67 #else
68 #       include <libgen.h>
69 #       include <sys/errno.h>
70 #endif
71
72 #include <sys/ioctl.h>
73 #include <sys/wait.h>
74 #include <sys/file.h>
75 #include <sys/resource.h>
76 #include <grp.h>
77
78 #if HAVE_SYS_TIMESPEC_H
79 # include <sys/timespec.h>
80 #endif
81
82 #if HAVE_SYS_STAT_H
83 #       include <sys/stat.h>
84 #endif
85
86 #include <signal.h>
87
88 #if HAVE_PATHS_H
89 #include <paths.h>
90 #endif
91
92 #ifdef USE_NETZIP
93 #include <zlib.h>
94 #endif
95
96 #include <netdb.h>
97
98 #include "pidfile.h"
99 #include "srUtils.h"
100 #include "stringbuf.h"
101 #include "syslogd-types.h"
102 #include "template.h"
103 #include "outchannel.h"
104 #include "syslogd.h"
105
106 #include "msg.h"
107 #include "modules.h"
108 #include "action.h"
109 #include "iminternal.h"
110 #include "cfsysline.h"
111 #include "omshell.h"
112 #include "omusrmsg.h"
113 #include "omfwd.h"
114 #include "omfile.h"
115 #include "ompipe.h"
116 #include "omdiscard.h"
117 #include "pmrfc5424.h"
118 #include "pmrfc3164.h"
119 #include "smfile.h"
120 #include "smtradfile.h"
121 #include "smfwd.h"
122 #include "smtradfwd.h"
123 #include "threads.h"
124 #include "wti.h"
125 #include "queue.h"
126 #include "stream.h"
127 #include "conf.h"
128 #include "errmsg.h"
129 #include "datetime.h"
130 #include "parser.h"
131 #include "batch.h"
132 #include "unicode-helper.h"
133 #include "ruleset.h"
134 #include "rule.h"
135 #include "net.h"
136 #include "vm.h"
137 #include "prop.h"
138 #include "sd-daemon.h"
139
140 /* definitions for objects we access */
141 DEFobjCurrIf(obj)
142 DEFobjCurrIf(glbl)
143 DEFobjCurrIf(datetime) /* TODO: make go away! */
144 DEFobjCurrIf(conf)
145 DEFobjCurrIf(expr)
146 DEFobjCurrIf(module)
147 DEFobjCurrIf(errmsg)
148 DEFobjCurrIf(rule)
149 DEFobjCurrIf(ruleset)
150 DEFobjCurrIf(prop)
151 DEFobjCurrIf(parser)
152 DEFobjCurrIf(net) /* TODO: make go away! */
153
154
155 /* forward definitions */
156 static rsRetVal GlobalClassExit(void);
157
158
159 #ifndef _PATH_LOGCONF 
160 #define _PATH_LOGCONF   "/etc/rsyslog.conf"
161 #endif
162
163 #ifndef _PATH_MODDIR
164 #       if defined(__FreeBSD__)
165 #               define _PATH_MODDIR     "/usr/local/lib/rsyslog/"
166 #       else
167 #               define _PATH_MODDIR     "/lib/rsyslog/"
168 #       endif
169 #endif
170
171 #if defined(SYSLOGD_PIDNAME)
172 #       undef _PATH_LOGPID
173 #       if defined(FSSTND)
174 #               ifdef OS_BSD
175 #                       define _PATH_VARRUN "/var/run/"
176 #               endif
177 #               if defined(__sun) || defined(__hpux)
178 #                       define _PATH_VARRUN "/var/run/"
179 #               endif
180 #               define _PATH_LOGPID _PATH_VARRUN SYSLOGD_PIDNAME
181 #       else
182 #               define _PATH_LOGPID "/etc/" SYSLOGD_PIDNAME
183 #       endif
184 #else
185 #       ifndef _PATH_LOGPID
186 #               if defined(__sun) || defined(__hpux)
187 #                       define _PATH_VARRUN "/var/run/"
188 #               endif
189 #               if defined(FSSTND)
190 #                       define _PATH_LOGPID _PATH_VARRUN "rsyslogd.pid"
191 #               else
192 #                       define _PATH_LOGPID "/etc/rsyslogd.pid"
193 #               endif
194 #       endif
195 #endif
196
197 #ifndef _PATH_TTY
198 #       define _PATH_TTY        "/dev/tty"
199 #endif
200
201 static prop_t *pInternalInputName = NULL;       /* there is only one global inputName for all internally-generated messages */
202 static prop_t *pLocalHostIP = NULL;             /* there is only one global IP for all internally-generated messages */
203 static uchar    *ConfFile = (uchar*) _PATH_LOGCONF; /* read-only after startup */
204 static char     *PidFile = _PATH_LOGPID; /* read-only after startup */
205
206 static pid_t myPid;     /* our pid for use in self-generated messages, e.g. on startup */
207 /* mypid is read-only after the initial fork() */
208 static int bHadHUP = 0; /* did we have a HUP? */
209
210 static int bFinished = 0;       /* used by termination signal handler, read-only except there
211                                  * is either 0 or the number of the signal that requested the
212                                  * termination.
213                                  */
214 static int iConfigVerify = 0;   /* is this just a config verify run? */
215
216 /* Intervals at which we flush out "message repeated" messages,
217  * in seconds after previous message is logged.  After each flush,
218  * we move to the next interval until we reach the largest.
219  * TODO: this shall go into action object! -- rgerhards, 2008-01-29
220  */
221 int     repeatinterval[2] = { 30, 60 }; /* # of secs before flush */
222
223 #define LIST_DELIMITER  ':'             /* delimiter between two hosts */
224
225 static pid_t ppid; /* This is a quick and dirty hack used for spliting main/startup thread */
226
227 typedef struct legacyOptsLL_s {
228         uchar *line;
229         struct legacyOptsLL_s *next;
230 } legacyOptsLL_t;
231 legacyOptsLL_t *pLegacyOptsLL = NULL;
232
233 /* global variables for config file state */
234 int     iCompatibilityMode = 0;         /* version we should be compatible with; 0 means sysklogd. It is
235                                            the default, so if no -c<n> option is given, we make ourselvs
236                                            as compatible to sysklogd as possible. */
237 #define DFLT_bLogStatusMsgs 1
238 static int      bLogStatusMsgs = DFLT_bLogStatusMsgs;   /* log rsyslog start/stop/HUP messages? */
239 static int      bDebugPrintTemplateList = 1;/* output template list in debug mode? */
240 static int      bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list in debug mode? */
241 static int      bDebugPrintModuleList = 1;/* output module list in debug mode? */
242 static int      bErrMsgToStderr = 1; /* print error messages to stderr (in addition to everything else)? */
243 int     bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */
244 int     bAbortOnUncleanConfig = 0; /* abort run (rather than starting with partial config) if there was any issue in conf */
245 int     bActExecWhenPrevSusp; /* execute action only when previous one was suspended? */
246 /* end global config file state variables */
247
248 int     MarkInterval = 20 * 60; /* interval between marks in seconds - read-only after startup */
249 int      send_to_all = 0;        /* send message to all IPv4/IPv6 addresses */
250 static int      NoFork = 0;     /* don't fork - don't run in daemon mode - read-only after startup */
251 static int      bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode - is available
252                                  * If the main queue is either not yet ready or not running in 
253                                  * queueing mode (mode DIRECT!), then this is set to 0.
254                                  */
255 static int uidDropPriv = 0;     /* user-id to which priveleges should be dropped to (AFTER init()!) */
256 static int gidDropPriv = 0;     /* group-id to which priveleges should be dropped to (AFTER init()!) */
257
258 extern  int errno;
259
260 static uchar *pszConfDAGFile = NULL;                            /* name of config DAG file, non-NULL means generate one */
261 /* main message queue and its configuration parameters */
262 qqueue_t *pMsgQueue = NULL;                             /* the main message queue */
263 static int iMainMsgQueueSize = 10000;                           /* size of the main message queue above */
264 static int iMainMsgQHighWtrMark = 8000;                         /* high water mark for disk-assisted queues */
265 static int iMainMsgQLowWtrMark = 2000;                          /* low water mark for disk-assisted queues */
266 static int iMainMsgQDiscardMark = 9800;                         /* begin to discard messages */
267 static int iMainMsgQDiscardSeverity = 8;                        /* by default, discard nothing to prevent unintentional loss */
268 static int iMainMsgQueueNumWorkers = 1;                         /* number of worker threads for the mm queue above */
269 static queueType_t MainMsgQueType = QUEUETYPE_FIXED_ARRAY;      /* type of the main message queue above */
270 static uchar *pszMainMsgQFName = NULL;                          /* prefix for the main message queue file */
271 static int64 iMainMsgQueMaxFileSize = 1024*1024;
272 static int iMainMsgQPersistUpdCnt = 0;                          /* persist queue info every n updates */
273 static int bMainMsgQSyncQeueFiles = 0;                          /* sync queue files on every write? */
274 static int iMainMsgQtoQShutdown = 1500;                         /* queue shutdown (ms) */ 
275 static int iMainMsgQtoActShutdown = 1000;                       /* action shutdown (in phase 2) */ 
276 static int iMainMsgQtoEnq = 2000;                               /* timeout for queue enque */ 
277 static int iMainMsgQtoWrkShutdown = 60000;                      /* timeout for worker thread shutdown */
278 static int iMainMsgQWrkMinMsgs = 100;                           /* minimum messages per worker needed to start a new one */
279 static int iMainMsgQDeqSlowdown = 0;                            /* dequeue slowdown (simple rate limiting) */
280 static int64 iMainMsgQueMaxDiskSpace = 0;                       /* max disk space allocated 0 ==> unlimited */
281 static int64 iMainMsgQueDeqBatchSize = 32;                      /* dequeue batch size */
282 static int bMainMsgQSaveOnShutdown = 1;                         /* save queue on shutdown (when DA enabled)? */
283 static int iMainMsgQueueDeqtWinFromHr = 0;                      /* hour begin of time frame when queue is to be dequeued */
284 static int iMainMsgQueueDeqtWinToHr = 25;                       /* hour begin of time frame when queue is to be dequeued */
285
286
287 /* Reset config variables to default values.
288  * rgerhards, 2007-07-17
289  */
290 static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
291 {
292         bLogStatusMsgs = DFLT_bLogStatusMsgs;
293         bActExecWhenPrevSusp = 0;
294         bDebugPrintTemplateList = 1;
295         bDebugPrintCfSysLineHandlerList = 1;
296         bDebugPrintModuleList = 1;
297         bReduceRepeatMsgs = 0;
298         bAbortOnUncleanConfig = 0;
299         free(pszMainMsgQFName);
300         pszMainMsgQFName = NULL;
301         iMainMsgQueueSize = 10000;
302         iMainMsgQHighWtrMark = 8000;
303         iMainMsgQLowWtrMark = 2000;
304         iMainMsgQDiscardMark = 9800;
305         iMainMsgQDiscardSeverity = 8;
306         iMainMsgQueMaxFileSize = 1024 * 1024;
307         iMainMsgQueueNumWorkers = 1;
308         iMainMsgQPersistUpdCnt = 0;
309         bMainMsgQSyncQeueFiles = 0;
310         iMainMsgQtoQShutdown = 1500;
311         iMainMsgQtoActShutdown = 1000;
312         iMainMsgQtoEnq = 2000;
313         iMainMsgQtoWrkShutdown = 60000;
314         iMainMsgQWrkMinMsgs = 100;
315         iMainMsgQDeqSlowdown = 0;
316         bMainMsgQSaveOnShutdown = 1;
317         MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
318         iMainMsgQueMaxDiskSpace = 0;
319         iMainMsgQueDeqBatchSize = 32;
320         glbliActionResumeRetryCount = 0;
321
322         return RS_RET_OK;
323 }
324
325
326 /* hardcoded standard templates (used for defaults) */
327 static uchar template_DebugFormat[] = "\"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%', HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\ninputname: %inputname% rawmsg: '%rawmsg%'\n\n\"";
328 static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\"";
329 static uchar template_TraditionalFileFormat[] = "=RSYSLOG_TraditionalFileFormat";
330 static uchar template_FileFormat[] = "=RSYSLOG_FileFormat";
331 static uchar template_ForwardFormat[] = "=RSYSLOG_ForwardFormat";
332 static uchar template_TraditionalForwardFormat[] = "=RSYSLOG_TraditionalForwardFormat";
333 static uchar template_WallFmt[] = "\"\r\n\7Message from syslogd@%HOSTNAME% at %timegenerated% ...\r\n %syslogtag%%msg%\n\r\"";
334 static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\"";
335 static uchar template_StdDBFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')\",SQL";
336 static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%')\",STDSQL";
337 static uchar template_StdJSONFmt[] = "\"{\\\"message\\\":\\\"%msg%\\\",\\\"fromhost\\\":\\\"%HOSTNAME%\\\",\\\"facility\\\":\\\"%syslogfacility-text%\\\",\\\"priority\\\":\\\"%syslogpriority-text%\\\",\\\"timereported\\\":\\\"%timereported:::date-rfc3339%\\\",\\\"timegenerated\\\":\\\"%timegenerated:::date-rfc3339%\\\"}\",JSON";
338 static uchar template_spoofadr[] = "\"%fromhost-ip%\"";
339 /* end templates */
340
341
342 /* up to the next comment, prototypes that should be removed by reordering */
343 /* Function prototypes. */
344 static char **crunch_list(char *list);
345 static void reapchild();
346 static void debug_switch();
347 static void sighup_handler();
348
349
350 static int usage(void)
351 {
352         fprintf(stderr, "usage: rsyslogd [-c<version>] [-46AdnqQvwx] [-l<hostlist>] [-s<domainlist>]\n"
353                         "                [-f<conffile>] [-i<pidfile>] [-N<level>] [-M<module load path>]\n"
354                         "                [-u<number>]\n"
355                         "To run rsyslogd in native mode, use \"rsyslogd -c5 <other options>\"\n\n"
356                         "For further information see http://www.rsyslog.com/doc\n");
357         exit(1); /* "good" exit - done to terminate usage() */
358 }
359
360
361 /* ------------------------------ some support functions for imdiag ------------------------------ *
362  * This is a bit dirty, but the only way to do it, at least with reasonable effort.
363  * rgerhards, 2009-05-25
364  */
365
366 /* return back the approximate current number of messages in the main message queue
367  * This number includes the messages that reside in an associated DA queue (if
368  * it exists) -- rgerhards, 2009-10-14
369  */
370 rsRetVal
371 diagGetMainMsgQSize(int *piSize)
372 {
373         DEFiRet;
374         assert(piSize != NULL);
375         *piSize = (pMsgQueue->pqDA != NULL) ? pMsgQueue->pqDA->iQueueSize : 0;
376         *piSize += pMsgQueue->iQueueSize;
377         RETiRet;
378 }
379
380
381 /* ------------------------------ end support functions for imdiag  ------------------------------ */
382
383
384 /* rgerhards, 2005-10-24: crunch_list is called only during option processing. So
385  * it is never called once rsyslogd is running. This code
386  * contains some exits, but they are considered safe because they only happen
387  * during startup. Anyhow, when we review the code here, we might want to
388  * reconsider the exit()s.
389  */
390 static char **crunch_list(char *list)
391 {
392         int count, i;
393         char *p, *q;
394         char **result = NULL;
395
396         p = list;
397
398         /* strip off trailing delimiters */
399         while (p[strlen(p)-1] == LIST_DELIMITER) {
400                 count--;
401                 p[strlen(p)-1] = '\0';
402         }
403         /* cut off leading delimiters */
404         while (p[0] == LIST_DELIMITER) {
405                 count--;
406                p++;
407         }
408
409         /* count delimiters to calculate elements */
410         for (count=i=0; p[i]; i++)
411                 if (p[i] == LIST_DELIMITER) count++;
412
413         if ((result = (char **)MALLOC(sizeof(char *) * (count+2))) == NULL) {
414                 printf ("Sorry, can't get enough memory, exiting.\n");
415                 exit(0); /* safe exit, because only called during startup */
416         }
417
418         /*
419          * We now can assume that the first and last
420          * characters are different from any delimiters,
421          * so we don't have to care about this.
422          */
423         count = 0;
424         while ((q=strchr(p, LIST_DELIMITER))) {
425                 result[count] = (char *) MALLOC((q - p + 1) * sizeof(char));
426                 if (result[count] == NULL) {
427                         printf ("Sorry, can't get enough memory, exiting.\n");
428                         exit(0); /* safe exit, because only called during startup */
429                 }
430                 strncpy(result[count], p, q - p);
431                 result[count][q - p] = '\0';
432                 p = q; p++;
433                 count++;
434         }
435         if ((result[count] = \
436              (char *)MALLOC(sizeof(char) * strlen(p) + 1)) == NULL) {
437                 printf ("Sorry, can't get enough memory, exiting.\n");
438                 exit(0); /* safe exit, because only called during startup */
439         }
440         strcpy(result[count],p);
441         result[++count] = NULL;
442
443 #if 0
444         count=0;
445         while (result[count])
446                 DBGPRINTF("#%d: %s\n", count, StripDomains[count++]);
447 #endif
448         return result;
449 }
450
451
452 void untty(void)
453 #ifdef HAVE_SETSID
454 {
455         if(!Debug) {
456                 setsid();
457         }
458         return;
459 }
460 #else
461 {
462         int i;
463
464         if(!Debug) {
465                 i = open(_PATH_TTY, O_RDWR|O_CLOEXEC);
466                 if (i >= 0) {
467 #                       if !defined(__hpux)
468                                 (void) ioctl(i, (int) TIOCNOTTY, NULL);
469 #                       else
470                                 /* TODO: we need to implement something for HP UX! -- rgerhards, 2008-03-04 */
471                                 /* actually, HP UX should have setsid, so the code directly above should
472                                  * trigger. So the actual question is why it doesn't do that...
473                                  */
474 #                       endif
475                         close(i);
476                 }
477         }
478 }
479 #endif
480
481
482 /* This takes a received message that must be decoded and submits it to
483  * the main message queue. This is a legacy function which is being provided
484  * to aid older input plugins that do not support message creation via
485  * the new interfaces themselves. It is not recommended to use this
486  * function for new plugins. -- rgerhards, 2009-10-12
487  */
488 rsRetVal
489 parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlType,
490         prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime)
491 {
492         prop_t *pProp = NULL;
493         msg_t *pMsg;
494         DEFiRet;
495
496         /* we now create our own message object and submit it to the queue */
497         if(stTime == NULL) {
498                 CHKiRet(msgConstruct(&pMsg));
499         } else {
500                 CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime));
501         }
502         if(pInputName != NULL)
503                 MsgSetInputName(pMsg, pInputName);
504         MsgSetRawMsg(pMsg, (char*)msg, len);
505         MsgSetFlowControlType(pMsg, flowCtlType);
506         pMsg->msgFlags  = flags | NEEDS_PARSING;
507
508         MsgSetRcvFromStr(pMsg, hname, ustrlen(hname), &pProp);
509         CHKiRet(prop.Destruct(&pProp));
510         CHKiRet(MsgSetRcvFromIPStr(pMsg, hnameIP, ustrlen(hnameIP), &pProp));
511         CHKiRet(prop.Destruct(&pProp));
512         CHKiRet(submitMsg(pMsg));
513
514 finalize_it:
515         RETiRet;
516 }
517
518
519 /* this is a special function used to submit an error message. This
520  * function is also passed to the runtime library as the generic error
521  * message handler. -- rgerhards, 2008-04-17
522  */
523 rsRetVal
524 submitErrMsg(int iErr, uchar *msg)
525 {
526         DEFiRet;
527         iRet = logmsgInternal(iErr, LOG_SYSLOG|LOG_ERR, msg, 0);
528         RETiRet;
529 }
530
531
532 /* rgerhards 2004-11-09: the following is a function that can be used
533  * to log a message orginating from the syslogd itself.
534  */
535 rsRetVal
536 logmsgInternal(int iErr, int pri, uchar *msg, int flags)
537 {
538         uchar pszTag[33];
539         msg_t *pMsg;
540         DEFiRet;
541
542         CHKiRet(msgConstruct(&pMsg));
543         MsgSetInputName(pMsg, pInternalInputName);
544         MsgSetRawMsgWOSize(pMsg, (char*)msg);
545         MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
546         MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp());
547         MsgSetRcvFromIP(pMsg, pLocalHostIP);
548         MsgSetMSGoffs(pMsg, 0);
549         /* check if we have an error code associated and, if so,
550          * adjust the tag. -- rgerhards, 2008-06-27
551          */
552         if(iErr == NO_ERRCODE) {
553                 MsgSetTAG(pMsg, UCHAR_CONSTANT("rsyslogd:"), sizeof("rsyslogd:") - 1);
554         } else {
555                 size_t len = snprintf((char*)pszTag, sizeof(pszTag), "rsyslogd%d:", iErr);
556                 pszTag[32] = '\0'; /* just to make sure... */
557                 MsgSetTAG(pMsg, pszTag, len);
558         }
559         pMsg->iFacility = LOG_FAC(pri);
560         pMsg->iSeverity = LOG_PRI(pri);
561         flags |= INTERNAL_MSG;
562         pMsg->msgFlags  = flags;
563
564         /* we now check if we should print internal messages out to stderr. This was
565          * suggested by HKS as a way to help people troubleshoot rsyslog configuration
566          * (by running it interactively. This makes an awful lot of sense, so I add
567          * it here. -- rgerhards, 2008-07-28
568          * Note that error messages can not be disable during a config verify. This
569          * permits us to process unmodified config files which otherwise contain a
570          * supressor statement.
571          */
572         if(((Debug == DEBUG_FULL || NoFork) && bErrMsgToStderr) || iConfigVerify) {
573                 if(LOG_PRI(pri) == LOG_ERR)
574                         fprintf(stderr, "rsyslogd: %s\n", msg);
575         }
576
577         if(bHaveMainQueue == 0) { /* not yet in queued mode */
578                 iminternalAddMsg(pMsg);
579         } else {
580                /* we have the queue, so we can simply provide the
581                  * message to the queue engine.
582                  */
583                 submitMsg(pMsg);
584         }
585 finalize_it:
586         RETiRet;
587 }
588
589 /* check message against ACL set
590  * rgerhards, 2009-11-16
591  */
592 #if 0
593 static inline rsRetVal
594 chkMsgAgainstACL() {
595         /* if we reach this point, we had a good receive and can process the packet received */
596         /* check if we have a different sender than before, if so, we need to query some new values */
597         if(net.CmpHost(&frominet, frominetPrev, socklen) != 0) {
598                 CHKiRet(net.cvthname(&frominet, fromHost, fromHostFQDN, fromHostIP));
599                 memcpy(frominetPrev, &frominet, socklen); /* update cache indicator */
600                 /* Here we check if a host is permitted to send us
601                 * syslog messages. If it isn't, we do not further
602                 * process the message but log a warning (if we are
603                 * configured to do this).
604                 * rgerhards, 2005-09-26
605                 */
606                 *pbIsPermitted = net.isAllowedSender((uchar*)"UDP",
607                                                     (struct sockaddr *)&frominet, (char*)fromHostFQDN);
608
609                 if(!*pbIsPermitted) {
610                         DBGPRINTF("%s is not an allowed sender\n", (char*)fromHostFQDN);
611                         if(glbl.GetOption_DisallowWarning) {
612                                 time_t tt;
613
614                                 datetime.GetTime(&tt);
615                                 if(tt > ttLastDiscard + 60) {
616                                         ttLastDiscard = tt;
617                                         errmsg.LogError(0, NO_ERRCODE,
618                                         "UDP message from disallowed sender %s discarded",
619                                         (char*)fromHost);
620                                 }
621                         }
622                 }
623         }
624 }
625 #endif
626
627
628 /* preprocess a batch of messages, that is ready them for actual processing. This is done
629  * as a first stage and totally in parallel to any other worker active in the system. So
630  * it helps us keep up the overall concurrency level.
631  * rgerhards, 2010-06-09
632  */
633 static inline rsRetVal
634 preprocessBatch(batch_t *pBatch) {
635         uchar fromHost[NI_MAXHOST];
636         uchar fromHostIP[NI_MAXHOST];
637         uchar fromHostFQDN[NI_MAXHOST];
638         prop_t *propFromHost = NULL;
639         prop_t *propFromHostIP = NULL;
640         int bSingleRuleset;
641         ruleset_t *batchRuleset; /* the ruleset used for all message inside the batch, if there is a single one */
642         int bIsPermitted;
643         msg_t *pMsg;
644         int i;
645         rsRetVal localRet;
646         DEFiRet;
647
648         bSingleRuleset = 1;
649         batchRuleset = (pBatch->nElem > 0) ? ((msg_t*) pBatch->pElem[0].pUsrp)->pRuleset : NULL;
650         
651         for(i = 0 ; i < pBatch->nElem  && !*(pBatch->pbShutdownImmediate) ; i++) {
652                 pMsg = (msg_t*) pBatch->pElem[i].pUsrp;
653                 if((pMsg->msgFlags & NEEDS_ACLCHK_U) != 0) {
654                         DBGPRINTF("msgConsumer: UDP ACL must be checked for message (hostname-based)\n");
655                         if(net.cvthname(pMsg->rcvFrom.pfrominet, fromHost, fromHostFQDN, fromHostIP) != RS_RET_OK)
656                                 continue;
657                         bIsPermitted = net.isAllowedSender2((uchar*)"UDP",
658                             (struct sockaddr *)pMsg->rcvFrom.pfrominet, (char*)fromHostFQDN, 1);
659                         if(!bIsPermitted) {
660                                 DBGPRINTF("Message from '%s' discarded, not a permitted sender host\n",
661                                           fromHostFQDN);
662                                 pBatch->pElem[i].state = BATCH_STATE_DISC;
663                         } else {
664                                 /* save some of the info we obtained */
665                                 MsgSetRcvFromStr(pMsg, fromHost, ustrlen(fromHost), &propFromHost);
666                                 CHKiRet(MsgSetRcvFromIPStr(pMsg, fromHostIP, ustrlen(fromHostIP), &propFromHostIP));
667                                 pMsg->msgFlags &= ~NEEDS_ACLCHK_U;
668                         }
669                 }
670                 if((pMsg->msgFlags & NEEDS_PARSING) != 0) {
671                         if((localRet = parser.ParseMsg(pMsg)) != RS_RET_OK)  {
672                                 DBGPRINTF("Message discarded, parsing error %d\n", localRet);
673                                 pBatch->pElem[i].state = BATCH_STATE_DISC;
674                         }
675                 }
676                 if(pMsg->pRuleset != batchRuleset)
677                         bSingleRuleset = 0;
678         }
679
680         batchSetSingleRuleset(pBatch, bSingleRuleset);
681
682 finalize_it:
683         if(propFromHost != NULL)
684                 prop.Destruct(&propFromHost);
685         if(propFromHostIP != NULL)
686                 prop.Destruct(&propFromHostIP);
687         RETiRet;
688 }
689
690 /* The consumer of dequeued messages. This function is called by the
691  * queue engine on dequeueing of a message. It runs on a SEPARATE
692  * THREAD. It receives an array of pointers, which it must iterate
693  * over. We do not do any further batching, as this is of no benefit
694  * for the main queue.
695  */
696 static rsRetVal
697 msgConsumer(void __attribute__((unused)) *notNeeded, batch_t *pBatch, int *pbShutdownImmediate)
698 {
699         DEFiRet;
700         assert(pBatch != NULL);
701         pBatch->pbShutdownImmediate = pbShutdownImmediate; /* TODO: move this to batch creation! */
702         preprocessBatch(pBatch);
703         ruleset.ProcessBatch(pBatch);
704 //TODO: the BATCH_STATE_COMM must be set somewhere down the road, but we 
705 //do not have this yet and so we emulate -- 2010-06-10
706 int i;
707         for(i = 0 ; i < pBatch->nElem  && !*pbShutdownImmediate ; i++) {
708                 pBatch->pElem[i].state = BATCH_STATE_COMM;
709         }
710         RETiRet;
711 }
712
713
714 /* submit a message to the main message queue.   This is primarily
715  * a hook to prevent the need for callers to know about the main message queue
716  * rgerhards, 2008-02-13
717  */
718 rsRetVal
719 submitMsg(msg_t *pMsg)
720 {
721         qqueue_t *pQueue;
722         ruleset_t *pRuleset;
723         DEFiRet;
724
725         ISOBJ_TYPE_assert(pMsg, msg);
726
727         pRuleset = MsgGetRuleset(pMsg);
728
729         pQueue = (pRuleset == NULL) ? pMsgQueue : ruleset.GetRulesetQueue(pRuleset);
730         MsgPrepareEnqueue(pMsg);
731         qqueueEnqObj(pQueue, pMsg->flowCtlType, (void*) pMsg);
732
733         RETiRet;
734 }
735
736
737 /* submit multiple messages at once, very similar to submitMsg, just
738  * for multi_submit_t. All messages need to go into the SAME queue!
739  * rgerhards, 2009-06-16
740  */
741 rsRetVal
742 multiSubmitMsg(multi_submit_t *pMultiSub)
743 {
744         int i;
745         qqueue_t *pQueue;
746         ruleset_t *pRuleset;
747         DEFiRet;
748         assert(pMultiSub != NULL);
749
750         if(pMultiSub->nElem == 0)
751                 FINALIZE;
752
753         for(i = 0 ; i < pMultiSub->nElem ; ++i) {
754                 MsgPrepareEnqueue(pMultiSub->ppMsgs[i]);
755         }
756
757         pRuleset = MsgGetRuleset(pMultiSub->ppMsgs[0]);
758         pQueue = (pRuleset == NULL) ? pMsgQueue : ruleset.GetRulesetQueue(pRuleset);
759         iRet = pQueue->MultiEnq(pQueue, pMultiSub);
760         pMultiSub->nElem = 0;
761
762 finalize_it:
763         RETiRet;
764 }
765
766
767
768
769 static void
770 reapchild()
771 {
772         int saved_errno = errno;
773         struct sigaction sigAct;
774
775         memset(&sigAct, 0, sizeof (sigAct));
776         sigemptyset(&sigAct.sa_mask);
777         sigAct.sa_handler = reapchild;
778         sigaction(SIGCHLD, &sigAct, NULL);  /* reset signal handler -ASP */
779
780         while(waitpid(-1, NULL, WNOHANG) > 0);
781         errno = saved_errno;
782 }
783
784
785 /* helper to doFlushRptdMsgs() to flush the individual action links via llExecFunc
786  * rgerhards, 2007-08-02
787  */
788 DEFFUNC_llExecFunc(flushRptdMsgsActions)
789 {
790         action_t *pAction = (action_t*) pData;
791         assert(pAction != NULL);
792
793         BEGINfunc
794         LockObj(pAction);
795         /* TODO: time() performance: the call below could be moved to
796          * the beginn of the llExec(). This makes it slightly less correct, but
797          * in an acceptable way. -- rgerhards, 2008-09-16
798          */
799         if (pAction->f_prevcount && datetime.GetTime(NULL) >= REPEATTIME(pAction)) {
800                 DBGPRINTF("flush %s: repeated %d times, %d sec.\n",
801                     module.GetStateName(pAction->pMod), pAction->f_prevcount,
802                     repeatinterval[pAction->f_repeatcount]);
803                 actionWriteToAction(pAction);
804                 BACKOFF(pAction);
805         }
806         UnlockObj(pAction);
807
808         ENDfunc
809         return RS_RET_OK; /* we ignore errors, we can not do anything either way */
810 }
811
812
813 /* This method flushes repeat messages.
814  */
815 static void
816 doFlushRptdMsgs(void)
817 {
818         ruleset.IterateAllActions(flushRptdMsgsActions, NULL);
819 }
820
821
822 static void debug_switch()
823 {
824         time_t tTime;
825         struct tm tp;
826         struct sigaction sigAct;
827
828         datetime.GetTime(&tTime);
829         localtime_r(&tTime, &tp);
830         if(debugging_on == 0) {
831                 debugging_on = 1;
832                 dbgprintf("\n");
833                 dbgprintf("\n");
834                 dbgprintf("********************************************************************************\n");
835                 dbgprintf("Switching debugging_on to true at %2.2d:%2.2d:%2.2d\n",
836                           tp.tm_hour, tp.tm_min, tp.tm_sec);
837                 dbgprintf("********************************************************************************\n");
838         } else {
839                 dbgprintf("********************************************************************************\n");
840                 dbgprintf("Switching debugging_on to false at %2.2d:%2.2d:%2.2d\n",
841                           tp.tm_hour, tp.tm_min, tp.tm_sec);
842                 dbgprintf("********************************************************************************\n");
843                 dbgprintf("\n");
844                 dbgprintf("\n");
845                 debugging_on = 0;
846         }
847
848         memset(&sigAct, 0, sizeof (sigAct));
849         sigemptyset(&sigAct.sa_mask);
850         sigAct.sa_handler = debug_switch;
851         sigaction(SIGUSR1, &sigAct, NULL);
852 }
853
854
855 void legacyOptsEnq(uchar *line)
856 {
857         legacyOptsLL_t *pNew;
858
859         pNew = MALLOC(sizeof(legacyOptsLL_t));
860         if(line == NULL)
861                 pNew->line = NULL;
862         else
863                 pNew->line = (uchar *) strdup((char *) line);
864         pNew->next = NULL;
865
866         if(pLegacyOptsLL == NULL)
867                 pLegacyOptsLL = pNew;
868         else {
869                 legacyOptsLL_t *pThis = pLegacyOptsLL;
870
871                 while(pThis->next != NULL)
872                         pThis = pThis->next;
873                 pThis->next = pNew;
874         }
875 }
876
877
878 void legacyOptsFree(void)
879 {
880         legacyOptsLL_t *pThis = pLegacyOptsLL, *pNext;
881
882         while(pThis != NULL) {
883                 if(pThis->line != NULL)
884                         free(pThis->line);
885                 pNext = pThis->next;
886                 free(pThis);
887                 pThis = pNext;
888         }
889 }
890
891
892 void legacyOptsHook(void)
893 {
894         legacyOptsLL_t *pThis = pLegacyOptsLL;
895
896         while(pThis != NULL) {
897                 if(pThis->line != NULL) {
898                         errno = 0;
899                         errmsg.LogError(0, NO_ERRCODE, "Warning: backward compatibility layer added to following "
900                                         "directive to rsyslog.conf: %s", pThis->line);
901                         conf.cfsysline(pThis->line);
902                 }
903                 pThis = pThis->next;
904         }
905 }
906
907
908 void legacyOptsParseTCP(char ch, char *arg)
909 {
910         register int i;
911         register char *pArg = arg;
912         static char conflict = '\0';
913
914         if((conflict == 'g' && ch == 't') || (conflict == 't' && ch == 'g')) {
915                 fprintf(stderr, "rsyslogd: If you want to use both -g and -t, use directives instead, -%c ignored.\n", ch);
916                 return;
917         } else
918                 conflict = ch;
919
920         /* extract port */
921         i = 0;
922         while(isdigit((int) *pArg))
923                 i = i * 10 + *pArg++ - '0';
924
925         /* number of sessions */
926         if(*pArg == '\0' || *pArg == ',') {
927                 if(ch == 't')
928                         legacyOptsEnq((uchar *) "ModLoad imtcp");
929                 else if(ch == 'g')
930                         legacyOptsEnq((uchar *) "ModLoad imgssapi");
931
932                 if(i >= 0 && i <= 65535) {
933                         uchar line[30];
934
935                         if(ch == 't') {
936                                 snprintf((char *) line, sizeof(line), "InputTCPServerRun %d", i);
937                         } else if(ch == 'g') {
938                                 snprintf((char *) line, sizeof(line), "InputGSSServerRun %d", i);
939                         }
940                         legacyOptsEnq(line);
941                 } else {
942                         if(ch == 't') {
943                                 fprintf(stderr, "rsyslogd: Invalid TCP listen port %d - changed to 514.\n", i);
944                                 legacyOptsEnq((uchar *) "InputTCPServerRun 514");
945                         } else if(ch == 'g') {
946                                 fprintf(stderr, "rsyslogd: Invalid GSS listen port %d - changed to 514.\n", i);
947                                 legacyOptsEnq((uchar *) "InputGSSServerRun 514");
948                         }
949                 }
950
951                 if(*pArg == ',') {
952                         ++pArg;
953                         while(isspace((int) *pArg))
954                                 ++pArg;
955                         i = 0;
956                         while(isdigit((int) *pArg)) {
957                                 i = i * 10 + *pArg++ - '0';
958                         }
959                         if(i > 0) {
960                                 uchar line[30];
961
962                                 snprintf((char *) line, sizeof(line), "InputTCPMaxSessions %d", i);
963                                 legacyOptsEnq(line);
964                         } else {
965                                 if(ch == 't') {
966                                         fprintf(stderr, "rsyslogd: TCP session max configured "
967                                                 "to %d [-t %s] - changing to 1.\n", i, arg);
968                                         legacyOptsEnq((uchar *) "InputTCPMaxSessions 1");
969                                 } else if (ch == 'g') {
970                                         fprintf(stderr, "rsyslogd: GSS session max configured "
971                                                 "to %d [-g %s] - changing to 1.\n", i, arg);
972                                         legacyOptsEnq((uchar *) "InputTCPMaxSessions 1");
973                                 }
974                         }
975                 }
976         } else
977                 fprintf(stderr, "rsyslogd: Invalid -t %s command line option.\n", arg);
978 }
979
980
981 /* doDie() is a signal handler. If called, it sets the bFinished variable
982  * to indicate the program should terminate. However, it does not terminate
983  * it itself, because that causes issues with multi-threading. The actual
984  * termination is then done on the main thread. This solution might introduce
985  * a minimal delay, but it is much cleaner than the approach of doing everything
986  * inside the signal handler.
987  * rgerhards, 2005-10-26
988  * Note: we do not call DBGPRINTF() as this may cause us to block in case something
989  * with the threading is wrong.
990  */
991 static void doDie(int sig)
992 {
993 #       define MSG1 "DoDie called.\n"
994 #       define MSG2 "DoDie called 5 times - unconditional exit\n"
995         static int iRetries = 0; /* debug aid */
996         dbgprintf(MSG1);
997         if(Debug == DEBUG_FULL)
998                 write(1, MSG1, sizeof(MSG1) - 1);
999         if(iRetries++ == 4) {
1000                 if(Debug == DEBUG_FULL)
1001                         write(1, MSG2, sizeof(MSG2) - 1);
1002                 abort();
1003         }
1004         bFinished = sig;
1005 #       undef MSG1
1006 #       undef MSG2
1007 }
1008
1009
1010 /* This function frees all dynamically allocated memory for program termination.
1011  * It must be called only immediately before exit(). It is primarily an aid
1012  * for memory debuggers, which prevents cluttered outupt.
1013  * rgerhards, 2008-03-20
1014  */
1015 static void
1016 freeAllDynMemForTermination(void)
1017 {
1018         free(pszMainMsgQFName);
1019         free(pModDir);
1020         free(pszConfDAGFile);
1021 }
1022
1023
1024 /* Finalize and destruct all actions.
1025  */
1026 static inline void
1027 destructAllActions(void)
1028 {
1029         ruleset.DestructAllActions();
1030         bHaveMainQueue = 0; // flag that internal messages need to be temporarily stored
1031 }
1032
1033
1034 /* die() is called when the program shall end. This typically only occurs
1035  * during sigterm or during the initialization.
1036  * As die() is intended to shutdown rsyslogd, it is
1037  * safe to call exit() here. Just make sure that die() itself is not called
1038  * at inapropriate places. As a general rule of thumb, it is a bad idea to add
1039  * any calls to die() in new code!
1040  * rgerhards, 2005-10-24
1041  */
1042 static void
1043 die(int sig)
1044 {
1045         char buf[256];
1046
1047         DBGPRINTF("exiting on signal %d\n", sig);
1048
1049         /* IMPORTANT: we should close the inputs first, and THEN send our termination
1050          * message. If we do it the other way around, logmsgInternal() may block on
1051          * a full queue and the inputs still fill up that queue. Depending on the
1052          * scheduling order, we may end up with logmsgInternal being held for a quite
1053          * long time. When the inputs are terminated first, that should not happen
1054          * because the queue is drained in parallel. The situation could only become
1055          * an issue with extremely long running actions in a queue full environment.
1056          * However, such actions are at least considered poorly written, if not
1057          * outright wrong. So we do not care about this very remote problem.
1058          * rgerhards, 2008-01-11
1059          */
1060
1061         /* close the inputs */
1062         DBGPRINTF("Terminating input threads...\n");
1063         glbl.SetGlobalInputTermination();
1064         thrdTerminateAll();
1065
1066         /* and THEN send the termination log message (see long comment above) */
1067         if(sig && bLogStatusMsgs) {
1068                 (void) snprintf(buf, sizeof(buf) / sizeof(char),
1069                  " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \
1070                  "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"]" " exiting on signal %d.",
1071                  (int) myPid, sig);
1072                 errno = 0;
1073                 logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0);
1074         }
1075
1076         /* drain queue (if configured so) and stop main queue worker thread pool */
1077         DBGPRINTF("Terminating main queue...\n");
1078         qqueueDestruct(&pMsgQueue);
1079         pMsgQueue = NULL;
1080
1081         /* Free ressources and close connections. This includes flushing any remaining
1082          * repeated msgs.
1083          */
1084         DBGPRINTF("Terminating outputs...\n");
1085         destructAllActions();
1086
1087         DBGPRINTF("all primary multi-thread sources have been terminated - now doing aux cleanup...\n");
1088         /* rger 2005-02-22
1089          * now clean up the in-memory structures. OK, the OS
1090          * would also take care of that, but if we do it
1091          * ourselfs, this makes finding memory leaks a lot
1092          * easier.
1093          */
1094         tplDeleteAll();
1095
1096         /* de-init some modules */
1097         modExitIminternal();
1098
1099         /*dbgPrintAllDebugInfo(); / * this is the last spot where this can be done - below output modules are unloaded! */
1100
1101         /* the following line cleans up CfSysLineHandlers that were not based on loadable
1102          * modules. As such, they are not yet cleared.
1103          */
1104         unregCfSysLineHdlrs();
1105
1106         legacyOptsFree();
1107
1108         /* destruct our global properties */
1109         if(pInternalInputName != NULL)
1110                 prop.Destruct(&pInternalInputName);
1111         if(pLocalHostIP != NULL)
1112                 prop.Destruct(&pLocalHostIP);
1113
1114         /* terminate the remaining classes */
1115         GlobalClassExit();
1116
1117         module.UnloadAndDestructAll(eMOD_LINK_ALL);
1118
1119         DBGPRINTF("Clean shutdown completed, bye\n");
1120         /* dbgClassExit MUST be the last one, because it de-inits the debug system */
1121         dbgClassExit();
1122
1123         /* free all remaining memory blocks - this is not absolutely necessary, but helps
1124          * us keep memory debugger logs clean and this is in aid in developing. It doesn't
1125          * cost much time, so we do it always. -- rgerhards, 2008-03-20
1126          */
1127         freeAllDynMemForTermination();
1128         /* NO CODE HERE - feeelAllDynMemForTermination() must be the last thing before exit()! */
1129
1130         remove_pid(PidFile);
1131
1132         exit(0); /* "good" exit, this is the terminator function for rsyslog [die()] */
1133 }
1134
1135 /*
1136  * Signal handler to terminate the parent process.
1137  * rgerhards, 2005-10-24: this is only called during forking of the
1138  * detached syslogd. I consider this method to be safe.
1139  */
1140 static void doexit()
1141 {
1142         exit(0); /* "good" exit, only during child-creation */
1143 }
1144
1145
1146 /* set the maximum message size */
1147 static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal)
1148 {
1149         return glbl.SetMaxLine(iNewVal);
1150 }
1151
1152
1153 /* set the action resume interval */
1154 static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int iNewVal)
1155 {
1156         return actionSetGlobalResumeInterval(iNewVal);
1157 }
1158
1159
1160 /* set the processes max number ob files (upon configuration request)
1161  * 2009-04-14 rgerhards
1162  */
1163 static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles)
1164 {
1165         struct rlimit maxFiles;
1166         char errStr[1024];
1167         DEFiRet;
1168
1169         maxFiles.rlim_cur = iFiles;
1170         maxFiles.rlim_max = iFiles;
1171
1172         if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) {
1173                 /* NOTE: under valgrind, we seem to be unable to extend the size! */
1174                 rs_strerror_r(errno, errStr, sizeof(errStr));
1175                 errmsg.LogError(0, RS_RET_ERR_RLIM_NOFILE, "could not set process file limit to %d: %s [kernel max %ld]",
1176                                 iFiles, errStr, (long) maxFiles.rlim_max);
1177                 ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE);
1178         }
1179 #ifdef USE_UNLIMITED_SELECT
1180         glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask));
1181 #endif
1182         DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max);
1183
1184 finalize_it:
1185         RETiRet;
1186 }
1187
1188
1189 /* set the processes umask (upon configuration request) */
1190 static rsRetVal setUmask(void __attribute__((unused)) *pVal, int iUmask)
1191 {
1192         umask(iUmask);
1193         DBGPRINTF("umask set to 0%3.3o.\n", iUmask);
1194
1195         return RS_RET_OK;
1196 }
1197
1198
1199 /* drop to specified group
1200  * if something goes wrong, the function never returns
1201  * Note that such an abort can cause damage to on-disk structures, so we should
1202  * re-design the "interface" in the long term. -- rgerhards, 2008-11-26
1203  */
1204 static void doDropPrivGid(int iGid)
1205 {
1206         int res;
1207         uchar szBuf[1024];
1208
1209         res = setgroups(0, NULL); /* remove all supplementary group IDs */
1210         if(res) {
1211                 perror("could not remove supplemental group IDs");
1212                 exit(1);
1213         }
1214         DBGPRINTF("setgroups(0, NULL): %d\n", res);
1215         res = setgid(iGid);
1216         if(res) {
1217                 /* if we can not set the userid, this is fatal, so let's unconditionally abort */
1218                 perror("could not set requested group id");
1219                 exit(1);
1220         }
1221         DBGPRINTF("setgid(%d): %d\n", iGid, res);
1222         snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's groupid changed to %d", iGid);
1223         logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
1224 }
1225
1226
1227 /* drop to specified user
1228  * if something goes wrong, the function never returns
1229  * Note that such an abort can cause damage to on-disk structures, so we should
1230  * re-design the "interface" in the long term. -- rgerhards, 2008-11-19
1231  */
1232 static void doDropPrivUid(int iUid)
1233 {
1234         int res;
1235         uchar szBuf[1024];
1236
1237         res = setuid(iUid);
1238         if(res) {
1239                 /* if we can not set the userid, this is fatal, so let's unconditionally abort */
1240                 perror("could not set requested userid");
1241                 exit(1);
1242         }
1243         DBGPRINTF("setuid(%d): %d\n", iUid, res);
1244         snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's userid changed to %d", iUid);
1245         logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
1246 }
1247
1248
1249 /* helper to generateConfigDAG, to print out all actions via
1250  * the llExecFunc() facility.
1251  * rgerhards, 2007-08-02
1252  */
1253 struct dag_info {
1254         FILE *fp;       /* output file */
1255         int iActUnit;   /* current action unit number */
1256         int iAct;       /* current action in unit */
1257         int bDiscarded; /* message discarded (config error) */
1258         };
1259 DEFFUNC_llExecFunc(generateConfigDAGAction)
1260 {
1261         action_t *pAction;
1262         uchar *pszModName;
1263         uchar *pszVertexName;
1264         struct dag_info *pDagInfo;
1265         DEFiRet;
1266
1267         pDagInfo = (struct dag_info*) pParam;
1268         pAction = (action_t*) pData;
1269
1270         pszModName = module.GetStateName(pAction->pMod);
1271
1272         /* vertex */
1273         if(pAction->pszName == NULL) {
1274                 if(!strcmp((char*)pszModName, "builtin-discard"))
1275                         pszVertexName = (uchar*)"discard";
1276                 else
1277                         pszVertexName = pszModName;
1278         } else {
1279                 pszVertexName = pAction->pszName;
1280         }
1281
1282         fprintf(pDagInfo->fp, "\tact%d_%d\t\t[label=\"%s\"%s%s]\n",
1283                 pDagInfo->iActUnit, pDagInfo->iAct, pszVertexName,
1284                 pDagInfo->bDiscarded ? " style=dotted color=red" : "",
1285                 (pAction->pQueue->qType == QUEUETYPE_DIRECT) ? "" : " shape=hexagon"
1286                 );
1287
1288         /* edge */
1289         if(pDagInfo->iAct == 0) {
1290         } else {
1291                 fprintf(pDagInfo->fp, "\tact%d_%d -> act%d_%d[%s%s]\n",
1292                         pDagInfo->iActUnit, pDagInfo->iAct - 1,
1293                         pDagInfo->iActUnit, pDagInfo->iAct,
1294                         pDagInfo->bDiscarded ? " style=dotted color=red" : "",
1295                         pAction->bExecWhenPrevSusp ? " label=\"only if\\nsuspended\"" : "" );
1296         }
1297
1298         /* check for discard */
1299         if(!strcmp((char*) pszModName, "builtin-discard")) {
1300                 fprintf(pDagInfo->fp, "\tact%d_%d\t\t[shape=box]\n",
1301                         pDagInfo->iActUnit, pDagInfo->iAct);
1302                 pDagInfo->bDiscarded = 1;
1303         }
1304
1305
1306         ++pDagInfo->iAct;
1307
1308         RETiRet;
1309 }
1310
1311
1312 /* create config DAG
1313  * This functions takes a rsyslog config and produces a .dot file for use
1314  * with graphviz (http://www.graphviz.org). This is done in an effort to
1315  * document, and also potentially troubleshoot, configurations. Plus, I
1316  * consider it a nice feature to explain some concepts. Note that the
1317  * current version only produces a graph with relatively little information.
1318  * This is a foundation that may be later expanded (if it turns out to be
1319  * useful enough).
1320  * rgerhards, 2009-05-11
1321  */
1322 static rsRetVal
1323 generateConfigDAG(uchar *pszDAGFile)
1324 {
1325         //rule_t *f;
1326         FILE *fp;
1327         int iActUnit = 1;
1328         //int bHasFilter = 0;   /* filter associated with this action unit? */
1329         //int bHadFilter;
1330         //int i;
1331         struct dag_info dagInfo;
1332         //char *pszFilterName;
1333         char szConnectingNode[64];
1334         DEFiRet;
1335
1336         assert(pszDAGFile != NULL);
1337         
1338         logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)
1339                 "Configuration graph generation is unfortunately disabled "
1340                 "in the current code base.", 0);
1341         ABORT_FINALIZE(RS_RET_FILENAME_INVALID);
1342
1343         if((fp = fopen((char*) pszDAGFile, "w")) == NULL) {
1344                 logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)
1345                         "configuraton graph output file could not be opened, none generated", 0);
1346                 ABORT_FINALIZE(RS_RET_FILENAME_INVALID);
1347         }
1348
1349         dagInfo.fp = fp;
1350
1351         /* from here on, we assume writes go well. This here is a really
1352          * unimportant utility function and if something goes wrong, it has
1353          * almost no effect. So let's not overdo this...
1354          */
1355         fprintf(fp, "# graph created by rsyslog " VERSION "\n\n"
1356                     "# use the dot tool from http://www.graphviz.org to visualize!\n"
1357                     "digraph rsyslogConfig {\n"
1358                     "\tinputs [shape=tripleoctagon]\n"
1359                     "\tinputs -> act0_0\n"
1360                     "\tact0_0 [label=\"main\\nqueue\" shape=hexagon]\n"
1361                     /*"\tmainq -> act1_0\n"*/
1362                     );
1363         strcpy(szConnectingNode, "act0_0");
1364         dagInfo.bDiscarded = 0;
1365
1366 /* TODO: re-enable! */
1367 #if 0
1368         for(f = Files; f != NULL ; f = f->f_next) {
1369                 /* BSD-Style filters are currently ignored */
1370                 bHadFilter = bHasFilter;
1371                 if(f->f_filter_type == FILTER_PRI) {
1372                         bHasFilter = 0;
1373                         for (i = 0; i <= LOG_NFACILITIES; i++)
1374                                 if (f->f_filterData.f_pmask[i] != 0xff) {
1375                                         bHasFilter = 1;
1376                                         break;
1377                                 }
1378                 } else {
1379                         bHasFilter = 1;
1380                 }
1381
1382                 /* we know we have a filter, so it can be false */
1383                 switch(f->f_filter_type) {
1384                         case FILTER_PRI:
1385                                 pszFilterName = "pri filter";
1386                                 break;
1387                         case FILTER_PROP:
1388                                 pszFilterName = "property filter";
1389                                 break;
1390                         case FILTER_EXPR:
1391                                 pszFilterName = "script filter";
1392                                 break;
1393                 }
1394
1395                 /* write action unit node */
1396                 if(bHasFilter) {
1397                         fprintf(fp, "\t%s -> act%d_end\t[label=\"%s:\\nfalse\"]\n",
1398                                 szConnectingNode, iActUnit, pszFilterName);
1399                         fprintf(fp, "\t%s -> act%d_0\t[label=\"%s:\\ntrue\"]\n",
1400                                 szConnectingNode, iActUnit, pszFilterName);
1401                         fprintf(fp, "\tact%d_end\t\t\t\t[shape=point]\n", iActUnit);
1402                         snprintf(szConnectingNode, sizeof(szConnectingNode), "act%d_end", iActUnit);
1403                 } else {
1404                         fprintf(fp, "\t%s -> act%d_0\t[label=\"no filter\"]\n",
1405                                 szConnectingNode, iActUnit);
1406                         snprintf(szConnectingNode, sizeof(szConnectingNode), "act%d_0", iActUnit);
1407                 }
1408
1409                 /* draw individual nodes */
1410                 dagInfo.iActUnit = iActUnit;
1411                 dagInfo.iAct = 0;
1412                 dagInfo.bDiscarded = 0;
1413                 llExecFunc(&f->llActList, generateConfigDAGAction, &dagInfo); /* actions */
1414
1415                 /* finish up */
1416                 if(bHasFilter && !dagInfo.bDiscarded) {
1417                         fprintf(fp, "\tact%d_%d -> %s\n",
1418                                 iActUnit, dagInfo.iAct - 1, szConnectingNode);
1419                 }
1420
1421                 ++iActUnit;
1422         }
1423 #endif
1424
1425         fprintf(fp, "\t%s -> act%d_0\n", szConnectingNode, iActUnit);
1426         fprintf(fp, "\tact%d_0\t\t[label=discard shape=box]\n"
1427                     "}\n", iActUnit);
1428         fclose(fp);
1429
1430 finalize_it:
1431         RETiRet;
1432 }
1433
1434
1435 /* print debug information as part of init(). This pretty much
1436  * outputs the whole config of rsyslogd. I've moved this code
1437  * out of init() to clean it somewhat up.
1438  * rgerhards, 2007-07-31
1439  */
1440 static void dbgPrintInitInfo(void)
1441 {
1442         ruleset.DebugPrintAll();
1443         DBGPRINTF("\n");
1444         if(bDebugPrintTemplateList)
1445                 tplPrintList();
1446         if(bDebugPrintModuleList)
1447                 module.PrintList();
1448         ochPrintList();
1449
1450         if(bDebugPrintCfSysLineHandlerList)
1451                 dbgPrintCfSysLineHandlers();
1452
1453         DBGPRINTF("Messages with malicious PTR DNS Records are %sdropped.\n",
1454                   glbl.GetDropMalPTRMsgs() ? "" : "not ");
1455
1456         DBGPRINTF("Main queue size %d messages.\n", iMainMsgQueueSize);
1457         DBGPRINTF("Main queue worker threads: %d, wThread shutdown: %d, Perists every %d updates.\n",
1458                   iMainMsgQueueNumWorkers, iMainMsgQtoWrkShutdown, iMainMsgQPersistUpdCnt);
1459         DBGPRINTF("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n",
1460                    iMainMsgQtoQShutdown, iMainMsgQtoActShutdown, iMainMsgQtoEnq);
1461         DBGPRINTF("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n",
1462                    iMainMsgQHighWtrMark, iMainMsgQLowWtrMark, iMainMsgQDiscardMark, iMainMsgQDiscardSeverity);
1463         DBGPRINTF("Main queue save on shutdown %d, max disk space allowed %lld\n",
1464                    bMainMsgQSaveOnShutdown, iMainMsgQueMaxDiskSpace);
1465         /* TODO: add
1466         iActionRetryCount = 0;
1467         iActionRetryInterval = 30000;
1468        static int iMainMsgQtoWrkMinMsgs = 100;
1469         static int iMainMsgQbSaveOnShutdown = 1;
1470         iMainMsgQueMaxDiskSpace = 0;
1471         setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100);
1472         setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1);
1473          */
1474         DBGPRINTF("Work Directory: '%s'.\n", glbl.GetWorkDir());
1475 }
1476
1477
1478 /* Actually run the input modules.  This happens after privileges are dropped,
1479  * if that is requested.
1480  */
1481 static rsRetVal
1482 runInputModules(void)
1483 {
1484         modInfo_t *pMod;
1485         int bNeedsCancel;
1486
1487         BEGINfunc
1488         /* loop through all modules and activate them (brr...) */
1489         pMod = module.GetNxtType(NULL, eMOD_IN);
1490         while(pMod != NULL) {
1491                 if(pMod->mod.im.bCanRun) {
1492                         /* activate here */
1493                         bNeedsCancel = (pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ?
1494                                        0 : 1;
1495                         thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun, bNeedsCancel);
1496                 }
1497         pMod = module.GetNxtType(pMod, eMOD_IN);
1498         }
1499
1500         ENDfunc
1501         return RS_RET_OK; /* intentional: we do not care about module errors */
1502 }
1503
1504
1505 /* Start the input modules. This function will probably undergo big changes
1506  * while we implement the input module interface. For now, it does the most
1507  * important thing to get at least my poor initial input modules up and
1508  * running. Almost no config option is taken.
1509  * rgerhards, 2007-12-14
1510  */
1511 static rsRetVal
1512 startInputModules(void)
1513 {
1514         DEFiRet;
1515         modInfo_t *pMod;
1516
1517         /* loop through all modules and activate them (brr...) */
1518         pMod = module.GetNxtType(NULL, eMOD_IN);
1519         while(pMod != NULL) {
1520                 iRet = pMod->mod.im.willRun();
1521                 pMod->mod.im.bCanRun = (iRet == RS_RET_OK);
1522                 if(!pMod->mod.im.bCanRun) {
1523                         DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) pMod, iRet);
1524                 }
1525         pMod = module.GetNxtType(pMod, eMOD_IN);
1526         }
1527
1528         ENDfunc
1529         return RS_RET_OK; /* intentional: we do not care about module errors */
1530 }
1531
1532
1533 /* create a main message queue, now also used for ruleset queues. This function
1534  * needs to be moved to some other module, but it is considered acceptable for
1535  * the time being (remember that we want to restructure config processing at large!).
1536  * rgerhards, 2009-10-27
1537  */
1538 rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName)
1539 {
1540         DEFiRet;
1541
1542         /* switch the message object to threaded operation, if necessary */
1543         if(MainMsgQueType == QUEUETYPE_DIRECT || iMainMsgQueueNumWorkers > 1) {
1544                 MsgEnableThreadSafety();
1545         }
1546
1547         /* create message queue */
1548         CHKiRet_Hdlr(qqueueConstruct(ppQueue, MainMsgQueType, iMainMsgQueueNumWorkers, iMainMsgQueueSize, msgConsumer)) {
1549                 /* no queue is fatal, we need to give up in that case... */
1550                 errmsg.LogError(0, iRet, "could not create (ruleset) main message queue"); \
1551         }
1552         /* name our main queue object (it's not fatal if it fails...) */
1553         obj.SetName((obj_t*) (*ppQueue), pszQueueName);
1554
1555         /* ... set some properties ... */
1556 #       define setQPROP(func, directive, data) \
1557         CHKiRet_Hdlr(func(*ppQueue, data)) { \
1558                 errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \
1559         }
1560 #       define setQPROPstr(func, directive, data) \
1561         CHKiRet_Hdlr(func(*ppQueue, data, (data == NULL)? 0 : strlen((char*) data))) { \
1562                 errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \
1563         }
1564
1565         setQPROP(qqueueSetMaxFileSize, "$MainMsgQueueFileSize", iMainMsgQueMaxFileSize);
1566         setQPROP(qqueueSetsizeOnDiskMax, "$MainMsgQueueMaxDiskSpace", iMainMsgQueMaxDiskSpace);
1567         setQPROP(qqueueSetiDeqBatchSize, "$MainMsgQueueDequeueBatchSize", iMainMsgQueDeqBatchSize);
1568         setQPROPstr(qqueueSetFilePrefix, "$MainMsgQueueFileName", pszMainMsgQFName);
1569         setQPROP(qqueueSetiPersistUpdCnt, "$MainMsgQueueCheckpointInterval", iMainMsgQPersistUpdCnt);
1570         setQPROP(qqueueSetbSyncQueueFiles, "$MainMsgQueueSyncQueueFiles", bMainMsgQSyncQeueFiles);
1571         setQPROP(qqueueSettoQShutdown, "$MainMsgQueueTimeoutShutdown", iMainMsgQtoQShutdown );
1572         setQPROP(qqueueSettoActShutdown, "$MainMsgQueueTimeoutActionCompletion", iMainMsgQtoActShutdown);
1573         setQPROP(qqueueSettoWrkShutdown, "$MainMsgQueueWorkerTimeoutThreadShutdown", iMainMsgQtoWrkShutdown);
1574         setQPROP(qqueueSettoEnq, "$MainMsgQueueTimeoutEnqueue", iMainMsgQtoEnq);
1575         setQPROP(qqueueSetiHighWtrMrk, "$MainMsgQueueHighWaterMark", iMainMsgQHighWtrMark);
1576         setQPROP(qqueueSetiLowWtrMrk, "$MainMsgQueueLowWaterMark", iMainMsgQLowWtrMark);
1577         setQPROP(qqueueSetiDiscardMrk, "$MainMsgQueueDiscardMark", iMainMsgQDiscardMark);
1578         setQPROP(qqueueSetiDiscardSeverity, "$MainMsgQueueDiscardSeverity", iMainMsgQDiscardSeverity);
1579         setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", iMainMsgQWrkMinMsgs);
1580         setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", bMainMsgQSaveOnShutdown);
1581         setQPROP(qqueueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", iMainMsgQDeqSlowdown);
1582         setQPROP(qqueueSetiDeqtWinFromHr,  "$MainMsgQueueDequeueTimeBegin", iMainMsgQueueDeqtWinFromHr);
1583         setQPROP(qqueueSetiDeqtWinToHr,    "$MainMsgQueueDequeueTimeEnd", iMainMsgQueueDeqtWinToHr);
1584
1585 #       undef setQPROP
1586 #       undef setQPROPstr
1587
1588         /* ... and finally start the queue! */
1589         CHKiRet_Hdlr(qqueueStart(*ppQueue)) {
1590                 /* no queue is fatal, we need to give up in that case... */
1591                 errmsg.LogError(0, iRet, "could not start (ruleset) main message queue"); \
1592         }
1593         RETiRet;
1594 }
1595
1596
1597 /* INIT -- Initialize syslogd
1598  * Note that if iConfigVerify is set, only the config file is verified but nothing
1599  * else happens. -- rgerhards, 2008-07-28
1600  */
1601 static rsRetVal
1602 init(void)
1603 {
1604         rsRetVal localRet;
1605         int iNbrActions;
1606         int bHadConfigErr = 0;
1607         ruleset_t *pRuleset;
1608         char cbuf[BUFSIZ];
1609         char bufStartUpMsg[512];
1610         struct sigaction sigAct;
1611         DEFiRet;
1612
1613         DBGPRINTF("rsyslog %s - called init()\n", VERSION);
1614
1615         /* construct the default ruleset */
1616         ruleset.Construct(&pRuleset);
1617         ruleset.SetName(pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset"));
1618         ruleset.ConstructFinalize(pRuleset);
1619
1620         /* open the configuration file */
1621         localRet = conf.processConfFile(ConfFile);
1622         CHKiRet(conf.GetNbrActActions(&iNbrActions));
1623
1624         if(localRet != RS_RET_OK) {
1625                 errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", ConfFile);
1626                 bHadConfigErr = 1;
1627         } else if(iNbrActions == 0) {
1628                 errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will "
1629                          "run, but no output whatsoever is created.");
1630                 bHadConfigErr = 1;
1631         }
1632
1633         if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) {
1634                 /* rgerhards: this code is executed to set defaults when the
1635                  * config file could not be opened. We might think about
1636                  * abandoning the run in this case - but this, too, is not
1637                  * very clever... So we stick with what we have.
1638                  * We ignore any errors while doing this - we would be lost anyhow...
1639                  */
1640                 errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!");
1641
1642                 /* note: we previously used _POSIY_TTY_NAME_MAX+1, but this turned out to be
1643                  * too low on linux... :-S   -- rgerhards, 2008-07-28
1644                  */
1645                 char szTTYNameBuf[128];
1646                 rule_t *pRule = NULL; /* initialization to NULL is *vitally* important! */
1647                 conf.cfline(UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule);
1648                 conf.cfline(UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule);
1649                 conf.cfline(UCHAR_CONSTANT("*.PANIC\t*"), &pRule);
1650                 conf.cfline(UCHAR_CONSTANT("syslog.*\troot"), &pRule);
1651                 if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) {
1652                         snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf);
1653                         conf.cfline((uchar*)cbuf, &pRule);
1654                 } else {
1655                         DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno);
1656                 }
1657                 ruleset.AddRule(ruleset.GetCurrent(), &pRule);
1658         }
1659
1660         legacyOptsHook();
1661
1662         /* some checks */
1663         if(iMainMsgQueueNumWorkers < 1) {
1664                 errmsg.LogError(0, NO_ERRCODE, "$MainMsgQueueNumWorkers must be at least 1! Set to 1.\n");
1665                 iMainMsgQueueNumWorkers = 1;
1666         }
1667
1668         if(MainMsgQueType == QUEUETYPE_DISK) {
1669                 errno = 0;      /* for logerror! */
1670                 if(glbl.GetWorkDir() == NULL) {
1671                         errmsg.LogError(0, NO_ERRCODE, "No $WorkDirectory specified - can not run main message queue in 'disk' mode. "
1672                                  "Using 'FixedArray' instead.\n");
1673                         MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
1674                 }
1675                 if(pszMainMsgQFName == NULL) {
1676                         errmsg.LogError(0, NO_ERRCODE, "No $MainMsgQueueFileName specified - can not run main message queue in "
1677                                  "'disk' mode. Using 'FixedArray' instead.\n");
1678                         MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
1679                 }
1680         }
1681
1682         /* check if we need to generate a config DAG and, if so, do that */
1683         if(pszConfDAGFile != NULL)
1684                 generateConfigDAG(pszConfDAGFile);
1685
1686         /* we are done checking the config - now validate if we should actually run or not.
1687          * If not, terminate. -- rgerhards, 2008-07-25
1688          */
1689         if(iConfigVerify) {
1690                 if(bHadConfigErr) {
1691                         /* a bit dirty, but useful... */
1692                         exit(1);
1693                 }
1694                 ABORT_FINALIZE(RS_RET_VALIDATION_RUN);
1695         }
1696
1697         if(bAbortOnUncleanConfig && bHadConfigErr) {
1698                 fprintf(stderr, "rsyslogd: $AbortOnUncleanConfig is set, and config is not clean.\n"
1699                                 "Check error log for details, fix errors and restart. As a last\n"
1700                                 "resort, you may want to remove $AbortOnUncleanConfig to permit a\n"
1701                                 "startup with a dirty config.\n");
1702                 exit(2);
1703         }
1704
1705         /* create message queue */
1706         CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"))) {
1707                 /* no queue is fatal, we need to give up in that case... */
1708                 fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet);
1709                 exit(1);
1710         }
1711
1712         bHaveMainQueue = (MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1;
1713         DBGPRINTF("Main processing queue is initialized and running\n");
1714
1715         /* the output part and the queue is now ready to run. So it is a good time
1716          * to initialize the inputs. Please note that the net code above should be
1717          * shuffled to down here once we have everything in input modules.
1718          * rgerhards, 2007-12-14
1719          * NOTE: as of 2009-06-29, the input modules are initialized, but not yet run.
1720          * Keep in mind. though, that the outputs already run if the queue was
1721          * persisted to disk. -- rgerhards
1722          */
1723         startInputModules();
1724
1725         if(Debug) {
1726                 dbgPrintInitInfo();
1727         }
1728
1729         memset(&sigAct, 0, sizeof (sigAct));
1730         sigemptyset(&sigAct.sa_mask);
1731         sigAct.sa_handler = sighup_handler;
1732         sigaction(SIGHUP, &sigAct, NULL);
1733
1734         DBGPRINTF(" started.\n");
1735
1736         /* we now generate the startup message. It now includes everything to
1737          * identify this instance. -- rgerhards, 2005-08-17
1738          */
1739         if(bLogStatusMsgs) {
1740                snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char),
1741                          " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \
1742                          "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] start",
1743                          (int) myPid);
1744                 logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)bufStartUpMsg, 0);
1745         }
1746
1747 finalize_it:
1748         RETiRet;
1749 }
1750
1751
1752 /* Switch the default ruleset (that, what servcies bind to if nothing specific
1753  * is specified).
1754  * rgerhards, 2009-06-12
1755  */
1756 static rsRetVal
1757 setDefaultRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
1758 {
1759         DEFiRet;
1760
1761         CHKiRet(ruleset.SetDefaultRuleset(pszName));
1762
1763 finalize_it:
1764         free(pszName); /* no longer needed */
1765         RETiRet;
1766 }
1767
1768
1769
1770 /* Put the rsyslog main thread to sleep for n seconds. This was introduced as
1771  * a quick and dirty workaround for a privilege drop race in regard to listener
1772  * startup, which itself was a result of the not-yet-done proper coding of
1773  * privilege drop code (quite some effort). It may be useful for other occasions, too.
1774  * is specified).
1775  * rgerhards, 2009-06-12
1776  */
1777 static rsRetVal
1778 putToSleep(void __attribute__((unused)) *pVal, int iNewVal)
1779 {
1780         DEFiRet;
1781         DBGPRINTF("rsyslog main thread put to sleep via $sleep %d directive...\n", iNewVal);
1782         srSleep(iNewVal, 0);
1783         DBGPRINTF("rsyslog main thread continues after $sleep %d\n", iNewVal);
1784         RETiRet;
1785 }
1786
1787
1788 /* Switch to either an already existing rule set or start a new one. The
1789  * named rule set becomes the new "current" rule set (what means that new
1790  * actions are added to it).
1791  * rgerhards, 2009-06-12
1792  */
1793 static rsRetVal
1794 setCurrRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
1795 {
1796         ruleset_t *pRuleset;
1797         rsRetVal localRet;
1798         DEFiRet;
1799
1800         localRet = ruleset.SetCurrRuleset(pszName);
1801
1802         if(localRet == RS_RET_NOT_FOUND) {
1803                 DBGPRINTF("begin new current rule set '%s'\n", pszName);
1804                 CHKiRet(ruleset.Construct(&pRuleset));
1805                 CHKiRet(ruleset.SetName(pRuleset, pszName));
1806                 CHKiRet(ruleset.ConstructFinalize(pRuleset));
1807         } else {
1808                 ABORT_FINALIZE(localRet);
1809         }
1810
1811 finalize_it:
1812         free(pszName); /* no longer needed */
1813         RETiRet;
1814 }
1815
1816
1817 /* set the main message queue mode
1818  * rgerhards, 2008-01-03
1819  */
1820 static rsRetVal setMainMsgQueType(void __attribute__((unused)) *pVal, uchar *pszType)
1821 {
1822         DEFiRet;
1823
1824         if (!strcasecmp((char *) pszType, "fixedarray")) {
1825                 MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
1826                 DBGPRINTF("main message queue type set to FIXED_ARRAY\n");
1827         } else if (!strcasecmp((char *) pszType, "linkedlist")) {
1828                 MainMsgQueType = QUEUETYPE_LINKEDLIST;
1829                 DBGPRINTF("main message queue type set to LINKEDLIST\n");
1830         } else if (!strcasecmp((char *) pszType, "disk")) {
1831                 MainMsgQueType = QUEUETYPE_DISK;
1832                 DBGPRINTF("main message queue type set to DISK\n");
1833         } else if (!strcasecmp((char *) pszType, "direct")) {
1834                 MainMsgQueType = QUEUETYPE_DIRECT;
1835                 DBGPRINTF("main message queue type set to DIRECT (no queueing at all)\n");
1836         } else {
1837                 errmsg.LogError(0, RS_RET_INVALID_PARAMS, "unknown mainmessagequeuetype parameter: %s", (char *) pszType);
1838                 iRet = RS_RET_INVALID_PARAMS;
1839         }
1840         free(pszType); /* no longer needed */
1841
1842         RETiRet;
1843 }
1844
1845
1846 /*
1847  * The following function is resposible for handling a SIGHUP signal.  Since
1848  * we are now doing mallocs/free as part of init we had better not being
1849  * doing this during a signal handler.  Instead this function simply sets
1850  * a flag variable which will tells the main loop to do "the right thing".
1851  */
1852 void sighup_handler()
1853 {
1854         struct sigaction sigAct;
1855
1856         bHadHUP = 1;
1857
1858         memset(&sigAct, 0, sizeof (sigAct));
1859         sigemptyset(&sigAct.sa_mask);
1860         sigAct.sa_handler = sighup_handler;
1861         sigaction(SIGHUP, &sigAct, NULL);
1862 }
1863
1864 void sigttin_handler()
1865 {
1866 }
1867
1868 /* this function pulls all internal messages from the buffer
1869  * and puts them into the processing engine.
1870  * We can only do limited error handling, as this would not
1871  * really help us. TODO: add error messages?
1872  * rgerhards, 2007-08-03
1873  */
1874 static inline void processImInternal(void)
1875 {
1876         msg_t *pMsg;
1877
1878         while(iminternalRemoveMsg(&pMsg) == RS_RET_OK) {
1879                 submitMsg(pMsg);
1880         }
1881 }
1882
1883
1884 /* helper to doHUP(), this "HUPs" each action. The necessary locking
1885  * is done inside the action class and nothing we need to take care of.
1886  * rgerhards, 2008-10-22
1887  */
1888 DEFFUNC_llExecFunc(doHUPActions)
1889 {
1890         BEGINfunc
1891         actionCallHUPHdlr((action_t*) pData);
1892         ENDfunc
1893         return RS_RET_OK; /* we ignore errors, we can not do anything either way */
1894 }
1895
1896
1897 /* This function processes a HUP after one has been detected. Note that this
1898  * is *NOT* the sighup handler. The signal is recorded by the handler, that record
1899  * detected inside the mainloop and then this function is called to do the
1900  * real work. -- rgerhards, 2008-10-22
1901  */
1902 static inline void
1903 doHUP(void)
1904 {
1905         char buf[512];
1906
1907         if(bLogStatusMsgs) {
1908                 snprintf(buf, sizeof(buf) / sizeof(char),
1909                          " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION
1910                          "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed",
1911                          (int) myPid);
1912                         errno = 0;
1913                 logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0);
1914         }
1915
1916         ruleset.IterateAllActions(doHUPActions, NULL);
1917 }
1918
1919
1920 /* This is the main processing loop. It is called after successful initialization.
1921  * When it returns, the syslogd terminates.
1922  * Its sole function is to provide some housekeeping things. The real work is done
1923  * by the other threads spawned.
1924  */
1925 static void
1926 mainloop(void)
1927 {
1928         struct timeval tvSelectTimeout;
1929
1930         BEGINfunc
1931         /* first check if we have any internal messages queued and spit them out. We used
1932          * to do that on any loop iteration, but that is no longer necessry. The reason
1933          * is that once we reach this point here, we always run on multiple threads and
1934          * thus the main queue is properly initialized. -- rgerhards, 2008-06-09
1935          */
1936         processImInternal();
1937
1938         while(!bFinished){
1939                 /* this is now just a wait - please note that we do use a near-"eternal"
1940                  * timeout of 1 day if we do not have repeated message reduction turned on
1941                  * (which it is not by default). This enables us to help safe the environment
1942                  * by not unnecessarily awaking rsyslog on a regular tick (just think
1943                  * powertop, for example). In that case, we primarily wait for a signal,
1944                  * but a once-a-day wakeup should be quite acceptable. -- rgerhards, 2008-06-09
1945                  */
1946                 tvSelectTimeout.tv_sec = (bReduceRepeatMsgs == 1) ? TIMERINTVL : 86400 /*1 day*/;
1947                 //tvSelectTimeout.tv_sec = TIMERINTVL; /* TODO: change this back to the above code when we have a better solution for apc */
1948                 tvSelectTimeout.tv_usec = 0;
1949                 select(1, NULL, NULL, NULL, &tvSelectTimeout);
1950                 if(bFinished)
1951                         break;  /* exit as quickly as possible - see long comment below */
1952
1953                 /* If we received a HUP signal, we call doFlushRptdMsgs() a bit early. This
1954                  * doesn't matter, because doFlushRptdMsgs() checks timestamps. What may happen,
1955                  * however, is that the too-early call may lead to a bit too-late output
1956                  * of "last message repeated n times" messages. But that is quite acceptable.
1957                  * rgerhards, 2007-12-21
1958                  * ... and just to explain, we flush here because that is exactly what the mainloop
1959                  * shall do - provide a periodic interval in which not-yet-flushed messages will
1960                  * be flushed. Be careful, there is a potential race condition: doFlushRptdMsgs()
1961                  * needs to aquire a lock on the action objects. If, however, long-running consumers
1962                  * cause the main queue worker threads to lock them for a long time, we may receive
1963                  * a starvation condition, resulting in the mainloop being held on lock for an extended
1964                  * period of time. That, in turn, could lead to unresponsiveness to termination
1965                  * requests. It is especially important that the bFinished flag is checked before
1966                  * doFlushRptdMsgs() is called (I know because I ran into that situation). I am
1967                  * not yet sure if the remaining probability window of a termination-related
1968                  * problem is large enough to justify changing the code - I would consider it
1969                  * extremely unlikely that the problem ever occurs in practice. Fixing it would
1970                  * require not only a lot of effort but would cost considerable performance. So
1971                  * for the time being, I think the remaining risk can be accepted.
1972                  * rgerhards, 2008-01-10
1973                  */
1974                 if(bReduceRepeatMsgs == 1)
1975                         doFlushRptdMsgs();
1976
1977                 if(bHadHUP) {
1978                         doHUP();
1979                         bHadHUP = 0;
1980                         continue;
1981                 }
1982                 // TODO: remove execScheduled(); /* handle Apc calls (if any) */
1983         }
1984         ENDfunc
1985 }
1986
1987
1988 /* load build-in modules
1989  * very first version begun on 2007-07-23 by rgerhards
1990  */
1991 static rsRetVal loadBuildInModules(void)
1992 {
1993         DEFiRet;
1994
1995         if((iRet = module.doModInit(modInitFile, UCHAR_CONSTANT("builtin-file"), NULL)) != RS_RET_OK) {
1996                 RETiRet;
1997         }
1998         if((iRet = module.doModInit(modInitPipe, UCHAR_CONSTANT("builtin-pipe"), NULL)) != RS_RET_OK) {
1999                 RETiRet;
2000         }
2001 #ifdef SYSLOG_INET
2002         if((iRet = module.doModInit(modInitFwd, UCHAR_CONSTANT("builtin-fwd"), NULL)) != RS_RET_OK) {
2003                 RETiRet;
2004         }
2005 #endif
2006         if((iRet = module.doModInit(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL)) != RS_RET_OK) {
2007                 RETiRet;
2008         }
2009         if((iRet = module.doModInit(modInitDiscard, UCHAR_CONSTANT("builtin-discard"), NULL)) != RS_RET_OK) {
2010                 RETiRet;
2011         }
2012
2013         /* dirty, but this must be for the time being: the usrmsg module must always be
2014          * loaded as last module. This is because it processes any type of action selector.
2015          * If we load it before other modules, these others will never have a chance of
2016          * working with the config file. We may change that implementation so that a user name
2017          * must start with an alnum, that would definitely help (but would it break backwards
2018          * compatibility?). * rgerhards, 2007-07-23
2019          * User names now must begin with:
2020          *   [a-zA-Z0-9_.]
2021          */
2022         CHKiRet(module.doModInit(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL));
2023
2024         /* load build-in parser modules */
2025         CHKiRet(module.doModInit(modInitpmrfc5424, UCHAR_CONSTANT("builtin-pmrfc5424"), NULL));
2026         CHKiRet(module.doModInit(modInitpmrfc3164, UCHAR_CONSTANT("builtin-pmrfc3164"), NULL));
2027
2028         /* and set default parser modules (order is *very* important, legacy (3164) parse needs to go last! */
2029         CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc5424")));
2030         CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc3164")));
2031
2032         /* load build-in strgen modules */
2033         CHKiRet(module.doModInit(modInitsmfile, UCHAR_CONSTANT("builtin-smfile"), NULL));
2034         CHKiRet(module.doModInit(modInitsmtradfile, UCHAR_CONSTANT("builtin-smtradfile"), NULL));
2035         CHKiRet(module.doModInit(modInitsmfwd, UCHAR_CONSTANT("builtin-smfwd"), NULL));
2036         CHKiRet(module.doModInit(modInitsmtradfwd, UCHAR_CONSTANT("builtin-smtradfwd"), NULL));
2037
2038         /* ok, initialization of the command handler probably does not 100% belong right in
2039          * this space here. However, with the current design, this is actually quite a good
2040          * place to put it. We might decide to shuffle it around later, but for the time
2041          * being, the code has found its home here. A not-just-sideeffect of this decision
2042          * is that rsyslog will terminate if we can not register our built-in config commands.
2043          * This, I think, is the right thing to do. -- rgerhards, 2007-07-31
2044          */
2045         CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary, NULL, &bLogStatusMsgs, NULL));
2046         CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeretrycount", 0, eCmdHdlrInt, NULL, &glbliActionResumeRetryCount, NULL));
2047         CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL));
2048         CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, setCurrRuleset, NULL, NULL));
2049         CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrInt, putToSleep, NULL, NULL));
2050         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL));
2051         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL));
2052         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQHighWtrMark, NULL));
2053         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuelowwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQLowWtrMark, NULL));
2054         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardmark", 0, eCmdHdlrInt, NULL, &iMainMsgQDiscardMark, NULL));
2055         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardseverity", 0, eCmdHdlrSeverity, NULL, &iMainMsgQDiscardSeverity, NULL));
2056         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuecheckpointinterval", 0, eCmdHdlrInt, NULL, &iMainMsgQPersistUpdCnt, NULL));
2057         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesyncqueuefiles", 0, eCmdHdlrBinary, NULL, &bMainMsgQSyncQeueFiles, NULL));
2058         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetype", 0, eCmdHdlrGetWord, setMainMsgQueType, NULL, NULL));
2059         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreads", 0, eCmdHdlrInt, NULL, &iMainMsgQueueNumWorkers, NULL));
2060         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutshutdown", 0, eCmdHdlrInt, NULL, &iMainMsgQtoQShutdown, NULL));
2061         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutactioncompletion", 0, eCmdHdlrInt, NULL, &iMainMsgQtoActShutdown, NULL));
2062         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutenqueue", 0, eCmdHdlrInt, NULL, &iMainMsgQtoEnq, NULL));
2063         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt, NULL, &iMainMsgQtoWrkShutdown, NULL));
2064         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeueslowdown", 0, eCmdHdlrInt, NULL, &iMainMsgQDeqSlowdown, NULL));
2065         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreadminimummessages", 0, eCmdHdlrInt, NULL, &iMainMsgQWrkMinMsgs, NULL));
2066         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxFileSize, NULL));
2067         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuebatchsize", 0, eCmdHdlrSize, NULL, &iMainMsgQueDeqBatchSize, NULL));
2068         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxDiskSpace, NULL));
2069         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &bMainMsgQSaveOnShutdown, NULL));
2070         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimebegin", 0, eCmdHdlrInt, NULL, &iMainMsgQueueDeqtWinFromHr, NULL));
2071         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &iMainMsgQueueDeqtWinToHr, NULL));
2072         CHKiRet(regCfSysLineHdlr((uchar *)"abortonuncleanconfig", 0, eCmdHdlrBinary, NULL, &bAbortOnUncleanConfig, NULL));
2073         CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary, NULL, &bReduceRepeatMsgs, NULL));
2074         CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlywhenpreviousissuspended", 0, eCmdHdlrBinary, NULL, &bActExecWhenPrevSusp, NULL));
2075         CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL));
2076         CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_TEMPLATE, NULL));
2077         CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL));
2078         CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_ALLOWEDSENDER, NULL));
2079         CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, conf.doModLoad, NULL, NULL));
2080         CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, conf.doIncludeLine, NULL, NULL));
2081         CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, setUmask, NULL, NULL));
2082         CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt, setMaxFiles, NULL, NULL));
2083         CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary, NULL, &bDebugPrintTemplateList, NULL));
2084         CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary, NULL, &bDebugPrintModuleList, NULL));
2085         CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary,
2086                  NULL, &bDebugPrintCfSysLineHandlerList, NULL));
2087         CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord, NULL, &pModDir, NULL));
2088         CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord, NULL, &pszConfDAGFile, NULL));
2089         CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
2090         CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &bErrMsgToStderr, NULL));
2091         CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL));
2092         CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID, NULL, &uidDropPriv, NULL));
2093         CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt, NULL, &uidDropPriv, NULL));
2094         CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL));
2095         CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroupid", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL));
2096
2097 finalize_it:
2098         RETiRet;
2099 }
2100
2101
2102 /* print version and compile-time setting information.
2103  */
2104 static void printVersion(void)
2105 {
2106         printf("rsyslogd %s, ", VERSION);
2107         printf("compiled with:\n");
2108 #ifdef FEATURE_REGEXP
2109         printf("\tFEATURE_REGEXP:\t\t\t\tYes\n");
2110 #else
2111         printf("\tFEATURE_REGEXP:\t\t\t\tNo\n");
2112 #endif
2113 #if defined(_LARGE_FILES) || (defined (_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS >= 64)
2114         printf("\tFEATURE_LARGEFILE:\t\t\tYes\n");
2115 #else
2116         printf("\tFEATURE_LARGEFILE:\t\t\tNo\n");
2117 #endif
2118 #if defined(SYSLOG_INET) && defined(USE_GSSAPI)
2119         printf("\tGSSAPI Kerberos 5 support:\t\tYes\n");
2120 #else
2121         printf("\tGSSAPI Kerberos 5 support:\t\tNo\n");
2122 #endif
2123 #ifndef NDEBUG
2124         printf("\tFEATURE_DEBUG (debug build, slow code):\tYes\n");
2125 #else
2126         printf("\tFEATURE_DEBUG (debug build, slow code):\tNo\n");
2127 #endif
2128 #ifdef  HAVE_ATOMIC_BUILTINS
2129         printf("\t32bit Atomic operations supported:\tYes\n");
2130 #else
2131         printf("\t32bit Atomic operations supported:\tNo\n");
2132 #endif
2133 #ifdef  HAVE_ATOMIC_BUILTINS_64BIT
2134         printf("\t64bit Atomic operations supported:\tYes\n");
2135 #else
2136         printf("\t64bit Atomic operations supported:\tNo\n");
2137 #endif
2138 #ifdef  RTINST
2139         printf("\tRuntime Instrumentation (slow code):\tYes\n");
2140 #else
2141         printf("\tRuntime Instrumentation (slow code):\tNo\n");
2142 #endif
2143         printf("\nSee http://www.rsyslog.com for more information.\n");
2144 }
2145
2146
2147 /* This function is called after initial initalization. It is used to
2148  * move code out of the too-long main() function.
2149  * rgerhards, 2007-10-17
2150  */
2151 static rsRetVal mainThread()
2152 {
2153         DEFiRet;
2154         uchar *pTmp;
2155
2156         /* initialize the build-in templates */
2157         pTmp = template_DebugFormat;
2158         tplAddLine("RSYSLOG_DebugFormat", &pTmp);
2159         pTmp = template_SyslogProtocol23Format;
2160         tplAddLine("RSYSLOG_SyslogProtocol23Format", &pTmp);
2161         pTmp = template_FileFormat; /* new format for files with high-precision stamp */
2162         tplAddLine("RSYSLOG_FileFormat", &pTmp);
2163         pTmp = template_TraditionalFileFormat;
2164         tplAddLine("RSYSLOG_TraditionalFileFormat", &pTmp);
2165         pTmp = template_WallFmt;
2166         tplAddLine(" WallFmt", &pTmp);
2167         pTmp = template_ForwardFormat;
2168         tplAddLine("RSYSLOG_ForwardFormat", &pTmp);
2169         pTmp = template_TraditionalForwardFormat;
2170         tplAddLine("RSYSLOG_TraditionalForwardFormat", &pTmp);
2171         pTmp = template_StdUsrMsgFmt;
2172         tplAddLine(" StdUsrMsgFmt", &pTmp);
2173         pTmp = template_StdDBFmt;
2174         tplAddLine(" StdDBFmt", &pTmp);
2175         pTmp = template_StdPgSQLFmt;
2176         tplAddLine(" StdPgSQLFmt", &pTmp);
2177         pTmp = template_StdJSONFmt;
2178         tplAddLine(" StdJSONFmt", &pTmp);
2179         pTmp = template_spoofadr;
2180         tplLastStaticInit(tplAddLine("RSYSLOG_omudpspoofDfltSourceTpl", &pTmp));
2181
2182         CHKiRet(init());
2183
2184         if(Debug && debugging_on) {
2185                 DBGPRINTF("Debugging enabled, SIGUSR1 to turn off debugging.\n");
2186         }
2187
2188         /* Send a signal to the parent so it can terminate.
2189          */
2190         if(myPid != ppid)
2191                 kill(ppid, SIGTERM);
2192
2193
2194         /* If instructed to do so, we now drop privileges. Note that this is not 100% secure,
2195          * because outputs are already running at this time. However, we can implement
2196          * dropping of privileges rather quickly and it will work in many cases. While it is not
2197          * the ultimate solution, the current one is still much better than not being able to
2198          * drop privileges at all. Doing it correctly, requires a change in architecture, which
2199          * we should do over time. TODO -- rgerhards, 2008-11-19
2200          */
2201         if(gidDropPriv != 0) {
2202                 doDropPrivGid(gidDropPriv);
2203         }
2204
2205         if(uidDropPriv != 0) {
2206                 doDropPrivUid(uidDropPriv);
2207         }
2208
2209         /* finally let the inputs run... */
2210         runInputModules();
2211
2212         /* END OF INTIALIZATION
2213          */
2214         DBGPRINTF("initialization completed, transitioning to regular run mode\n");
2215
2216         /* close stderr and stdout if they are kept open during a fork. Note that this
2217          * may introduce subtle security issues: if we are in a jail, one may break out of
2218          * it via these descriptors. But if I close them earlier, error messages will (once
2219          * again) not be emitted to the user that starts the daemon. As root jail support
2220          * is still in its infancy (and not really done), we currently accept this issue.
2221          * rgerhards, 2009-06-29
2222          */
2223         if(!(Debug == DEBUG_FULL || NoFork)) {
2224                 close(1);
2225                 close(2);
2226                 bErrMsgToStderr = 0;
2227         }
2228
2229         mainloop();
2230
2231 finalize_it:
2232         RETiRet;
2233 }
2234
2235
2236 /* Method to initialize all global classes and use the objects that we need.
2237  * rgerhards, 2008-01-04
2238  * rgerhards, 2008-04-16: the actual initialization is now carried out by the runtime
2239  */
2240 static rsRetVal
2241 InitGlobalClasses(void)
2242 {
2243         DEFiRet;
2244         char *pErrObj; /* tells us which object failed if that happens (useful for troubleshooting!) */
2245
2246         /* Intialize the runtime system */
2247         pErrObj = "rsyslog runtime"; /* set in case the runtime errors before setting an object */
2248         CHKiRet(rsrtInit(&pErrObj, &obj));
2249         CHKiRet(rsrtSetErrLogger(submitErrMsg)); /* set out error handler */
2250
2251         /* Now tell the system which classes we need ourselfs */
2252         pErrObj = "glbl";
2253         CHKiRet(objUse(glbl,     CORE_COMPONENT));
2254         pErrObj = "errmsg";
2255         CHKiRet(objUse(errmsg,   CORE_COMPONENT));
2256         pErrObj = "module";
2257         CHKiRet(objUse(module,   CORE_COMPONENT));
2258         pErrObj = "datetime";
2259         CHKiRet(objUse(datetime, CORE_COMPONENT));
2260         pErrObj = "expr";
2261         CHKiRet(objUse(expr,     CORE_COMPONENT));
2262         pErrObj = "rule";
2263         CHKiRet(objUse(rule,     CORE_COMPONENT));
2264         pErrObj = "ruleset";
2265         CHKiRet(objUse(ruleset,  CORE_COMPONENT));
2266         pErrObj = "conf";
2267         CHKiRet(objUse(conf,     CORE_COMPONENT));
2268         pErrObj = "prop";
2269         CHKiRet(objUse(prop,     CORE_COMPONENT));
2270         pErrObj = "parser";
2271         CHKiRet(objUse(parser,     CORE_COMPONENT));
2272
2273         /* intialize some dummy classes that are not part of the runtime */
2274         pErrObj = "action";
2275         CHKiRet(actionClassInit());
2276         pErrObj = "template";
2277         CHKiRet(templateInit());
2278
2279         /* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */
2280         pErrObj = "net";
2281         CHKiRet(objUse(net, LM_NET_FILENAME));
2282
2283 finalize_it:
2284         if(iRet != RS_RET_OK) {
2285                 /* we know we are inside the init sequence, so we can safely emit
2286                  * messages to stderr. -- rgerhards, 2008-04-02
2287                  */
2288                 fprintf(stderr, "Error during class init for object '%s' - failing...\n", pErrObj);
2289         }
2290
2291         RETiRet;
2292 }
2293
2294
2295 /* Method to exit all global classes. We do not do any error checking here,
2296  * because that wouldn't help us at all. So better try to deinit blindly
2297  * as much as succeeds (which usually means everything will). We just must
2298  * be careful to do the de-init in the opposite order of the init, because
2299  * of the dependencies. However, its not as important this time, because
2300  * we have reference counting.
2301  * rgerhards, 2008-03-10
2302  */
2303 static rsRetVal
2304 GlobalClassExit(void)
2305 {
2306         DEFiRet;
2307
2308         /* first, release everything we used ourself */
2309         objRelease(net,      LM_NET_FILENAME);/* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */
2310         objRelease(prop,     CORE_COMPONENT);
2311         objRelease(conf,     CORE_COMPONENT);
2312         objRelease(ruleset,  CORE_COMPONENT);
2313         objRelease(rule,     CORE_COMPONENT);
2314         objRelease(expr,     CORE_COMPONENT);
2315         vmClassExit();                                  /* this is hack, currently core_modules do not get this automatically called */
2316         parserClassExit();                                      /* this is hack, currently core_modules do not get this automatically called */
2317         objRelease(datetime, CORE_COMPONENT);
2318
2319         /* TODO: implement the rest of the deinit */
2320         /* dummy "classes */
2321         strExit();
2322
2323 #if 0
2324         CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */
2325         /* the following classes were intialized by objClassInit() */
2326         CHKiRet(objUse(errmsg,   CORE_COMPONENT));
2327         CHKiRet(objUse(module,   CORE_COMPONENT));
2328 #endif
2329         rsrtExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */
2330
2331         RETiRet;
2332 }
2333
2334
2335 /* some support for command line option parsing. Any non-trivial options must be
2336  * buffered until the complete command line has been parsed. This is necessary to
2337  * prevent dependencies between the options. That, in turn, means we need to have
2338  * something that is capable of buffering options and there values. The follwing
2339  * functions handle that.
2340  * rgerhards, 2008-04-04
2341  */
2342 typedef struct bufOpt {
2343         struct bufOpt *pNext;
2344         char optchar;
2345         char *arg;
2346 } bufOpt_t;
2347 static bufOpt_t *bufOptRoot = NULL;
2348 static bufOpt_t *bufOptLast = NULL;
2349
2350 /* add option buffer */
2351 static rsRetVal
2352 bufOptAdd(char opt, char *arg)
2353 {
2354         DEFiRet;
2355         bufOpt_t *pBuf;
2356
2357         if((pBuf = MALLOC(sizeof(bufOpt_t))) == NULL)
2358                 ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
2359
2360         pBuf->optchar = opt;
2361         pBuf->arg = arg;
2362         pBuf->pNext = NULL;
2363
2364         if(bufOptLast == NULL) {
2365                 bufOptRoot = pBuf; /* then there is also no root! */
2366         } else {
2367                 bufOptLast->pNext = pBuf;
2368         }
2369         bufOptLast = pBuf;
2370
2371 finalize_it:
2372         RETiRet;
2373 }
2374
2375
2376
2377 /* remove option buffer from top of list, return values and destruct buffer itself.
2378  * returns RS_RET_END_OF_LINKEDLIST when no more options are present.
2379  * (we use int *opt instead of char *opt to keep consistent with getopt())
2380  */
2381 static rsRetVal
2382 bufOptRemove(int *opt, char **arg)
2383 {
2384         DEFiRet;
2385         bufOpt_t *pBuf;
2386
2387         if(bufOptRoot == NULL)
2388                 ABORT_FINALIZE(RS_RET_END_OF_LINKEDLIST);
2389         pBuf = bufOptRoot;
2390
2391         *opt = pBuf->optchar;
2392         *arg = pBuf->arg;
2393
2394         bufOptRoot = pBuf->pNext;
2395         free(pBuf);
2396
2397 finalize_it:
2398         RETiRet;
2399 }
2400
2401
2402 /* global initialization, to be done only once and before the mainloop is started.
2403  * rgerhards, 2008-07-28 (extracted from realMain())
2404  */
2405 static rsRetVal
2406 doGlblProcessInit(void)
2407 {
2408         struct sigaction sigAct;
2409         int num_fds;
2410         int i;
2411         DEFiRet;
2412
2413         thrdInit();
2414
2415         if( !(Debug == DEBUG_FULL || NoFork) )
2416         {
2417                 DBGPRINTF("Checking pidfile.\n");
2418                 if (!check_pid(PidFile))
2419                 {
2420                         memset(&sigAct, 0, sizeof (sigAct));
2421                         sigemptyset(&sigAct.sa_mask);
2422                         sigAct.sa_handler = doexit;
2423                         sigaction(SIGTERM, &sigAct, NULL);
2424
2425                         if (fork()) {
2426                                 /* Parent process
2427                                  */
2428                                 sleep(300);
2429                                 /* Not reached unless something major went wrong.  5
2430                                  * minutes should be a fair amount of time to wait.
2431                                  * Please note that this procedure is important since
2432                                  * the father must not exit before syslogd isn't
2433                                  * initialized or the klogd won't be able to flush its
2434                                  * logs.  -Joey
2435                                  */
2436                                 exit(1); /* "good" exit - after forking, not diasabling anything */
2437                         }
2438
2439                         num_fds = getdtablesize();
2440                         close(0);
2441                         /* we keep stdout and stderr open in case we have to emit something */
2442                         i = 3;
2443
2444                         /* if (sd_booted()) */ {
2445                                 const char *e;
2446                                 char buf[24] = { '\0' };
2447                                 char *p = NULL;
2448                                 unsigned long l;
2449                                 int sd_fds;
2450
2451                                 /* fork & systemd socket activation:
2452                                  * fetch listen pid and update to ours,
2453                                  * when it is set to pid of our parent.
2454                                  */
2455                                 if ( (e = getenv("LISTEN_PID"))) {
2456                                         errno = 0;
2457                                         l = strtoul(e, &p, 10);
2458                                         if (errno ==  0 && l > 0 && (!p || !*p)) {
2459                                                 if (getppid() == (pid_t)l) {
2460                                                         snprintf(buf, sizeof(buf), "%d",
2461                                                                  getpid());
2462                                                         setenv("LISTEN_PID", buf, 1);
2463                                                 }
2464                                         }
2465                                 }
2466
2467                                 /*
2468                                  * close only all further fds, except
2469                                  * of the fds provided by systemd.
2470                                  */
2471                                 sd_fds = sd_listen_fds(0);
2472                                 if (sd_fds > 0)
2473                                         i = SD_LISTEN_FDS_START + sd_fds;
2474                         }
2475                         for ( ; i < num_fds; i++)
2476                                 (void) close(i);
2477
2478                         untty();
2479                 } else {
2480                         fputs(" Already running. If you want to run multiple instances, you need "
2481                               "to specify different pid files (use -i option)\n", stderr);
2482                         exit(1); /* "good" exit, done if syslogd is already running */
2483                 }
2484         }
2485
2486         /* tuck my process id away */
2487         DBGPRINTF("Writing pidfile %s.\n", PidFile);
2488         if (!check_pid(PidFile))
2489         {
2490                 if (!write_pid(PidFile))
2491                 {
2492                         fputs("Can't write pid.\n", stderr);
2493                         exit(1); /* exit during startup - questionable */
2494                 }
2495         }
2496         else
2497         {
2498                 fputs("Pidfile (and pid) already exist.\n", stderr);
2499                 exit(1); /* exit during startup - questionable */
2500         }
2501         myPid = getpid();       /* save our pid for further testing (also used for messages) */
2502
2503         memset(&sigAct, 0, sizeof (sigAct));
2504         sigemptyset(&sigAct.sa_mask);
2505
2506         sigAct.sa_handler = sigsegvHdlr;
2507         sigaction(SIGSEGV, &sigAct, NULL);
2508         sigAct.sa_handler = sigsegvHdlr;
2509         sigaction(SIGABRT, &sigAct, NULL);
2510         sigAct.sa_handler = doDie;
2511         sigaction(SIGTERM, &sigAct, NULL);
2512         sigAct.sa_handler = Debug ? doDie : SIG_IGN;
2513         sigaction(SIGINT, &sigAct, NULL);
2514         sigaction(SIGQUIT, &sigAct, NULL);
2515         sigAct.sa_handler = reapchild;
2516         sigaction(SIGCHLD, &sigAct, NULL);
2517         sigAct.sa_handler = Debug ? debug_switch : SIG_IGN;
2518         sigaction(SIGUSR1, &sigAct, NULL);
2519         sigAct.sa_handler = sigttin_handler;
2520         sigaction(SIGTTIN, &sigAct, NULL); /* (ab)used to interrupt input threads */
2521         sigAct.sa_handler = SIG_IGN;
2522         sigaction(SIGPIPE, &sigAct, NULL);
2523         sigaction(SIGXFSZ, &sigAct, NULL); /* do not abort if 2gig file limit is hit */
2524
2525         RETiRet;
2526 }
2527
2528
2529 /* This is the main entry point into rsyslogd. Over time, we should try to
2530  * modularize it a bit more...
2531  */
2532 int realMain(int argc, char **argv)
2533 {
2534         DEFiRet;
2535
2536         register uchar *p;
2537         int ch;
2538         struct hostent *hent;
2539         extern int optind;
2540         extern char *optarg;
2541         int bEOptionWasGiven = 0;
2542         int bImUxSockLoaded = 0; /* already generated a $ModLoad imuxsock? */
2543         int iHelperUOpt;
2544         int bChDirRoot = 1; /* change the current working directory to "/"? */
2545         char *arg;      /* for command line option processing */
2546         uchar legacyConfLine[80];
2547         uchar *LocalHostName;
2548         uchar *LocalDomain;
2549         uchar *LocalFQDNName;
2550         char cwdbuf[128]; /* buffer to obtain/display current working directory */
2551
2552         /* first, parse the command line options. We do not carry out any actual work, just
2553          * see what we should do. This relieves us from certain anomalies and we can process
2554          * the parameters down below in the correct order. For example, we must know the
2555          * value of -M before we can do the init, but at the same time we need to have
2556          * the base classes init before we can process most of the options. Now, with the
2557          * split of functionality, this is no longer a problem. Thanks to varmofekoj for
2558          * suggesting this algo.
2559          * Note: where we just need to set some flags and can do so without knowledge
2560          * of other options, we do this during the inital option processing. With later
2561          * versions (if a dependency on -c option is introduced), we must move that code
2562          * to other places, but I think it is quite appropriate and saves code to do this
2563         * only when actually neeeded.
2564          * rgerhards, 2008-04-04
2565          */
2566         while((ch = getopt(argc, argv, "46a:Ac:def:g:hi:l:m:M:nN:op:qQr::s:t:T:u:vwx")) != EOF) {
2567                 switch((char)ch) {
2568                 case '4':
2569                 case '6':
2570                 case 'A':
2571                 case 'a':
2572                 case 'f': /* configuration file */
2573                 case 'h':
2574                 case 'i': /* pid file name */
2575                 case 'l':
2576                 case 'm': /* mark interval */
2577                 case 'n': /* don't fork */
2578                 case 'N': /* enable config verify mode */
2579                 case 'o':
2580                 case 'p':
2581                 case 'q': /* add hostname if DNS resolving has failed */
2582                 case 'Q': /* dont resolve hostnames in ACL to IPs */
2583                 case 's':
2584                 case 'T': /* chroot on startup (primarily for testing) */
2585                 case 'u': /* misc user settings */
2586                 case 'w': /* disable disallowed host warnings */
2587                 case 'x': /* disable dns for remote messages */
2588                         CHKiRet(bufOptAdd(ch, optarg));
2589                         break;
2590                 case 'c':               /* compatibility mode */
2591                         iCompatibilityMode = atoi(optarg);
2592                         break;
2593                 case 'd': /* debug - must be handled now, so that debug is active during init! */
2594                         debugging_on = 1;
2595                         Debug = 1;
2596                         break;
2597                 case 'e':               /* log every message (no repeat message supression) */
2598                         fprintf(stderr, "note: -e option is no longer supported, every message is now logged by default\n");
2599                         bEOptionWasGiven = 1;
2600                         break;
2601                 case 'g':               /* enable tcp gssapi logging */
2602 #if defined(SYSLOG_INET) && defined(USE_GSSAPI)
2603                         CHKiRet(bufOptAdd('g', optarg));
2604 #else
2605                         fprintf(stderr, "rsyslogd: -g not valid - not compiled with gssapi support");
2606 #endif
2607                         break;
2608                 case 'M': /* default module load path -- this MUST be carried out immediately! */
2609                         glblModPath = (uchar*) optarg;
2610                         break;
2611                 case 'r':               /* accept remote messages */
2612 #ifdef SYSLOG_INET
2613                         CHKiRet(bufOptAdd(ch, optarg));
2614 #else
2615                         fprintf(stderr, "rsyslogd: -r not valid - not compiled with network support\n");
2616 #endif
2617                         break;
2618                 case 't':               /* enable tcp logging */
2619 #ifdef SYSLOG_INET
2620                         CHKiRet(bufOptAdd(ch, optarg));
2621 #else
2622                         fprintf(stderr, "rsyslogd: -t not valid - not compiled with network support\n");
2623 #endif
2624                         break;
2625                 case 'v': /* MUST be carried out immediately! */
2626                         printVersion();
2627                         exit(0); /* exit for -v option - so this is a "good one" */
2628                case '?':
2629                 default:
2630                         usage();
2631                 }
2632         }
2633
2634         if(argc - optind)
2635                 usage();
2636
2637         DBGPRINTF("rsyslogd %s startup, compatibility mode %d, module path '%s', cwd:%s\n",
2638                   VERSION, iCompatibilityMode, glblModPath == NULL ? "" : (char*)glblModPath,
2639                   getcwd(cwdbuf, sizeof(cwdbuf)));
2640
2641         /* we are done with the initial option parsing and processing. Now we init the system. */
2642
2643         ppid = getpid();
2644
2645         CHKiRet_Hdlr(InitGlobalClasses()) {
2646                 fprintf(stderr, "rsyslogd initializiation failed - global classes could not be initialized.\n"
2647                                 "Did you do a \"make install\"?\n"
2648                                 "Suggested action: run rsyslogd with -d -n options to see what exactly "
2649                                 "fails.\n");
2650                 FINALIZE;
2651         }
2652
2653         /* doing some core initializations */
2654
2655         /* we need to create the inputName property (only once during our lifetime) */
2656         CHKiRet(prop.Construct(&pInternalInputName));
2657         CHKiRet(prop.SetString(pInternalInputName, UCHAR_CONSTANT("rsyslogd"), sizeof("rsyslgod") - 1));
2658         CHKiRet(prop.ConstructFinalize(pInternalInputName));
2659
2660         CHKiRet(prop.Construct(&pLocalHostIP));
2661         CHKiRet(prop.SetString(pLocalHostIP, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1));
2662         CHKiRet(prop.ConstructFinalize(pLocalHostIP));
2663
2664         /* get our host and domain names - we need to do this early as we may emit
2665          * error log messages, which need the correct hostname. -- rgerhards, 2008-04-04
2666          */
2667         net.getLocalHostname(&LocalFQDNName);
2668         CHKmalloc(LocalHostName = (uchar*) strdup((char*)LocalFQDNName));
2669         glbl.SetLocalFQDNName(LocalFQDNName); /* set the FQDN before we modify it */
2670         if((p = (uchar*)strchr((char*)LocalHostName, '.'))) {
2671                 *p++ = '\0';
2672                 LocalDomain = p;
2673         } else {
2674                 LocalDomain = (uchar*)"";
2675
2676                 /* It's not clearly defined whether gethostname()
2677                  * should return the simple hostname or the fqdn. A
2678                  * good piece of software should be aware of both and
2679                  * we want to distribute good software.  Joey
2680                  *
2681                  * Good software also always checks its return values...
2682                  * If syslogd starts up before DNS is up & /etc/hosts
2683                  * doesn't have LocalHostName listed, gethostbyname will
2684                 * return NULL.
2685                  */
2686                 /* TODO: gethostbyname() is not thread-safe, but replacing it is
2687                  * not urgent as we do not run on multiple threads here. rgerhards, 2007-09-25
2688                  */
2689                 hent = gethostbyname((char*)LocalHostName);
2690                 if(hent) {
2691                         int i = 0;
2692
2693                         if(hent->h_aliases) {
2694                                 size_t hnlen;
2695
2696                                 hnlen = strlen((char *) LocalHostName);
2697
2698                                 for (i = 0; hent->h_aliases[i]; i++) {
2699                                         if (!strncmp(hent->h_aliases[i], (char *) LocalHostName, hnlen)
2700                                             && hent->h_aliases[i][hnlen] == '.') {
2701                                                 /* found a matching hostname */
2702                                                 break;
2703                                         }
2704                                 }
2705                         }
2706
2707                         free(LocalHostName);
2708                         if(hent->h_aliases && hent->h_aliases[i]) {
2709                                 CHKmalloc(LocalHostName = (uchar*)strdup(hent->h_aliases[i]));
2710                         } else {
2711                                 CHKmalloc(LocalHostName = (uchar*)strdup(hent->h_name));
2712                         }
2713
2714                         if((p = (uchar*)strchr((char*)LocalHostName, '.')))
2715                         {
2716                                 *p++ = '\0';
2717                                 LocalDomain = p;
2718                         }
2719                 }
2720         }
2721
2722         /* Convert to lower case to recognize the correct domain laterly */
2723         for(p = LocalDomain ; *p ; p++)
2724                 *p = (char)tolower((int)*p);
2725
2726         /* we now have our hostname and can set it inside the global vars.
2727          * TODO: think if all of this would better be a runtime function
2728          * rgerhards, 2008-04-17
2729          */
2730         glbl.SetLocalHostName(LocalHostName);
2731         glbl.SetLocalDomain(LocalDomain);
2732         glbl.GenerateLocalHostNameProperty(); /* must be redone after conf processing, FQDN setting may have changed */
2733
2734         /* initialize the objects */
2735         if((iRet = modInitIminternal()) != RS_RET_OK) {
2736                 fprintf(stderr, "fatal error: could not initialize errbuf object (error code %d).\n",
2737                         iRet);
2738                 exit(1); /* "good" exit, leaving at init for fatal error */
2739         }
2740
2741         if((iRet = loadBuildInModules()) != RS_RET_OK) {
2742                 fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n",
2743                         iRet);
2744                 exit(1); /* "good" exit, leaving at init for fatal error */
2745         }
2746
2747         /* END core initializations - we now come back to carrying out command line options*/
2748
2749         while((iRet = bufOptRemove(&ch, &arg)) == RS_RET_OK) {
2750                 DBGPRINTF("deque option %c, optarg '%s'\n", ch, (arg == NULL) ? "" : arg);
2751                 switch((char)ch) {
2752                 case '4':
2753                         glbl.SetDefPFFamily(PF_INET);
2754                         break;
2755                 case '6':
2756                         glbl.SetDefPFFamily(PF_INET6);
2757                         break;
2758                 case 'A':
2759                         send_to_all++;
2760                         break;
2761                 case 'a':
2762                         if(iCompatibilityMode < 3) {
2763                                 if(!bImUxSockLoaded) {
2764                                         legacyOptsEnq((uchar *) "ModLoad imuxsock");
2765                                         bImUxSockLoaded = 1;
2766                                 }
2767                                 snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "addunixlistensocket %s", arg);
2768                                 legacyOptsEnq(legacyConfLine);
2769                         } else {
2770                                 fprintf(stderr, "error -a is no longer supported, use module imuxsock instead");
2771                         }
2772                         break;
2773                 case 'f':               /* configuration file */
2774                         ConfFile = (uchar*) arg;
2775                         break;
2776                 case 'g':               /* enable tcp gssapi logging */
2777                         if(iCompatibilityMode < 3) {
2778                                 legacyOptsParseTCP(ch, arg);
2779                         } else
2780                                 fprintf(stderr, "-g option only supported in compatibility modes 0 to 2 - ignored\n");
2781                         break;
2782                 case 'h':
2783                         if(iCompatibilityMode < 3) {
2784                                 errmsg.LogError(0, NO_ERRCODE, "WARNING: -h option is no longer supported - ignored");
2785                         } else {
2786                                 usage(); /* for v3 and above, it simply is an error */
2787                         }
2788                         break;
2789                 case 'i':               /* pid file name */
2790                         PidFile = arg;
2791                         break;
2792                 case 'l':
2793                         if(glbl.GetLocalHosts() != NULL) {
2794                                 fprintf (stderr, "rsyslogd: Only one -l argument allowed, the first one is taken.\n");
2795                         } else {
2796                                 glbl.SetLocalHosts(crunch_list(arg));
2797                         }
2798                         break;
2799                 case 'm':               /* mark interval */
2800                         if(iCompatibilityMode < 3) {
2801                                 MarkInterval = atoi(arg) * 60;
2802                         } else
2803                                 fprintf(stderr,
2804                                         "-m option only supported in compatibility modes 0 to 2 - ignored\n");
2805                         break;
2806                 case 'n':               /* don't fork */
2807                         NoFork = 1;
2808                         break;
2809                 case 'N':               /* enable config verify mode */
2810                         iConfigVerify = atoi(arg);
2811                         break;
2812                 case 'o':
2813                         if(iCompatibilityMode < 3) {
2814                                 if(!bImUxSockLoaded) {
2815                                         legacyOptsEnq((uchar *) "ModLoad imuxsock");
2816                                         bImUxSockLoaded = 1;
2817                                 }
2818                                 legacyOptsEnq((uchar *) "OmitLocalLogging");
2819                         } else {
2820                                 fprintf(stderr, "error -o is no longer supported, use module imuxsock instead");
2821                         }
2822                         break;
2823                 case 'p':
2824                         if(iCompatibilityMode < 3) {
2825                                 if(!bImUxSockLoaded) {
2826                                         legacyOptsEnq((uchar *) "ModLoad imuxsock");
2827                                         bImUxSockLoaded = 1;
2828                                 }
2829                                 snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "SystemLogSocketName %s", arg);
2830                                 legacyOptsEnq(legacyConfLine);
2831                         } else {
2832                                 fprintf(stderr, "error -p is no longer supported, use module imuxsock instead");
2833                         }
2834                         break;
2835                 case 'q':               /* add hostname if DNS resolving has failed */
2836                         *(net.pACLAddHostnameOnFail) = 1;
2837                         break;
2838                 case 'Q':               /* dont resolve hostnames in ACL to IPs */
2839                         *(net.pACLDontResolve) = 1;
2840                         break;
2841                 case 'r':               /* accept remote messages */
2842                         if(iCompatibilityMode < 3) {
2843                                 legacyOptsEnq((uchar *) "ModLoad imudp");
2844                                 snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "UDPServerRun %s", arg);
2845                                 legacyOptsEnq(legacyConfLine);
2846                         } else
2847                                 fprintf(stderr, "-r option only supported in compatibility modes 0 to 2 - ignored\n");
2848                         break;
2849                 case 's':
2850                         if(glbl.GetStripDomains() != NULL) {
2851                                 fprintf (stderr, "rsyslogd: Only one -s argument allowed, the first one is taken.\n");
2852                         } else {
2853                                 glbl.SetStripDomains(crunch_list(arg));
2854                         }
2855                         break;
2856                 case 't':               /* enable tcp logging */
2857                         if(iCompatibilityMode < 3) {
2858                                 legacyOptsParseTCP(ch, arg);
2859                         } else
2860                                 fprintf(stderr, "-t option only supported in compatibility modes 0 to 2 - ignored\n");
2861                         break;
2862                 case 'T':/* chroot() immediately at program startup, but only for testing, NOT security yet */
2863                         if(chroot(arg) != 0) {
2864                                 perror("chroot");
2865                                 exit(1);
2866                         }
2867                         break;
2868                 case 'u':               /* misc user settings */
2869                         iHelperUOpt = atoi(arg);
2870                         if(iHelperUOpt & 0x01)
2871                                 glbl.SetParseHOSTNAMEandTAG(0);
2872                         if(iHelperUOpt & 0x02)
2873                                 bChDirRoot = 0;
2874                         break;
2875                 case 'w':               /* disable disallowed host warnigs */
2876                         glbl.SetOption_DisallowWarning(0);
2877                         break;
2878                 case 'x':               /* disable dns for remote messages */
2879                         glbl.SetDisableDNS(1);
2880                         break;
2881                case '?':
2882                 default:
2883                         usage();
2884                 }
2885         }
2886
2887         if(iRet != RS_RET_END_OF_LINKEDLIST)
2888                 FINALIZE;
2889
2890         if(iConfigVerify) {
2891                 fprintf(stderr, "rsyslogd: version %s, config validation run (level %d), master config %s\n",
2892                         VERSION, iConfigVerify, ConfFile);
2893         }
2894
2895         if(bChDirRoot) {
2896                 if(chdir("/") != 0)
2897                         fprintf(stderr, "Can not do 'cd /' - still trying to run\n");
2898         }
2899
2900
2901         /* process compatibility mode settings */
2902         if(iCompatibilityMode < 4) {
2903                 errmsg.LogError(0, NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically "
2904                                             "generated config directives may interfer with your rsyslog.conf settings. "
2905                                             "We suggest upgrading your config and adding -c5 as the first "
2906                                             "rsyslogd option.");
2907         }
2908
2909         if(iCompatibilityMode < 3) {
2910                 if(MarkInterval > 0) {
2911                         legacyOptsEnq((uchar *) "ModLoad immark");
2912                         snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "MarkMessagePeriod %d", MarkInterval);
2913                         legacyOptsEnq(legacyConfLine);
2914                 }
2915                 if(!bImUxSockLoaded) {
2916                         legacyOptsEnq((uchar *) "ModLoad imuxsock");
2917                 }
2918         }
2919
2920         if(bEOptionWasGiven && iCompatibilityMode < 3) {
2921                 errmsg.LogError(0, NO_ERRCODE, "WARNING: \"message repeated n times\" feature MUST be turned on in "
2922                                             "rsyslog.conf - CURRENTLY EVERY MESSAGE WILL BE LOGGED. Visit "
2923                                             "http://www.rsyslog.com/rptdmsgreduction to learn "
2924                                             "more and cast your vote if you want us to keep this feature.");
2925         }
2926
2927         if(!iConfigVerify)
2928                 CHKiRet(doGlblProcessInit());
2929
2930         CHKiRet(mainThread());
2931
2932         /* do any de-init's that need to be done AFTER this comment */
2933
2934         die(bFinished);
2935
2936         thrdExit();
2937
2938 finalize_it:
2939         if(iRet == RS_RET_VALIDATION_RUN) {
2940                 fprintf(stderr, "rsyslogd: End of config validation run. Bye.\n");
2941         } else if(iRet != RS_RET_OK) {
2942                 fprintf(stderr, "rsyslogd run failed with error %d (see rsyslog.h "
2943                                 "or try http://www.rsyslog.com/e/%d to learn what that number means)\n", iRet, iRet*-1);
2944         }
2945
2946         ENDfunc
2947         return 0;
2948 }
2949
2950
2951 /* This is the main entry point into rsyslogd. This must be a function in its own
2952  * right in order to intialize the debug system in a portable way (otherwise we would
2953  * need to have a statement before variable definitions.
2954  * rgerhards, 20080-01-28
2955  */
2956 int main(int argc, char **argv)
2957 {
2958         dbgClassInit();
2959         return realMain(argc, argv);
2960 }
2961 /* vim:set ai:
2962  */