]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/monitor.c
Add BackendInfo.bi_extra for backend custom APIs
[openldap] / servers / slapd / back-bdb / monitor.c
1 /* monitor.c - monitor bdb backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2006 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21 #include <ac/unistd.h>
22 #include <ac/stdlib.h>
23 #include <ac/errno.h>
24 #include <sys/stat.h>
25 #include "lutil.h"
26 #include "back-bdb.h"
27
28 #include "../back-monitor/back-monitor.h"
29
30 static ObjectClass              *oc_olmBDBDatabase;
31
32 static AttributeDescription     *ad_olmBDBEntryCache,
33         *ad_olmBDBEntryInfo, *ad_olmBDBIDLCache,
34         *ad_olmDbDirectory;
35
36 /*
37  * NOTE: there's some confusion in monitor OID arc;
38  * by now, let's consider:
39  * 
40  * Subsystems monitor attributes        1.3.6.1.4.1.4203.666.1.55.0
41  * Databases monitor attributes         1.3.6.1.4.1.4203.666.1.55.0.1
42  * BDB database monitor attributes      1.3.6.1.4.1.4203.666.1.55.0.1.1
43  *
44  * Subsystems monitor objectclasses     1.3.6.1.4.1.4203.666.3.16.0
45  * Databases monitor objectclasses      1.3.6.1.4.1.4203.666.3.16.0.1
46  * BDB database monitor objectclasses   1.3.6.1.4.1.4203.666.3.16.0.1.1
47  */
48
49 static struct {
50         char                    *name;
51         char                    *oid;
52 }               s_oid[] = {
53         { "olmBDBAttributes",                   "olmDatabaseAttributes:1" },
54         { "olmBDBObjectClasses",                "olmDatabaseObjectClasses:1" },
55
56         { NULL }
57 };
58
59 static struct {
60         char                    *name;
61         char                    *desc;
62         AttributeDescription    **ad;
63 }               s_at[] = {
64         { "olmBDBEntryCache", "( olmBDBAttributes:1 "
65                 "NAME ( 'olmBDBEntryCache' ) "
66                 "DESC 'Number of items in Entry Cache' "
67                 "SUP monitorCounter "
68                 "NO-USER-MODIFICATION "
69                 "USAGE directoryOperation )",
70                 &ad_olmBDBEntryCache },
71
72         { "olmBDBEntryInfo", "( olmBDBAttributes:2 "
73                 "NAME ( 'olmBDBEntryInfo' ) "
74                 "DESC 'Number of items in EntryInfo Cache' "
75                 "SUP monitorCounter "
76                 "NO-USER-MODIFICATION "
77                 "USAGE directoryOperation )",
78                 &ad_olmBDBEntryInfo },
79
80         { "olmBDBIDLCache", "( olmBDBAttributes:3 "
81                 "NAME ( 'olmBDBIDLCache' ) "
82                 "DESC 'Number of items in IDL Cache' "
83                 "SUP monitorCounter "
84                 "NO-USER-MODIFICATION "
85                 "USAGE directoryOperation )",
86                 &ad_olmBDBIDLCache },
87
88         { "olmDbDirectory", "( olmBDBAttributes:4 "
89                 "NAME ( 'olmDbDirectory' ) "
90                 "DESC 'Path name of the directory "
91                         "where the database environment resides' "
92                 "SUP monitoredInfo "
93                 "NO-USER-MODIFICATION "
94                 "USAGE directoryOperation )",
95                 &ad_olmDbDirectory },
96
97         { NULL }
98 };
99
100 static struct {
101         char            *name;
102         char            *desc;
103         ObjectClass     **oc;
104 }               s_oc[] = {
105         /* augments an existing object, so it must be AUXILIARY
106          * FIXME: derive from some ABSTRACT "monitoredEntity"? */
107         { "olmBDBDatabase", "( olmBDBObjectClasses:1 "
108                 "NAME ( 'olmBDBDatabase' ) "
109                 "SUP top AUXILIARY "
110                 "MAY ( "
111                         "olmBDBEntryCache "
112                         "$ olmBDBEntryInfo "
113                         "$ olmBDBIDLCache "
114                         "$ olmDbDirectory "
115                         ") )",
116                 &oc_olmBDBDatabase },
117
118         { NULL }
119 };
120
121 static int
122 bdb_monitor_update(
123         Operation       *op,
124         SlapReply       *rs,
125         Entry           *e,
126         void            *priv )
127 {
128         struct bdb_info         *bdb = (struct bdb_info *) priv;
129         Attribute               *a;
130
131         char                    buf[ BUFSIZ ];
132         struct berval           bv;
133
134         assert( ad_olmBDBEntryCache != NULL );
135
136         a = attr_find( e->e_attrs, ad_olmBDBEntryCache );
137         assert( a != NULL );
138         bv.bv_val = buf;
139         bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_cache.c_cursize );
140         ber_bvreplace( &a->a_vals[ 0 ], &bv );
141
142         a = attr_find( e->e_attrs, ad_olmBDBEntryInfo );
143         assert( a != NULL );
144         bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_cache.c_eiused );
145         ber_bvreplace( &a->a_vals[ 0 ], &bv );
146
147         a = attr_find( e->e_attrs, ad_olmBDBIDLCache );
148         assert( a != NULL );
149         bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_idl_cache_size );
150         ber_bvreplace( &a->a_vals[ 0 ], &bv );
151         
152         return SLAP_CB_CONTINUE;
153 }
154
155 static int
156 bdb_monitor_modify(
157         Operation       *op,
158         SlapReply       *rs,
159         Entry           *e,
160         void            *priv )
161 {
162         return SLAP_CB_CONTINUE;
163 }
164
165 static int
166 bdb_monitor_free(
167         Entry           *e,
168         void            *priv )
169 {
170         struct berval   values[ 2 ];
171         Modification    mod = { 0 };
172
173         const char      *text;
174         char            textbuf[ SLAP_TEXT_BUFLEN ];
175
176         int             i, rc;
177
178         /* Remove objectClass */
179         mod.sm_op = LDAP_MOD_DELETE;
180         mod.sm_desc = slap_schema.si_ad_objectClass;
181         mod.sm_values = values;
182         values[ 0 ] = oc_olmBDBDatabase->soc_cname;
183         BER_BVZERO( &values[ 1 ] );
184
185         rc = modify_delete_values( e, &mod, 1, &text,
186                 textbuf, sizeof( textbuf ) );
187         /* don't care too much about return code... */
188
189         /* remove attrs */
190         for ( i = 0; s_at[ i ].name != NULL; i++ ) {
191                 mod.sm_desc = *s_at[ i ].ad;
192                 mod.sm_values = NULL;
193                 rc = modify_delete_values( e, &mod, 1, &text,
194                         textbuf, sizeof( textbuf ) );
195                 /* don't care too much about return code... */
196         }
197         
198         return SLAP_CB_CONTINUE;
199 }
200
201 /*
202  * call from within bdb_initialize()
203  */
204 int
205 bdb_monitor_initialize( void )
206 {
207         int             i, code;
208         const char      *err;
209         BackendInfo *bi;
210
211         static int      bdb_monitor_initialized = 0;
212
213         bi = backend_info("monitor");
214         if ( !bi )
215                 return -1;
216
217         /* register schema here */
218
219         if ( bdb_monitor_initialized++ ) {
220                 return 0;
221         }
222
223         for ( i = 0; s_oid[ i ].name; i++ ) {
224                 char    *argv[ 3 ];
225         
226                 argv[ 0 ] = "back-bdb/back-hdb monitor";
227                 argv[ 1 ] = s_oid[ i ].name;
228                 argv[ 2 ] = s_oid[ i ].oid;
229
230                 if ( parse_oidm( argv[ 0 ], i, 3, argv, 0, NULL ) != 0 ) {
231                         Debug( LDAP_DEBUG_ANY,
232                                 "bdb_monitor_initialize: unable to add "
233                                 "objectIdentifier \"%s=%s\"\n",
234                                 s_oid[ i ].name, s_oid[ i ].oid, 0 );
235                         return 1;
236                 }
237         }
238
239         for ( i = 0; s_at[ i ].name != NULL; i++ ) {
240                 LDAPAttributeType       *at;
241
242                 at = ldap_str2attributetype( s_at[ i ].desc,
243                         &code, &err, LDAP_SCHEMA_ALLOW_ALL );
244                 if ( !at ) {
245                         Debug( LDAP_DEBUG_ANY,
246                                 "bdb_monitor_initialize: "
247                                 "AttributeType load failed: %s %s\n",
248                                 ldap_scherr2str( code ), err, 0 );
249                         return LDAP_INVALID_SYNTAX;
250                 }
251
252                 code = at_add( at, 0, NULL, &err );
253                 if ( code != LDAP_SUCCESS ) {
254                         Debug( LDAP_DEBUG_ANY,
255                                 "bdb_monitor_initialize: "
256                                 "AttributeType load failed: %s %s\n",
257                                 scherr2str( code ), err, 0 );
258                         code = LDAP_INVALID_SYNTAX;
259                         goto done_at;
260                 }
261
262                 code = slap_str2ad( s_at[ i ].name,
263                                 s_at[ i ].ad, &err );
264                 if ( code != LDAP_SUCCESS ) {
265                         Debug( LDAP_DEBUG_ANY,
266                                 "bdb_monitor_initialize: "
267                                 "unable to find AttributeDescription "
268                                 "\"%s\": %d (%s)\n",
269                                 s_at[ i ].name, code, err );
270                         code = LDAP_UNDEFINED_TYPE;
271                         goto done_at;
272                 }
273
274 done_at:;
275                 if ( code ) {
276                         ldap_attributetype_free( at );
277                         return code;
278                 }
279
280                 ldap_memfree( at );
281         }
282
283         for ( i = 0; s_oc[ i ].name != NULL; i++ ) {
284                 LDAPObjectClass *oc;
285
286                 oc = ldap_str2objectclass( s_oc[ i ].desc,
287                                 &code, &err, LDAP_SCHEMA_ALLOW_ALL );
288                 if ( !oc ) {
289                         Debug( LDAP_DEBUG_ANY,
290                                 "bdb_monitor_initialize: "
291                                 "ObjectClass load failed: %s %s\n",
292                                 ldap_scherr2str( code ), err, 0 );
293                         return LDAP_INVALID_SYNTAX;
294                 }
295
296                 code = oc_add( oc, 0, NULL, &err );
297                 if ( code != LDAP_SUCCESS ) {
298                         Debug( LDAP_DEBUG_ANY,
299                                 "bdb_monitor_initialize: "
300                                 "ObjectClass load failed: %s %s\n",
301                                 scherr2str( code ), err, 0 );
302                         code = LDAP_INVALID_SYNTAX;
303                         goto done_oc;
304                 }
305
306                 *s_oc[ i ].oc = oc_find( s_oc[ i ].name );
307                 if ( *s_oc[ i ].oc == NULL ) {
308                         code = LDAP_UNDEFINED_TYPE;
309                         Debug( LDAP_DEBUG_ANY,
310                                 "bdb_monitor_initialize: "
311                                 "unable to find objectClass \"%s\"\n",
312                                 s_oc[ i ].name, 0, 0 );
313                         goto done_oc;
314                 }
315
316 done_oc:;
317                 if ( code != LDAP_SUCCESS ) {
318                         ldap_objectclass_free( oc );
319                         return code;
320                 }
321
322                 ldap_memfree( oc );
323         }
324
325         return 0;
326 }
327
328 /*
329  * call from within bdb_db_init()
330  */
331 int
332 bdb_monitor_init( BackendDB *be )
333 {
334         if ( bdb_monitor_initialize() == LDAP_SUCCESS ) {
335                 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
336         }
337
338         return 0;
339 }
340
341 /*
342  * call from within bdb_db_open()
343  */
344 int
345 bdb_monitor_open( BackendDB *be )
346 {
347         struct bdb_info         *bdb = (struct bdb_info *) be->be_private;
348         Attribute               *a, *next;
349         monitor_callback_t      *cb = NULL;
350         struct berval           suffix, *filter, *base;
351         char                    *ptr;
352         int                     rc = 0;
353         monitor_extra_t *mbe;
354
355         if ( !SLAP_DBMONITORING( be ) ) {
356                 return 0;
357         }
358
359         {
360                 BackendInfo *mi = backend_info( "monitor" );
361                 if ( !mi || !mi->bi_extra ) {
362                         SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
363                         return 0;
364                 }
365                 mbe = mi->bi_extra;
366         }
367
368         /* don't bother if monitor is not configured */
369         if ( !mbe->is_configured() ) {
370                 static int warning = 0;
371
372                 if ( warning++ == 0 ) {
373                         Debug( LDAP_DEBUG_ANY, "bdb_monitor_open: "
374                                 "monitoring disabled; "
375                                 "configure monitor database to enable\n",
376                                 0, 0, 0 );
377                 }
378
379                 return 0;
380         }
381
382         bdb->bi_monitor.bdm_scope = LDAP_SCOPE_SUBORDINATE;
383         base = &bdb->bi_monitor.bdm_nbase;
384         BER_BVSTR( base, "cn=databases,cn=monitor" );
385         filter = &bdb->bi_monitor.bdm_filter;
386         BER_BVZERO( filter );
387
388         suffix.bv_len = ldap_bv2escaped_filter_value_len( &be->be_nsuffix[ 0 ] );
389         if ( suffix.bv_len == be->be_nsuffix[ 0 ].bv_len ) {
390                 suffix = be->be_nsuffix[ 0 ];
391
392         } else {
393                 ldap_bv2escaped_filter_value( &be->be_nsuffix[ 0 ], &suffix );
394         }
395         
396         filter->bv_len = STRLENOF( "(&(monitoredInfo=" )
397                 + strlen( be->bd_info->bi_type )
398                 + STRLENOF( ")(namingContexts:distinguishedNameMatch:=" )
399                 + suffix.bv_len + STRLENOF( "))" );
400         ptr = filter->bv_val = ch_malloc( filter->bv_len + 1 );
401         ptr = lutil_strcopy( ptr, "(&(monitoredInfo=" );
402         ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
403         ptr = lutil_strcopy( ptr, ")(namingContexts:distinguishedNameMatch:=" );
404         ptr = lutil_strncopy( ptr, suffix.bv_val, suffix.bv_len );
405         ptr = lutil_strcopy( ptr, "))" );
406         ptr[ 0 ] = '\0';
407         assert( filter->bv_len == ptr - filter->bv_val );
408         
409         if ( suffix.bv_val != be->be_nsuffix[ 0 ].bv_val ) {
410                 ch_free( suffix.bv_val );
411         }
412
413         /* alloc as many as required (plus 1 for objectClass) */
414         a = attrs_alloc( 1 + 4 );
415         if ( a == NULL ) {
416                 rc = 1;
417                 goto cleanup;
418         }
419
420         a->a_desc = slap_schema.si_ad_objectClass;
421         value_add_one( &a->a_vals, &oc_olmBDBDatabase->soc_cname );
422         a->a_nvals = a->a_vals;
423         next = a->a_next;
424
425         {
426                 struct berval   bv = BER_BVC( "0" );
427
428                 next->a_desc = ad_olmBDBEntryCache;
429                 value_add_one( &next->a_vals, &bv );
430                 next->a_nvals = next->a_vals;
431                 next = next->a_next;
432
433                 next->a_desc = ad_olmBDBEntryInfo;
434                 value_add_one( &next->a_vals, &bv );
435                 next->a_nvals = next->a_vals;
436                 next = next->a_next;
437
438                 next->a_desc = ad_olmBDBIDLCache;
439                 value_add_one( &next->a_vals, &bv );
440                 next->a_nvals = next->a_vals;
441                 next = next->a_next;
442         }
443
444         {
445                 struct berval   bv, nbv;
446                 ber_len_t       pathlen = 0, len = 0;
447                 char            path[ PATH_MAX ] = { '\0' };
448                 char            *fname = bdb->bi_dbenv_home,
449                                 *ptr;
450
451                 len = strlen( fname );
452                 if ( fname[ 0 ] != '/' ) {
453                         /* get full path name */
454                         getcwd( path, sizeof( path ) );
455                         pathlen = strlen( path );
456
457                         if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
458                                 fname += 2;
459                                 len -= 2;
460                         }
461                 }
462
463                 bv.bv_len = pathlen + STRLENOF( "/" ) + len;
464                 ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
465                 if ( pathlen ) {
466                         ptr = lutil_strncopy( ptr, path, pathlen );
467                         ptr[ 0 ] = '/';
468                         ptr++;
469                 }
470                 ptr = lutil_strncopy( ptr, fname, len );
471                 if ( ptr[ -1 ] != '/' ) {
472                         ptr[ 0 ] = '/';
473                         ptr++;
474                 }
475                 ptr[ 0 ] = '\0';
476                 
477                 attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
478
479                 next->a_desc = ad_olmDbDirectory;
480                 next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
481                 next->a_vals[ 0 ] = bv;
482
483                 if ( BER_BVISNULL( &nbv ) ) {
484                         next->a_nvals = next->a_vals;
485
486                 } else {
487                         next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
488                         next->a_nvals[ 0 ] = nbv;
489                 }
490
491                 next = next->a_next;
492         }
493
494         cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
495         cb->mc_update = bdb_monitor_update;
496         cb->mc_modify = bdb_monitor_modify;
497         cb->mc_free = bdb_monitor_free;
498         cb->mc_private = (void *)bdb;
499
500         rc = mbe->register_entry_attrs( NULL, a, cb,
501                 base, LDAP_SCOPE_SUBORDINATE, filter );
502
503 cleanup:;
504         if ( rc != 0 ) {
505                 if ( cb != NULL ) {
506                         ch_free( cb );
507                         cb = NULL;
508                 }
509
510                 if ( a != NULL ) {
511                         attrs_free( a );
512                         a = NULL;
513                 }
514
515                 if ( !BER_BVISNULL( filter ) ) {
516                         ch_free( filter->bv_val );
517                         BER_BVZERO( filter );
518                 }
519         }
520
521         /* store for cleanup */
522         bdb->bi_monitor.bdm_cb = (void *)cb;
523
524         /* we don't need to keep track of the attributes, because
525          * bdb_monitor_free() takes care of everything */
526         if ( a != NULL ) {
527                 attrs_free( a );
528         }
529
530         return rc;
531 }
532
533 /*
534  * call from within bdb_db_close()
535  */
536 int
537 bdb_monitor_close( BackendDB *be )
538 {
539         struct bdb_info         *bdb = (struct bdb_info *) be->be_private;
540
541         if ( !BER_BVISNULL( &bdb->bi_monitor.bdm_filter ) ) {
542                 BackendInfo *mi = backend_info( "monitor" );
543                 monitor_extra_t *mbe;
544
545                 if ( !mi || !mi->bi_extra )
546                         return 0;
547                 mbe = mi->bi_extra;
548                 mbe->unregister_entry_callback( NULL,
549                         (monitor_callback_t *)bdb->bi_monitor.bdm_cb,
550                         &bdb->bi_monitor.bdm_nbase,
551                         bdb->bi_monitor.bdm_scope,
552                         &bdb->bi_monitor.bdm_filter );
553
554                 if ( !BER_BVISNULL( &bdb->bi_monitor.bdm_filter ) ) {
555                         ch_free( bdb->bi_monitor.bdm_filter.bv_val );
556                 }
557
558                 memset( &bdb->bi_monitor, 0, sizeof( bdb->bi_monitor ) );
559         }
560
561         return 0;
562 }
563
564 /*
565  * call from within bdb_db_destroy()
566  */
567 int
568 bdb_monitor_destroy( BackendDB *be )
569 {
570         return 0;
571 }