]> git.sur5r.net Git - openldap/blob - servers/slapd/repl.c
Changed be_[n]suffix, be_[n]suffixAlias to BerVarray. No more bvec's anywhere.
[openldap] / servers / slapd / repl.c
1 /* repl.c - log modifications for replication purposes */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/string.h>
13 #include <ac/ctype.h>
14 #include <ac/socket.h>
15
16 #ifdef HAVE_SYS_FILE_H
17 #include <sys/file.h>
18 #endif
19
20 #include "slap.h"
21 #include "ldif.h"
22
23 int
24 add_replica_info(
25     Backend     *be,
26     const char  *host 
27 )
28 {
29         int i = 0;
30
31         assert( be );
32         assert( host );
33
34         if ( be->be_replica != NULL ) {
35                 for ( ; be->be_replica[ i ] != NULL; i++ );
36         }
37                 
38         be->be_replica = ch_realloc( be->be_replica, 
39                 sizeof( struct slap_replica_info * )*( i + 2 ) );
40
41         be->be_replica[ i ] 
42                 = ch_calloc( sizeof( struct slap_replica_info ), 1 );
43         be->be_replica[ i ]->ri_host = ch_strdup( host );
44         be->be_replica[ i ]->ri_nsuffix = NULL;
45         be->be_replica[ i ]->ri_attrs = NULL;
46         be->be_replica[ i + 1 ] = NULL;
47
48         return( i );
49 }
50
51 int
52 add_replica_suffix(
53     Backend     *be,
54     int         nr,
55     const char  *suffix
56 )
57 {
58         struct berval dn, ndn;
59         int rc;
60
61         dn.bv_val = (char *) suffix;
62         dn.bv_len = strlen( dn.bv_val );
63
64         rc = dnNormalize2( NULL, &dn, &ndn );
65         if( rc != LDAP_SUCCESS ) {
66                 return 2;
67         }
68
69         if ( select_backend( &ndn, 0, 0 ) != be ) {
70                 free( ndn.bv_val );
71                 return 1;
72         }
73
74         ber_bvarray_add( &be->be_replica[nr]->ri_nsuffix, &ndn );
75         return 0;
76 }
77
78 int
79 add_replica_attrs(
80         Backend *be,
81         int     nr,
82         char    *attrs,
83         int     exclude
84 )
85 {
86         if ( be->be_replica[nr]->ri_attrs != NULL ) {
87                 if ( be->be_replica[nr]->ri_exclude != exclude ) {
88                         fprintf( stderr, "attr selective replication directive '%s' conflicts with previous one (discarded)\n", attrs );
89                         ch_free( be->be_replica[nr]->ri_attrs );
90                         be->be_replica[nr]->ri_attrs = NULL;
91                 }
92         }
93
94         be->be_replica[nr]->ri_exclude = exclude;
95         be->be_replica[nr]->ri_attrs = str2anlist( be->be_replica[nr]->ri_attrs,
96                 attrs, "," );
97         return ( be->be_replica[nr]->ri_attrs == NULL );
98 }
99    
100 static void
101 print_vals( FILE *fp, struct berval *type, struct berval *bv );
102 static void
103 replog1( struct slap_replica_info *ri, Operation *op, void *change, FILE *fp, void *first);
104
105 void
106 replog(
107     Backend     *be,
108     Operation *op,
109     struct berval *dn,
110     struct berval *ndn,
111     void        *change
112 )
113 {
114         Modifications   *ml = NULL;
115         Attribute       *a = NULL;
116         Entry   *e;
117         FILE    *fp, *lfp;
118         int     i;
119 /* undef NO_LOG_WHEN_NO_REPLICAS */
120 #ifdef NO_LOG_WHEN_NO_REPLICAS
121         int     count = 0;
122 #endif
123         int     subsets = 0;
124         long now = slap_get_time();
125
126         if ( be->be_replogfile == NULL && replogfile == NULL ) {
127                 return;
128         }
129
130         ldap_pvt_thread_mutex_lock( &replog_mutex );
131         if ( (fp = lock_fopen( be->be_replogfile ? be->be_replogfile :
132             replogfile, "a", &lfp )) == NULL ) {
133                 ldap_pvt_thread_mutex_unlock( &replog_mutex );
134                 return;
135         }
136
137         for ( i = 0; be->be_replica != NULL && be->be_replica[i] != NULL; i++ ) {
138                 /* check if dn's suffix matches legal suffixes, if any */
139                 if ( be->be_replica[i]->ri_nsuffix != NULL ) {
140                         int j;
141
142                         for ( j = 0; be->be_replica[i]->ri_nsuffix[j].bv_val; j++ ) {
143                                 if ( dnIsSuffix( ndn, &be->be_replica[i]->ri_nsuffix[j] ) ) {
144                                         break;
145                                 }
146                         }
147
148                         if ( !be->be_replica[i]->ri_nsuffix[j].bv_val ) {
149                                 /* do not add "replica:" line */
150                                 continue;
151                         }
152                 }
153                 /* See if we only want a subset of attributes */
154                 if ( be->be_replica[i]->ri_attrs != NULL &&
155                         ( op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_ADD || op->o_tag == LDAP_REQ_EXTENDED ) ) {
156                         if ( !subsets ) {
157                                 subsets = i + 1;
158                         }
159                         /* Do attribute subsets by themselves in a second pass */
160                         continue;
161                 }
162
163                 fprintf( fp, "replica: %s\n", be->be_replica[i]->ri_host );
164 #ifdef NO_LOG_WHEN_NO_REPLICAS
165                 ++count;
166 #endif
167         }
168
169 #ifdef NO_LOG_WHEN_NO_REPLICAS
170         if ( count == 0 && subsets == 0 ) {
171                 /* if no replicas matched, drop the log 
172                  * (should we log it anyway?) */
173                 lock_fclose( fp, lfp );
174                 ldap_pvt_thread_mutex_unlock( &replog_mutex );
175
176                 return;
177         }
178 #endif
179
180         fprintf( fp, "time: %ld\n", now );
181         fprintf( fp, "dn: %s\n", dn->bv_val );
182
183         replog1( NULL, op, change, fp, NULL );
184
185         if ( subsets > 0 ) {
186                 void *first;
187                 for ( i = subsets - 1; be->be_replica != NULL && be->be_replica[i] != NULL; i++ ) {
188
189                         /* If no attrs, we already did this above */
190                         if ( be->be_replica[i]->ri_attrs == NULL ) {
191                                 continue;
192                         }
193
194                         /* check if dn's suffix matches legal suffixes, if any */
195                         if ( be->be_replica[i]->ri_nsuffix != NULL ) {
196                                 int j;
197
198                                 for ( j = 0; be->be_replica[i]->ri_nsuffix[j].bv_val; j++ ) {
199                                         if ( dnIsSuffix( ndn, &be->be_replica[i]->ri_nsuffix[j] ) ) {
200                                                 break;
201                                         }
202                                 }
203
204                                 if ( !be->be_replica[i]->ri_nsuffix[j].bv_val ) {
205                                         /* do not add "replica:" line */
206                                         continue;
207                                 }
208                         }
209                         subsets = 0;
210                         first = NULL;
211                         switch( op->o_tag ) {
212                         case LDAP_REQ_EXTENDED:
213                                 /* quick hack for extended operations */
214                                 /* assume change parameter is a Modfications* */
215                                 /* fall thru */
216                         case LDAP_REQ_MODIFY:
217                                 for ( ml = change; ml != NULL; ml = ml->sml_next ) {
218                                         int is_in, exclude;
219
220                                         is_in = ad_inlist( ml->sml_desc, be->be_replica[i]->ri_attrs );
221                                         exclude = be->be_replica[i]->ri_exclude;
222                                         
223                                         /*
224                                          * there might be a more clever way to do this test,
225                                          * but this way, at least, is comprehensible :)
226                                          */
227                                         if ( ( is_in && !exclude ) || ( !is_in && exclude ) ) {
228                                                 subsets = 1;
229                                                 first = ml;
230                                                 break;
231                                         }
232                                 }
233                                 if ( !subsets ) {
234                                         continue;
235                                 }
236                                 break;
237                         case LDAP_REQ_ADD:
238                                 e = change;
239                                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
240                                         int is_in, exclude;
241
242                                         is_in = ad_inlist( a->a_desc, be->be_replica[i]->ri_attrs );
243                                         exclude = be->be_replica[i]->ri_exclude;
244                                         
245                                         if ( ( is_in && !exclude ) || ( !is_in && exclude ) ) {
246                                                 subsets = 1;
247                                                 first = a;
248                                                 break;
249                                         }
250                                 }
251                                 if ( !subsets ) {
252                                         continue;
253                                 }
254                                 break;
255                         default:
256                                 /* Other operations were logged in the first pass */
257                                 continue;
258                         }
259                         fprintf( fp, "replica: %s\n", be->be_replica[i]->ri_host );
260                         fprintf( fp, "time: %ld\n", now );
261                         fprintf( fp, "dn: %s\n", dn->bv_val );
262                         replog1( be->be_replica[i], op, change, fp, first );
263                 }
264         }
265
266         lock_fclose( fp, lfp );
267         ldap_pvt_thread_mutex_unlock( &replog_mutex );
268 }
269
270
271 static void
272 replog1(
273     struct slap_replica_info *ri,
274     Operation *op,
275     void        *change,
276     FILE        *fp,
277         void    *first
278 )
279 {
280         Modifications   *ml;
281         Attribute       *a;
282         Entry           *e;
283         struct slap_replog_moddn *moddn;
284
285         switch ( op->o_tag ) {
286         case LDAP_REQ_EXTENDED:
287                 /* quick hack for extended operations */
288                 /* assume change parameter is a Modfications* */
289                 /* fall thru */
290
291         case LDAP_REQ_MODIFY:
292                 fprintf( fp, "changetype: modify\n" );
293                 ml = first ? first : change;
294                 for ( ; ml != NULL; ml = ml->sml_next ) {
295                         char *type;
296                         if ( ri && ri->ri_attrs ) {
297                                 int is_in = ad_inlist( ml->sml_desc, ri->ri_attrs );
298
299                                 if ( ( !is_in && !ri->ri_exclude ) || ( is_in && ri->ri_exclude ) ) {
300                                         continue;
301                                 }
302                         }
303                         type = ml->sml_desc->ad_cname.bv_val;
304                         switch ( ml->sml_op ) {
305                         case LDAP_MOD_ADD:
306                                 fprintf( fp, "add: %s\n", type );
307                                 break;
308
309                         case LDAP_MOD_DELETE:
310                                 fprintf( fp, "delete: %s\n", type );
311                                 break;
312
313                         case LDAP_MOD_REPLACE:
314                                 fprintf( fp, "replace: %s\n", type );
315                                 break;
316                         }
317                         if ( ml->sml_bvalues )
318                                 print_vals( fp, &ml->sml_desc->ad_cname, ml->sml_bvalues );
319                         fprintf( fp, "-\n" );
320                 }
321                 break;
322
323         case LDAP_REQ_ADD:
324                 e = change;
325                 fprintf( fp, "changetype: add\n" );
326                 a = first ? first : e->e_attrs;
327                 for ( ; a != NULL; a=a->a_next ) {
328                         if ( ri && ri->ri_attrs ) {
329                                 int is_in = ad_inlist( a->a_desc, ri->ri_attrs );
330                                 if ( ( !is_in && !ri->ri_exclude ) || ( is_in && ri->ri_exclude ) ) {
331                                         continue;
332                                 }
333                                 /* If the list includes objectClass names,
334                                  * only include those classes in the
335                                  * objectClass attribute
336                                  */
337                                 if ( a->a_desc == slap_schema.si_ad_objectClass ) {
338                                         int ocs = 0;
339                                         AttributeName *an;
340                                         struct berval vals[2];
341                                         vals[1].bv_val = NULL;
342                                         vals[1].bv_len = 0;
343                                         for ( an = ri->ri_attrs; an->an_name.bv_val; an++ ) {
344                                                 if ( an->an_oc ) {
345                                                         int i;
346                                                         for ( i=0; a->a_vals[i].bv_val; i++ ) {
347                                                                 if ( a->a_vals[i].bv_len == an->an_name.bv_len
348                                                                         && !strcasecmp(a->a_vals[i].bv_val,
349                                                                                 an->an_name.bv_val ) ) {
350                                                                         ocs = 1;
351                                                                         vals[0] = an->an_name;
352                                                                         print_vals( fp, &a->a_desc->ad_cname, vals );
353                                                                         break;
354                                                                 }
355                                                         }
356                                                 }
357                                         }
358                                         if ( ocs ) continue;
359                                 }
360                         }
361                         print_vals( fp, &a->a_desc->ad_cname, a->a_vals );
362                 }
363                 break;
364
365         case LDAP_REQ_DELETE:
366                 fprintf( fp, "changetype: delete\n" );
367                 break;
368
369         case LDAP_REQ_MODRDN:
370                 moddn = change;
371                 fprintf( fp, "changetype: modrdn\n" );
372                 fprintf( fp, "newrdn: %s\n", moddn->newrdn->bv_val );
373                 fprintf( fp, "deleteoldrdn: %d\n", moddn->deloldrdn ? 1 : 0 );
374                 if( moddn->newsup != NULL ) {
375                         fprintf( fp, "newsuperior: %s\n", moddn->newsup->bv_val );
376                 }
377         }
378         fprintf( fp, "\n" );
379 }
380
381 static void
382 print_vals(
383         FILE *fp,
384         struct berval *type,
385         struct berval *bv )
386 {
387         ber_len_t i, len;
388         char    *buf, *bufp;
389
390         for ( i = 0, len = 0; bv && bv[i].bv_val; i++ ) {
391                 if ( bv[i].bv_len > len )
392                         len = bv[i].bv_len;
393         }
394
395         len = LDIF_SIZE_NEEDED( type->bv_len, len ) + 1;
396         buf = (char *) ch_malloc( len );
397
398         for ( ; bv && bv->bv_val; bv++ ) {
399                 bufp = buf;
400                 ldif_sput( &bufp, LDIF_PUT_VALUE, type->bv_val,
401                                     bv->bv_val, bv->bv_len );
402                 *bufp = '\0';
403
404                 fputs( buf, fp );
405
406         }
407         free( buf );
408 }