xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-mdb/monitor.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: monitor.c,v 1.1.1.1 2014/05/28 09:58:50 tron Exp $	*/
2 
3 /* monitor.c - monitor mdb backend */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2000-2014 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 
19 #include "portable.h"
20 
21 #include <stdio.h>
22 #include <ac/string.h>
23 #include <ac/unistd.h>
24 #include <ac/stdlib.h>
25 #include <ac/errno.h>
26 #include <sys/stat.h>
27 #include "lutil.h"
28 #include "back-mdb.h"
29 
30 #include "../back-monitor/back-monitor.h"
31 
32 #include "config.h"
33 
34 static ObjectClass		*oc_olmMDBDatabase;
35 
36 static AttributeDescription *ad_olmDbDirectory;
37 
38 #ifdef MDB_MONITOR_IDX
39 static int
40 mdb_monitor_idx_entry_add(
41 	struct mdb_info	*mdb,
42 	Entry		*e );
43 
44 static AttributeDescription	*ad_olmDbNotIndexed;
45 #endif /* MDB_MONITOR_IDX */
46 
47 /*
48  * NOTE: there's some confusion in monitor OID arc;
49  * by now, let's consider:
50  *
51  * Subsystems monitor attributes	1.3.6.1.4.1.4203.666.1.55.0
52  * Databases monitor attributes		1.3.6.1.4.1.4203.666.1.55.0.1
53  * MDB database monitor attributes	1.3.6.1.4.1.4203.666.1.55.0.1.3
54  *
55  * Subsystems monitor objectclasses	1.3.6.1.4.1.4203.666.3.16.0
56  * Databases monitor objectclasses	1.3.6.1.4.1.4203.666.3.16.0.1
57  * MDB database monitor objectclasses	1.3.6.1.4.1.4203.666.3.16.0.1.3
58  */
59 
60 static struct {
61 	char			*name;
62 	char			*oid;
63 }		s_oid[] = {
64 	{ "olmMDBAttributes",			"olmDatabaseAttributes:1" },
65 	{ "olmMDBObjectClasses",		"olmDatabaseObjectClasses:1" },
66 
67 	{ NULL }
68 };
69 
70 static struct {
71 	char			*desc;
72 	AttributeDescription	**ad;
73 }		s_at[] = {
74 	{ "( olmDatabaseAttributes:1 "
75 		"NAME ( 'olmDbDirectory' ) "
76 		"DESC 'Path name of the directory "
77 			"where the database environment resides' "
78 		"SUP monitoredInfo "
79 		"NO-USER-MODIFICATION "
80 		"USAGE dSAOperation )",
81 		&ad_olmDbDirectory },
82 
83 #ifdef MDB_MONITOR_IDX
84 	{ "( olmDatabaseAttributes:2 "
85 		"NAME ( 'olmDbNotIndexed' ) "
86 		"DESC 'Missing indexes resulting from candidate selection' "
87 		"SUP monitoredInfo "
88 		"NO-USER-MODIFICATION "
89 		"USAGE dSAOperation )",
90 		&ad_olmDbNotIndexed },
91 #endif /* MDB_MONITOR_IDX */
92 
93 	{ NULL }
94 };
95 
96 static struct {
97 	char		*desc;
98 	ObjectClass	**oc;
99 }		s_oc[] = {
100 	/* augments an existing object, so it must be AUXILIARY
101 	 * FIXME: derive from some ABSTRACT "monitoredEntity"? */
102 	{ "( olmMDBObjectClasses:2 "
103 		"NAME ( 'olmMDBDatabase' ) "
104 		"SUP top AUXILIARY "
105 		"MAY ( "
106 			"olmDbDirectory "
107 #ifdef MDB_MONITOR_IDX
108 			"$ olmDbNotIndexed "
109 #endif /* MDB_MONITOR_IDX */
110 			") )",
111 		&oc_olmMDBDatabase },
112 
113 	{ NULL }
114 };
115 
116 static int
117 mdb_monitor_update(
118 	Operation	*op,
119 	SlapReply	*rs,
120 	Entry		*e,
121 	void		*priv )
122 {
123 	struct mdb_info		*mdb = (struct mdb_info *) priv;
124 
125 #ifdef MDB_MONITOR_IDX
126 	mdb_monitor_idx_entry_add( mdb, e );
127 #endif /* MDB_MONITOR_IDX */
128 
129 	return SLAP_CB_CONTINUE;
130 }
131 
132 #if 0	/* uncomment if required */
133 static int
134 mdb_monitor_modify(
135 	Operation	*op,
136 	SlapReply	*rs,
137 	Entry		*e,
138 	void		*priv )
139 {
140 	return SLAP_CB_CONTINUE;
141 }
142 #endif
143 
144 static int
145 mdb_monitor_free(
146 	Entry		*e,
147 	void		**priv )
148 {
149 	struct berval	values[ 2 ];
150 	Modification	mod = { 0 };
151 
152 	const char	*text;
153 	char		textbuf[ SLAP_TEXT_BUFLEN ];
154 
155 	int		i, rc;
156 
157 	/* NOTE: if slap_shutdown != 0, priv might have already been freed */
158 	*priv = NULL;
159 
160 	/* Remove objectClass */
161 	mod.sm_op = LDAP_MOD_DELETE;
162 	mod.sm_desc = slap_schema.si_ad_objectClass;
163 	mod.sm_values = values;
164 	mod.sm_numvals = 1;
165 	values[ 0 ] = oc_olmMDBDatabase->soc_cname;
166 	BER_BVZERO( &values[ 1 ] );
167 
168 	rc = modify_delete_values( e, &mod, 1, &text,
169 		textbuf, sizeof( textbuf ) );
170 	/* don't care too much about return code... */
171 
172 	/* remove attrs */
173 	mod.sm_values = NULL;
174 	mod.sm_numvals = 0;
175 	for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
176 		mod.sm_desc = *s_at[ i ].ad;
177 		rc = modify_delete_values( e, &mod, 1, &text,
178 			textbuf, sizeof( textbuf ) );
179 		/* don't care too much about return code... */
180 	}
181 
182 	return SLAP_CB_CONTINUE;
183 }
184 
185 /*
186  * call from within mdb_initialize()
187  */
188 static int
189 mdb_monitor_initialize( void )
190 {
191 	int		i, code;
192 	ConfigArgs c;
193 	char	*argv[ 3 ];
194 
195 	static int	mdb_monitor_initialized = 0;
196 
197 	/* set to 0 when successfully initialized; otherwise, remember failure */
198 	static int	mdb_monitor_initialized_failure = 1;
199 
200 	if ( mdb_monitor_initialized++ ) {
201 		return mdb_monitor_initialized_failure;
202 	}
203 
204 	if ( backend_info( "monitor" ) == NULL ) {
205 		return -1;
206 	}
207 
208 	/* register schema here */
209 
210 	argv[ 0 ] = "back-mdb monitor";
211 	c.argv = argv;
212 	c.argc = 3;
213 	c.fname = argv[0];
214 
215 	for ( i = 0; s_oid[ i ].name; i++ ) {
216 		c.lineno = i;
217 		argv[ 1 ] = s_oid[ i ].name;
218 		argv[ 2 ] = s_oid[ i ].oid;
219 
220 		if ( parse_oidm( &c, 0, NULL ) != 0 ) {
221 			Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
222 				": unable to add "
223 				"objectIdentifier \"%s=%s\"\n",
224 				s_oid[ i ].name, s_oid[ i ].oid, 0 );
225 			return 2;
226 		}
227 	}
228 
229 	for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
230 		code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
231 		if ( code != LDAP_SUCCESS ) {
232 			Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
233 				": register_at failed for attributeType (%s)\n",
234 				s_at[ i ].desc, 0, 0 );
235 			return 3;
236 
237 		} else {
238 			(*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
239 		}
240 	}
241 
242 	for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
243 		code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
244 		if ( code != LDAP_SUCCESS ) {
245 			Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
246 				": register_oc failed for objectClass (%s)\n",
247 				s_oc[ i ].desc, 0, 0 );
248 			return 4;
249 
250 		} else {
251 			(*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
252 		}
253 	}
254 
255 	return ( mdb_monitor_initialized_failure = LDAP_SUCCESS );
256 }
257 
258 /*
259  * call from within mdb_db_init()
260  */
261 int
262 mdb_monitor_db_init( BackendDB *be )
263 {
264 	struct mdb_info		*mdb = (struct mdb_info *) be->be_private;
265 
266 	if ( mdb_monitor_initialize() == LDAP_SUCCESS ) {
267 		/* monitoring in back-mdb is on by default */
268 		SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
269 	}
270 
271 #ifdef MDB_MONITOR_IDX
272 	mdb->mi_idx = NULL;
273 	ldap_pvt_thread_mutex_init( &mdb->mi_idx_mutex );
274 #endif /* MDB_MONITOR_IDX */
275 
276 	return 0;
277 }
278 
279 /*
280  * call from within mdb_db_open()
281  */
282 int
283 mdb_monitor_db_open( BackendDB *be )
284 {
285 	struct mdb_info		*mdb = (struct mdb_info *) be->be_private;
286 	Attribute		*a, *next;
287 	monitor_callback_t	*cb = NULL;
288 	int			rc = 0;
289 	BackendInfo		*mi;
290 	monitor_extra_t		*mbe;
291 
292 	if ( !SLAP_DBMONITORING( be ) ) {
293 		return 0;
294 	}
295 
296 	mi = backend_info( "monitor" );
297 	if ( !mi || !mi->bi_extra ) {
298 		SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
299 		return 0;
300 	}
301 	mbe = mi->bi_extra;
302 
303 	/* don't bother if monitor is not configured */
304 	if ( !mbe->is_configured() ) {
305 		static int warning = 0;
306 
307 		if ( warning++ == 0 ) {
308 			Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_db_open)
309 				": monitoring disabled; "
310 				"configure monitor database to enable\n",
311 				0, 0, 0 );
312 		}
313 
314 		return 0;
315 	}
316 
317 	/* alloc as many as required (plus 1 for objectClass) */
318 	a = attrs_alloc( 1 + 1 );
319 	if ( a == NULL ) {
320 		rc = 1;
321 		goto cleanup;
322 	}
323 
324 	a->a_desc = slap_schema.si_ad_objectClass;
325 	attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 );
326 	next = a->a_next;
327 
328 	{
329 		struct berval	bv, nbv;
330 		ber_len_t	pathlen = 0, len = 0;
331 		char		path[ MAXPATHLEN ] = { '\0' };
332 		char		*fname = mdb->mi_dbenv_home,
333 				*ptr;
334 
335 		len = strlen( fname );
336 		if ( fname[ 0 ] != '/' ) {
337 			/* get full path name */
338 			getcwd( path, sizeof( path ) );
339 			pathlen = strlen( path );
340 
341 			if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
342 				fname += 2;
343 				len -= 2;
344 			}
345 		}
346 
347 		bv.bv_len = pathlen + STRLENOF( "/" ) + len;
348 		ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
349 		if ( pathlen ) {
350 			ptr = lutil_strncopy( ptr, path, pathlen );
351 			ptr[ 0 ] = '/';
352 			ptr++;
353 		}
354 		ptr = lutil_strncopy( ptr, fname, len );
355 		if ( ptr[ -1 ] != '/' ) {
356 			ptr[ 0 ] = '/';
357 			ptr++;
358 		}
359 		ptr[ 0 ] = '\0';
360 
361 		attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
362 
363 		next->a_desc = ad_olmDbDirectory;
364 		next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
365 		next->a_vals[ 0 ] = bv;
366 		next->a_numvals = 1;
367 
368 		if ( BER_BVISNULL( &nbv ) ) {
369 			next->a_nvals = next->a_vals;
370 
371 		} else {
372 			next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
373 			next->a_nvals[ 0 ] = nbv;
374 		}
375 
376 		next = next->a_next;
377 	}
378 
379 	cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
380 	cb->mc_update = mdb_monitor_update;
381 #if 0	/* uncomment if required */
382 	cb->mc_modify = mdb_monitor_modify;
383 #endif
384 	cb->mc_free = mdb_monitor_free;
385 	cb->mc_private = (void *)mdb;
386 
387 	/* make sure the database is registered; then add monitor attributes */
388 	rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn );
389 	if ( rc == 0 ) {
390 		rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb,
391 			NULL, -1, NULL );
392 	}
393 
394 cleanup:;
395 	if ( rc != 0 ) {
396 		if ( cb != NULL ) {
397 			ch_free( cb );
398 			cb = NULL;
399 		}
400 
401 		if ( a != NULL ) {
402 			attrs_free( a );
403 			a = NULL;
404 		}
405 	}
406 
407 	/* store for cleanup */
408 	mdb->mi_monitor.mdm_cb = (void *)cb;
409 
410 	/* we don't need to keep track of the attributes, because
411 	 * mdb_monitor_free() takes care of everything */
412 	if ( a != NULL ) {
413 		attrs_free( a );
414 	}
415 
416 	return rc;
417 }
418 
419 /*
420  * call from within mdb_db_close()
421  */
422 int
423 mdb_monitor_db_close( BackendDB *be )
424 {
425 	struct mdb_info		*mdb = (struct mdb_info *) be->be_private;
426 
427 	if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) {
428 		BackendInfo		*mi = backend_info( "monitor" );
429 		monitor_extra_t		*mbe;
430 
431 		if ( mi && &mi->bi_extra ) {
432 			mbe = mi->bi_extra;
433 			mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn,
434 				(monitor_callback_t *)mdb->mi_monitor.mdm_cb,
435 				NULL, 0, NULL );
436 		}
437 
438 		memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) );
439 	}
440 
441 	return 0;
442 }
443 
444 /*
445  * call from within mdb_db_destroy()
446  */
447 int
448 mdb_monitor_db_destroy( BackendDB *be )
449 {
450 #ifdef MDB_MONITOR_IDX
451 	struct mdb_info		*mdb = (struct mdb_info *) be->be_private;
452 
453 	/* TODO: free tree */
454 	ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex );
455 	avl_free( mdb->mi_idx, ch_free );
456 #endif /* MDB_MONITOR_IDX */
457 
458 	return 0;
459 }
460 
461 #ifdef MDB_MONITOR_IDX
462 
463 #define MDB_MONITOR_IDX_TYPES	(4)
464 
465 typedef struct monitor_idx_t monitor_idx_t;
466 
467 struct monitor_idx_t {
468 	AttributeDescription	*idx_ad;
469 	unsigned long		idx_count[MDB_MONITOR_IDX_TYPES];
470 };
471 
472 static int
473 mdb_monitor_bitmask2key( slap_mask_t bitmask )
474 {
475 	int	key;
476 
477 	for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U );
478 			key++ )
479 		bitmask >>= 1;
480 
481 	return key;
482 }
483 
484 static struct berval idxbv[] = {
485 	BER_BVC( "present=" ),
486 	BER_BVC( "equality=" ),
487 	BER_BVC( "approx=" ),
488 	BER_BVC( "substr=" ),
489 	BER_BVNULL
490 };
491 
492 static ber_len_t
493 mdb_monitor_idx2len( monitor_idx_t *idx )
494 {
495 	int		i;
496 	ber_len_t	len = 0;
497 
498 	for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
499 		if ( idx->idx_count[ i ] != 0 ) {
500 			len += idxbv[i].bv_len;
501 		}
502 	}
503 
504 	return len;
505 }
506 
507 static int
508 monitor_idx_cmp( const void *p1, const void *p2 )
509 {
510 	const monitor_idx_t	*idx1 = (const monitor_idx_t *)p1;
511 	const monitor_idx_t	*idx2 = (const monitor_idx_t *)p2;
512 
513 	return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad );
514 }
515 
516 static int
517 monitor_idx_dup( void *p1, void *p2 )
518 {
519 	monitor_idx_t	*idx1 = (monitor_idx_t *)p1;
520 	monitor_idx_t	*idx2 = (monitor_idx_t *)p2;
521 
522 	return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0;
523 }
524 
525 int
526 mdb_monitor_idx_add(
527 	struct mdb_info		*mdb,
528 	AttributeDescription	*desc,
529 	slap_mask_t		type )
530 {
531 	monitor_idx_t		idx_dummy = { 0 },
532 				*idx;
533 	int			rc = 0, key;
534 
535 	idx_dummy.idx_ad = desc;
536 	key = mdb_monitor_bitmask2key( type ) - 1;
537 	if ( key >= MDB_MONITOR_IDX_TYPES ) {
538 		/* invalid index type */
539 		return -1;
540 	}
541 
542 	ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
543 
544 	idx = (monitor_idx_t *)avl_find( mdb->mi_idx,
545 		(caddr_t)&idx_dummy, monitor_idx_cmp );
546 	if ( idx == NULL ) {
547 		idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 );
548 		idx->idx_ad = desc;
549 		idx->idx_count[ key ] = 1;
550 
551 		switch ( avl_insert( &mdb->mi_idx, (caddr_t)idx,
552 			monitor_idx_cmp, monitor_idx_dup ) )
553 		{
554 		case 0:
555 			break;
556 
557 		default:
558 			ch_free( idx );
559 			rc = -1;
560 		}
561 
562 	} else {
563 		idx->idx_count[ key ]++;
564 	}
565 
566 	ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
567 
568 	return rc;
569 }
570 
571 static int
572 mdb_monitor_idx_apply( void *v_idx, void *v_valp )
573 {
574 	monitor_idx_t	*idx = (monitor_idx_t *)v_idx;
575 	BerVarray	*valp = (BerVarray *)v_valp;
576 
577 	struct berval	bv;
578 	char		*ptr;
579 	char		count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ];
580 	ber_len_t	count_len[ MDB_MONITOR_IDX_TYPES ],
581 			idx_len;
582 	int		i, num = 0;
583 
584 	idx_len = mdb_monitor_idx2len( idx );
585 
586 	bv.bv_len = 0;
587 	for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
588 		if ( idx->idx_count[ i ] == 0 ) {
589 			continue;
590 		}
591 
592 		count_len[ i ] = snprintf( count_buf[ i ],
593 			sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] );
594 		bv.bv_len += count_len[ i ];
595 		num++;
596 	}
597 
598 	bv.bv_len += idx->idx_ad->ad_cname.bv_len
599 		+ num
600 		+ idx_len;
601 	ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 );
602 	ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val );
603 	for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
604 		if ( idx->idx_count[ i ] == 0 ) {
605 			continue;
606 		}
607 
608 		ptr[ 0 ] = '#';
609 		++ptr;
610 		ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val );
611 		ptr = lutil_strcopy( ptr, count_buf[ i ] );
612 	}
613 
614 	ber_bvarray_add( valp, &bv );
615 
616 	return 0;
617 }
618 
619 static int
620 mdb_monitor_idx_entry_add(
621 	struct mdb_info	*mdb,
622 	Entry		*e )
623 {
624 	BerVarray	vals = NULL;
625 	Attribute	*a;
626 
627 	a = attr_find( e->e_attrs, ad_olmDbNotIndexed );
628 
629 	ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
630 
631 	avl_apply( mdb->mi_idx, mdb_monitor_idx_apply,
632 		&vals, -1, AVL_INORDER );
633 
634 	ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
635 
636 	if ( vals != NULL ) {
637 		if ( a != NULL ) {
638 			assert( a->a_nvals == a->a_vals );
639 
640 			ber_bvarray_free( a->a_vals );
641 
642 		} else {
643 			Attribute	**ap;
644 
645 			for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
646 				;
647 			*ap = attr_alloc( ad_olmDbNotIndexed );
648 			a = *ap;
649 		}
650 		a->a_vals = vals;
651 		a->a_nvals = a->a_vals;
652 	}
653 
654 	return 0;
655 }
656 
657 #endif /* MDB_MONITOR_IDX */
658