1 /* rsyslog.c - the main entry point into rsyslog's runtime library (RTL)
2  *
3  * This module contains all function which work on a RTL global level. It's
4  * name is abbreviated to "rsrt" (rsyslog runtime).
5  *
6  * Please note that the runtime library tends to be plugin-safe. That is, it must be
7  * initialized by calling a global initialization function. However, that
8  * function checks if the library is already initialized and, if so, does
9  * nothing except incrementing a refeence count. Similarly, the deinit
10  * function does nothing as long as there are still other users (which
11  * is tracked via the refcount). As such, it is safe to call init and
12  * exit multiple times, as long as this are always matching calls. This
13  * capability is needed for a plugin system, where one plugin never
14  * knows what the other did. HOWEVER, as of this writing, not all runtime
15  * library objects may work cleanly without static global data (the
16  * debug system is a very good example of this). So while we aim at the
17  * ability to work well in a plugin environment, things may not really work
18  * out. If you intend to use the rsyslog runtime library inside plugins,
19  * you should investigate the situation in detail. Please note that the
20  * rsyslog project itself does not yet need this functionality - thus you
21  * can safely assume it is totally untested ;).
22  *
23  * rgerhards, 2008-04-17: I have now once again checked on the plugin-safety.
24  * Unfortunately, there is currently no hook at all with which we could
25  * abstract a global data instance class. As such, we can NOT make the
26  * runtime plugin-safe in the above-described sense. As the rsyslog
27  * project itself does not need this functionality (and it is quesationable
28  * if someone else ever will), we do currently do not make an effort to
29  * support it. So if you intend to use rsyslog runtime inside a non-rsyslog
30  * plugin system, be careful!
31  *
32  * The rsyslog runtime library is in general reentrant and thread-safe. There
33  * are some intentional exceptions (e.g. inside the msg object). These are
34  * documented. Any other threading and reentrency issue can be considered a bug.
35  *
36  * Module begun 2008-04-16 by Rainer Gerhards
37  *
38  * Copyright 2008-2016 Rainer Gerhards and Adiscon GmbH.
39  *
40  * This file is part of the rsyslog runtime library.
41  *
42  * The rsyslog runtime library is free software: you can redistribute it and/or modify
43  * it under the terms of the GNU Lesser General Public License as published by
44  * the Free Software Foundation, either version 3 of the License, or
45  * (at your option) any later version.
46  *
47  * The rsyslog runtime library is distributed in the hope that it will be useful,
48  * but WITHOUT ANY WARRANTY; without even the implied warranty of
49  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
50  * GNU Lesser General Public License for more details.
51  *
52  * You should have received a copy of the GNU Lesser General Public License
53  * along with the rsyslog runtime library.  If not, see <http://www.gnu.org/licenses/>.
54  *
55  * A copy of the GPL can be found in the file "COPYING" in this distribution.
56  * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
57  */
58 #include "config.h"
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <assert.h>
62 #ifdef ENABLE_LIBLOGGING_STDLOG
63 #include <liblogging/stdlog.h>
64 #endif
65 
66 #include "rsyslog.h"
67 #include "obj.h"
68 #include "stringbuf.h"
69 #include "wti.h"
70 #include "wtp.h"
71 #include "datetime.h"
72 #include "queue.h"
73 #include "conf.h"
74 #include "rsconf.h"
75 #include "glbl.h"
76 #include "errmsg.h"
77 #include "prop.h"
78 #include "ruleset.h"
79 #include "parser.h"
80 #include "lookup.h"
81 #include "strgen.h"
82 #include "statsobj.h"
83 #include "atomic.h"
84 #include "srUtils.h"
85 
86 pthread_attr_t default_thread_attr;
87 #ifdef HAVE_PTHREAD_SETSCHEDPARAM
88 struct sched_param default_sched_param;
89 int default_thr_sched_policy;
90 #endif
91 
92 /* globally visible static data - see comment in rsyslog.h for details */
93 uchar *glblModPath; /* module load path */
94 void (*glblErrLogger)(const int, const int, const uchar*) = dfltErrLogger;
95 /* the error logger to use by the errmsg module */
96 
97 /* static data */
98 static int iRefCount = 0; /* our refcount - it MUST exist only once inside a process (not thread)
99 			thus it is perfectly OK to use a static. MUST be initialized to 0! */
100 
101 /* This is the default instance of the error logger. It simply writes the message
102  * to stderr. It is expected that this is replaced by the runtime user very early
103  * during startup (at least if the default is unsuitable). However, we provide a
104  * default so that we can log errors during the intial phase, most importantly
105  * during initialization. -- rgerhards. 2008-04-17
106  */
107 void
dfltErrLogger(const int severity,const int iErr,const uchar * errMsg)108 dfltErrLogger(const int severity, const int iErr, const uchar *errMsg)
109 {
110 	fprintf(stderr, "rsyslog internal message (%d,%d): %s\n", severity, iErr, errMsg);
111 }
112 
113 
114 /* set the error log function
115  * rgerhards, 2008-04-18
116  */
117 void
rsrtSetErrLogger(void (* errLogger)(const int,const int,const uchar *))118 rsrtSetErrLogger(void (*errLogger)(const int, const int, const uchar*))
119 {
120 	assert(errLogger != NULL);
121 	glblErrLogger = errLogger;
122 }
123 
124 
125 /* globally initialze the runtime system
126  * NOTE: this is NOT thread safe and must not be called concurrently. If that
127  * ever poses a problem, we may use proper mutex calls - not considered needed yet.
128  * If ppErrObj is provided, it receives a char pointer to the name of the object that
129  * caused the problem (if one occured). The caller must never free this pointer. If
130  * ppErrObj is NULL, no such information will be provided. pObjIF is the pointer to
131  * the "obj" object interface, which may be used to query any other rsyslog objects.
132  * rgerhards, 2008-04-16
133  */
134 rsRetVal
rsrtInit(const char ** ppErrObj,obj_if_t * pObjIF)135 rsrtInit(const char **ppErrObj, obj_if_t *pObjIF)
136 {
137 	DEFiRet;
138 	int ret;
139 	char errstr[1024];
140 
141 	if(iRefCount == 0) {
142 		seedRandomNumber();
143 		/* init runtime only if not yet done */
144 #ifdef ENABLE_LIBLOGGING_STDLOG
145 		stdlog_init(0);
146 		stdlog_hdl = stdlog_open("rsyslogd", 0, STDLOG_SYSLOG, NULL);
147 #endif
148 		ret = pthread_attr_init(&default_thread_attr);
149 		if(ret != 0) {
150 			rs_strerror_r(ret, errstr, sizeof(errstr));
151 			fprintf(stderr, "rsyslogd: pthread_attr_init failed during "
152 				"startup - can not continue. Error was %s\n", errstr);
153 			exit(1);
154 		}
155 		pthread_attr_setstacksize(&default_thread_attr, 4096*1024);
156 #ifdef HAVE_PTHREAD_SETSCHEDPARAM
157 		ret = pthread_getschedparam(pthread_self(), &default_thr_sched_policy,
158 			&default_sched_param);
159 		if(ret != 0) {
160 			rs_strerror_r(ret, errstr, sizeof(errstr));
161 			fprintf(stderr, "rsyslogd: pthread_getschedparam failed during "
162 				"startup - ignoring. Error was %s\n", errstr);
163 			default_thr_sched_policy = 0; /* should be default on all platforms */
164 		}
165 #if defined (_AIX)
166 		pthread_attr_setstacksize(&default_thread_attr, 4096*512);
167 #endif
168 
169 
170 		ret = pthread_attr_setschedpolicy(&default_thread_attr, default_thr_sched_policy);
171 		if(ret != 0) {
172 			rs_strerror_r(ret, errstr, sizeof(errstr));
173 			fprintf(stderr, "rsyslogd: pthread_attr_setschedpolicy failed during "
174 				"startup - tried to set priority %d, now using default "
175 				"priority instead. Error was: %s\n",
176 				default_thr_sched_policy, errstr);
177 		}
178 		ret = pthread_attr_setschedparam(&default_thread_attr, &default_sched_param);
179 		if(ret != 0) {
180 			rs_strerror_r(ret, errstr, sizeof(errstr));
181 			fprintf(stderr, "rsyslogd: pthread_attr_setschedparam failed during "
182 				"startup - ignored Error was: %s\n", errstr);
183 		}
184 		ret = pthread_attr_setinheritsched(&default_thread_attr, PTHREAD_EXPLICIT_SCHED);
185 		if(ret != 0) {
186 			rs_strerror_r(ret, errstr, sizeof(errstr));
187 			fprintf(stderr, "rsyslogd: pthread_attr_setinheritsched failed during "
188 				"startup - ignoring. Error was: %s\n", errstr);
189 		}
190 #endif
191 		if(ppErrObj != NULL) *ppErrObj = "obj";
192 		CHKiRet(objClassInit(NULL)); /* *THIS* *MUST* always be the first class initilizer being called! */
193 		CHKiRet(objGetObjInterface(pObjIF)); /* this provides the root pointer for all other queries */
194 
195 		/* initialize core classes. We must be very careful with the order of events. Some
196 		 * classes use others and if we do not initialize them in the right order, we may end
197 		 * up with an invalid call. The most important thing that can happen is that an error
198 		 * is detected and needs to be logged, wich in turn requires a broader number of classes
199 		 * to be available. The solution is that we take care in the order of calls AND use a
200 		 * class immediately after it is initialized. And, of course, we load those classes
201 		 * first that we use ourselfs... -- rgerhards, 2008-03-07
202 		 */
203 		if(ppErrObj != NULL) *ppErrObj = "statsobj";
204 		CHKiRet(statsobjClassInit(NULL));
205 		if(ppErrObj != NULL) *ppErrObj = "prop";
206 		CHKiRet(propClassInit(NULL));
207 		if(ppErrObj != NULL) *ppErrObj = "glbl";
208 		CHKiRet(glblClassInit(NULL));
209 		if(ppErrObj != NULL) *ppErrObj = "msg";
210 		CHKiRet(msgClassInit(NULL));
211 		if(ppErrObj != NULL) *ppErrObj = "ruleset";
212 		CHKiRet(rulesetClassInit(NULL));
213 		if(ppErrObj != NULL) *ppErrObj = "wti";
214 		CHKiRet(wtiClassInit(NULL));
215 		if(ppErrObj != NULL) *ppErrObj = "wtp";
216 		CHKiRet(wtpClassInit(NULL));
217 		if(ppErrObj != NULL) *ppErrObj = "queue";
218 		CHKiRet(qqueueClassInit(NULL));
219 		if(ppErrObj != NULL) *ppErrObj = "conf";
220 		CHKiRet(confClassInit(NULL));
221 		if(ppErrObj != NULL) *ppErrObj = "parser";
222 		CHKiRet(parserClassInit(NULL));
223 		if(ppErrObj != NULL) *ppErrObj = "strgen";
224 		CHKiRet(strgenClassInit(NULL));
225 		if(ppErrObj != NULL) *ppErrObj = "rsconf";
226 		CHKiRet(rsconfClassInit(NULL));
227 		if(ppErrObj != NULL) *ppErrObj = "lookup";
228 		CHKiRet(lookupClassInit());
229 		if(ppErrObj != NULL) *ppErrObj = "dynstats";
230 		CHKiRet(dynstatsClassInit());
231 		if(ppErrObj != NULL) *ppErrObj = "perctile_stats";
232 		CHKiRet(perctileClassInit());
233 
234 		/* dummy "classes" */
235 		if(ppErrObj != NULL) *ppErrObj = "str";
236 		CHKiRet(strInit());
237 	}
238 
239 	++iRefCount;
240 	dbgprintf("rsyslog runtime initialized, version %s, current users %d\n", VERSION, iRefCount);
241 
242 finalize_it:
243 	RETiRet;
244 }
245 
246 
247 /* globally de-initialze the runtime system
248  * NOTE: this is NOT thread safe and must not be called concurrently. If that
249  * ever poses a problem, we may use proper mutex calls - not considered needed yet.
250  * This function must be provided with the caller's obj object pointer. This is
251  * automatically deinitialized by the runtime system.
252  * rgerhards, 2008-04-16
253  */
254 rsRetVal
rsrtExit(void)255 rsrtExit(void)
256 {
257 	DEFiRet;
258 
259 	if(iRefCount == 1) {
260 		/* do actual de-init only if we are the last runtime user */
261 		confClassExit();
262 		glblClassExit();
263 		rulesetClassExit();
264 		wtiClassExit();
265 		wtpClassExit();
266 		strgenClassExit();
267 		propClassExit();
268 		statsobjClassExit();
269 
270 		objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being
271 				called (except debug)! */
272 	}
273 
274 	--iRefCount;
275 	/* TODO we must deinit this pointer! pObjIF = NULL; / * no longer exists for this caller */
276 
277 	dbgprintf("rsyslog runtime de-initialized, current users %d\n", iRefCount);
278 
279 	RETiRet;
280 }
281 
282 
283 /* returns 0 if the rsyslog runtime is not initialized and another value
284  * if it is. This function is primarily meant to be used by runtime functions
285  * itself. However, it is safe to call it before initializing the runtime.
286  * Plugins should NOT rely on this function. The reason is that another caller
287  * may have already initialized it but deinits it before this plugin is done.
288  * So for plugins and like architectures, the right course of action is to
289  * call rsrtInit() and rsrtExit(), which can be called by multiple callers.
290  * rgerhards, 2008-04-16
291  */
rsrtIsInit(void)292 int rsrtIsInit(void)
293 {
294 	return iRefCount;
295 }
296 
297 
298 /* vim:set ai:
299  */
300