debug.c 6.82 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2004 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
7
8
9
10
11
12
13
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
14
 */
15
16
17
18
19
20

#include "portable.h"

#include <stdio.h>

#include <ac/stdarg.h>
21
#include <ac/stdlib.h>
22
#include <ac/string.h>
23
#include <ac/time.h>
Julius Enarusai's avatar
   
Julius Enarusai committed
24
#include <ac/ctype.h>
25

Howard Chu's avatar
Howard Chu committed
26
27
28
29
#ifdef LDAP_SYSLOG
#include <ac/syslog.h>
#endif

30
31
#include "ldap_log.h"
#include "ldap_defaults.h"
32
#include "lber.h"
Julius Enarusai's avatar
   
Julius Enarusai committed
33
#include "ldap_pvt.h"
34

Julius Enarusai's avatar
   
Julius Enarusai committed
35
int ldap_loglevels[LDAP_SUBSYS_NUM];
36

Kurt Zeilenga's avatar
Kurt Zeilenga committed
37
38
39
40
41
42
43
44
static FILE *log_file = NULL;
static int global_level = 0;

#ifdef LDAP_SYSLOG
static int use_syslog = 0;

static int debug2syslog(int l) {
	switch (l) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
45
46
47
48
49
50
51
	case LDAP_LEVEL_EMERG: return LOG_EMERG;
	case LDAP_LEVEL_ALERT: return LOG_ALERT;
	case LDAP_LEVEL_CRIT: return LOG_CRIT;
	case LDAP_LEVEL_ERR: return LOG_ERR;
	case LDAP_LEVEL_WARNING: return LOG_WARNING;
	case LDAP_LEVEL_NOTICE: return LOG_NOTICE;
	case LDAP_LEVEL_INFO: return LOG_INFO;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
52
	}
Howard Chu's avatar
Howard Chu committed
53
	return LOG_DEBUG;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
54
55
}
#endif
56

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
57
static char *debug_levels[] = {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
58
59
60
61
62
63
	"emergency", "alert", "critical",
	"error", "warning", "notice",
	"information", "entry", "args",
	"results", "detail1", "detail2",
	NULL };

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
64
65
static char *debug_subsys[LDAP_SUBSYS_NUM] = {
	"GLOBAL", "OPERATION", "TRANSPORT",
Howard Chu's avatar
Howard Chu committed
66
67
68
69
70
	"CONNECTION", "FILTER", "BER", 
	"CONFIG", "ACL", "CACHE", "INDEX", 
	"LDIF", "TOOLS", "SLAPD", "SLURPD",
	"BACKEND", "BACK_BDB", "BACK_LDBM", 
	"BACK_LDAP", "BACK_META", "BACK_MON" };
Julius Enarusai's avatar
   
Julius Enarusai committed
71
72
73

int lutil_mnem2subsys( const char *subsys )
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
74
75
	int i;
	for( i = 0; i < LDAP_SUBSYS_NUM; i++ ) {
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
76
		if ( !strcasecmp( subsys, debug_subsys[i] ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
77
			return i;
Julius Enarusai's avatar
   
Julius Enarusai committed
78
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
79
80
	}
	return -1;
Julius Enarusai's avatar
   
Julius Enarusai committed
81
82
}

83
void lutil_set_all_backends( int level )
Julius Enarusai's avatar
   
Julius Enarusai committed
84
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
85
86
	int i;
	for( i = 0; i < LDAP_SUBSYS_NUM; i++ ) {
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
87
		if ( !strncasecmp( "BACK_", debug_subsys[i], sizeof("BACK_")-1 ) ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
88
89
			ldap_loglevels[i] = level;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
90
	}
Julius Enarusai's avatar
   
Julius Enarusai committed
91
92
}

93
int lutil_mnem2level( const char *level )
Gary Williams's avatar
Gary Williams committed
94
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
95
	int i;
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
96
97
	for( i = 0; debug_levels[i] != NULL; i++ ) {
		if ( !strcasecmp( level, debug_levels[i] ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
98
99
			return i;
		}
Gary Williams's avatar
Gary Williams committed
100
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
101
	return -1;
Gary Williams's avatar
Gary Williams committed
102
103
}

Julius Enarusai's avatar
   
Julius Enarusai committed
104
static int addSubsys( const char *subsys, int level )
105
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
106
	int subsys_num;
Gary Williams's avatar
Gary Williams committed
107

Howard Chu's avatar
Howard Chu committed
108
	if ( !strcasecmp( subsys, "BACKEND" ) ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
109
		lutil_set_all_backends( level );
Julius Enarusai's avatar
   
Julius Enarusai committed
110
		return level;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
111
112

	} else {
Julius Enarusai's avatar
   
Julius Enarusai committed
113
		subsys_num = lutil_mnem2subsys(subsys);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
114
		if(subsys_num < 0) {
115
			fprintf(stderr, _("Unknown Subsystem name [ %s ] - Discarded\n"), 
Julius Enarusai's avatar
   
Julius Enarusai committed
116
117
118
119
120
				subsys);
			fflush(stderr);
			return -1;
		}

Julius Enarusai's avatar
   
Julius Enarusai committed
121
		ldap_loglevels[subsys_num] = level;
Julius Enarusai's avatar
   
Julius Enarusai committed
122
		return level;
123
	}
Julius Enarusai's avatar
   
Julius Enarusai committed
124
	return -1;
125
126
}

Julius Enarusai's avatar
   
Julius Enarusai committed
127
int lutil_set_debug_level( const char* subsys, int level )
128
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
129
	return( addSubsys( subsys, level ) );
130
131
}

132
133
int lutil_debug_file( FILE *file )
{
134
	log_file = file;
135
	ber_set_option( NULL, LBER_OPT_LOG_PRINT_FILE, file );
136
137
138
139

	return 0;
}

140
141
void lutil_log_int(
	FILE* file,
142
	const char *subsys, int level,
143
	const char *fmt, va_list vl )
144
{
Howard Chu's avatar
Howard Chu committed
145
#ifdef HAVE_WINSOCK
146
147
	time_t now;
	struct tm *today;
Howard Chu's avatar
Howard Chu committed
148
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
149
	size_t i;
Julius Enarusai's avatar
   
Julius Enarusai committed
150
	char * tmp;
151

Kurt Zeilenga's avatar
Kurt Zeilenga committed
152
153
154
#ifdef LDAP_SYSLOG
	/* we're configured to use syslog */
	if( use_syslog ) {
Howard Chu's avatar
Howard Chu committed
155
#ifdef HAVE_VSYSLOG
156
		vsyslog( debug2syslog(level), fmt, vl );
Howard Chu's avatar
Howard Chu committed
157
#else
158
		char data[4096];
Howard Chu's avatar
Howard Chu committed
159
160
161
		vsnprintf( data, sizeof(data), fmt, vl );
		syslog( debug2syslog(level), data );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
162
		return;
163
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
164
#endif
165
166

#if 0
Kurt Zeilenga's avatar
Kurt Zeilenga committed
167
168
169
170
#ifdef HAVE_WINSOCK
	if( log_file == NULL ) {
		log_file = fopen( LDAP_RUNDIR LDAP_DIRSEP "openldap.log", "w" );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
171
		if ( log_file == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172
			log_file = fopen( "openldap.log", "w" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
173
174
			if ( log_file == NULL ) return;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
175
176

		ber_set_option( NULL, LBER_OPT_LOG_PRINT_FILE, log_file );
177
178
179
	}
#endif
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
180

Gary Williams's avatar
Gary Williams committed
181
	if( file == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
182
183
184
185
186
187
188
		/*
		 * Use stderr unless file was specified via:
		 *   ber_set_option( NULL, LBER_OPT_LOG_PRINT_FILE, file)
		 */
		file = stderr;
	}

189
190
191
192
193
#ifdef HAVE_WINSOCK
	/*
	 * Stick the time in the buffer to output when using Winsock
	 * as NT can't pipe to a timestamp program like Unix can.
	 * This, of course, makes some logs hard to read.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
194
	 */
195
196
197
198
199
200
201
202
203
204
205
	time( &now );
	today = localtime( &now );
	fprintf( file, "%4d%02d%02d:%02d:%02d:%02d ",
		today->tm_year + 1900, today->tm_mon + 1,
		today->tm_mday, today->tm_hour,
		today->tm_min, today->tm_sec );
#endif

	/*
	 * format the output data.
	 */
Julius Enarusai's avatar
   
Julius Enarusai committed
206

Howard Chu's avatar
Howard Chu committed
207
	fprintf(file, "\n%s:: ", subsys ); 
208
	vfprintf( file, fmt, vl );
Julius Enarusai's avatar
   
Julius Enarusai committed
209
	fflush( file );
210
211
212
}

/*
Gary Williams's avatar
Gary Williams committed
213
 * The primary logging routine.	 Takes the subsystem being logged from, the
214
215
216
 * level of the log output and the format and data.  Send this on to the
 * internal routine with the print file, if any.
 */
Julius Enarusai's avatar
   
Julius Enarusai committed
217
void lutil_log( const int subsys, int level, const char *fmt, ... )
218
219
220
221
222
{
	FILE* outfile = NULL;
	va_list vl;
	va_start( vl, fmt );
	ber_get_option( NULL, LBER_OPT_LOG_PRINT_FILE, &outfile );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
223
	lutil_log_int( outfile, debug_subsys[subsys], level, fmt, vl );
224
225
226
227
228
	va_end( vl );
}

void lutil_log_initialize(int argc, char **argv)
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
229
230
231
232
233
234
235
236
237
238
239
240
241
242
	int i;
	/*
	 * Start by setting the hook for the libraries to use this logging
	 * routine.
	 */
	ber_set_option( NULL, LBER_OPT_LOG_PROC, (void*)lutil_log_int );

	if ( argc == 0 ) return;

	/*
	 * Now go through the command line options to set the debugging
	 * levels
	 */
	for( i = 0; i < argc; i++ ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
243
244
		char *next = argv[i];
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
245
246
247
248
249
250
251
		if ( i < argc-1 && next[0] == '-' && next[1] == 'd' ) {
			char subsys[64];
			int level;
			char *optarg = argv[i+1];
			char *index = strchr( optarg, '=' );

			if ( index != NULL ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
252
253
254
255
256
257
				*index = 0;
				strcpy ( subsys, optarg );
				level = atoi( index+1 );
				if ( level <= 0 ) level = lutil_mnem2level( index + 1 );
				lutil_set_debug_level( subsys, level );
				*index = '=';
Kurt Zeilenga's avatar
Kurt Zeilenga committed
258
259

			} else {
Julius Enarusai's avatar
   
Julius Enarusai committed
260
261
262
				global_level = atoi( optarg );
				ldap_loglevels[0] = global_level;
				/* 
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
263
264
265
		 		 * if a negative number was used, make the global level the
		 		 * maximum sane level.
		 		 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
266
				if ( global_level < 0 ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
267
268
					global_level = 65535;
					ldap_loglevels[0] = 65535;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
269
270
				}
			}
Julius Enarusai's avatar
   
Julius Enarusai committed
271
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
272
	}
273
274
}

275
void (lutil_debug)( int debug, int level, const char *fmt, ... )
276
277
278
279
{
	char buffer[4096];
	va_list vl;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
280
	if ( !(level & debug ) ) return;
281
282

#ifdef HAVE_WINSOCK
Ben Collins's avatar
Ben Collins committed
283
	if( log_file == NULL ) {
284
		log_file = fopen( LDAP_RUNDIR LDAP_DIRSEP "openldap.log", "w" );
285

Kurt Zeilenga's avatar
Kurt Zeilenga committed
286
		if ( log_file == NULL ) {
287
			log_file = fopen( "openldap.log", "w" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
288
289
			if ( log_file == NULL ) return;
		}
290

Ben Collins's avatar
Ben Collins committed
291
		ber_set_option( NULL, LBER_OPT_LOG_PRINT_FILE, log_file );
292
293
294
	}
#endif

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
295
	va_start( vl, fmt );
296
297
298
299
300
301
	vsnprintf( buffer, sizeof(buffer), fmt, vl );
	buffer[sizeof(buffer)-1] = '\0';
	if( log_file != NULL ) {
		fputs( buffer, log_file );
		fflush( log_file );
	}
Howard Chu's avatar
Howard Chu committed
302
	fputs( buffer, stderr );
303
304
	va_end( vl );
}
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

#if defined(HAVE_EBCDIC) && defined(LDAP_SYSLOG)
void eb_syslog( int pri, const char *fmt, ... )
{
	char buffer[4096];
	va_list vl;

	va_start( vl, fmt );
	vsnprintf( buffer, sizeof(buffer), fmt, vl );
	buffer[sizeof(buffer)-1] = '\0';

	__atoe(buffer);
	syslog( pri, "%s", buffer );
	va_end( vl );
}
#endif