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