OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / rsyslog / 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>. See
20  * AUTHORS to learn who helped make it become a reality.
21  *
22  * If you have questions about rsyslogd in general, please email
23  * info@adiscon.com. To learn more about rsyslogd, please visit
24  * http://www.rsyslog.com.
25  *
26  * \author Rainer Gerhards <rgerhards@adiscon.com>
27  * \date 2003-10-17
28  *       Some initial modifications on the sysklogd package to support
29  *       liblogging. These have actually not yet been merged to the
30  *       source you see currently (but they hopefully will)
31  *
32  * \date 2004-10-28
33  *       Restarted the modifications of sysklogd. This time, we
34  *       focus on a simpler approach first. The initial goal is to
35  *       provide MySQL database support (so that syslogd can log
36  *       to the database).
37  *
38  * rsyslog - An Enhanced syslogd Replacement.
39  * Copyright 2003-2008 Rainer Gerhards and Adiscon GmbH.
40  *
41  * This file is part of rsyslog.
42  *
43  * Rsyslog is free software: you can redistribute it and/or modify
44  * it under the terms of the GNU General Public License as published by
45  * the Free Software Foundation, either version 3 of the License, or
46  * (at your option) any later version.
47  *
48  * Rsyslog is distributed in the hope that it will be useful,
49  * but WITHOUT ANY WARRANTY; without even the implied warranty of
50  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
51  * GNU General Public License for more details.
52  *
53  * You should have received a copy of the GNU General Public License
54  * along with Rsyslog.  If not, see <http://www.gnu.org/licenses/>.
55  *
56  * A copy of the GPL can be found in the file "COPYING" in this distribution.
57  */
58 #include "config.h"
59 #include "rsyslog.h"
60
61 /* change the following setting to e.g. 32768 if you would like to
62  * support large message sizes for IHE (32k is the current maximum
63  * needed for IHE). I was initially tempted to increase it to 32k,
64  * but there is a large memory footprint with the current
65  * implementation in rsyslog. This will change as the processing
66  * changes, but I have re-set it to 1k, because the vast majority
67  * of messages is below that and the memory savings is huge, at
68  * least compared to the overall memory footprint.
69  *
70  * If you intend to receive Windows Event Log data (e.g. via
71  * EventReporter - www.eventreporter.com), you might want to 
72  * increase this number to an even higher value, as event
73  * log messages can be very lengthy.
74  * rgerhards, 2005-07-05
75  *
76  * during my recent testing, it showed that 4k seems to be
77  * the typical maximum for UDP based syslog. This is a IP stack
78  * restriction. Not always ... but very often. If you go beyond
79  * that value, be sure to test that rsyslogd actually does what
80  * you think it should do ;) Also, it is a good idea to check the
81  * doc set for anything on IHE - it most probably has information on
82  * message sizes.
83  * rgerhards, 2005-08-05
84  * 
85  * I have increased the default message size to 2048 to be in sync
86  * with recent IETF syslog standardization efforts.
87  * rgerhards, 2006-11-30
88  */
89 #define DEFUPRI         (LOG_USER|LOG_NOTICE)
90 #define TIMERINTVL      30              /* interval for checking flush, mark */
91
92 #include <unistd.h>
93 #include <stdlib.h>
94 #include <stdio.h>
95 #include <stddef.h>
96 #include <ctype.h>
97 #include <limits.h>
98 #define GNU_SOURCE
99 #include <string.h>
100 #include <stdarg.h>
101 #include <time.h>
102 #include <assert.h>
103 #include <libgen.h>
104
105 #ifdef  __sun
106 #       include <errno.h>
107 #else
108 #       include <sys/errno.h>
109 #endif
110 #include <sys/ioctl.h>
111 #include <sys/wait.h>
112 #include <sys/file.h>
113
114 #if HAVE_SYS_TIMESPEC_H
115 # include <sys/timespec.h>
116 #endif
117
118 #if HAVE_SYS_STAT_H
119 #       include <sys/stat.h>
120 #endif
121
122 #include <signal.h>
123
124 #if HAVE_PATHS_H
125 #include <paths.h>
126 #endif
127
128 #ifdef USE_NETZIP
129 #include <zlib.h>
130 #endif
131
132 #include "pidfile.h"
133 #include "srUtils.h"
134 #include "stringbuf.h"
135 #include "syslogd-types.h"
136 #include "template.h"
137 #include "outchannel.h"
138 #include "syslogd.h"
139
140 #include "msg.h"
141 #include "modules.h"
142 #include "action.h"
143 #include "tcpsyslog.h"
144 #include "iminternal.h"
145 #include "cfsysline.h"
146 #include "omshell.h"
147 #include "omusrmsg.h"
148 #include "omfwd.h"
149 #include "omfile.h"
150 #include "omdiscard.h"
151 #include "threads.h"
152 #include "queue.h"
153 #include "stream.h"
154 #include "wti.h"
155 #include "wtp.h"
156 #include "expr.h"
157 #include "ctok.h"
158 #include "conf.h"
159 #include "vmop.h"
160 #include "vmstk.h"
161 #include "vm.h"
162 #include "vmprg.h"
163 #include "errmsg.h"
164 #include "datetime.h"
165 #include "sysvar.h"
166
167 /* definitions for objects we access */
168 DEFobjCurrIf(obj)
169 DEFobjCurrIf(datetime)
170 DEFobjCurrIf(conf)
171 DEFobjCurrIf(expr)
172 DEFobjCurrIf(vm)
173 DEFobjCurrIf(var)
174 DEFobjCurrIf(module)
175 DEFobjCurrIf(errmsg)
176 DEFobjCurrIf(net) /* TODO: make go away! */
177
178
179 /* forward definitions */
180 static rsRetVal GlobalClassExit(void);
181
182 /* We define our own set of syslog defintions so that we
183  * do not need to rely on (possibly different) implementations.
184  * 2007-07-19 rgerhards
185  */
186 /* missing definitions for solaris
187  * 2006-02-16 Rger
188  */
189 #ifdef __sun
190 #       define LOG_AUTHPRIV LOG_AUTH
191 #endif
192 #define INTERNAL_NOPRI  0x10    /* the "no priority" priority */
193 #define LOG_FTP         (11<<3) /* ftp daemon */
194
195
196 #ifndef UTMP_FILE
197 #ifdef UTMP_FILENAME
198 #define UTMP_FILE UTMP_FILENAME
199 #else
200 #ifdef _PATH_UTMP
201 #define UTMP_FILE _PATH_UTMP
202 #else
203 #define UTMP_FILE "/etc/utmp"
204 #endif
205 #endif
206 #endif
207
208 #ifndef _PATH_LOGCONF 
209 #define _PATH_LOGCONF   "/etc/rsyslog.conf"
210 #endif
211
212 #ifndef _PATH_MODDIR
213 #define _PATH_MODDIR    "/lib/rsyslog/"
214 #endif
215
216 #if defined(SYSLOGD_PIDNAME)
217 #       undef _PATH_LOGPID
218 #       if defined(FSSTND)
219 #               ifdef BSD
220 #                       define _PATH_VARRUN "/var/run/"
221 #               endif
222 #               if defined(__sun) || defined(__hpux)
223 #                       define _PATH_VARRUN "/var/run/"
224 #               endif
225 #               define _PATH_LOGPID _PATH_VARRUN SYSLOGD_PIDNAME
226 #       else
227 #               define _PATH_LOGPID "/etc/" SYSLOGD_PIDNAME
228 #       endif
229 #else
230 #       ifndef _PATH_LOGPID
231 #               if defined(__sun) || defined(__hpux)
232 #                       define _PATH_VARRUN "/var/run/"
233 #               endif
234 #               if defined(FSSTND)
235 #                       define _PATH_LOGPID _PATH_VARRUN "rsyslogd.pid"
236 #               else
237 #                       define _PATH_LOGPID "/etc/rsyslogd.pid"
238 #               endif
239 #       endif
240 #endif
241
242 #ifndef _PATH_DEV
243 #       define _PATH_DEV        "/dev/"
244 #endif
245
246 #ifndef _PATH_CONSOLE
247 #define _PATH_CONSOLE   "/dev/console"
248 #endif
249
250 #ifndef _PATH_TTY
251 #define _PATH_TTY       "/dev/tty"
252 #endif
253
254 static uchar    *ConfFile = (uchar*) _PATH_LOGCONF; /* read-only after startup */
255 static char     *PidFile = _PATH_LOGPID; /* read-only after startup */
256 char    ctty[] = _PATH_CONSOLE; /* this is read-only; used by omfile -- TODO: remove that dependency */
257
258 static pid_t myPid;     /* our pid for use in self-generated messages, e.g. on startup */
259 /* mypid is read-only after the initial fork() */
260 static int restart = 0; /* do restart (config read) - multithread safe */
261
262 int glblHadMemShortage = 0; /* indicates if we had memory shortage some time during the run */
263
264
265 static int bParseHOSTNAMEandTAG = 1; /* global config var: should the hostname and tag be
266                                       * parsed inside message - rgerhards, 2006-03-13 */
267 static int bFinished = 0;       /* used by termination signal handler, read-only except there
268                                  * is either 0 or the number of the signal that requested the
269                                  * termination.
270                                  */
271
272 /* Intervals at which we flush out "message repeated" messages,
273  * in seconds after previous message is logged.  After each flush,
274  * we move to the next interval until we reach the largest.
275  * TODO: this shall go into action object! -- rgerhards, 2008-01-29
276  */
277 int     repeatinterval[2] = { 30, 60 }; /* # of secs before flush */
278
279 #define LIST_DELIMITER  ':'             /* delimiter between two hosts */
280
281 struct  filed *Files = NULL; /* read-only after init() (but beware of sigusr1!) */
282
283 static pid_t ppid; /* This is a quick and dirty hack used for spliting main/startup thread */
284
285 typedef struct legacyOptsLL_s {
286         uchar *line;
287         struct legacyOptsLL_s *next;
288 } legacyOptsLL_t;
289 legacyOptsLL_t *pLegacyOptsLL = NULL;
290
291 /* global variables for config file state */
292 static int      bDropTrailingLF = 1; /* drop trailing LF's on reception? */
293 int     iCompatibilityMode = 0;         /* version we should be compatible with; 0 means sysklogd. It is
294                                            the default, so if no -c<n> option is given, we make ourselvs
295                                            as compatible to sysklogd as possible. */
296 static int      bDebugPrintTemplateList = 1;/* output template list in debug mode? */
297 static int      bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list in debug mode? */
298 static int      bDebugPrintModuleList = 1;/* output module list in debug mode? */
299 int     bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records during DNS lookup */
300 static uchar    cCCEscapeChar = '\\';/* character to be used to start an escape sequence for control chars */
301 static int      bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */
302 int     bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */
303 int     bActExecWhenPrevSusp; /* execute action only when previous one was suspended? */
304 uchar *pszWorkDir = NULL;/* name of rsyslog's spool directory (without trailing slash) */
305 /* end global config file state variables */
306
307 char    LocalHostName[MAXHOSTNAMELEN+1];/* our hostname  - read-only after startup */
308 char    *LocalDomain;   /* our local domain name  - read-only after startup */
309 int     MarkInterval = 20 * 60; /* interval between marks in seconds - read-only after startup */
310 int      family = PF_UNSPEC;     /* protocol family (IPv4, IPv6 or both), set via cmdline */
311 int      send_to_all = 0;        /* send message to all IPv4/IPv6 addresses */
312 static int      NoFork = 0;     /* don't fork - don't run in daemon mode - read-only after startup */
313 int     DisableDNS = 0; /* don't look up IP addresses of remote messages */
314 char    **StripDomains = NULL;/* these domains may be stripped before writing logs  - r/o after s.u., never touched by init */
315 char    **LocalHosts = NULL;/* these hosts are logged with their hostname  - read-only after startup, never touched by init */
316 static int      bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode - is available
317                                  * If the main queue is either not yet ready or not running in 
318                                  * queueing mode (mode DIRECT!), then this is set to 0.
319                                  */
320
321 extern  int errno;
322
323 /* main message queue and its configuration parameters */
324 static queue_t *pMsgQueue = NULL;                               /* the main message queue */
325 static int iMainMsgQueueSize = 10000;                           /* size of the main message queue above */
326 static int iMainMsgQHighWtrMark = 8000;                         /* high water mark for disk-assisted queues */
327 static int iMainMsgQLowWtrMark = 2000;                          /* low water mark for disk-assisted queues */
328 static int iMainMsgQDiscardMark = 9800;                         /* begin to discard messages */
329 static int iMainMsgQDiscardSeverity = 8;                        /* by default, discard nothing to prevent unintentional loss */
330 static int iMainMsgQueueNumWorkers = 1;                         /* number of worker threads for the mm queue above */
331 static queueType_t MainMsgQueType = QUEUETYPE_FIXED_ARRAY;      /* type of the main message queue above */
332 static uchar *pszMainMsgQFName = NULL;                          /* prefix for the main message queue file */
333 static int64 iMainMsgQueMaxFileSize = 1024*1024;
334 static int iMainMsgQPersistUpdCnt = 0;                          /* persist queue info every n updates */
335 static int iMainMsgQtoQShutdown = 0;                            /* queue shutdown */ 
336 static int iMainMsgQtoActShutdown = 1000;                       /* action shutdown (in phase 2) */ 
337 static int iMainMsgQtoEnq = 2000;                               /* timeout for queue enque */ 
338 static int iMainMsgQtoWrkShutdown = 60000;                      /* timeout for worker thread shutdown */
339 static int iMainMsgQWrkMinMsgs = 100;                           /* minimum messages per worker needed to start a new one */
340 static int iMainMsgQDeqSlowdown = 0;                            /* dequeue slowdown (simple rate limiting) */
341 static int bMainMsgQSaveOnShutdown = 1;                         /* save queue on shutdown (when DA enabled)? */
342 static int64 iMainMsgQueMaxDiskSpace = 0;                       /* max disk space allocated 0 ==> unlimited */
343
344
345 /* support for simple textual representation of FIOP names
346  * rgerhards, 2005-09-27
347  */
348 static char* getFIOPName(unsigned iFIOP)
349 {
350         char *pRet;
351         switch(iFIOP) {
352                 case FIOP_CONTAINS:
353                         pRet = "contains";
354                         break;
355                 case FIOP_ISEQUAL:
356                         pRet = "isequal";
357                         break;
358                 case FIOP_STARTSWITH:
359                         pRet = "startswith";
360                         break;
361                 case FIOP_REGEX:
362                         pRet = "regex";
363                         break;
364                 default:
365                         pRet = "NOP";
366                         break;
367         }
368         return pRet;
369 }
370
371
372 /* Reset config variables to default values.
373  * rgerhards, 2007-07-17
374  */
375 static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
376 {
377         cCCEscapeChar = '#';
378         bActExecWhenPrevSusp = 0;
379         bDebugPrintTemplateList = 1;
380         bDebugPrintCfSysLineHandlerList = 1;
381         bDebugPrintModuleList = 1;
382         bEscapeCCOnRcv = 1; /* default is to escape control characters */
383         bReduceRepeatMsgs = 0;
384         bDropMalPTRMsgs = 0;
385         if(pszWorkDir != NULL) {
386                 free(pszWorkDir);
387                 pszWorkDir = NULL;
388         }
389         if(pszMainMsgQFName != NULL) {
390                 free(pszMainMsgQFName);
391                 pszMainMsgQFName = NULL;
392         }
393         iMainMsgQueueSize = 10000;
394         iMainMsgQHighWtrMark = 8000;
395         iMainMsgQLowWtrMark = 2000;
396         iMainMsgQDiscardMark = 9800;
397         iMainMsgQDiscardSeverity = 4;
398         iMainMsgQueMaxFileSize = 1024 * 1024;
399         iMainMsgQueueNumWorkers = 1;
400         iMainMsgQPersistUpdCnt = 0;
401         iMainMsgQtoQShutdown = 0;
402         iMainMsgQtoActShutdown = 1000;
403         iMainMsgQtoEnq = 2000;
404         iMainMsgQtoWrkShutdown = 60000;
405         iMainMsgQWrkMinMsgs = 100;
406         iMainMsgQDeqSlowdown = 0;
407         bMainMsgQSaveOnShutdown = 1;
408         MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
409         iMainMsgQueMaxDiskSpace = 0;
410         glbliActionResumeRetryCount = 0;
411
412         return RS_RET_OK;
413 }
414
415
416
417 int option_DisallowWarning = 1; /* complain if message from disallowed sender is received */
418
419
420 /* hardcoded standard templates (used for defaults) */
421 static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\"";
422 static uchar template_TraditionalFileFormat[] = "\"%TIMESTAMP% %HOSTNAME% %syslogtag%%msg:::drop-last-lf%\n\"";
423 static uchar template_FileFormat[] = "\"%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::drop-last-lf%\n\"";
424 static uchar template_WallFmt[] = "\"\r\n\7Message from syslogd@%HOSTNAME% at %timegenerated% ...\r\n %syslogtag%%msg%\n\r\"";
425 static uchar template_ForwardFormat[] = "\"<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag:1:32%%msg%\"";
426 static uchar template_TraditionalForwardFormat[] = "\"<%PRI%>%TIMESTAMP% %HOSTNAME% %syslogtag:1:32%%msg%\"";
427 static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\"";
428 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";
429 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";
430 /* end template */
431
432
433 /* up to the next comment, prototypes that should be removed by reordering */
434 /* Function prototypes. */
435 static char **crunch_list(char *list);
436 static void reapchild();
437 static void debug_switch();
438 static void sighup_handler();
439 static void freeSelectors(void);
440 static void processImInternal(void);
441
442
443 static int usage(void)
444 {
445         fprintf(stderr, "usage: rsyslogd [-cversion] [-46AdnqQvwx] [-lhostlist] [-sdomainlist]\n"
446                         "                [-fconffile] [-ipidfile]\n"
447                         "To run rsyslogd in native mode, use \"rsyslogd -c3 <other options>\"\n\n"
448                         "For further information see http://www.rsyslog.com/doc\n");
449         exit(1); /* "good" exit - done to terminate usage() */
450 }
451
452
453 /* function to destruct a selector_t object
454  * rgerhards, 2007-08-01
455  */
456 rsRetVal
457 selectorDestruct(void *pVal)
458 {
459         selector_t *pThis = (selector_t *) pVal;
460
461         assert(pThis != NULL);
462
463         if(pThis->pCSHostnameComp != NULL)
464                 rsCStrDestruct(&pThis->pCSHostnameComp);
465         if(pThis->pCSProgNameComp != NULL)
466                 rsCStrDestruct(&pThis->pCSProgNameComp);
467
468         if(pThis->f_filter_type == FILTER_PROP) {
469                 if(pThis->f_filterData.prop.pCSPropName != NULL)
470                         rsCStrDestruct(&pThis->f_filterData.prop.pCSPropName);
471                 if(pThis->f_filterData.prop.pCSCompValue != NULL)
472                         rsCStrDestruct(&pThis->f_filterData.prop.pCSCompValue);
473         } else if(pThis->f_filter_type == FILTER_EXPR) {
474                 if(pThis->f_filterData.f_expr != NULL)
475                         expr.Destruct(&pThis->f_filterData.f_expr);
476         }
477
478         llDestroy(&pThis->llActList);
479         free(pThis);
480         
481         return RS_RET_OK;
482 }
483
484
485 /* function to construct a selector_t object
486  * rgerhards, 2007-08-01
487  */
488 rsRetVal
489 selectorConstruct(selector_t **ppThis)
490 {
491         DEFiRet;
492         selector_t *pThis;
493
494         assert(ppThis != NULL);
495         
496         if((pThis = (selector_t*) calloc(1, sizeof(selector_t))) == NULL) {
497                 glblHadMemShortage = 1;
498                 ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
499         }
500         CHKiRet(llInit(&pThis->llActList, actionDestruct, NULL, NULL));
501
502 finalize_it:
503         if(iRet != RS_RET_OK) {
504                 if(pThis != NULL) {
505                         selectorDestruct(pThis);
506                 }
507         }
508         *ppThis = pThis;
509         RETiRet;
510 }
511
512
513 /* rgerhards, 2005-10-24: crunch_list is called only during option processing. So
514  * it is never called once rsyslogd is running (not even when HUPed). This code
515  * contains some exits, but they are considered safe because they only happen
516  * during startup. Anyhow, when we review the code here, we might want to
517  * reconsider the exit()s.
518  */
519 static char **crunch_list(char *list)
520 {
521         int count, i;
522         char *p, *q;
523         char **result = NULL;
524
525         p = list;
526         
527         /* strip off trailing delimiters */
528         while (p[strlen(p)-1] == LIST_DELIMITER) {
529                 count--;
530                 p[strlen(p)-1] = '\0';
531         }
532         /* cut off leading delimiters */
533         while (p[0] == LIST_DELIMITER) {
534                 count--;
535                 p++; 
536         }
537         
538         /* count delimiters to calculate elements */
539         for (count=i=0; p[i]; i++)
540                 if (p[i] == LIST_DELIMITER) count++;
541         
542         if ((result = (char **)malloc(sizeof(char *) * (count+2))) == NULL) {
543                 printf ("Sorry, can't get enough memory, exiting.\n");
544                 exit(0); /* safe exit, because only called during startup */
545         }
546         
547         /*
548          * We now can assume that the first and last
549          * characters are different from any delimiters,
550          * so we don't have to care about this.
551          */
552         count = 0;
553         while ((q=strchr(p, LIST_DELIMITER))) {
554                 result[count] = (char *) malloc((q - p + 1) * sizeof(char));
555                 if (result[count] == NULL) {
556                         printf ("Sorry, can't get enough memory, exiting.\n");
557                         exit(0); /* safe exit, because only called during startup */
558                 }
559                 strncpy(result[count], p, q - p);
560                 result[count][q - p] = '\0';
561                 p = q; p++;
562                 count++;
563         }
564         if ((result[count] = \
565              (char *)malloc(sizeof(char) * strlen(p) + 1)) == NULL) {
566                 printf ("Sorry, can't get enough memory, exiting.\n");
567                 exit(0); /* safe exit, because only called during startup */
568         }
569         strcpy(result[count],p);
570         result[++count] = NULL;
571
572 #if 0
573         count=0;
574         while (result[count])
575                 dbgprintf("#%d: %s\n", count, StripDomains[count++]);
576 #endif
577         return result;
578 }
579
580
581 void untty(void)
582 #ifdef HAVE_SETSID
583 {
584         if ( !Debug ) {
585                 setsid();
586         }
587         return;
588 }
589 #else
590 {
591         int i;
592
593         if ( !Debug ) {
594                 i = open(_PATH_TTY, O_RDWR);
595                 if (i >= 0) {
596 #                       if !defined(__hpux)
597                                 (void) ioctl(i, (int) TIOCNOTTY, (char *)0);
598 #                       else
599                                 /* TODO: we need to implement something for HP UX! -- rgerhards, 2008-03-04 */
600                                 /* actually, HP UX should have setsid, so the code directly above should
601                                  * trigger. So the actual question is why it doesn't do that...
602                                  */
603 #                       endif
604                         (void) close(i);
605                 }
606         }
607 }
608 #endif
609
610
611 /* Take a raw input line, decode the message, and print the message
612  * on the appropriate log files.
613  * rgerhards 2004-11-08: Please note
614  * that this function does only a partial decoding. At best, it splits 
615  * the PRI part. No further decode happens. The rest is done in 
616  * logmsg().
617  * Added the iSource parameter so that we know if we have to parse
618  * HOSTNAME or not. rgerhards 2004-11-16.
619  * changed parameter iSource to bParseHost. For details, see comment in
620  * printchopped(). rgerhards 2005-10-06
621  * rgerhards: 2008-03-06: added "flags" to allow an input module to specify
622  * flags, most importantly to request ignoring the messages' timestamp.
623  *
624  * rgerhards, 2008-03-19:
625  * I added an additional calling parameter to permit specifying the flow
626  * control capability of the source.
627  */
628 rsRetVal printline(char *hname, char *msg, int bParseHost, int flags, flowControl_t flowCtlType)
629 {
630         DEFiRet;
631         register char *p;
632         int pri;
633         msg_t *pMsg;
634
635         /* Now it is time to create the message object (rgerhards)
636         */
637         CHKiRet(msgConstruct(&pMsg));
638         MsgSetFlowControlType(pMsg, flowCtlType);
639         MsgSetRawMsg(pMsg, msg);
640         
641         pMsg->bParseHOSTNAME  = bParseHost;
642         /* test for special codes */
643         pri = DEFUPRI;
644         p = msg;
645         if (*p == '<') {
646                 pri = 0;
647                 while (isdigit((int) *++p))
648                 {
649                    pri = 10 * pri + (*p - '0');
650                 }
651                 if (*p == '>')
652                         ++p;
653         }
654         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
655                 pri = DEFUPRI;
656         pMsg->iFacility = LOG_FAC(pri);
657         pMsg->iSeverity = LOG_PRI(pri);
658
659         /* Now we look at the HOSTNAME. That is a bit complicated...
660          * If we have a locally received message, it does NOT
661          * contain any hostname information in the message itself.
662          * As such, the HOSTNAME is the same as the system that
663          * the message was received from (that, for obvious reasons,
664          * being the local host).  rgerhards 2004-11-16
665          */
666         if(bParseHost == 0)
667                 MsgSetHOSTNAME(pMsg, hname);
668         MsgSetRcvFrom(pMsg, hname);
669
670         /* rgerhards 2004-11-19: well, well... we've now seen that we
671          * have the "hostname problem" also with the traditional Unix
672          * message. As we like to emulate it, we need to add the hostname
673          * to it.
674          */
675         if(MsgSetUxTradMsg(pMsg, p) != 0)
676                 ABORT_FINALIZE(RS_RET_ERR);
677
678         logmsg(pMsg, flags | SYNC_FILE);
679
680 finalize_it:
681         RETiRet;
682 }
683
684
685 /* This takes a received message that must be decoded and submits it to
686  * the main message queue. The function calls the necessary parser.
687  *
688  * rgerhards, 2006-11-30: I have greatly changed this function. Formerly,
689  * it tried to reassemble multi-part messages, which is a legacy stock
690  * sysklogd concept. In essence, that was that messages not ending with
691  * \0 were glued together. As far as I can see, this is a sysklogd
692  * specific feature and, from looking at the code, seems to be used
693  * pretty seldom (if at all). I remove this now, not the least because it is totally
694  * incompatible with upcoming IETF syslog standards. If you experience
695  * strange behaviour with messages beeing split across multiple lines,
696  * this function here might be the place to look at.
697  *
698  * Some previous history worth noting:
699  * I added the "iSource" parameter. This is needed to distinguish between
700  * messages that have a hostname in them (received from the internet) and
701  * those that do not have (most prominently /dev/log).  rgerhards 2004-11-16
702  * And now I removed the "iSource" parameter and changed it to be "bParseHost",
703  * because all that it actually controls is whether the host is parsed or not.
704  * For rfc3195 support, we needed to modify the algo for host parsing, so we can
705  * no longer rely just on the source (rfc3195d forwarded messages arrive via
706  * unix domain sockets but contain the hostname). rgerhards, 2005-10-06
707  *
708  * rgerhards, 2008-02-18:
709  * This function was previously called "printchopped"() and has been renamed
710  * as part of the effort to create a clean internal message submission interface.
711  * It also has been adopted to our usual calling interface, but currently does
712  * not provide any useful return states. But we now have the hook and things can
713  * improve in the future. <-- TODO!
714  *
715  * rgerhards, 2008-03-19:
716  * I added an additional calling parameter to permit specifying the flow
717  * control capability of the source.
718  */
719 rsRetVal
720 parseAndSubmitMessage(char *hname, char *msg, int len, int bParseHost, int flags, flowControl_t flowCtlType)
721 {
722         DEFiRet;
723         register int iMsg;
724         char *pMsg;
725         char *pData;
726         char *pEnd;
727         char tmpline[MAXLINE + 1];
728 #       ifdef USE_NETZIP
729         char deflateBuf[MAXLINE + 1];
730         uLongf iLenDefBuf;
731 #       endif
732
733         assert(hname != NULL);
734         assert(msg != NULL);
735         assert(len >= 0);
736
737         /* we first check if we have a NUL character at the very end of the
738          * message. This seems to be a frequent problem with a number of senders.
739          * So I have now decided to drop these NULs. However, if they are intentional,
740          * that may cause us some problems, e.g. with syslog-sign. On the other hand,
741          * current code always has problems with intentional NULs (as it needs to escape
742          * them to prevent problems with the C string libraries), so that does not
743          * really matter. Just to be on the save side, we'll log destruction of such
744          * NULs in the debug log.
745          * rgerhards, 2007-09-14
746          */
747         if(*(msg + len - 1) == '\0') {
748                 dbgprintf("dropped NUL at very end of message\n");
749                 len--;
750         }
751
752         /* then we check if we need to drop trailing LFs, which often make
753          * their way into syslog messages unintentionally. In order to remain
754          * compatible to recent IETF developments, we allow the user to
755          * turn on/off this handling.  rgerhards, 2007-07-23
756          */
757         if(bDropTrailingLF && *(msg + len - 1) == '\n') {
758                 dbgprintf("dropped LF at very end of message (DropTrailingLF is set)\n");
759                 len--;
760         }
761
762         iMsg = 0;       /* initialize receiving buffer index */
763         pMsg = tmpline; /* set receiving buffer pointer */
764         pData = msg;    /* set source buffer pointer */
765         pEnd = msg + len; /* this is one off, which is intensional */
766
767 #       ifdef USE_NETZIP
768         /* we first need to check if we have a compressed record. If so,
769          * we must decompress it.
770          */
771         if(len > 0 && *msg == 'z') { /* compressed data present? (do NOT change order if conditions!) */
772                 /* we have compressed data, so let's deflate it. We support a maximum
773                  * message size of MAXLINE. If it is larger, an error message is logged
774                  * and the message is dropped. We do NOT try to decompress larger messages
775                  * as such might be used for denial of service. It might happen to later
776                  * builds that such functionality be added as an optional, operator-configurable
777                  * feature.
778                  */
779                 int ret;
780                 iLenDefBuf = MAXLINE;
781                 ret = uncompress((uchar *) deflateBuf, &iLenDefBuf, (uchar *) msg+1, len-1);
782                 dbgprintf("Compressed message uncompressed with status %d, length: new %ld, old %d.\n",
783                         ret, (long) iLenDefBuf, len-1);
784                 /* Now check if the uncompression worked. If not, there is not much we can do. In
785                  * that case, we log an error message but ignore the message itself. Storing the
786                  * compressed text is dangerous, as it contains control characters. So we do
787                  * not do this. If someone would like to have a copy, this code here could be
788                  * modified to do a hex-dump of the buffer in question. We do not include
789                  * this functionality right now.
790                  * rgerhards, 2006-12-07
791                  */
792                 if(ret != Z_OK) {
793                         errmsg.LogError(NO_ERRCODE, "Uncompression of a message failed with return code %d "
794                                     "- enable debug logging if you need further information. "
795                                     "Message ignored.", ret);
796                         FINALIZE; /* unconditional exit, nothing left to do... */
797                 }
798                 pData = deflateBuf;
799                 pEnd = deflateBuf + iLenDefBuf;
800         }
801 #       else /* ifdef USE_NETZIP */
802         /* in this case, we still need to check if the message is compressed. If so, we must
803          * tell the user we can not accept it.
804          */
805         if(len > 0 && *msg == 'z') {
806                 errmsg.LogError(NO_ERRCODE, "Received a compressed message, but rsyslogd does not have compression "
807                          "support enabled. The message will be ignored.");
808                 FINALIZE;
809         }       
810 #       endif /* ifdef USE_NETZIP */
811
812         while(pData < pEnd) {
813                 if(iMsg >= MAXLINE) {
814                         /* emergency, we now need to flush, no matter if
815                          * we are at end of message or not...
816                          */
817                         if(iMsg == MAXLINE) {
818                                 *(pMsg + iMsg) = '\0'; /* space *is* reserved for this! */
819                                 printline(hname, tmpline, bParseHost, flags, flowCtlType);
820                         } else {
821                                 /* This case in theory never can happen. If it happens, we have
822                                  * a logic error. I am checking for it, because if I would not,
823                                  * we would address memory invalidly with the code above. I
824                                  * do not care much about this case, just a debug log entry
825                                  * (I couldn't do any more smart things anyway...).
826                                  * rgerhards, 2007-9-20
827                                  */
828                                 dbgprintf("internal error: iMsg > MAXLINE in printchopped()\n");
829                         }
830                         FINALIZE; /* in this case, we are done... nothing left we can do */
831                 }
832                 if(*pData == '\0') { /* guard against \0 characters... */
833                         /* changed to the sequence (somewhat) proposed in
834                          * draft-ietf-syslog-protocol-19. rgerhards, 2006-11-30
835                          */
836                         if(iMsg + 3 < MAXLINE) { /* do we have space? */
837                                 *(pMsg + iMsg++) =  cCCEscapeChar;
838                                 *(pMsg + iMsg++) = '0';
839                                 *(pMsg + iMsg++) = '0';
840                                 *(pMsg + iMsg++) = '0';
841                         } /* if we do not have space, we simply ignore the '\0'... */
842                           /* log an error? Very questionable... rgerhards, 2006-11-30 */
843                           /* decided: we do not log an error, it won't help... rger, 2007-06-21 */
844                         ++pData;
845                 } else if(bEscapeCCOnRcv && iscntrl((int) *pData)) {
846                         /* we are configured to escape control characters. Please note
847                          * that this most probably break non-western character sets like
848                          * Japanese, Korean or Chinese. rgerhards, 2007-07-17
849                          * Note: sysklogd logs octal values only for DEL and CCs above 127.
850                          * For others, it logs ^n where n is the control char converted to an
851                          * alphabet character. We like consistency and thus escape it to octal
852                          * in all cases. If someone complains, we may change the mode. At least
853                          * we known now what's going on.
854                          * rgerhards, 2007-07-17
855                          */
856                         if(iMsg + 3 < MAXLINE) { /* do we have space? */
857                                 *(pMsg + iMsg++) = cCCEscapeChar;
858                                 *(pMsg + iMsg++) = '0' + ((*pData & 0300) >> 6);
859                                 *(pMsg + iMsg++) = '0' + ((*pData & 0070) >> 3);
860                                 *(pMsg + iMsg++) = '0' + ((*pData & 0007));
861                         } /* again, if we do not have space, we ignore the char - see comment at '\0' */
862                         ++pData;
863                 } else {
864                         *(pMsg + iMsg++) = *pData++;
865                 }
866         }
867
868         *(pMsg + iMsg) = '\0'; /* space *is* reserved for this! */
869
870         /* typically, we should end up here! */
871         printline(hname, tmpline, bParseHost, flags, flowCtlType);
872
873 finalize_it:
874         RETiRet;
875 }
876
877 /* rgerhards 2004-11-09: the following is a function that can be used
878  * to log a message orginating from the syslogd itself. In sysklogd code,
879  * this is done by simply calling logmsg(). However, logmsg() is changed in
880  * rsyslog so that it takes a msg "object". So it can no longer be called
881  * directly. This method here solves the need. It provides an interface that
882  * allows to construct a locally-generated message. Please note that this
883  * function here probably is only an interim solution and that we need to
884  * think on the best way to do this.
885  */
886 rsRetVal
887 logmsgInternal(int pri, char *msg, int flags)
888 {
889         DEFiRet;
890         msg_t *pMsg;
891
892         CHKiRet(msgConstruct(&pMsg));
893         MsgSetUxTradMsg(pMsg, msg);
894         MsgSetRawMsg(pMsg, msg);
895         MsgSetHOSTNAME(pMsg, LocalHostName);
896         MsgSetRcvFrom(pMsg, LocalHostName);
897         MsgSetTAG(pMsg, "rsyslogd:");
898         pMsg->iFacility = LOG_FAC(pri);
899         pMsg->iSeverity = LOG_PRI(pri);
900         pMsg->bParseHOSTNAME = 0;
901         datetime.getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */
902         flags |= INTERNAL_MSG;
903
904         if(bHaveMainQueue == 0) { /* not yet in queued mode */
905                 iminternalAddMsg(pri, pMsg, flags);
906         } else {
907                 /* we have the queue, so we can simply provide the 
908                  * message to the queue engine.
909                  */
910                 logmsg(pMsg, flags);
911         }
912 finalize_it:
913         RETiRet;
914 }
915
916 /* This functions looks at the given message and checks if it matches the
917  * provided filter condition. If so, it returns true, else it returns
918  * false. This is a helper to logmsg() and meant to drive the decision
919  * process if a message is to be processed or not. As I expect this
920  * decision code to grow more complex over time AND logmsg() is already
921  * a very lengthy function, I thought a separate function is more appropriate.
922  * 2005-09-19 rgerhards
923  * 2008-02-25 rgerhards: changed interface, now utilizes iRet, bProcessMsg
924  * returns is message should be procesed.
925  */
926 static rsRetVal shouldProcessThisMessage(selector_t *f, msg_t *pMsg, int *bProcessMsg)
927 {
928         DEFiRet;
929         unsigned short pbMustBeFreed;
930         char *pszPropVal;
931         int bRet = 0;
932         vm_t *pVM = NULL;
933         var_t *pResult = NULL;
934
935         assert(f != NULL);
936         assert(pMsg != NULL);
937
938         /* we first have a look at the global, BSD-style block filters (for tag
939          * and host). Only if they match, we evaluate the actual filter.
940          * rgerhards, 2005-10-18
941          */
942         if(f->eHostnameCmpMode == HN_NO_COMP) {
943                 /* EMPTY BY INTENSION - we check this value first, because
944                  * it is the one most often used, so this saves us time!
945                  */
946         } else if(f->eHostnameCmpMode == HN_COMP_MATCH) {
947                 if(rsCStrSzStrCmp(f->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) {
948                         /* not equal, so we are already done... */
949                         dbgprintf("hostname filter '+%s' does not match '%s'\n", 
950                                 rsCStrGetSzStrNoNULL(f->pCSHostnameComp), getHOSTNAME(pMsg));
951                         FINALIZE;
952                 }
953         } else { /* must be -hostname */
954                 if(!rsCStrSzStrCmp(f->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) {
955                         /* not equal, so we are already done... */
956                         dbgprintf("hostname filter '-%s' does not match '%s'\n", 
957                                 rsCStrGetSzStrNoNULL(f->pCSHostnameComp), getHOSTNAME(pMsg));
958                         FINALIZE;
959                 }
960         }
961         
962         if(f->pCSProgNameComp != NULL) {
963                 int bInv = 0, bEqv = 0, offset = 0;
964                 if(*(rsCStrGetSzStrNoNULL(f->pCSProgNameComp)) == '-') {
965                         if(*(rsCStrGetSzStrNoNULL(f->pCSProgNameComp) + 1) == '-')
966                                 offset = 1;
967                         else {
968                                 bInv = 1;
969                                 offset = 1;
970                         }
971                 }
972                 if(!rsCStrOffsetSzStrCmp(f->pCSProgNameComp, offset, (uchar*) getProgramName(pMsg), getProgramNameLen(pMsg)))
973                         bEqv = 1;
974
975                 if((!bEqv && !bInv) || (bEqv && bInv)) {
976                         /* not equal or inverted selection, so we are already done... */
977                         dbgprintf("programname filter '%s' does not match '%s'\n", 
978                                 rsCStrGetSzStrNoNULL(f->pCSProgNameComp), getProgramName(pMsg));
979                         FINALIZE;
980                 }
981         }
982         
983         /* done with the BSD-style block filters */
984
985         if(f->f_filter_type == FILTER_PRI) {
986                 /* skip messages that are incorrect priority */
987                 if ( (f->f_filterData.f_pmask[pMsg->iFacility] == TABLE_NOPRI) || \
988                     ((f->f_filterData.f_pmask[pMsg->iFacility] & (1<<pMsg->iSeverity)) == 0) )
989                         bRet = 0;
990                 else
991                         bRet = 1;
992         } else if(f->f_filter_type == FILTER_EXPR) {
993                 CHKiRet(vm.Construct(&pVM));
994                 CHKiRet(vm.ConstructFinalize(pVM));
995                 CHKiRet(vm.SetMsg(pVM, pMsg));
996                 CHKiRet(vm.ExecProg(pVM, f->f_filterData.f_expr->pVmprg));
997                 CHKiRet(vm.PopBoolFromStack(pVM, &pResult));
998                 dbgprintf("result of expression evaluation: %lld\n", pResult->val.num);
999                 /* VM is destructed on function exit */
1000                 bRet = (pResult->val.num) ? 1 : 0;
1001         } else {
1002                 assert(f->f_filter_type == FILTER_PROP); /* assert() just in case... */
1003                 pszPropVal = MsgGetProp(pMsg, NULL, f->f_filterData.prop.pCSPropName, &pbMustBeFreed);
1004
1005                 /* Now do the compares (short list currently ;)) */
1006                 switch(f->f_filterData.prop.operation ) {
1007                 case FIOP_CONTAINS:
1008                         if(rsCStrLocateInSzStr(f->f_filterData.prop.pCSCompValue, (uchar*) pszPropVal) != -1)
1009                                 bRet = 1;
1010                         break;
1011                 case FIOP_ISEQUAL:
1012                         if(rsCStrSzStrCmp(f->f_filterData.prop.pCSCompValue,
1013                                           (uchar*) pszPropVal, strlen(pszPropVal)) == 0)
1014                                 bRet = 1; /* process message! */
1015                         break;
1016                 case FIOP_STARTSWITH:
1017                         if(rsCStrSzStrStartsWithCStr(f->f_filterData.prop.pCSCompValue,
1018                                           (uchar*) pszPropVal, strlen(pszPropVal)) == 0)
1019                                 bRet = 1; /* process message! */
1020                         break;
1021                 case FIOP_REGEX:
1022                         if(rsCStrSzStrMatchRegex(f->f_filterData.prop.pCSCompValue,
1023                                           (unsigned char*) pszPropVal) == 0)
1024                                 bRet = 1;
1025                         break;
1026                 default:
1027                         /* here, it handles NOP (for performance reasons) */
1028                         assert(f->f_filterData.prop.operation == FIOP_NOP);
1029                         bRet = 1; /* as good as any other default ;) */
1030                         break;
1031                 }
1032
1033                 /* now check if the value must be negated */
1034                 if(f->f_filterData.prop.isNegated)
1035                         bRet = (bRet == 1) ?  0 : 1;
1036
1037                 if(Debug) {
1038                         dbgprintf("Filter: check for property '%s' (value '%s') ",
1039                                 rsCStrGetSzStrNoNULL(f->f_filterData.prop.pCSPropName),
1040                                 pszPropVal);
1041                         if(f->f_filterData.prop.isNegated)
1042                                 dbgprintf("NOT ");
1043                         dbgprintf("%s '%s': %s\n",
1044                                getFIOPName(f->f_filterData.prop.operation),
1045                                rsCStrGetSzStrNoNULL(f->f_filterData.prop.pCSCompValue),
1046                                bRet ? "TRUE" : "FALSE");
1047                 }
1048
1049                 /* cleanup */
1050                 if(pbMustBeFreed)
1051                         free(pszPropVal);
1052         }
1053
1054 finalize_it:
1055         /* destruct in any case, not just on error, but it makes error handling much easier */
1056         if(pVM != NULL)
1057                 vm.Destruct(&pVM);
1058
1059         if(pResult != NULL)
1060                 var.Destruct(&pResult);
1061
1062         *bProcessMsg = bRet;
1063         RETiRet;
1064 }
1065
1066
1067 /* helper to processMsg(), used to call the configured actions. It is
1068  * executed from within llExecFunc() of the action list.
1069  * rgerhards, 2007-08-02
1070  */
1071 typedef struct processMsgDoActions_s {
1072         int bPrevWasSuspended; /* was the previous action suspended? */
1073         msg_t *pMsg;
1074 } processMsgDoActions_t;
1075 DEFFUNC_llExecFunc(processMsgDoActions)
1076 {
1077         DEFiRet;
1078         rsRetVal iRetMod;       /* return value of module - we do not always pass that back */
1079         action_t *pAction = (action_t*) pData;
1080         processMsgDoActions_t *pDoActData = (processMsgDoActions_t*) pParam;
1081
1082         assert(pAction != NULL);
1083
1084         if((pAction->bExecWhenPrevSusp  == 1) && (pDoActData->bPrevWasSuspended == 0)) {
1085                 dbgprintf("not calling action because the previous one is not suspended\n");
1086                 ABORT_FINALIZE(RS_RET_OK);
1087         }
1088
1089         iRetMod = actionCallAction(pAction, pDoActData->pMsg);
1090         if(iRetMod == RS_RET_DISCARDMSG) {
1091                 ABORT_FINALIZE(RS_RET_DISCARDMSG);
1092         } else if(iRetMod == RS_RET_SUSPENDED) {
1093                 /* indicate suspension for next module to be called */
1094                 pDoActData->bPrevWasSuspended = 1;
1095         } else {
1096                 pDoActData->bPrevWasSuspended = 0;
1097         }
1098
1099 finalize_it:
1100         RETiRet;
1101 }
1102
1103
1104 /* Process (consume) a received message. Calls the actions configured.
1105  * rgerhards, 2005-10-13
1106  */
1107 static void
1108 processMsg(msg_t *pMsg)
1109 {
1110         selector_t *f;
1111         int bContinue;
1112         int bProcessMsg;
1113         processMsgDoActions_t DoActData;
1114         rsRetVal iRet;
1115
1116         BEGINfunc
1117         assert(pMsg != NULL);
1118
1119         /* log the message to the particular outputs */
1120
1121         bContinue = 1;
1122         for (f = Files; f != NULL && bContinue ; f = f->f_next) {
1123                 /* first check the filters... */
1124                 iRet = shouldProcessThisMessage(f, pMsg, &bProcessMsg);
1125                 if(!bProcessMsg) {
1126                         continue;
1127                 }
1128
1129                 /* ok -- from here, we have action-specific code, nothing really selector-specific -- rger 2007-08-01 */
1130                 DoActData.pMsg = pMsg;
1131                 DoActData.bPrevWasSuspended = 0;
1132                 if(llExecFunc(&f->llActList, processMsgDoActions, (void*)&DoActData) == RS_RET_DISCARDMSG)
1133                         bContinue = 0;
1134         }
1135         ENDfunc
1136 }
1137
1138
1139 /* The consumer of dequeued messages. This function is called by the
1140  * queue engine on dequeueing of a message. It runs on a SEPARATE
1141  * THREAD.
1142  * NOTE: Having more than one worker requires guarding of some
1143  * message object structures and potentially others - need to be checked
1144  * before we support multiple worker threads on the message queue.
1145  * Please note: the message object is destructed by the queue itself!
1146  */
1147 static rsRetVal
1148 msgConsumer(void __attribute__((unused)) *notNeeded, void *pUsr)
1149 {
1150         DEFiRet;
1151         msg_t *pMsg = (msg_t*) pUsr;
1152
1153         assert(pMsg != NULL);
1154
1155         processMsg(pMsg);
1156         msgDestruct(&pMsg);
1157
1158         RETiRet;
1159 }
1160
1161
1162 /* Helper to parseRFCSyslogMsg. This function parses a field up to
1163  * (and including) the SP character after it. The field contents is
1164  * returned in a caller-provided buffer. The parsepointer is advanced
1165  * to after the terminating SP. The caller must ensure that the 
1166  * provided buffer is large enough to hold the to be extracted value.
1167  * Returns 0 if everything is fine or 1 if either the field is not
1168  * SP-terminated or any other error occurs.
1169  * rger, 2005-11-24
1170  */
1171 static int parseRFCField(char **pp2parse, char *pResult)
1172 {
1173         char *p2parse;
1174         int iRet = 0;
1175
1176         assert(pp2parse != NULL);
1177         assert(*pp2parse != NULL);
1178         assert(pResult != NULL);
1179
1180         p2parse = *pp2parse;
1181
1182         /* this is the actual parsing loop */
1183         while(*p2parse && *p2parse != ' ') {
1184                 *pResult++ = *p2parse++;
1185         }
1186
1187         if(*p2parse == ' ')
1188                 ++p2parse; /* eat SP, but only if not at end of string */
1189         else
1190                 iRet = 1; /* there MUST be an SP! */
1191         *pResult = '\0';
1192
1193         /* set the new parse pointer */
1194         *pp2parse = p2parse;
1195         return 0;
1196 }
1197
1198
1199 /* Helper to parseRFCSyslogMsg. This function parses the structured
1200  * data field of a message. It does NOT parse inside structured data,
1201  * just gets the field as whole. Parsing the single entities is left
1202  * to other functions. The parsepointer is advanced
1203  * to after the terminating SP. The caller must ensure that the 
1204  * provided buffer is large enough to hold the to be extracted value.
1205  * Returns 0 if everything is fine or 1 if either the field is not
1206  * SP-terminated or any other error occurs.
1207  * rger, 2005-11-24
1208  */
1209 static int parseRFCStructuredData(char **pp2parse, char *pResult)
1210 {
1211         char *p2parse;
1212         int bCont = 1;
1213         int iRet = 0;
1214
1215         assert(pp2parse != NULL);
1216         assert(*pp2parse != NULL);
1217         assert(pResult != NULL);
1218
1219         p2parse = *pp2parse;
1220
1221         /* this is the actual parsing loop
1222          * Remeber: structured data starts with [ and includes any characters
1223          * until the first ] followed by a SP. There may be spaces inside
1224          * structured data. There may also be \] inside the structured data, which
1225          * do NOT terminate an element.
1226          */
1227         if(*p2parse != '[')
1228                 return 1; /* this is NOT structured data! */
1229
1230         while(bCont) {
1231                 if(*p2parse == '\0') {
1232                         iRet = 1; /* this is not valid! */
1233                         bCont = 0;
1234                 } else if(*p2parse == '\\' && *(p2parse+1) == ']') {
1235                         /* this is escaped, need to copy both */
1236                         *pResult++ = *p2parse++;
1237                         *pResult++ = *p2parse++;
1238                 } else if(*p2parse == ']' && *(p2parse+1) == ' ') {
1239                         /* found end, just need to copy the ] and eat the SP */
1240                         *pResult++ = *p2parse;
1241                         p2parse += 2;
1242                         bCont = 0;
1243                 } else {
1244                         *pResult++ = *p2parse++;
1245                 }
1246         }
1247
1248         if(*p2parse == ' ')
1249                 ++p2parse; /* eat SP, but only if not at end of string */
1250         else
1251                 iRet = 1; /* there MUST be an SP! */
1252         *pResult = '\0';
1253
1254         /* set the new parse pointer */
1255         *pp2parse = p2parse;
1256         return 0;
1257 }
1258
1259 /* parse a RFC-formatted syslog message. This function returns
1260  * 0 if processing of the message shall continue and 1 if something
1261  * went wrong and this messe should be ignored. This function has been
1262  * implemented in the effort to support syslog-protocol. Please note that
1263  * the name (parse *RFC*) stems from the hope that syslog-protocol will
1264  * some time become an RFC. Do not confuse this with informational
1265  * RFC 3164 (which is legacy syslog).
1266  *
1267  * currently supported format:
1268  *
1269  * <PRI>VERSION SP TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID SP [SD-ID]s SP MSG
1270  *
1271  * <PRI> is already stripped when this function is entered. VERSION already
1272  * has been confirmed to be "1", but has NOT been stripped from the message.
1273  *
1274  * rger, 2005-11-24
1275  */
1276 static int parseRFCSyslogMsg(msg_t *pMsg, int flags)
1277 {
1278         char *p2parse;
1279         char *pBuf;
1280         int bContParse = 1;
1281
1282         assert(pMsg != NULL);
1283         assert(pMsg->pszUxTradMsg != NULL);
1284         p2parse = (char*) pMsg->pszUxTradMsg;
1285
1286         /* do a sanity check on the version and eat it */
1287         assert(p2parse[0] == '1' && p2parse[1] == ' ');
1288         p2parse += 2;
1289
1290         /* Now get us some memory we can use as a work buffer while parsing.
1291          * We simply allocated a buffer sufficiently large to hold all of the
1292          * message, so we can not run into any troubles. I think this is
1293          * more wise then to use individual buffers.
1294          */
1295         if((pBuf = malloc(sizeof(char)* strlen(p2parse) + 1)) == NULL)
1296                 return 1;
1297                 
1298         /* IMPORTANT NOTE:
1299          * Validation is not actually done below nor are any errors handled. I have
1300          * NOT included this for the current proof of concept. However, it is strongly
1301          * advisable to add it when this code actually goes into production.
1302          * rgerhards, 2005-11-24
1303          */
1304
1305         /* TIMESTAMP */
1306         if(datetime.ParseTIMESTAMP3339(&(pMsg->tTIMESTAMP),  &p2parse) == FALSE) {
1307                 dbgprintf("no TIMESTAMP detected!\n");
1308                 bContParse = 0;
1309                 flags |= ADDDATE;
1310         }
1311
1312         if (flags & ADDDATE) {
1313                 datetime.getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */
1314         }
1315
1316         /* HOSTNAME */
1317         if(bContParse) {
1318                 parseRFCField(&p2parse, pBuf);
1319                 MsgSetHOSTNAME(pMsg, pBuf);
1320         } else {
1321                 /* we can not parse, so we get the system we
1322                  * received the data from.
1323                  */
1324                 MsgSetHOSTNAME(pMsg, getRcvFrom(pMsg));
1325         }
1326
1327         /* APP-NAME */
1328         if(bContParse) {
1329                 parseRFCField(&p2parse, pBuf);
1330                 MsgSetAPPNAME(pMsg, pBuf);
1331         }
1332
1333         /* PROCID */
1334         if(bContParse) {
1335                 parseRFCField(&p2parse, pBuf);
1336                 MsgSetPROCID(pMsg, pBuf);
1337         }
1338
1339         /* MSGID */
1340         if(bContParse) {
1341                 parseRFCField(&p2parse, pBuf);
1342                 MsgSetMSGID(pMsg, pBuf);
1343         }
1344
1345         /* STRUCTURED-DATA */
1346         if(bContParse) {
1347                 parseRFCStructuredData(&p2parse, pBuf);
1348                 MsgSetStructuredData(pMsg, pBuf);
1349         }
1350
1351         /* MSG */
1352         MsgSetMSG(pMsg, p2parse);
1353
1354         free(pBuf);
1355         return 0; /* all ok */
1356 }
1357
1358
1359 /* parse a legay-formatted syslog message. This function returns
1360  * 0 if processing of the message shall continue and 1 if something
1361  * went wrong and this messe should be ignored. This function has been
1362  * implemented in the effort to support syslog-protocol.
1363  * rger, 2005-11-24
1364  * As of 2006-01-10, I am removing the logic to continue parsing only
1365  * when a valid TIMESTAMP is detected. Validity of other fields already
1366  * is ignored. This is due to the fact that the parser has grown smarter
1367  * and is now more able to understand different dialects of the syslog
1368  * message format. I do not expect any bad side effects of this change,
1369  * but I thought I log it in this comment.
1370  * rgerhards, 2006-01-10
1371  */
1372 static int parseLegacySyslogMsg(msg_t *pMsg, int flags)
1373 {
1374         char *p2parse;
1375         char *pBuf;
1376         char *pWork;
1377         cstr_t *pStrB;
1378         int iCnt;
1379         int bTAGCharDetected;
1380
1381         assert(pMsg != NULL);
1382         assert(pMsg->pszUxTradMsg != NULL);
1383         p2parse = (char*) pMsg->pszUxTradMsg;
1384
1385         /* Check to see if msg contains a timestamp. We stary trying with a
1386          * high-precision one...
1387          */
1388         if(datetime.ParseTIMESTAMP3339(&(pMsg->tTIMESTAMP), &p2parse) == TRUE)
1389                 /* we are done - parse pointer is moved by ParseTIMESTAMP3339 */;
1390         else if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), p2parse) == TRUE)
1391                 p2parse += 16;
1392         else {
1393                 flags |= ADDDATE;
1394         }
1395
1396         /* here we need to check if the timestamp is valid. If it is not,
1397          * we can not continue to parse but must treat the rest as the 
1398          * MSG part of the message (as of RFC 3164).
1399          * rgerhards 2004-12-03
1400          */
1401         if(flags & ADDDATE) {
1402                 datetime.getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */
1403         }
1404
1405         /* rgerhards, 2006-03-13: next, we parse the hostname and tag. But we 
1406          * do this only when the user has not forbidden this. I now introduce some
1407          * code that allows a user to configure rsyslogd to treat the rest of the
1408          * message as MSG part completely. In this case, the hostname will be the
1409          * machine that we received the message from and the tag will be empty. This
1410          * is meant to be an interim solution, but for now it is in the code.
1411          */
1412         if(bParseHOSTNAMEandTAG && !(flags & INTERNAL_MSG)) {
1413                 /* parse HOSTNAME - but only if this is network-received!
1414                  * rger, 2005-11-14: we still have a problem with BSD messages. These messages
1415                  * do NOT include a host name. In most cases, this leads to the TAG to be treated
1416                  * as hostname and the first word of the message as the TAG. Clearly, this is not
1417                  * of advantage ;) I think I have now found a way to handle this situation: there
1418                  * are certain characters which are frequently used in TAG (e.g. ':'), which are
1419                  * *invalid* in host names. So while parsing the hostname, I check for these characters.
1420                  * If I find them, I set a simple flag but continue. After parsing, I check the flag.
1421                  * If it was set, then we most probably do not have a hostname but a TAG. Thus, I change
1422                  * the fields. I think this logic shall work with any type of syslog message.
1423                  */
1424                 bTAGCharDetected = 0;
1425                 if(pMsg->bParseHOSTNAME) {
1426                         /* TODO: quick and dirty memory allocation */
1427                         /* the memory allocated is far too much in most cases. But on the plus side,
1428                          * it is quite fast... - rgerhards, 2007-09-20
1429                          */
1430                         if((pBuf = malloc(sizeof(char)* (strlen(p2parse) +1))) == NULL)
1431                                 return 1;
1432                         pWork = pBuf;
1433                         /* this is the actual parsing loop */
1434                         while(*p2parse && *p2parse != ' ' && *p2parse != ':') {
1435                                 if(*p2parse == '[' || *p2parse == ']' || *p2parse == '/')
1436                                         bTAGCharDetected = 1;
1437                                 *pWork++ = *p2parse++;
1438                         }
1439                         /* we need to handle ':' seperately, because it terminates the
1440                          * TAG - so we also need to terminate the parser here!
1441                          * rgerhards, 2007-09-10 *p2parse points to a valid address here in 
1442                          * any case. We can reach this point only if we are at end of string,
1443                          * or we have a ':' or ' '. What the if below does is check if we are
1444                          * not at end of string and, if so, advance the parse pointer. If we 
1445                          * are already at end of string, *p2parse is equal to '\0', neither if
1446                          * will be true and the parse pointer remain as is. This is perfectly
1447                          * well.
1448                          */
1449                         if(*p2parse == ':') {
1450                                 bTAGCharDetected = 1;
1451                                 /* We will move hostname to tag, so preserve ':' (otherwise we 
1452                                  * will needlessly change the message format) */
1453                                 *pWork++ = *p2parse++; 
1454                         } else if(*p2parse == ' ')
1455                                 ++p2parse;
1456                         *pWork = '\0';
1457                         MsgAssignHOSTNAME(pMsg, pBuf);
1458                 }
1459                 /* check if we seem to have a TAG */
1460                 if(bTAGCharDetected) {
1461                         /* indeed, this smells like a TAG, so lets use it for this. We take
1462                          * the HOSTNAME from the sender system instead.
1463                          */
1464                         dbgprintf("HOSTNAME contains invalid characters, assuming it to be a TAG.\n");
1465                         moveHOSTNAMEtoTAG(pMsg);
1466                         MsgSetHOSTNAME(pMsg, getRcvFrom(pMsg));
1467                 }
1468
1469                 /* now parse TAG - that should be present in message from all sources.
1470                  * This code is somewhat not compliant with RFC 3164. As of 3164,
1471                  * the TAG field is ended by any non-alphanumeric character. In
1472                  * practice, however, the TAG often contains dashes and other things,
1473                  * which would end the TAG. So it is not desirable. As such, we only
1474                  * accept colon and SP to be terminators. Even there is a slight difference:
1475                  * a colon is PART of the TAG, while a SP is NOT part of the tag
1476                  * (it is CONTENT). Starting 2008-04-04, we have removed the 32 character
1477                  * size limit (from RFC3164) on the tag. This had bad effects on existing
1478                  * envrionments, as sysklogd didn't obey it either (probably another bug
1479                  * in RFC3164...). We now receive the full size, but will modify the
1480                  * outputs so that only 32 characters max are used by default.
1481                  */
1482                 /* The following code in general is quick & dirty - I need to get
1483                  * it going for a test, rgerhards 2004-11-16 */
1484                 /* lol.. we tried to solve it, just to remind ourselfs that 32 octets
1485                  * is the max size ;) we need to shuffle the code again... Just for 
1486                  * the records: the code is currently clean, but we could optimize it! */
1487                 if(!bTAGCharDetected) {
1488                         uchar *pszTAG;
1489                         if(rsCStrConstruct(&pStrB) != RS_RET_OK) 
1490                                 return 1;
1491                         rsCStrSetAllocIncrement(pStrB, 33);
1492                         pWork = pBuf;
1493                         iCnt = 0;
1494                         while(*p2parse && *p2parse != ':' && *p2parse != ' ') {
1495                                 rsCStrAppendChar(pStrB, *p2parse++);
1496                                 ++iCnt;
1497                         }
1498                         if(*p2parse == ':') {
1499                                 ++p2parse; 
1500                                 rsCStrAppendChar(pStrB, ':');
1501                         }
1502                         rsCStrFinish(pStrB);
1503
1504                         rsCStrConvSzStrAndDestruct(pStrB, &pszTAG, 1);
1505                         if(pszTAG == NULL)
1506                         {       /* rger, 2005-11-10: no TAG found - this implies that what
1507                                  * we have considered to be the HOSTNAME is most probably the
1508                                  * TAG. We consider it so probable, that we now adjust it
1509                                  * that way. So we pick up the previously set hostname, assign
1510                                  * it to tag and use the sender system (from IP stack) as
1511                                  * the hostname. This situation is the standard case with
1512                                  * stock BSD syslogd.
1513                                  */
1514                                 dbgprintf("No TAG in message, assuming that HOSTNAME is missing.\n");
1515                                 moveHOSTNAMEtoTAG(pMsg);
1516                                 MsgSetHOSTNAME(pMsg, getRcvFrom(pMsg));
1517                         } else { /* we have a TAG, so we can happily set it ;) */
1518                                 MsgAssignTAG(pMsg, pszTAG);
1519                         }
1520                 } else {
1521                         /* we have no TAG, so we ... */
1522                         /*DO NOTHING*/;
1523                 }
1524         } else {
1525                 /* we enter this code area when the user has instructed rsyslog NOT
1526                  * to parse HOSTNAME and TAG - rgerhards, 2006-03-13
1527                  */
1528                 if(!(flags & INTERNAL_MSG))
1529                 {
1530                         dbgprintf("HOSTNAME and TAG not parsed by user configuraton.\n");
1531                         MsgSetHOSTNAME(pMsg, getRcvFrom(pMsg));
1532                 }
1533         }
1534
1535         /* The rest is the actual MSG */
1536         MsgSetMSG(pMsg, p2parse);
1537
1538         return 0; /* all ok */
1539 }
1540
1541
1542 /* submit a fully created message to the main message queue. The message is
1543  * fully processed and parsed, so no parsing at all happens. This is primarily
1544  * a hook to prevent the need for callers to know about the main message queue
1545  * (which may change in the future as we will probably have multiple rule
1546  * sets and thus queues...).
1547  * rgerhards, 2008-02-13
1548  */
1549 rsRetVal
1550 submitMsg(msg_t *pMsg)
1551 {
1552         DEFiRet;
1553
1554         ISOBJ_TYPE_assert(pMsg, msg);
1555         
1556         MsgPrepareEnqueue(pMsg);
1557         queueEnqObj(pMsgQueue, pMsg->flowCtlType, (void*) pMsg);
1558
1559         RETiRet;
1560 }
1561
1562
1563 /*
1564  * Log a message to the appropriate log files, users, etc. based on
1565  * the priority.
1566  * rgerhards 2004-11-08: actually, this also decodes all but the PRI part.
1567  * rgerhards 2004-11-09: ... but only, if syslogd could properly be initialized
1568  *                       if not, we use emergency logging to the console and in
1569  *                       this case, no further decoding happens.
1570  * changed to no longer receive a plain message but a msg object instead.
1571  * rgerhards-2004-11-16: OK, we are now up to another change... This method
1572  * actually needs to PARSE the message. How exactly this needs to happen depends on
1573  * a number of things. Most importantly, it depends on the source. For example,
1574  * locally received messages (SOURCE_UNIXAF) do NOT have a hostname in them. So
1575  * we need to treat them differntly form network-received messages which have.
1576  * Well, actually not all network-received message really have a hostname. We
1577  * can just hope they do, but we can not be sure. So this method tries to find
1578  * whatever can be found in the message and uses that... Obviously, there is some
1579  * potential for misinterpretation, which we simply can not solve under the
1580  * circumstances given.
1581  */
1582 void
1583 logmsg(msg_t *pMsg, int flags)
1584 {
1585         char *msg;
1586
1587         BEGINfunc
1588         assert(pMsg != NULL);
1589         assert(pMsg->pszUxTradMsg != NULL);
1590         msg = (char*) pMsg->pszUxTradMsg;
1591         dbgprintf("logmsg: flags %x, from '%s', msg %s\n", flags, getRcvFrom(pMsg), msg);
1592
1593         /* rger 2005-11-24 (happy thanksgiving!): we now need to check if we have
1594          * a traditional syslog message or one formatted according to syslog-protocol.
1595          * We need to apply different parsers depending on that. We use the
1596          * -protocol VERSION field for the detection.
1597          */
1598         if(msg[0] == '1' && msg[1] == ' ') {
1599                 dbgprintf("Message has syslog-protocol format.\n");
1600                 setProtocolVersion(pMsg, 1);
1601                 if(parseRFCSyslogMsg(pMsg, flags) == 1) {
1602                         msgDestruct(&pMsg);
1603                         return;
1604                 }
1605         } else { /* we have legacy syslog */
1606                 dbgprintf("Message has legacy syslog format.\n");
1607                 setProtocolVersion(pMsg, 0);
1608                 if(parseLegacySyslogMsg(pMsg, flags) == 1) {
1609                         msgDestruct(&pMsg);
1610                         return;
1611                 }
1612         }
1613
1614         /* ---------------------- END PARSING ---------------- */
1615         
1616         /* now submit the message to the main queue - then we are done */
1617         pMsg->msgFlags = flags;
1618         MsgPrepareEnqueue(pMsg);
1619         queueEnqObj(pMsgQueue, pMsg->flowCtlType, (void*) pMsg);
1620         ENDfunc
1621 }
1622
1623
1624 static void
1625 reapchild()
1626 {
1627         int saved_errno = errno;
1628         struct sigaction sigAct;
1629
1630         memset(&sigAct, 0, sizeof (sigAct));
1631         sigemptyset(&sigAct.sa_mask);
1632         sigAct.sa_handler = reapchild;
1633         sigaction(SIGCHLD, &sigAct, NULL);  /* reset signal handler -ASP */
1634
1635         while(waitpid(-1, NULL, WNOHANG) > 0);
1636         errno = saved_errno;
1637 }
1638
1639
1640 /* helper to doFlushRptdMsgs() to flush the individual action links via llExecFunc
1641  * rgerhards, 2007-08-02
1642  */
1643 DEFFUNC_llExecFunc(flushRptdMsgsActions)
1644 {
1645         action_t *pAction = (action_t*) pData;
1646
1647         assert(pAction != NULL);
1648         
1649         BEGINfunc
1650         LockObj(pAction);
1651         if (pAction->f_prevcount && time(NULL) >= REPEATTIME(pAction)) {
1652                 dbgprintf("flush %s: repeated %d times, %d sec.\n",
1653                     module.GetStateName(pAction->pMod), pAction->f_prevcount,
1654                     repeatinterval[pAction->f_repeatcount]);
1655                 actionWriteToAction(pAction);
1656                 BACKOFF(pAction);
1657         }
1658         UnlockObj(pAction);
1659
1660         ENDfunc
1661         return RS_RET_OK; /* we ignore errors, we can not do anything either way */
1662 }
1663
1664
1665 /* This method flushes reapeat messages.
1666  */
1667 static void
1668 doFlushRptdMsgs(void)
1669 {
1670         register selector_t *f;
1671
1672         /* see if we need to flush any "message repeated n times"... 
1673          * Note that this interferes with objects running on other threads.
1674          * We are using appropriate locking inside the function to handle that.
1675          */
1676         for (f = Files; f != NULL ; f = f->f_next) {
1677                 llExecFunc(&f->llActList, flushRptdMsgsActions, NULL);
1678         }
1679 }
1680
1681
1682 static void debug_switch()
1683 {
1684         struct sigaction sigAct;
1685
1686         if(debugging_on == 0) {
1687                 debugging_on = 1;
1688                 dbgprintf("Switching debugging_on to true\n");
1689         } else {
1690                 dbgprintf("Switching debugging_on to false\n");
1691                 debugging_on = 0;
1692         }
1693         
1694         memset(&sigAct, 0, sizeof (sigAct));
1695         sigemptyset(&sigAct.sa_mask);
1696         sigAct.sa_handler = debug_switch;
1697         sigaction(SIGUSR1, &sigAct, NULL);
1698 }
1699
1700
1701 void legacyOptsEnq(uchar *line)
1702 {
1703         legacyOptsLL_t *pNew;
1704
1705         pNew = malloc(sizeof(legacyOptsLL_t));
1706         if(line == NULL)
1707                 pNew->line = NULL;
1708         else
1709                 pNew->line = (uchar *) strdup((char *) line);
1710         pNew->next = NULL;
1711
1712         if(pLegacyOptsLL == NULL)
1713                 pLegacyOptsLL = pNew;
1714         else {
1715                 legacyOptsLL_t *pThis = pLegacyOptsLL;
1716
1717                 while(pThis->next != NULL)
1718                         pThis = pThis->next;
1719                 pThis->next = pNew;
1720         }
1721 }
1722
1723
1724 void legacyOptsFree(void)
1725 {
1726         legacyOptsLL_t *pThis = pLegacyOptsLL, *pNext;
1727
1728         while(pThis != NULL) {
1729                 if(pThis->line != NULL)
1730                         free(pThis->line);
1731                 pNext = pThis->next;
1732                 free(pThis);
1733                 pThis = pNext;
1734         }
1735 }
1736
1737
1738 void legacyOptsHook(void)
1739 {
1740         legacyOptsLL_t *pThis = pLegacyOptsLL;
1741
1742         while(pThis != NULL) {
1743                 if(pThis->line != NULL) {
1744                         errno = 0;
1745                         errmsg.LogError(NO_ERRCODE, "Warning: backward compatibility layer added to following "
1746                                         "directive to rsyslog.conf: %s", pThis->line);
1747                         conf.cfsysline(pThis->line);
1748                 }
1749                 pThis = pThis->next;
1750         }
1751 }
1752
1753
1754 void legacyOptsParseTCP(char ch, char *arg)
1755 {
1756         register int i;
1757         register char *pArg = arg;
1758         static char conflict = '\0';
1759
1760         if((conflict == 'g' && ch == 't') || (conflict == 't' && ch == 'g')) {
1761                 fprintf(stderr, "rsyslog: If you want to use both -g and -t, use directives instead, -%c ignored.\n", ch);
1762                 return;
1763         } else
1764                 conflict = ch;
1765
1766         /* extract port */
1767         i = 0;
1768         while(isdigit((int) *pArg))
1769                 i = i * 10 + *pArg++ - '0';
1770
1771         /* number of sessions */
1772         if(*pArg == '\0' || *pArg == ',') {
1773                 if(ch == 't')
1774                         legacyOptsEnq((uchar *) "ModLoad imtcp");
1775                 else if(ch == 'g')
1776                         legacyOptsEnq((uchar *) "ModLoad imgssapi");
1777
1778                 if(i >= 0 && i <= 65535) {
1779                         uchar line[30];
1780
1781                         if(ch == 't') {
1782                                 snprintf((char *) line, sizeof(line), "InputTCPServerRun %d", i);
1783                         } else if(ch == 'g') {
1784                                 snprintf((char *) line, sizeof(line), "InputGSSServerRun %d", i);
1785                         }
1786                         legacyOptsEnq(line);
1787                 } else {
1788                         if(ch == 't') {
1789                                 fprintf(stderr, "rsyslogd: Invalid TCP listen port %d - changed to 514.\n", i);
1790                                 legacyOptsEnq((uchar *) "InputTCPServerRun 514");
1791                         } else if(ch == 'g') {
1792                                 fprintf(stderr, "rsyslogd: Invalid GSS listen port %d - changed to 514.\n", i);
1793                                 legacyOptsEnq((uchar *) "InputGSSServerRun 514");
1794                         }
1795                 }
1796
1797                 if(*pArg == ',') {
1798                         ++pArg;
1799                         while(isspace((int) *pArg))
1800                                 ++pArg;
1801                         i = 0;
1802                         while(isdigit((int) *pArg)) {
1803                                 i = i * 10 + *pArg++ - '0';
1804                         }
1805                         if(i > 0) {
1806                                 uchar line[30];
1807
1808                                 snprintf((char *) line, sizeof(line), "InputTCPMaxSessions %d", i);
1809                                 legacyOptsEnq(line);
1810                         } else {
1811                                 if(ch == 't') {
1812                                         fprintf(stderr, "rsyslogd: TCP session max configured "
1813                                                 "to %d [-t %s] - changing to 1.\n", i, arg);
1814                                         legacyOptsEnq((uchar *) "InputTCPMaxSessions 1");
1815                                 } else if (ch == 'g') {
1816                                         fprintf(stderr, "rsyslogd: GSS session max configured "
1817                                                 "to %d [-g %s] - changing to 1.\n", i, arg);
1818                                         legacyOptsEnq((uchar *) "InputTCPMaxSessions 1");
1819                                 }
1820                         }
1821                 }
1822         } else
1823                 fprintf(stderr, "rsyslogd: Invalid -t %s command line option.\n", arg);
1824 }
1825
1826
1827 /* doDie() is a signal handler. If called, it sets the bFinished variable
1828  * to indicate the program should terminate. However, it does not terminate
1829  * it itself, because that causes issues with multi-threading. The actual
1830  * termination is then done on the main thread. This solution might introduce
1831  * a minimal delay, but it is much cleaner than the approach of doing everything
1832  * inside the signal handler.
1833  * rgerhards, 2005-10-26
1834  */
1835 static void doDie(int sig)
1836 {
1837         static int iRetries = 0; /* debug aid */
1838         printf("DoDie called.\n");
1839         if(iRetries++ == 4) {
1840                 printf("DoDie called 5 times - unconditional exit\n");
1841                 abort();
1842         }
1843         bFinished = sig;
1844 }
1845
1846
1847 /* This function frees all dynamically allocated memory for program termination.
1848  * It must be called only immediately before exit(). It is primarily an aid
1849  * for memory debuggers, which prevents cluttered outupt.
1850  * rgerhards, 2008-03-20
1851  */
1852 static void
1853 freeAllDynMemForTermination(void)
1854 {
1855         if(pszWorkDir != NULL)
1856                 free(pszWorkDir);
1857         if(pszMainMsgQFName != NULL)
1858                 free(pszMainMsgQFName);
1859         if(pModDir != NULL)
1860                 free(pModDir);
1861 }
1862
1863
1864 /* die() is called when the program shall end. This typically only occurs
1865  * during sigterm or during the initialization. 
1866  * As die() is intended to shutdown rsyslogd, it is
1867  * safe to call exit() here. Just make sure that die() itself is not called
1868  * at inapropriate places. As a general rule of thumb, it is a bad idea to add
1869  * any calls to die() in new code!
1870  * rgerhards, 2005-10-24
1871  */
1872 static void
1873 die(int sig)
1874 {
1875         char buf[256];
1876
1877         dbgprintf("exiting on signal %d\n", sig);
1878
1879         /* IMPORTANT: we should close the inputs first, and THEN send our termination
1880          * message. If we do it the other way around, logmsgInternal() may block on
1881          * a full queue and the inputs still fill up that queue. Depending on the
1882          * scheduling order, we may end up with logmsgInternal being held for a quite
1883          * long time. When the inputs are terminated first, that should not happen
1884          * because the queue is drained in parallel. The situation could only become
1885          * an issue with extremely long running actions in a queue full environment.
1886          * However, such actions are at least considered poorly written, if not
1887          * outright wrong. So we do not care about this very remote problem.
1888          * rgerhards, 2008-01-11
1889          */
1890
1891         /* close the inputs */
1892         dbgprintf("Terminating input threads...\n");
1893         thrdTerminateAll(); /* TODO: inputs only, please */
1894
1895         /* and THEN send the termination log message (see long comment above) */
1896         if (sig) {
1897                 (void) snprintf(buf, sizeof(buf) / sizeof(char),
1898                  " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \
1899                  "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"]" " exiting on signal %d.",
1900                  (int) myPid, sig);
1901                 errno = 0;
1902                 logmsgInternal(LOG_SYSLOG|LOG_INFO, buf, ADDDATE);
1903         }
1904         
1905         /* drain queue (if configured so) and stop main queue worker thread pool */
1906         dbgprintf("Terminating main queue...\n");
1907         queueDestruct(&pMsgQueue);
1908         pMsgQueue = NULL;
1909
1910         /* Free ressources and close connections. This includes flushing any remaining
1911          * repeated msgs.
1912          */
1913         dbgprintf("Terminating outputs...\n");
1914         freeSelectors();
1915
1916         dbgprintf("all primary multi-thread sources have been terminated - now doing aux cleanup...\n");
1917         /* rger 2005-02-22
1918          * now clean up the in-memory structures. OK, the OS
1919          * would also take care of that, but if we do it
1920          * ourselfs, this makes finding memory leaks a lot
1921          * easier.
1922          */
1923         tplDeleteAll();
1924
1925         remove_pid(PidFile);
1926         if(glblHadMemShortage)
1927                 dbgprintf("Had memory shortage at least once during the run.\n");
1928
1929         /* de-init some modules */
1930         modExitIminternal();
1931
1932         /*dbgPrintAllDebugInfo(); / * this is the last spot where this can be done - below output modules are unloaded! */
1933
1934         /* the following line cleans up CfSysLineHandlers that were not based on loadable
1935          * modules. As such, they are not yet cleared.
1936          */
1937         unregCfSysLineHdlrs();
1938
1939         legacyOptsFree();
1940
1941         /* terminate the remaining classes */
1942         GlobalClassExit();
1943
1944         /* TODO: this would also be the right place to de-init the builtin output modules. We
1945          * do not currently do that, because the module interface does not allow for
1946          * it. This will come some time later (it's essential with loadable modules).
1947          * For the time being, this is a memory leak on exit, but as the process is
1948          * terminated, we do not really bother about it.
1949          * rgerhards, 2007-08-03
1950          * I have added some code now, but all that mod init/de-init should be moved to
1951          * init, so that modules are unloaded and reloaded on HUP to. Eventually it should go
1952          * into freeSelectors() - but that needs to be seen. -- rgerhards, 2007-08-09
1953          */
1954         module.UnloadAndDestructAll(eMOD_LINK_ALL);
1955
1956         dbgprintf("Clean shutdown completed, bye\n");
1957         /* dbgClassExit MUST be the last one, because it de-inits the debug system */
1958         dbgClassExit();
1959
1960         /* free all remaining memory blocks - this is not absolutely necessary, but helps
1961          * us keep memory debugger logs clean and this is in aid in developing. It doesn't
1962          * cost much time, so we do it always. -- rgerhards, 2008-03-20
1963          */
1964         freeAllDynMemForTermination();
1965         /* NO CODE HERE - feeelAllDynMemForTermination() must be the last thing before exit()! */
1966         exit(0); /* "good" exit, this is the terminator function for rsyslog [die()] */
1967 }
1968
1969 /*
1970  * Signal handler to terminate the parent process.
1971  * rgerhards, 2005-10-24: this is only called during forking of the
1972  * detached syslogd. I consider this method to be safe.
1973  */
1974 static void doexit()
1975 {
1976         exit(0); /* "good" exit, only during child-creation */
1977 }
1978
1979
1980 /* set the action resume interval
1981  */
1982 static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int iNewVal)
1983 {
1984         return actionSetGlobalResumeInterval(iNewVal);
1985 }
1986
1987
1988 /* set the processes umask (upon configuration request)
1989  */
1990 static rsRetVal setUmask(void __attribute__((unused)) *pVal, int iUmask)
1991 {
1992         umask(iUmask);
1993         dbgprintf("umask set to 0%3.3o.\n", iUmask);
1994
1995         return RS_RET_OK;
1996 }
1997
1998
1999 /* helper to freeSelectors(), used with llExecFunc() to flush 
2000  * pending output.  -- rgerhards, 2007-08-02
2001  * We do not need to lock the action object here as the processing
2002  * queue is already empty and no other threads are running when
2003  * we call this function. -- rgerhards, 2007-12-12
2004  */
2005 DEFFUNC_llExecFunc(freeSelectorsActions)
2006 {
2007         action_t *pAction = (action_t*) pData;
2008
2009         assert(pAction != NULL);
2010
2011         /* flush any pending output */
2012         if(pAction->f_prevcount) {
2013                 actionWriteToAction(pAction);
2014         }
2015
2016         return RS_RET_OK; /* never fails ;) */
2017 }
2018
2019
2020 /*  Close all open log files and free selector descriptor array.
2021  */
2022 static void freeSelectors(void)
2023 {
2024         selector_t *f;
2025         selector_t *fPrev;
2026
2027         if(Files != NULL) {
2028                 dbgprintf("Freeing log structures.\n");
2029
2030                 for(f = Files ; f != NULL ; f = f->f_next) {
2031                         llExecFunc(&f->llActList, freeSelectorsActions, NULL);
2032                 }
2033
2034                 /* actions flushed and ready for destruction - so do that... */
2035                 f = Files;
2036                 while (f != NULL) {
2037                         fPrev = f;
2038                         f = f->f_next;
2039                         selectorDestruct(fPrev);
2040                 }
2041
2042                 /* Reflect the deletion of the selectors linked list. */
2043                 Files = NULL;
2044                 bHaveMainQueue = 0;
2045         }
2046 }
2047
2048
2049 /* helper to dbPrintInitInfo, to print out all actions via
2050  * the llExecFunc() facility.
2051  * rgerhards, 2007-08-02
2052  */
2053 DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
2054 {
2055         DEFiRet;
2056         iRet = actionDbgPrint((action_t*) pData);
2057         dbgprintf("\n");
2058
2059         RETiRet;
2060 }
2061
2062 /* print debug information as part of init(). This pretty much
2063  * outputs the whole config of rsyslogd. I've moved this code
2064  * out of init() to clean it somewhat up.
2065  * rgerhards, 2007-07-31
2066  */
2067 static void dbgPrintInitInfo(void)
2068 {
2069         register selector_t *f;
2070         int iSelNbr = 1;
2071         int i;
2072
2073         dbgprintf("\nActive selectors:\n");
2074         for (f = Files; f != NULL ; f = f->f_next) {
2075                 dbgprintf("Selector %d:\n", iSelNbr++);
2076                 if(f->pCSProgNameComp != NULL)
2077                         dbgprintf("tag: '%s'\n", rsCStrGetSzStrNoNULL(f->pCSProgNameComp));
2078                 if(f->eHostnameCmpMode != HN_NO_COMP)
2079                         dbgprintf("hostname: %s '%s'\n",
2080                                 f->eHostnameCmpMode == HN_COMP_MATCH ?
2081                                         "only" : "allbut",
2082                                 rsCStrGetSzStrNoNULL(f->pCSHostnameComp));
2083                 if(f->f_filter_type == FILTER_PRI) {
2084                         for (i = 0; i <= LOG_NFACILITIES; i++)
2085                                 if (f->f_filterData.f_pmask[i] == TABLE_NOPRI)
2086                                         dbgprintf(" X ");
2087                                 else
2088                                         dbgprintf("%2X ", f->f_filterData.f_pmask[i]);
2089                 } else if(f->f_filter_type == FILTER_EXPR) {
2090                         dbgprintf("EXPRESSION-BASED Filter: can currently not be displayed");
2091                 } else {
2092                         dbgprintf("PROPERTY-BASED Filter:\n");
2093                         dbgprintf("\tProperty.: '%s'\n",
2094                                rsCStrGetSzStrNoNULL(f->f_filterData.prop.pCSPropName));
2095                         dbgprintf("\tOperation: ");
2096                         if(f->f_filterData.prop.isNegated)
2097                                 dbgprintf("NOT ");
2098                         dbgprintf("'%s'\n", getFIOPName(f->f_filterData.prop.operation));
2099                         dbgprintf("\tValue....: '%s'\n",
2100                                rsCStrGetSzStrNoNULL(f->f_filterData.prop.pCSCompValue));
2101                         dbgprintf("\tAction...: ");
2102                 }
2103
2104                 dbgprintf("\nActions:\n");
2105                 llExecFunc(&f->llActList, dbgPrintInitInfoAction, NULL); /* actions */
2106
2107                 dbgprintf("\n");
2108         }
2109         dbgprintf("\n");
2110         if(bDebugPrintTemplateList)
2111                 tplPrintList();
2112         if(bDebugPrintModuleList)
2113                 module.PrintList();
2114         ochPrintList();
2115
2116         if(bDebugPrintCfSysLineHandlerList)
2117                 dbgPrintCfSysLineHandlers();
2118
2119         dbgprintf("Messages with malicious PTR DNS Records are %sdropped.\n",
2120                 bDropMalPTRMsgs ? "" : "not ");
2121
2122         dbgprintf("Control characters are %sreplaced upon reception.\n",
2123                         bEscapeCCOnRcv? "" : "not ");
2124
2125         if(bEscapeCCOnRcv)
2126                 dbgprintf("Control character escape sequence prefix is '%c'.\n",
2127                         cCCEscapeChar);
2128
2129         dbgprintf("Main queue size %d messages.\n", iMainMsgQueueSize);
2130         dbgprintf("Main queue worker threads: %d, Perists every %d updates.\n",
2131                   iMainMsgQueueNumWorkers, iMainMsgQPersistUpdCnt);
2132         dbgprintf("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n",
2133                    iMainMsgQtoQShutdown, iMainMsgQtoActShutdown, iMainMsgQtoEnq);
2134         dbgprintf("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n",
2135                    iMainMsgQHighWtrMark, iMainMsgQLowWtrMark, iMainMsgQDiscardMark, iMainMsgQDiscardSeverity);
2136         dbgprintf("Main queue save on shutdown %d, max disk space allowed %lld\n",
2137                    bMainMsgQSaveOnShutdown, iMainMsgQueMaxDiskSpace);
2138         /* TODO: add
2139         iActionRetryCount = 0;
2140         iActionRetryInterval = 30000;
2141         static int iMainMsgQtoWrkShutdown = 60000;
2142         static int iMainMsgQtoWrkMinMsgs = 100; 
2143         static int iMainMsgQbSaveOnShutdown = 1;
2144         iMainMsgQueMaxDiskSpace = 0;
2145         setQPROP(queueSettoWrkShutdown, "$MainMsgQueueTimeoutWorkerThreadShutdown", 5000);
2146         setQPROP(queueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100);
2147         setQPROP(queueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1);
2148          */
2149         dbgprintf("Work Directory: '%s'.\n", pszWorkDir);
2150 }
2151
2152
2153 /* Start the input modules. This function will probably undergo big changes
2154  * while we implement the input module interface. For now, it does the most
2155  * important thing to get at least my poor initial input modules up and
2156  * running. Almost no config option is taken.
2157  * rgerhards, 2007-12-14
2158  */
2159 static rsRetVal
2160 startInputModules(void)
2161 {
2162         DEFiRet;
2163         modInfo_t *pMod;
2164
2165         /* loop through all modules and activate them (brr...) */
2166         pMod = module.GetNxtType(NULL, eMOD_IN);
2167         while(pMod != NULL) {
2168                 if((iRet = pMod->mod.im.willRun()) == RS_RET_OK) {
2169                         /* activate here */
2170                         thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun);
2171                 } else {
2172                         dbgprintf("module %lx will not run, iRet %d\n", (unsigned long) pMod, iRet);
2173                 }
2174         pMod = module.GetNxtType(pMod, eMOD_IN);
2175         }
2176
2177         ENDfunc
2178         return RS_RET_OK; /* intentional: we do not care about module errors */
2179 }
2180
2181
2182 /* INIT -- Initialize syslogd from configuration table
2183  * init() is called at initial startup AND each time syslogd is HUPed
2184  */
2185 static void
2186 init(void)
2187 {
2188         DEFiRet;
2189         char cbuf[BUFSIZ];
2190         char bufStartUpMsg[512];
2191         struct sigaction sigAct;
2192
2193         thrdTerminateAll(); /* stop all running input threads - TODO: reconsider location! */
2194
2195         /* initialize some static variables */
2196         pDfltHostnameCmp = NULL;
2197         pDfltProgNameCmp = NULL;
2198         eDfltHostnameCmpMode = HN_NO_COMP;
2199
2200         dbgprintf("rsyslog %s.\n", VERSION);
2201         dbgprintf("Called init.\n");
2202
2203         /* delete the message queue, which also flushes all messages left over */
2204         if(pMsgQueue != NULL) {
2205                 dbgprintf("deleting main message queue\n");
2206                 queueDestruct(&pMsgQueue); /* delete pThis here! */
2207                 pMsgQueue = NULL;
2208         }
2209
2210         /*  Close all open log files and free log descriptor array. This also frees
2211          *  all output-modules instance data.
2212          */
2213         freeSelectors();
2214
2215         /* Unload all non-static modules */
2216         dbgprintf("Unloading non-static modules.\n");
2217         module.UnloadAndDestructAll(eMOD_LINK_DYNAMIC_LOADED);
2218
2219         dbgprintf("Clearing templates.\n");
2220         tplDeleteNew();
2221
2222         /* re-setting values to defaults (where applicable) */
2223         /* TODO: once we have loadable modules, we must re-visit this code. The reason is
2224          * that config variables are not re-set, because the module is not yet loaded. On
2225          * the other hand, that doesn't matter, because the module got unloaded and is then
2226          * re-loaded, so the variables should be re-set via that way. In any case, we should
2227          * think about the whole situation when we implement loadable plugins.
2228          * rgerhards, 2007-07-31
2229          */
2230         conf.cfsysline((uchar*)"ResetConfigVariables");
2231
2232         /* open the configuration file */
2233         if((iRet = conf.processConfFile(ConfFile)) != RS_RET_OK) {
2234                 /* rgerhards: this code is executed to set defaults when the
2235                  * config file could not be opened. We might think about
2236                  * abandoning the run in this case - but this, too, is not
2237                  * very clever... So we stick with what we have.
2238                  * We ignore any errors while doing this - we would be lost anyhow...
2239                  */
2240                 selector_t *f = NULL;
2241                 char szTTYNameBuf[_POSIX_TTY_NAME_MAX+1]; /* +1 for NULL character */
2242                 dbgprintf("primary config file could not be opened - using emergency definitions.\n");
2243                 conf.cfline((uchar*)"*.ERR\t" _PATH_CONSOLE, &f);
2244                 conf.cfline((uchar*)"*.PANIC\t*", &f);
2245                 if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) {
2246                         snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf);
2247                         conf.cfline((uchar*)cbuf, &f);
2248                 }
2249                 selectorAddList(f);
2250         }
2251
2252         legacyOptsHook();
2253
2254         /* we are now done with reading the configuration. This is the right time to
2255          * free some objects that were just needed for loading it. rgerhards 2005-10-19
2256          */
2257         if(pDfltHostnameCmp != NULL) {
2258                 rsCStrDestruct(&pDfltHostnameCmp);
2259         }
2260
2261         if(pDfltProgNameCmp != NULL) {
2262                 rsCStrDestruct(&pDfltProgNameCmp);
2263         }
2264
2265         /* some checks */
2266         if(iMainMsgQueueNumWorkers < 1) {
2267                 errmsg.LogError(NO_ERRCODE, "$MainMsgQueueNumWorkers must be at least 1! Set to 1.\n");
2268                 iMainMsgQueueNumWorkers = 1;
2269         }
2270
2271         if(MainMsgQueType == QUEUETYPE_DISK) {
2272                 errno = 0;      /* for logerror! */
2273                 if(pszWorkDir == NULL) {
2274                         errmsg.LogError(NO_ERRCODE, "No $WorkDirectory specified - can not run main message queue in 'disk' mode. "
2275                                  "Using 'FixedArray' instead.\n");
2276                         MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
2277                 }
2278                 if(pszMainMsgQFName == NULL) {
2279                         errmsg.LogError(NO_ERRCODE, "No $MainMsgQueueFileName specified - can not run main message queue in "
2280                                  "'disk' mode. Using 'FixedArray' instead.\n");
2281                         MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
2282                 }
2283         }
2284
2285         /* switch the message object to threaded operation, if necessary */
2286         if(MainMsgQueType == QUEUETYPE_DIRECT || iMainMsgQueueNumWorkers > 1) {
2287                 MsgEnableThreadSafety();
2288         }
2289
2290         /* create message queue */
2291         CHKiRet_Hdlr(queueConstruct(&pMsgQueue, MainMsgQueType, iMainMsgQueueNumWorkers, iMainMsgQueueSize, msgConsumer)) {
2292                 /* no queue is fatal, we need to give up in that case... */
2293                 fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet);
2294                 exit(1);
2295         }
2296         /* name our main queue object (it's not fatal if it fails...) */
2297         obj.SetName((obj_t*) pMsgQueue, (uchar*) "main queue");
2298
2299         /* ... set some properties ... */
2300 #       define setQPROP(func, directive, data) \
2301         CHKiRet_Hdlr(func(pMsgQueue, data)) { \
2302                 errmsg.LogError(NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \
2303         }
2304 #       define setQPROPstr(func, directive, data) \
2305         CHKiRet_Hdlr(func(pMsgQueue, data, (data == NULL)? 0 : strlen((char*) data))) { \
2306                 errmsg.LogError(NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \
2307         }
2308
2309         setQPROP(queueSetMaxFileSize, "$MainMsgQueueFileSize", iMainMsgQueMaxFileSize);
2310         setQPROP(queueSetsizeOnDiskMax, "$MainMsgQueueMaxDiskSpace", iMainMsgQueMaxDiskSpace);
2311         setQPROPstr(queueSetFilePrefix, "$MainMsgQueueFileName", pszMainMsgQFName);
2312         setQPROP(queueSetiPersistUpdCnt, "$MainMsgQueueCheckpointInterval", iMainMsgQPersistUpdCnt);
2313         setQPROP(queueSettoQShutdown, "$MainMsgQueueTimeoutShutdown", iMainMsgQtoQShutdown );
2314         setQPROP(queueSettoActShutdown, "$MainMsgQueueTimeoutActionCompletion", iMainMsgQtoActShutdown);
2315         setQPROP(queueSettoWrkShutdown, "$MainMsgQueueWorkerTimeoutThreadShutdown", iMainMsgQtoWrkShutdown);
2316         setQPROP(queueSettoEnq, "$MainMsgQueueTimeoutEnqueue", iMainMsgQtoEnq);
2317         setQPROP(queueSetiHighWtrMrk, "$MainMsgQueueHighWaterMark", iMainMsgQHighWtrMark);
2318         setQPROP(queueSetiLowWtrMrk, "$MainMsgQueueLowWaterMark", iMainMsgQLowWtrMark);
2319         setQPROP(queueSetiDiscardMrk, "$MainMsgQueueDiscardMark", iMainMsgQDiscardMark);
2320         setQPROP(queueSetiDiscardSeverity, "$MainMsgQueueDiscardSeverity", iMainMsgQDiscardSeverity);
2321         setQPROP(queueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", iMainMsgQWrkMinMsgs);
2322         setQPROP(queueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", bMainMsgQSaveOnShutdown);
2323         setQPROP(queueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", iMainMsgQDeqSlowdown);
2324
2325 #       undef setQPROP
2326 #       undef setQPROPstr
2327
2328         /* ... and finally start the queue! */
2329         CHKiRet_Hdlr(queueStart(pMsgQueue)) {
2330                 /* no queue is fatal, we need to give up in that case... */
2331                 fprintf(stderr, "fatal error %d: could not start message queue - rsyslogd can not run!\n", iRet);
2332                 exit(1);
2333         }
2334
2335         bHaveMainQueue = (MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1;
2336         dbgprintf("Main processing queue is initialized and running\n");
2337
2338         /* the output part and the queue is now ready to run. So it is a good time
2339          * to start the inputs. Please note that the net code above should be
2340          * shuffled to down here once we have everything in input modules.
2341          * rgerhards, 2007-12-14
2342          */
2343         startInputModules();
2344
2345         if(Debug) {
2346                 dbgPrintInitInfo();
2347         }
2348
2349         /* we now generate the startup message. It now includes everything to
2350          * identify this instance. -- rgerhards, 2005-08-17
2351          */
2352         snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char), 
2353                  " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \
2354                  "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] restart",
2355                  (int) myPid);
2356         logmsgInternal(LOG_SYSLOG|LOG_INFO, bufStartUpMsg, ADDDATE);
2357
2358         memset(&sigAct, 0, sizeof (sigAct));
2359         sigemptyset(&sigAct.sa_mask);
2360         sigAct.sa_handler = sighup_handler;
2361         sigaction(SIGHUP, &sigAct, NULL);
2362
2363         dbgprintf(" (re)started.\n");
2364         ENDfunc
2365 }
2366
2367
2368 /* add a completely-processed selector (after config line parsing) to
2369  * the linked list of selectors. We now need to check
2370  * if it has any actions associated and, if so, link it to the linked
2371  * list. If it has nothing associated with it, we can simply discard
2372  * it.
2373  * We have one special case during initialization: then, the current
2374  * selector is NULL, which means we do not need to care about it at
2375  * all.  -- rgerhards, 2007-08-01
2376  */
2377 rsRetVal
2378 selectorAddList(selector_t *f)
2379 {
2380         DEFiRet;
2381         int iActionCnt;
2382
2383         static selector_t *nextp = NULL; /* TODO: make this go away (see comment below) */
2384
2385         if(f != NULL) {
2386                 CHKiRet(llGetNumElts(&f->llActList, &iActionCnt));
2387                 if(iActionCnt == 0) {
2388                         errmsg.LogError(NO_ERRCODE, "warning: selector line without actions will be discarded");
2389                         selectorDestruct(f);
2390                 } else {
2391                         /* successfully created an entry */
2392                         dbgprintf("selector line successfully processed\n");
2393                         /* TODO: we should use the linked list class for the selector list, else we need to add globals
2394                          * ... well nextp could be added temporarily...
2395                          * Thanks to varmojfekoj for having the idea to just use "Files" to make this
2396                          * code work. I had actually forgotten to fix the code here before moving to 1.18.0.
2397                          * And, of course, I also did not migrate the selector_t structure to the linked list class.
2398                          * However, that should still be one of the very next things to happen.
2399                          * rgerhards, 2007-08-06
2400                          */
2401                         if(Files == NULL) {
2402                                 Files = f;
2403                         } else {
2404                                 nextp->f_next = f;
2405                         }
2406                         nextp = f;
2407                 }
2408         }
2409
2410 finalize_it:
2411         RETiRet;
2412 }
2413
2414
2415 /* set the main message queue mode
2416  * rgerhards, 2008-01-03
2417  */
2418 static rsRetVal setMainMsgQueType(void __attribute__((unused)) *pVal, uchar *pszType)
2419 {
2420         DEFiRet;
2421
2422         if (!strcasecmp((char *) pszType, "fixedarray")) {
2423                 MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
2424                 dbgprintf("main message queue type set to FIXED_ARRAY\n");
2425         } else if (!strcasecmp((char *) pszType, "linkedlist")) {
2426                 MainMsgQueType = QUEUETYPE_LINKEDLIST;
2427                 dbgprintf("main message queue type set to LINKEDLIST\n");
2428         } else if (!strcasecmp((char *) pszType, "disk")) {
2429                 MainMsgQueType = QUEUETYPE_DISK;
2430                 dbgprintf("main message queue type set to DISK\n");
2431         } else if (!strcasecmp((char *) pszType, "direct")) {
2432                 MainMsgQueType = QUEUETYPE_DIRECT;
2433                 dbgprintf("main message queue type set to DIRECT (no queueing at all)\n");
2434         } else {
2435                 errmsg.LogError(NO_ERRCODE, "unknown mainmessagequeuetype parameter: %s", (char *) pszType);
2436                 iRet = RS_RET_INVALID_PARAMS;
2437         }
2438         free(pszType); /* no longer needed */
2439
2440         RETiRet;
2441 }
2442
2443
2444 /*
2445  * The following function is resposible for handling a SIGHUP signal.  Since
2446  * we are now doing mallocs/free as part of init we had better not being
2447  * doing this during a signal handler.  Instead this function simply sets
2448  * a flag variable which will tell the main loop to go through a restart.
2449  */
2450 void sighup_handler()
2451 {
2452         struct sigaction sigAct;
2453         
2454         restart = 1;
2455
2456         memset(&sigAct, 0, sizeof (sigAct));
2457         sigemptyset(&sigAct.sa_mask);
2458         sigAct.sa_handler = sighup_handler;
2459         sigaction(SIGHUP, &sigAct, NULL);
2460
2461         return;
2462 }
2463
2464
2465 /**
2466  * getSubString
2467  *
2468  * Copy a string byte by byte until the occurrence  
2469  * of a given separator.
2470  *
2471  * \param ppSrc         Pointer to a pointer of the source array of characters. If a
2472                         separator detected the Pointer points to the next char after the
2473                         separator. Except if the end of the string is dedected ('\n'). 
2474                         Then it points to the terminator char. 
2475  * \param pDst          Pointer to the destination array of characters. Here the substing
2476                         will be stored.
2477  * \param DstSize       Maximum numbers of characters to store.
2478  * \param cSep          Separator char.
2479  * \ret int             Returns 0 if no error occured.
2480  *
2481  * rgerhards, 2008-02-12: some notes are due... I will once again fix this function, this time
2482  * so that it treats ' ' as a request for whitespace. But in general, the function and its callers
2483  * should be changed over time, this is not really very good code...
2484  */
2485 int getSubString(uchar **ppSrc,  char *pDst, size_t DstSize, char cSep)
2486 {
2487         uchar *pSrc = *ppSrc;
2488         int iErr = 0; /* 0 = no error, >0 = error */
2489         while((cSep == ' ' ? !isspace(*pSrc) : *pSrc != cSep) && *pSrc != '\n' && *pSrc != '\0' && DstSize>1) {
2490                 *pDst++ = *(pSrc)++;
2491                 DstSize--;
2492         }
2493         /* check if the Dst buffer was to small */
2494         if ((cSep == ' ' ? !isspace(*pSrc) : *pSrc != cSep) && *pSrc != '\n' && *pSrc != '\0') { 
2495                 dbgprintf("in getSubString, error Src buffer > Dst buffer\n");
2496                 iErr = 1;
2497         }       
2498         if (*pSrc == '\0' || *pSrc == '\n')
2499                 /* this line was missing, causing ppSrc to be invalid when it
2500                  * was returned in case of end-of-string. rgerhards 2005-07-29
2501                  */
2502                 *ppSrc = pSrc;
2503         else
2504                 *ppSrc = pSrc+1;
2505         *pDst = '\0';
2506         return iErr;
2507 }
2508
2509
2510 /* this function pulls all internal messages from the buffer
2511  * and puts them into the processing engine.
2512  * We can only do limited error handling, as this would not
2513  * really help us. TODO: add error messages?
2514  * rgerhards, 2007-08-03
2515  */
2516 static void processImInternal(void)
2517 {
2518         int iPri;
2519         int iFlags;
2520         msg_t *pMsg;
2521
2522         while(iminternalRemoveMsg(&iPri, &pMsg, &iFlags) == RS_RET_OK) {
2523                 logmsg(pMsg, iFlags);
2524         }
2525 }
2526
2527
2528 /* This is the main processing loop. It is called after successful initialization.
2529  * When it returns, the syslogd terminates.
2530  * Its sole function is to provide some housekeeping things. The real work is done
2531  * by the other threads spawned.
2532  */
2533 static void
2534 mainloop(void)
2535 {
2536         struct timeval tvSelectTimeout;
2537
2538         BEGINfunc
2539         while(!bFinished){
2540                 /* first check if we have any internal messages queued and spit them out */
2541                 /* TODO: do we need this any longer? I doubt it, but let's care about it
2542                  * later -- rgerhards, 2007-12-21
2543                  */
2544                 processImInternal();
2545
2546                 /* this is now just a wait */
2547                 tvSelectTimeout.tv_sec = TIMERINTVL;
2548                 tvSelectTimeout.tv_usec = 0;
2549                 select(1, NULL, NULL, NULL, &tvSelectTimeout);
2550                 if(bFinished)
2551                         break;  /* exit as quickly as possible - see long comment below */
2552
2553                 /* If we received a HUP signal, we call doFlushRptdMsgs() a bit early. This
2554                  * doesn't matter, because doFlushRptdMsgs() checks timestamps. What may happen,
2555                  * however, is that the too-early call may lead to a bit too-late output
2556                  * of "last message repeated n times" messages. But that is quite acceptable.
2557                  * rgerhards, 2007-12-21
2558                  * ... and just to explain, we flush here because that is exactly what the mainloop
2559                  * shall do - provide a periodic interval in which not-yet-flushed messages will
2560                  * be flushed. Be careful, there is a potential race condition: doFlushRptdMsgs()
2561                  * needs to aquire a lock on the action objects. If, however, long-running consumers
2562                  * cause the main queue worker threads to lock them for a long time, we may receive
2563                  * a starvation condition, resulting in the mainloop being held on lock for an extended
2564                  * period of time. That, in turn, could lead to unresponsiveness to termination
2565                  * requests. It is especially important that the bFinished flag is checked before
2566                  * doFlushRptdMsgs() is called (I know because I ran into that situation). I am
2567                  * not yet sure if the remaining probability window of a termination-related
2568                  * problem is large enough to justify changing the code - I would consider it
2569                  * extremely unlikely that the problem ever occurs in practice. Fixing it would
2570                  * require not only a lot of effort but would cost considerable performance. So
2571                  * for the time being, I think the remaining risk can be accepted.
2572                  * rgerhards, 2008-01-10
2573                  */
2574                 doFlushRptdMsgs();
2575
2576                 if(restart) {
2577                         dbgprintf("\nReceived SIGHUP, reloading rsyslogd.\n");
2578                         /* main queue is stopped as part of init() */
2579                         init();
2580                         restart = 0;
2581                         continue;
2582                 }
2583         }
2584         ENDfunc
2585 }
2586
2587 /* If user is not root, prints warnings or even exits 
2588  * TODO: check all dynafiles for write permission
2589  * ... but it is probably better to wait here until we have
2590  * a module interface - rgerhards, 2007-07-23
2591  */
2592 static void checkPermissions()
2593 {
2594 #if 0
2595         /* TODO: this function must either be redone or removed - now with the input modules,
2596          * there is no such simple check we can do. What we can check, however, is if there is
2597          * any input module active and terminate, if not. -- rgerhards, 2007-12-26
2598          */
2599         /* we are not root */
2600         if (geteuid() != 0)
2601         {
2602                 fputs("WARNING: Local messages will not be logged! If you want to log them, run rsyslog as root.\n",stderr); 
2603 #ifdef SYSLOG_INET      
2604                 /* udp enabled and port number less than or equal to 1024 */
2605                 if ( AcceptRemote && (atoi(LogPort) <= 1024) )
2606                         fprintf(stderr, "WARNING: Will not listen on UDP port %s. Use port number higher than 1024 or run rsyslog as root!\n", LogPort);
2607                 
2608                 /* tcp enabled and port number less or equal to 1024 */
2609                 if( bEnableTCP   && (atoi(TCPLstnPort) <= 1024) )
2610                         fprintf(stderr, "WARNING: Will not listen on TCP port %s. Use port number higher than 1024 or run rsyslog as root!\n", TCPLstnPort);
2611
2612                 /* Neither explicit high UDP port nor explicit high TCP port.
2613                  * It is useless to run anymore */
2614                 if( !(AcceptRemote && (atoi(LogPort) > 1024)) && !( bEnableTCP && (atoi(TCPLstnPort) > 1024)) )
2615                 {
2616 #endif
2617                         fprintf(stderr, "ERROR: Nothing to log, no reason to run. Please run rsyslog as root.\n");
2618                         exit(EXIT_FAILURE);
2619 #ifdef SYSLOG_INET
2620                 }
2621 #endif
2622         }
2623 #endif
2624 }
2625
2626
2627 /* load build-in modules
2628  * very first version begun on 2007-07-23 by rgerhards
2629  */
2630 static rsRetVal loadBuildInModules(void)
2631 {
2632         DEFiRet;
2633
2634         if((iRet = module.doModInit(modInitFile, (uchar*) "builtin-file", NULL)) != RS_RET_OK) {
2635                 RETiRet;
2636         }
2637 #ifdef SYSLOG_INET
2638         if((iRet = module.doModInit(modInitFwd, (uchar*) "builtin-fwd", NULL)) != RS_RET_OK) {
2639                 RETiRet;
2640         }
2641 #endif
2642         if((iRet = module.doModInit(modInitShell, (uchar*) "builtin-shell", NULL)) != RS_RET_OK) {
2643                 RETiRet;
2644         }
2645         if((iRet = module.doModInit(modInitDiscard, (uchar*) "builtin-discard", NULL)) != RS_RET_OK) {
2646                 RETiRet;
2647         }
2648
2649         /* dirty, but this must be for the time being: the usrmsg module must always be
2650          * loaded as last module. This is because it processes any time of action selector.
2651          * If we load it before other modules, these others will never have a chance of
2652          * working with the config file. We may change that implementation so that a user name
2653          * must start with an alnum, that would definitely help (but would it break backwards
2654          * compatibility?). * rgerhards, 2007-07-23
2655          * User names now must begin with:
2656          *   [a-zA-Z0-9_.]
2657          */
2658         if((iRet = module.doModInit(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL)) != RS_RET_OK)
2659                 RETiRet;
2660
2661         /* ok, initialization of the command handler probably does not 100% belong right in
2662          * this space here. However, with the current design, this is actually quite a good
2663          * place to put it. We might decide to shuffle it around later, but for the time
2664          * being, the code has found its home here. A not-just-sideeffect of this decision
2665          * is that rsyslog will terminate if we can not register our built-in config commands.
2666          * This, I think, is the right thing to do. -- rgerhards, 2007-07-31
2667          */
2668         CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, NULL, &pszWorkDir, NULL));
2669         CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeretrycount", 0, eCmdHdlrInt, NULL, &glbliActionResumeRetryCount, NULL));
2670         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL));
2671         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL));
2672         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQHighWtrMark, NULL));
2673         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuelowwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQLowWtrMark, NULL));
2674         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardmark", 0, eCmdHdlrInt, NULL, &iMainMsgQDiscardMark, NULL));
2675         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardseverity", 0, eCmdHdlrSeverity, NULL, &iMainMsgQDiscardSeverity, NULL));
2676         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuecheckpointinterval", 0, eCmdHdlrInt, NULL, &iMainMsgQPersistUpdCnt, NULL));
2677         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetype", 0, eCmdHdlrGetWord, setMainMsgQueType, NULL, NULL));
2678         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreads", 0, eCmdHdlrInt, NULL, &iMainMsgQueueNumWorkers, NULL));
2679         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutshutdown", 0, eCmdHdlrInt, NULL, &iMainMsgQtoQShutdown, NULL));
2680         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutactioncompletion", 0, eCmdHdlrInt, NULL, &iMainMsgQtoActShutdown, NULL));
2681         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutenqueue", 0, eCmdHdlrInt, NULL, &iMainMsgQtoEnq, NULL));
2682         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworketimeoutrthreadshutdown", 0, eCmdHdlrInt, NULL, &iMainMsgQtoWrkShutdown, NULL));
2683         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeueslowdown", 0, eCmdHdlrInt, NULL, &iMainMsgQDeqSlowdown, NULL));
2684         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreadminimummessages", 0, eCmdHdlrInt, NULL, &iMainMsgQWrkMinMsgs, NULL));
2685         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxFileSize, NULL));
2686         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxDiskSpace, NULL));
2687         CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &bMainMsgQSaveOnShutdown, NULL));
2688         CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary, NULL, &bReduceRepeatMsgs, NULL));
2689         CHKiRet(regCfSysLineHdlr((uchar *)"actionexeconlywhenpreviousissuspended", 0, eCmdHdlrBinary, NULL, &bActExecWhenPrevSusp, NULL));
2690         CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL));
2691         CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL));
2692         CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL));
2693         CHKiRet(regCfSysLineHdlr((uchar *)"dropmsgswithmaliciousdnsptrrecords", 0, eCmdHdlrBinary, NULL, &bDropMalPTRMsgs, NULL));
2694         CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL));
2695         CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_TEMPLATE, NULL));
2696         CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL));
2697         CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_ALLOWEDSENDER, NULL));
2698         CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, conf.doModLoad, NULL, NULL));
2699         CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, conf.doIncludeLine, NULL, NULL));
2700         CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, setUmask, NULL, NULL));
2701         CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary, NULL, &bDebugPrintTemplateList, NULL));
2702         CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary, NULL, &bDebugPrintModuleList, NULL));
2703         CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary,
2704                  NULL, &bDebugPrintCfSysLineHandlerList, NULL));
2705         CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord, NULL, &pModDir, NULL));
2706         CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
2707
2708         /* now add other modules handlers (we should work on that to be able to do it in ClassInit(), but so far
2709          * that is not possible). -- rgerhards, 2008-01-28
2710          */
2711         CHKiRet(actionAddCfSysLineHdrl());
2712
2713 finalize_it:
2714         RETiRet;
2715 }
2716
2717
2718 /* print version and compile-time setting information.
2719  */
2720 static void printVersion(void)
2721 {
2722         printf("rsyslogd %s, ", VERSION);
2723         printf("compiled with:\n");
2724 #ifdef FEATURE_REGEXP
2725         printf("\tFEATURE_REGEXP:\t\t\t\tYes\n");
2726 #else
2727         printf("\tFEATURE_REGEXP:\t\t\t\tNo\n");
2728 #endif
2729 #ifndef NOLARGEFILE
2730         printf("\tFEATURE_LARGEFILE:\t\t\tYes\n");
2731 #else
2732         printf("\tFEATURE_LARGEFILE:\t\t\tNo\n");
2733 #endif
2734 #ifdef  USE_NETZIP
2735         printf("\tFEATURE_NETZIP (message compression):\tYes\n");
2736 #else
2737         printf("\tFEATURE_NETZIP (message compression):\tNo\n");
2738 #endif
2739 #if defined(SYSLOG_INET) && defined(USE_GSSAPI)
2740         printf("\tGSSAPI Kerberos 5 support:\t\tYes\n");
2741 #else
2742         printf("\tGSSAPI Kerberos 5 support:\t\tNo\n");
2743 #endif
2744 #ifndef NDEBUG
2745         printf("\tFEATURE_DEBUG (debug build, slow code):\tYes\n");
2746 #else
2747         printf("\tFEATURE_DEBUG (debug build, slow code):\tNo\n");
2748 #endif
2749 #ifdef  RTINST
2750         printf("\tRuntime Instrumentation (slow code):\tYes\n");
2751 #else
2752         printf("\tRuntime Instrumentation (slow code):\tNo\n");
2753 #endif
2754         printf("\nSee http://www.rsyslog.com for more information.\n");
2755 }
2756
2757
2758 /* This function is called after initial initalization. It is used to
2759  * move code out of the too-long main() function.
2760  * rgerhards, 2007-10-17
2761  */
2762 static void mainThread()
2763 {
2764         BEGINfunc
2765         uchar *pTmp;
2766
2767 #if 0 // code moved back to main()
2768         /* doing some core initializations */
2769         if((iRet = modInitIminternal()) != RS_RET_OK) {
2770                 fprintf(stderr, "fatal error: could not initialize errbuf object (error code %d).\n",
2771                         iRet);
2772                 exit(1); /* "good" exit, leaving at init for fatal error */
2773         }
2774
2775         if((iRet = loadBuildInModules()) != RS_RET_OK) {
2776                 fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n",
2777                         iRet);
2778                 exit(1); /* "good" exit, leaving at init for fatal error */
2779         }
2780 #endif
2781
2782         /* Note: signals MUST be processed by the thread this code is running in. The reason
2783          * is that we need to interrupt the select() system call. -- rgerhards, 2007-10-17
2784          */
2785
2786         /* initialize the build-in templates */
2787         pTmp = template_SyslogProtocol23Format;
2788         tplAddLine("RSYSLOG_SyslogProtocol23Format", &pTmp);
2789         pTmp = template_FileFormat; /* new format for files with high-precision stamp */
2790         tplAddLine("RSYSLOG_FileFormat", &pTmp);
2791         pTmp = template_TraditionalFileFormat;
2792         tplAddLine("RSYSLOG_TraditionalFileFormat", &pTmp);
2793         pTmp = template_WallFmt;
2794         tplAddLine(" WallFmt", &pTmp);
2795         pTmp = template_ForwardFormat;
2796         tplAddLine("RSYSLOG_ForwardFormat", &pTmp);
2797         pTmp = template_TraditionalForwardFormat;
2798         tplAddLine("RSYSLOG_TraditionalForwardFormat", &pTmp);
2799         pTmp = template_StdUsrMsgFmt;
2800         tplAddLine(" StdUsrMsgFmt", &pTmp);
2801         pTmp = template_StdDBFmt;
2802         tplAddLine(" StdDBFmt", &pTmp);
2803         pTmp = template_StdPgSQLFmt;
2804         tplLastStaticInit(tplAddLine(" StdPgSQLFmt", &pTmp));
2805
2806         dbgprintf("Starting.\n");
2807         init();
2808         if(Debug) {
2809                 dbgprintf("Debugging enabled, SIGUSR1 to turn off debugging.\n");
2810                 debugging_on = 1;
2811         }
2812         /* Send a signal to the parent so it can terminate.
2813          */
2814         if (myPid != ppid)
2815                 kill (ppid, SIGTERM);
2816
2817         /* END OF INTIALIZATION
2818          * ... but keep in mind that we might do a restart and thus init() might
2819          * be called again. If that happens, we must shut down the worker thread,
2820          * do the init() and then restart things.
2821          * rgerhards, 2005-10-24
2822          */
2823
2824         mainloop();
2825         ENDfunc
2826 }
2827
2828
2829 /* Method to initialize all global classes.
2830  * rgerhards, 2008-01-04
2831  */
2832 static rsRetVal
2833 InitGlobalClasses(void)
2834 {
2835         DEFiRet;
2836         char *pErrObj; /* tells us which object failed if that happens (useful for troubleshooting!) */
2837
2838         pErrObj = "obj";
2839         CHKiRet(objClassInit(NULL)); /* *THIS* *MUST* always be the first class initilizer being called! */
2840         CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */
2841         /* the following classes were intialized by objClassInit() */
2842         pErrObj = "errmsg";
2843         CHKiRet(objUse(errmsg,   CORE_COMPONENT));
2844         pErrObj = "module";
2845         CHKiRet(objUse(module,   CORE_COMPONENT));
2846         pErrObj = "var";
2847         CHKiRet(objUse(var,      CORE_COMPONENT));
2848
2849         /* initialize and use classes. We must be very careful with the order of events. Some
2850          * classes use others and if we do not initialize them in the right order, we may end
2851          * up with an invalid call. The most important thing that can happen is that an error
2852          * is detected and needs to be logged, wich in turn requires a broader number of classes
2853          * to be available. The solution is that we take care in the order of calls AND use a
2854          * class immediately after it is initialized. And, of course, we load those classes
2855          * first that we use ourselfs... -- rgerhards, 2008-03-07
2856          */
2857         pErrObj = "datetime";
2858         CHKiRet(datetimeClassInit(NULL));
2859         CHKiRet(objUse(datetime, CORE_COMPONENT));
2860         pErrObj = "msg";
2861         CHKiRet(msgClassInit(NULL));
2862         pErrObj = "str,";
2863         CHKiRet(strmClassInit(NULL));
2864         pErrObj = "wti";
2865         CHKiRet(wtiClassInit(NULL));
2866         pErrObj = "wtp";
2867         CHKiRet(wtpClassInit(NULL));
2868         pErrObj = "queue";
2869         CHKiRet(queueClassInit(NULL));
2870         pErrObj = "vmstk";
2871         CHKiRet(vmstkClassInit(NULL));
2872         pErrObj = "sysvar";
2873         CHKiRet(sysvarClassInit(NULL));
2874         pErrObj = "vm";
2875         CHKiRet(vmClassInit(NULL));
2876         CHKiRet(objUse(vm,       CORE_COMPONENT));
2877         pErrObj = "vmop";
2878         CHKiRet(vmopClassInit(NULL));
2879         pErrObj = "vmprg";
2880         CHKiRet(vmprgClassInit(NULL));
2881         pErrObj = "ctok_token";
2882         CHKiRet(ctok_tokenClassInit(NULL));
2883         pErrObj = "ctok";
2884         CHKiRet(ctokClassInit(NULL));
2885         pErrObj = "expr";
2886         CHKiRet(exprClassInit(NULL));
2887         CHKiRet(objUse(expr,     CORE_COMPONENT));
2888         pErrObj = "conf";
2889         CHKiRet(confClassInit(NULL));
2890         CHKiRet(objUse(conf,     CORE_COMPONENT));
2891
2892         /* dummy "classes" */
2893         pErrObj = "action";
2894         CHKiRet(actionClassInit());
2895         pErrObj = "template";
2896         CHKiRet(templateInit());
2897         pErrObj = "str";
2898         CHKiRet(strInit());
2899
2900         /* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */
2901         pErrObj = "net";
2902         CHKiRet(objUse(net, LM_NET_FILENAME));
2903
2904 finalize_it:
2905         if(iRet != RS_RET_OK) {
2906                 /* we know we are inside the init sequence, so we can safely emit
2907                  * messages to stderr. -- rgerhards, 2008-04-02
2908                  */
2909                 fprintf(stderr, "Error during class init for object '%s' - failing...\n", pErrObj);
2910         }
2911
2912         RETiRet;
2913 }
2914
2915
2916 /* Method to exit all global classes. We do not do any error checking here,
2917  * because that wouldn't help us at all. So better try to deinit blindly
2918  * as much as succeeds (which usually means everything will). We just must
2919  * be careful to do the de-init in the opposite order of the init, because
2920  * of the dependencies. However, its not as important this time, because
2921  * we have reference counting.
2922  * rgerhards, 2008-03-10
2923  */
2924 static rsRetVal
2925 GlobalClassExit(void)
2926 {
2927         DEFiRet;
2928
2929         /* first, release everything we used ourself */
2930         objRelease(net,      LM_NET_FILENAME);/* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */
2931         objRelease(conf,     CORE_COMPONENT);
2932         objRelease(expr,     CORE_COMPONENT);
2933         objRelease(vm,       CORE_COMPONENT);
2934         objRelease(var,      CORE_COMPONENT);
2935         objRelease(datetime, CORE_COMPONENT);
2936
2937         /* TODO: implement the rest of the deinit */
2938         confClassExit();
2939 #if 0
2940         CHKiRet(datetimeClassInit(NULL));
2941         CHKiRet(msgClassInit(NULL));
2942         CHKiRet(strmClassInit(NULL));
2943         CHKiRet(wtiClassInit(NULL));
2944         CHKiRet(wtpClassInit(NULL));
2945         CHKiRet(queueClassInit(NULL));
2946         CHKiRet(vmstkClassInit(NULL));
2947         CHKiRet(sysvarClassInit(NULL));
2948         CHKiRet(vmClassInit(NULL));
2949         CHKiRet(vmopClassInit(NULL));
2950         CHKiRet(vmprgClassInit(NULL));
2951         CHKiRet(ctok_tokenClassInit(NULL));
2952         CHKiRet(ctokClassInit(NULL));
2953         CHKiRet(exprClassInit(NULL));
2954
2955         /* dummy "classes" */
2956         CHKiRet(actionClassInit());
2957         CHKiRet(templateInit());
2958 #endif
2959         /* dummy "classes */
2960         strExit();
2961
2962 #if 0
2963         CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */
2964         /* the following classes were intialized by objClassInit() */
2965         CHKiRet(objUse(errmsg,   CORE_COMPONENT));
2966         CHKiRet(objUse(module,   CORE_COMPONENT));
2967 #endif
2968         objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */
2969
2970         RETiRet;
2971 }
2972
2973
2974
2975 /* This is the main entry point into rsyslogd. Over time, we should try to
2976  * modularize it a bit more...
2977  */
2978 int realMain(int argc, char **argv)
2979 {       
2980         DEFiRet;
2981
2982         register int i;
2983         register char *p;
2984         int num_fds;
2985         int ch;
2986         struct hostent *hent;
2987         extern int optind;
2988         extern char *optarg;
2989         struct sigaction sigAct;
2990         int bIsFirstOption = 1;
2991         int bEOptionWasGiven = 0;
2992         int bImUxSockLoaded = 0; /* already generated a $ModLoad imuxsock? */
2993         uchar legacyConfLine[80];
2994
2995         gethostname(LocalHostName, sizeof(LocalHostName));
2996         if ( (p = strchr(LocalHostName, '.')) ) {
2997                 *p++ = '\0';
2998                 LocalDomain = p;
2999         }
3000         else
3001         {
3002                 LocalDomain = "";
3003
3004                 /* It's not clearly defined whether gethostname()
3005                  * should return the simple hostname or the fqdn. A
3006                  * good piece of software should be aware of both and
3007                  * we want to distribute good software.  Joey
3008                  *
3009                  * Good software also always checks its return values...
3010                  * If syslogd starts up before DNS is up & /etc/hosts
3011                  * doesn't have LocalHostName listed, gethostbyname will
3012                  * return NULL. 
3013                  */
3014                 /* TODO: gethostbyname() is not thread-safe, but replacing it is
3015                  * not urgent as we do not run on multiple threads here. rgerhards, 2007-09-25
3016                  */
3017                 hent = gethostbyname(LocalHostName);
3018                 if(hent) {
3019                         snprintf(LocalHostName, sizeof(LocalHostName), "%s", hent->h_name);
3020                                 
3021                         if ( (p = strchr(LocalHostName, '.')) )
3022                         {
3023                                 *p++ = '\0';
3024                                 LocalDomain = p;
3025                         }
3026                 }
3027         }
3028
3029         /* Convert to lower case to recognize the correct domain laterly
3030          */
3031         for (p = (char *)LocalDomain; *p ; p++)
3032                 if (isupper((int) *p))
3033                         *p = (char)tolower((int)*p);
3034
3035         CHKiRet_Hdlr(InitGlobalClasses()) {
3036                 fprintf(stderr, "rsyslogd initializiation failed - global classes could not be initialized.\n"
3037                                 "Did you do a \"make install\"?\n"
3038                                 "Suggested action: run rsyslogd with -d -n options to see what exactly "
3039                                 "fails.\n");
3040                 FINALIZE;
3041         }
3042
3043         /* doing some core initializations */
3044         if((iRet = modInitIminternal()) != RS_RET_OK) {
3045                 fprintf(stderr, "fatal error: could not initialize errbuf object (error code %d).\n",
3046                         iRet);
3047                 exit(1); /* "good" exit, leaving at init for fatal error */
3048         }
3049
3050         if((iRet = loadBuildInModules()) != RS_RET_OK) {
3051                 fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n",
3052                         iRet);
3053                 exit(1); /* "good" exit, leaving at init for fatal error */
3054         }
3055
3056         ppid = getpid();
3057
3058         if(chdir ("/") != 0)
3059                 fprintf(stderr, "Can not do 'cd /' - still trying to run\n");
3060
3061         /* END core initializations */
3062
3063         while ((ch = getopt(argc, argv, "46aAc:def:g:hi:l:m:M:nopqQr::s:t:u:vwx")) != EOF) {
3064                 switch((char)ch) {
3065                 case '4':
3066                         family = PF_INET;
3067                         break;
3068                 case '6':
3069                         family = PF_INET6;
3070                         break;
3071                 case 'A':
3072                         send_to_all++;
3073                         break;
3074                 case 'a':
3075                         if(iCompatibilityMode < 3) {
3076                                 if(!bImUxSockLoaded) {
3077                                         legacyOptsEnq((uchar *) "ModLoad imuxsock");
3078                                         bImUxSockLoaded = 1;
3079                                 }
3080                                 snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "addunixlistensocket %s", optarg);
3081                                 legacyOptsEnq(legacyConfLine);
3082                         } else {
3083                                 fprintf(stderr, "error -a is no longer supported, use module imuxsock instead");
3084                         }
3085                         break;
3086                 case 'c':               /* compatibility mode */
3087                         if(!bIsFirstOption) {
3088                                 fprintf(stderr, "-c option MUST be specified as the first option - aborting...\n");
3089                                 usage();
3090                                 exit(1);
3091                         }
3092                         iCompatibilityMode = atoi(optarg);
3093                         break;
3094                 case 'd':               /* debug */
3095                         Debug = 1;
3096                         break;
3097                 case 'e':               /* log every message (no repeat message supression) */
3098                         fprintf(stderr, "note: -e option is no longer supported, every message is now logged by default\n");
3099                         bEOptionWasGiven = 1;
3100                         break;
3101                 case 'f':               /* configuration file */
3102                         ConfFile = (uchar*) optarg;
3103                         break;
3104                 case 'g':               /* enable tcp gssapi logging */
3105 #if defined(SYSLOG_INET) && defined(USE_GSSAPI)
3106                         if(iCompatibilityMode < 3) {
3107                                 legacyOptsParseTCP(ch, optarg);
3108                         } else
3109                                 fprintf(stderr, "-g option only supported in compatibility modes 0 to 2 - ignored\n");
3110 #else
3111                         fprintf(stderr, "rsyslogd: -g not valid - not compiled with gssapi support");
3112 #endif
3113                         break;
3114                 case 'h':
3115                         if(iCompatibilityMode < 3) {
3116                                 errmsg.LogError(NO_ERRCODE, "WARNING: -h option is no longer supported - ignored");
3117                         } else {
3118                                 usage(); /* for v3 and above, it simply is an error */
3119                         }
3120                         break;
3121                 case 'i':               /* pid file name */
3122                         PidFile = optarg;
3123                         break;
3124                 case 'l':
3125                         if (LocalHosts) {
3126                                 fprintf (stderr, "rsyslogd: Only one -l argument allowed, the first one is taken.\n");
3127                         } else {
3128                                 LocalHosts = crunch_list(optarg);
3129                         }
3130                         break;
3131                 case 'm':               /* mark interval */
3132                         if(iCompatibilityMode < 3) {
3133                                 MarkInterval = atoi(optarg) * 60;
3134                         } else
3135                                 fprintf(stderr,
3136                                         "-m option only supported in compatibility modes 0 to 2 - ignored\n");
3137                         break;
3138                 case 'M': /* default module load path */
3139                         module.SetModDir((uchar*)optarg);
3140                         break;
3141                 case 'n':               /* don't fork */
3142                         NoFork = 1;
3143                         break;
3144                 case 'o':
3145                         if(iCompatibilityMode < 3) {
3146                                 if(!bImUxSockLoaded) {
3147                                         legacyOptsEnq((uchar *) "ModLoad imuxsock");
3148                                         bImUxSockLoaded = 1;
3149                                 }
3150                                 legacyOptsEnq((uchar *) "OmitLocalLogging");
3151                         } else {
3152                                 fprintf(stderr, "error -o is no longer supported, use module imuxsock instead");
3153                         }
3154                         break;
3155                 case 'p':
3156                         if(iCompatibilityMode < 3) {
3157                                 if(!bImUxSockLoaded) {
3158                                         legacyOptsEnq((uchar *) "ModLoad imuxsock");
3159                                         bImUxSockLoaded = 1;
3160                                 }
3161                                 snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "SystemLogSocketName %s", optarg);
3162                                 legacyOptsEnq(legacyConfLine);
3163                         } else {
3164                                 fprintf(stderr, "error -p is no longer supported, use module imuxsock instead");
3165                         }
3166                 case 'q':               /* add hostname if DNS resolving has failed */
3167                         *net.pACLAddHostnameOnFail = 1;
3168                         break;
3169                 case 'Q':               /* dont resolve hostnames in ACL to IPs */
3170                         *net.pACLDontResolve = 1;
3171                         break;
3172                 case 'r':               /* accept remote messages */
3173 #ifdef SYSLOG_INET
3174                         if(iCompatibilityMode < 3) {
3175                                 legacyOptsEnq((uchar *) "ModLoad imudp");
3176                                 snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "UDPServerRun %s", optarg);
3177                                 legacyOptsEnq(legacyConfLine);
3178                         } else
3179                                 fprintf(stderr,
3180                                         "-r option only supported in compatibility modes 0 to 2 - ignored\n");
3181 #else
3182                         fprintf(stderr, "rsyslogd: -r not valid - not compiled with network support\n");
3183 #endif
3184                         break;
3185                 case 's':
3186                         if (StripDomains) {
3187                                 fprintf (stderr, "rsyslogd: Only one -s argument allowed, the first one is taken.\n");
3188                         } else {
3189                                 StripDomains = crunch_list(optarg);
3190                         }
3191                         break;
3192                 case 't':               /* enable tcp logging */
3193 #ifdef SYSLOG_INET
3194                         if(iCompatibilityMode < 3) {
3195                                 legacyOptsParseTCP(ch, optarg);
3196                         } else
3197                                 fprintf(stderr, "-t option only supported in compatibility modes 0 to 2 - ignored\n");
3198 #else
3199                         fprintf(stderr, "rsyslogd: -t not valid - not compiled with network support\n");
3200 #endif
3201                         break;
3202                 case 'u':               /* misc user settings */
3203                         if(atoi(optarg) == 1)
3204                                 bParseHOSTNAMEandTAG = 0;
3205                         break;
3206                 case 'v':
3207                         printVersion();
3208                         exit(0); /* exit for -v option - so this is a "good one" */
3209                 case 'w':               /* disable disallowed host warnigs */
3210                         option_DisallowWarning = 0;
3211                         break;
3212                 case 'x':               /* disable dns for remote messages */
3213                         DisableDNS = 1;
3214                         break;
3215                 case '?':              
3216                 default:
3217                         usage();
3218                 }
3219                 bIsFirstOption = 0; /* we already saw an option character */
3220         }
3221
3222         if ((argc -= optind))
3223                 usage();
3224
3225         /* TODO: this should go away at a reasonable stage of v3 development.
3226          * rgerhards, 2007-12-19
3227          */
3228         if(iCompatibilityMode < 3) {
3229                 errmsg.LogError(NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically "
3230                                             "generated config directives may interfer with your rsyslog.conf settings. "
3231                                             "We suggest upgrading your config and adding -c3 as the first "
3232                                             "rsyslogd option.");
3233                 if(MarkInterval > 0) {
3234                         legacyOptsEnq((uchar *) "ModLoad immark");
3235                         snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "MarkMessagePeriod %d", MarkInterval);
3236                         legacyOptsEnq(legacyConfLine);
3237                 }
3238                 if(!bImUxSockLoaded) {
3239                         legacyOptsEnq((uchar *) "ModLoad imuxsock");
3240                 }
3241         }
3242
3243         if(bEOptionWasGiven && iCompatibilityMode < 3) {
3244                 errmsg.LogError(NO_ERRCODE, "WARNING: \"message repeated n times\" feature MUST be turned on in "
3245                                             "rsyslog.conf - CURRENTLY EVERY MESSAGE WILL BE LOGGED. Visit "
3246                                             "http://www.rsyslog.com/rptdmsgreduction to learn "
3247                                             "more and cast your vote if you want us to keep this feature.");
3248         }
3249
3250         checkPermissions();
3251         thrdInit();
3252
3253         if ( !(Debug || NoFork) )
3254         {
3255                 dbgprintf("Checking pidfile.\n");
3256                 if (!check_pid(PidFile))
3257                 {
3258                         memset(&sigAct, 0, sizeof (sigAct));
3259                         sigemptyset(&sigAct.sa_mask);
3260                         sigAct.sa_handler = doexit;
3261                         sigaction(SIGTERM, &sigAct, NULL);
3262
3263                         if (fork()) {
3264                                 /*
3265                                  * Parent process
3266                                  */
3267                                 sleep(300);
3268                                 /*
3269                                  * Not reached unless something major went wrong.  5
3270                                  * minutes should be a fair amount of time to wait.
3271                                  * Please note that this procedure is important since
3272                                  * the father must not exit before syslogd isn't
3273                                  * initialized or the klogd won't be able to flush its
3274                                  * logs.  -Joey
3275                                  */
3276                                 exit(1); /* "good" exit - after forking, not diasabling anything */
3277                         }
3278                         num_fds = getdtablesize();
3279                         for (i= 0; i < num_fds; i++)
3280                                 (void) close(i);
3281                         untty();
3282                 }
3283                 else
3284                 {
3285                         fputs(" Already running.\n", stderr);
3286                         exit(1); /* "good" exit, done if syslogd is already running */
3287                 }
3288         }
3289         else
3290                 debugging_on = 1;
3291
3292         dbgprintf("Compatibility Mode: %d\n", iCompatibilityMode);
3293
3294         /* tuck my process id away */
3295         dbgprintf("Writing pidfile %s.\n", PidFile);
3296         if (!check_pid(PidFile))
3297         {
3298                 if (!write_pid(PidFile))
3299                 {
3300                         fputs("Can't write pid.\n", stderr);
3301                         exit(1); /* exit during startup - questionable */
3302                 }
3303         }
3304         else
3305         {
3306                 fputs("Pidfile (and pid) already exist.\n", stderr);
3307                 exit(1); /* exit during startup - questionable */
3308         }
3309         myPid = getpid();       /* save our pid for further testing (also used for messages) */
3310
3311         memset(&sigAct, 0, sizeof (sigAct));
3312         sigemptyset(&sigAct.sa_mask);
3313
3314         sigAct.sa_handler = sigsegvHdlr;
3315         sigaction(SIGSEGV, &sigAct, NULL);
3316         sigAct.sa_handler = sigsegvHdlr;
3317         sigaction(SIGABRT, &sigAct, NULL);
3318         sigAct.sa_handler = doDie;
3319         sigaction(SIGTERM, &sigAct, NULL);
3320         sigAct.sa_handler = Debug ? doDie : SIG_IGN;
3321         sigaction(SIGINT, &sigAct, NULL);
3322         sigaction(SIGQUIT, &sigAct, NULL);
3323         sigAct.sa_handler = reapchild;
3324         sigaction(SIGCHLD, &sigAct, NULL);
3325         sigAct.sa_handler = Debug ? debug_switch : SIG_IGN;
3326         sigaction(SIGUSR1, &sigAct, NULL);
3327         sigAct.sa_handler = SIG_IGN;
3328         sigaction(SIGPIPE, &sigAct, NULL);
3329         sigaction(SIGXFSZ, &sigAct, NULL); /* do not abort if 2gig file limit is hit */
3330
3331         mainThread();
3332
3333         /* do any de-init's that need to be done AFTER this comment */
3334
3335         die(bFinished);
3336         
3337         thrdExit();
3338
3339 finalize_it:
3340         if(iRet != RS_RET_OK)
3341                 fprintf(stderr, "rsyslogd run failed with error %d\n(see rsyslog.h "
3342                                 "or http://www.rsyslog.com/errcode to learn what that number means)\n", iRet);
3343
3344         ENDfunc
3345         return 0;
3346 }
3347
3348
3349 /* This is the main entry point into rsyslogd. This must be a function in its own
3350  * right in order to intialize the debug system in a portable way (otherwise we would
3351  * need to have a statement before variable definitions.
3352  * rgerhards, 20080-01-28
3353  */
3354 int main(int argc, char **argv)
3355 {       
3356         dbgClassInit();
3357         return realMain(argc, argv);
3358 }
3359
3360 /* vim:set ai:
3361  */