1 static const char version[] = "$Id: init.c,v 1.22 2013/09/29 17:50:09 valtri Exp $";
2 
3 /*
4  * init.c
5  *
6  * Copyright 2001-2003, Meiosys (www.meiosys.com). All rights reserved.
7  *
8  * See the COPYING file for the terms of usage and distribution.
9  */
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13 
14 #include <log4c/init.h>
15 #include <log4c/category.h>
16 #include <log4c/appender.h>
17 #include <log4c/layout.h>
18 #include <log4c/rollingpolicy.h>
19 #include <log4c/rc.h>
20 #include <sd/error.h>
21 #include <sd/sprintf.h>
22 #include <sd/factory.h>
23 #include <sd/sd_xplatform.h>
24 #include <stdlib.h>
25 
26 #include <appender_type_stream.h>
27 #include <appender_type_stream2.h>
28 #include <appender_type_syslog.h>
29 #include <appender_type_mmap.h>
30 #include <appender_type_rollingfile.h>
31 #include <rollingpolicy_type_sizewin.h>
32 #include <layout_type_basic.h>
33 #include <layout_type_dated.h>
34 #include <layout_type_dated_local.h>
35 #include <layout_type_basic_r.h>
36 #include <layout_type_dated_r.h>
37 #include <layout_type_dated_local_r.h>
38 
39 #if defined(__LOG4C_DEBUG__) && defined(__GLIBC__)
40 #include <mcheck.h>
41 #endif
42 
43 static const log4c_layout_type_t * const layout_types[] = {
44     &log4c_layout_type_basic,
45     &log4c_layout_type_dated,
46     &log4c_layout_type_dated_local,
47     &log4c_layout_type_basic_r,
48     &log4c_layout_type_dated_r,
49     &log4c_layout_type_dated_local_r,
50 };
51 static size_t nlayout_types = sizeof(layout_types) / sizeof(layout_types[0]);
52 
53 static const log4c_appender_type_t * const appender_types[] = {
54     &log4c_appender_type_stream,
55     &log4c_appender_type_stream2,
56 #ifdef HAVE_MMAP
57     &log4c_appender_type_mmap,
58 #endif
59 #ifdef HAVE_SYSLOG_H
60     &log4c_appender_type_syslog,
61 #endif
62 #ifdef WITH_ROLLINGFILE
63     &log4c_appender_type_rollingfile
64 #endif
65 };
66 static size_t nappender_types = sizeof(appender_types) / sizeof(appender_types[0]);
67 
68 #ifdef WITH_ROLLINGFILE
69 static const log4c_rollingpolicy_type_t * const rollingpolicy_types[] = {
70     &log4c_rollingpolicy_type_sizewin
71 };
72 static size_t nrollingpolicy_types =
73     sizeof(rollingpolicy_types) / sizeof(rollingpolicy_types[0]);
74 #endif
75 
76 static int log4c_is_init = 0;
77 typedef struct rcfile
78 {
79 	char name[256];
80 	time_t ctime;
81 	int    exists;
82 } rcfile_t;
83 
84 static rcfile_t rcfiles[] = {
85 	{ "$LOG4C_RCPATH/log4crc" },
86 	{  "$HOME/.log4crc" },
87 	{ "./log4crc" }
88 	};
89 
90 static const int nrcfiles = sizeof(rcfiles) / sizeof(rcfiles[0]);
91 
92 
93 /******************************************************************************/
log4c_init(void)94 extern int log4c_init(void)
95 {
96     size_t i;
97     int ret = 0;
98 
99     sd_debug("log4c_init[");
100 
101     /* activate GLIBC allocation debugging */
102 #if defined(__LOG4C_DEBUG__) && defined(__GLIBC__)
103     mtrace();
104 #endif
105 
106     if (log4c_is_init){
107 	sd_debug("log4c already initialized ]");
108 	return 0;
109     }
110 
111     log4c_is_init++;
112 
113     /* Initialize default types: layouts, appenders, rollingpolicies */
114     sd_debug("intializing default types: appenders, layouts, rollingpolicies");
115     for (i = 0; i < nlayout_types; i++)
116 	log4c_layout_type_set(layout_types[i]);
117 
118     for (i = 0; i < nappender_types; i++)
119 	log4c_appender_type_set(appender_types[i]);
120 #ifdef WITH_ROLLINGFILE
121     for (i = 0; i < nrollingpolicy_types; i++)
122 	log4c_rollingpolicy_type_set(rollingpolicy_types[i]);
123 #endif
124 
125     /* load configuration files */
126     {
127 	int i;
128 	sd_debug("looking for conf files...");
129 	snprintf(rcfiles[0].name, sizeof(rcfiles[0].name) - 1, "%s/log4crc",
130 		 getenv("LOG4C_RCPATH") ? getenv("LOG4C_RCPATH") : LOG4C_RCPATH);
131 	snprintf(rcfiles[1].name, sizeof(rcfiles[1].name) - 1, "%s/.log4crc",
132 		 getenv("HOME") ? getenv("HOME") : "");
133 
134 	for (i = 0; i < nrcfiles; i++) {
135 	    sd_debug("checking for conf file at '%s'", rcfiles[i].name);
136 	    if (SD_ACCESS_READ(rcfiles[i].name)) continue;
137 	    if (SD_STAT_CTIME(rcfiles[i].name,&rcfiles[i].ctime) != 0)
138 		sd_error("sd_stat_ctime %s failed", rcfiles[i].name);
139 	    rcfiles[i].exists=1;
140 	    if (log4c_load(rcfiles[i].name) == -1) {
141 		sd_error("loading %s failed", rcfiles[i].name);
142 		ret = -1;
143 	    }
144 	    else {
145 		sd_debug("loading %s succeeded", rcfiles[i].name);
146 		ret = 0;
147 		break;
148 	    }
149 	}
150     }
151 
152     /* override configuration with environment variables */
153     {
154 	const char* priority;
155 	const char* appender;
156 
157 	sd_debug("checking environment variables...");
158 	if ( (priority = getenv("LOG4C_PRIORITY")) != NULL){
159 	    sd_debug("setting priority of root category to '%s'",
160 		     priority);
161 	    log4c_category_set_priority(log4c_category_get("root"),
162 					log4c_priority_to_int(priority));
163 	}
164 
165 	if ( (appender = getenv("LOG4C_APPENDER")) != NULL){
166 	    sd_debug("setting appender of root category to '%s'",
167 		     appender);
168 	    log4c_category_set_appender(log4c_category_get("root"),
169 					log4c_appender_get(appender));
170 	}
171     }
172 
173     /*
174      *   For debug dump current types and instances:
175      *   this allows the caller of log4c_init() to see:
176      *   1. all types currently registered, including perhaps his own.
177      *   2. all instances instantiated via the configuration file.
178      *
179      *   If the caller goes on to programmatically create instaces then he
180      *   can call log4c_dump_all_instances() later himself to
181      *   verify that they were created as expected.
182      *
183      */
184 #ifdef __SD_DEBUG__
185     if( getenv("SD_DEBUG")){
186 	log4c_dump_all_types(stderr);
187 	log4c_dump_all_instances(stderr);
188     }
189 #endif
190 
191 
192     sd_debug("]");
193     return ret;
194 }
195 
196 /******************************************************************************/
__log4c_reread(void)197 void __log4c_reread(void)
198 {
199     time_t file_ctime;
200     int i;
201 
202     for (i = 0; i < nrcfiles; i++){
203 	/* only reread files that existed when we first initialized */
204 	if (rcfiles[i].exists && SD_STAT_CTIME(rcfiles[i].name,&file_ctime) == 0){
205 	    /* time_t is number of second since epoch, just compare for == */
206 	    if (file_ctime != rcfiles[i].ctime){
207 		sd_debug("Need reread on file %s\n",rcfiles[i].name);
208 		SD_STAT_CTIME(rcfiles[i].name,&rcfiles[i].ctime);
209 		if (log4c_rc_load(log4c_rc, rcfiles[i].name) == -1){
210 		    sd_error("re-loading config file %s failed", rcfiles[i].name);
211 		}
212 	    }
213 	}
214     }
215 }
216 
217 /******************************************************************************/
218 /*
219  * Rereads any log4crc files that have changed
220  */
log4c_reread(void)221 void log4c_reread(void)
222 {
223 #ifdef __ENABLE_REREAD__
224     if (0 != log4c_rc->config.reread){
225 	__log4c_reread();
226     }
227 #endif
228 }
229 
230 
231 
232 /******************************************************************************/
log4c_fini(void)233 extern int log4c_fini(void)
234 {
235     /* Some acceptable use of goto here to avoid lots of nested ifs
236      * when we need a quick exit
237      */
238     sd_debug("log4c_fini[");
239     if (log4c_rc->config.nocleanup){
240 	sd_debug("not cleaning up--nocleanup specified in conf");
241 	goto log4c_fini_exit;
242     }
243 
244     if (!log4c_is_init){
245 	sd_debug("not cleaning up--log4c not initialized");
246 	goto log4c_fini_exit;
247     }
248 
249     log4c_is_init--;
250 
251     sd_debug("cleaning up category, appender, layout and"
252 	     "rollingpolicy instances");
253     if (log4c_category_factory) {
254 	sd_factory_delete(log4c_category_factory);
255 	log4c_category_factory = NULL;
256     }
257 
258     if (log4c_appender_factory) {
259 	sd_factory_delete(log4c_appender_factory);
260 	log4c_appender_factory = NULL;
261     }
262     log4c_appender_types_free();
263 
264     if (log4c_layout_factory) {
265 	sd_factory_delete(log4c_layout_factory);
266 	log4c_layout_factory = NULL;
267     }
268     log4c_layout_types_free();
269 
270 #ifdef WITH_ROLLINGFILE
271     if (log4c_rollingpolicy_factory) {
272 	sd_factory_delete(log4c_rollingpolicy_factory);
273 	log4c_rollingpolicy_factory = NULL;
274     }
275     log4c_rollingpolicy_types_free();
276 #endif
277 
278 #ifdef __SD_DEBUG__
279     if( getenv("SD_DEBUG")){
280 	sd_debug("Instance dump after cleanup:");
281 	log4c_dump_all_instances(stderr);
282     }
283 #endif
284 #if defined(__LOG4C_DEBUG__) && defined(__GLIBC__)
285     muntrace();
286 #endif
287 
288 log4c_fini_exit:
289     sd_debug("]");
290 
291     return 0;
292 }
293 
294 
295 /******************************************************************************/
296 #ifdef __GNUC__
__log4c_init(void)297 extern void __attribute__ ((constructor)) __log4c_init(void)
298 {
299 #ifdef WITH_CONSTRUCTORS
300     log4c_init();
301 #endif
302 }
303 
__log4c_fini(void)304 extern void __attribute__ ((destructor)) __log4c_fini(void)
305 {
306 #ifdef WITH_CONSTRUCTORS
307     log4c_fini();
308 #endif
309 }
310 #endif
311 
312 /******************************************************************************/
313 
log4c_dump_all_types(FILE * fp)314 extern void log4c_dump_all_types(FILE *fp){
315     /*
316      *
317      * For debug, dump all the types that have been registered during init. We just
318      * display the name of the the type for the moment--the rest of the type info
319      * right now consists of functions to call, so not really printable.
320      */
321 
322     log4c_appender_types_print(fp);
323     log4c_layout_types_print(fp);
324 #ifdef WITH_ROLLINGFILE
325     log4c_rollingpolicy_types_print(fp);
326 #endif
327 }
328 
log4c_dump_all_instances(FILE * fp)329 extern void log4c_dump_all_instances(FILE *fp){
330 
331     /*
332      * Also dump any instances that were created during init by
333      * reading the conf file.
334      *
335      * An instances of a type consists of the base
336      * type information (name plus function table) and an instance name and
337      * configuration.  For example one can have an instance of the rollingfile
338      * appender which logs to /var/tmp and another instance which logs to
339      * /usr/tmp.  They are both of type rollingfile, but are distinct instances of
340      * it
341      */
342     fprintf(fp, "instance dump follows (may be empty):\n");
343     sd_factory_print(log4c_category_factory, fp);
344     sd_factory_print(log4c_appender_factory, fp);
345     sd_factory_print(log4c_layout_factory, fp);
346 #ifdef WITH_ROLLINGFILE
347     sd_factory_print(log4c_rollingpolicy_factory, fp);
348 #endif
349 }
350