]> git.sur5r.net Git - openldap/blob - servers/slapd/repl.c
Added replica attr=<attribute list> support to filter replog content
[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 + 1 ] = NULL;
45
46         return( i );
47 }
48
49 int
50 add_replica_suffix(
51     Backend     *be,
52     int         nr,
53     const char  *suffix
54 )
55 {
56         struct berval dn, *ndn = NULL;
57         int rc;
58
59         dn.bv_val = (char *) suffix;
60         dn.bv_len = strlen( dn.bv_val );
61
62         rc = dnNormalize( NULL, &dn, &ndn );
63         if( rc != LDAP_SUCCESS ) {
64                 return 2;
65         }
66
67         if ( select_backend( ndn, 0, 0 ) != be ) {
68                 ber_bvfree( ndn );
69                 return 1;
70         }
71
72         ber_bvecadd( &be->be_replica[nr]->ri_nsuffix, ndn );
73         return 0;
74 }
75
76 int
77 add_replica_attrs(
78         Backend *be,
79         int     nr,
80         char    *attrs
81 )
82 {
83         be->be_replica[nr]->ri_attrs = str2anlist( be->be_replica[nr]->ri_attrs,
84                 attrs, "," );
85         return ( be->be_replica[nr]->ri_attrs == NULL );
86 }
87    
88 static void
89 print_vals( FILE *fp, struct berval *type, struct berval *bv );
90 static void
91 replog1( struct slap_replica_info *ri, Operation *op, void *change, FILE *fp, void *first);
92
93 void
94 replog(
95     Backend     *be,
96     Operation *op,
97     struct berval *dn,
98     struct berval *ndn,
99     void        *change
100 )
101 {
102         Modifications   *ml = NULL;
103         Attribute       *a = NULL;
104         Entry   *e;
105         FILE    *fp, *lfp;
106         int     i;
107 /* undef NO_LOG_WHEN_NO_REPLICAS */
108 #ifdef NO_LOG_WHEN_NO_REPLICAS
109         int     count = 0;
110 #endif
111         int     subsets = 0;
112         long now = slap_get_time();
113
114         if ( be->be_replogfile == NULL && replogfile == NULL ) {
115                 return;
116         }
117
118         ldap_pvt_thread_mutex_lock( &replog_mutex );
119         if ( (fp = lock_fopen( be->be_replogfile ? be->be_replogfile :
120             replogfile, "a", &lfp )) == NULL ) {
121                 ldap_pvt_thread_mutex_unlock( &replog_mutex );
122                 return;
123         }
124
125         for ( i = 0; be->be_replica != NULL && be->be_replica[i] != NULL; i++ ) {
126                 /* check if dn's suffix matches legal suffixes, if any */
127                 if ( be->be_replica[i]->ri_nsuffix != NULL ) {
128                         int j;
129
130                         for ( j = 0; be->be_replica[i]->ri_nsuffix[j]; j++ ) {
131                                 if ( dnIsSuffix( ndn, be->be_replica[i]->ri_nsuffix[j] ) ) {
132                                         break;
133                                 }
134                         }
135
136                         if ( !be->be_replica[i]->ri_nsuffix[j] ) {
137                                 /* do not add "replica:" line */
138                                 continue;
139                         }
140                 }
141                 /* See if we only want a subset of attributes */
142                 if ( be->be_replica[i]->ri_attrs != NULL &&
143                         ( op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_ADD || op->o_tag == LDAP_REQ_EXTENDED ) ) {
144                         if ( !subsets ) {
145                                 subsets = i + 1;
146                         }
147                         /* Do attribute subsets by themselves in a second pass */
148                         continue;
149                 }
150
151                 fprintf( fp, "replica: %s\n", be->be_replica[i]->ri_host );
152 #ifdef NO_LOG_WHEN_NO_REPLICAS
153                 ++count;
154 #endif
155         }
156
157 #ifdef NO_LOG_WHEN_NO_REPLICAS
158         if ( count == 0 && subsets == 0 ) {
159                 /* if no replicas matched, drop the log 
160                  * (should we log it anyway?) */
161                 lock_fclose( fp, lfp );
162                 ldap_pvt_thread_mutex_unlock( &replog_mutex );
163
164                 return;
165         }
166 #endif
167
168         fprintf( fp, "time: %ld\n", now );
169         fprintf( fp, "dn: %s\n", dn->bv_val );
170
171         replog1( NULL, op, change, fp, NULL );
172
173         if ( subsets > 0 ) {
174                 void *first;
175                 for ( i = subsets - 1; be->be_replica != NULL && be->be_replica[i] != NULL; i++ ) {
176
177                         /* If no attrs, we already did this above */
178                         if ( be->be_replica[i]->ri_attrs == NULL ) {
179                                 continue;
180                         }
181
182                         /* check if dn's suffix matches legal suffixes, if any */
183                         if ( be->be_replica[i]->ri_nsuffix != NULL ) {
184                                 int j;
185
186                                 for ( j = 0; be->be_replica[i]->ri_nsuffix[j]; j++ ) {
187                                         if ( dnIsSuffix( ndn, be->be_replica[i]->ri_nsuffix[j] ) ) {
188                                                 break;
189                                         }
190                                 }
191
192                                 if ( !be->be_replica[i]->ri_nsuffix[j] ) {
193                                         /* do not add "replica:" line */
194                                         continue;
195                                 }
196                         }
197                         subsets = 0;
198                         first = NULL;
199                         switch( op->o_tag ) {
200                         case LDAP_REQ_EXTENDED:
201                                 /* quick hack for extended operations */
202                                 /* assume change parameter is a Modfications* */
203                                 /* fall thru */
204                         case LDAP_REQ_MODIFY:
205                                 for ( ml = change; ml != NULL; ml = ml->sml_next ) {
206                                         if ( ad_inlist( ml->sml_desc, be->be_replica[i]->ri_attrs ) ) {
207                                                 subsets = 1;
208                                                 first = ml;
209                                                 break;
210                                         }
211                                 }
212                                 if ( !subsets ) {
213                                         continue;
214                                 }
215                                 break;
216                         case LDAP_REQ_ADD:
217                                 e = change;
218                                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
219                                         if ( ad_inlist( a->a_desc, be->be_replica[i]->ri_attrs ) ) {
220                                                 subsets = 1;
221                                                 first = a;
222                                                 break;
223                                         }
224                                 }
225                                 if ( !subsets ) {
226                                         continue;
227                                 }
228                                 break;
229                         default:
230                                 /* Other operations were logged in the first pass */
231                                 continue;
232                         }
233                         fprintf( fp, "replica: %s\n", be->be_replica[i]->ri_host );
234                         fprintf( fp, "time: %ld\n", now );
235                         fprintf( fp, "dn: %s\n", dn->bv_val );
236                         replog1( be->be_replica[i], op, change, fp, first );
237                 }
238         }
239
240         lock_fclose( fp, lfp );
241         ldap_pvt_thread_mutex_unlock( &replog_mutex );
242 }
243
244
245 static void
246 replog1(
247     struct slap_replica_info *ri,
248     Operation *op,
249     void        *change,
250     FILE        *fp,
251         void    *first
252 )
253 {
254         Modifications   *ml;
255         Attribute       *a;
256         Entry           *e;
257         struct slap_replog_moddn *moddn;
258
259         switch ( op->o_tag ) {
260         case LDAP_REQ_EXTENDED:
261                 /* quick hack for extended operations */
262                 /* assume change parameter is a Modfications* */
263                 /* fall thru */
264
265         case LDAP_REQ_MODIFY:
266                 fprintf( fp, "changetype: modify\n" );
267                 ml = first ? first : change;
268                 for ( ; ml != NULL; ml = ml->sml_next ) {
269                         char *type;
270                         if ( ri && ri->ri_attrs && !ad_inlist( ml->sml_desc, ri->ri_attrs ) ) {
271                                 continue;
272                         }
273                         type = ml->sml_desc->ad_cname.bv_val;
274                         switch ( ml->sml_op ) {
275                         case LDAP_MOD_ADD:
276                                 fprintf( fp, "add: %s\n", type );
277                                 break;
278
279                         case LDAP_MOD_DELETE:
280                                 fprintf( fp, "delete: %s\n", type );
281                                 break;
282
283                         case LDAP_MOD_REPLACE:
284                                 fprintf( fp, "replace: %s\n", type );
285                                 break;
286                         }
287
288                         print_vals( fp, &ml->sml_desc->ad_cname, ml->sml_bvalues );
289                         fprintf( fp, "-\n" );
290                 }
291                 break;
292
293         case LDAP_REQ_ADD:
294                 e = change;
295                 fprintf( fp, "changetype: add\n" );
296                 a = first ? first : e->e_attrs;
297                 for ( ; a != NULL; a=a->a_next ) {
298                         if ( ri && ri->ri_attrs && !ad_inlist( a->a_desc, ri->ri_attrs ) ) {
299                                 continue;
300                         }
301                         print_vals( fp, &a->a_desc->ad_cname, a->a_vals );
302                 }
303                 break;
304
305         case LDAP_REQ_DELETE:
306                 fprintf( fp, "changetype: delete\n" );
307                 break;
308
309         case LDAP_REQ_MODRDN:
310                 moddn = change;
311                 fprintf( fp, "changetype: modrdn\n" );
312                 fprintf( fp, "newrdn: %s\n", moddn->newrdn->bv_val );
313                 fprintf( fp, "deleteoldrdn: %d\n", moddn->deloldrdn ? 1 : 0 );
314                 if( moddn->newsup != NULL ) {
315                         fprintf( fp, "newsuperior: %s\n", moddn->newsup->bv_val );
316                 }
317         }
318         fprintf( fp, "\n" );
319 }
320
321 static void
322 print_vals(
323         FILE *fp,
324         struct berval *type,
325         struct berval *bv )
326 {
327         int len;
328         char    *buf, *bufp;
329
330         for ( ; bv && bv->bv_val; bv++ )
331         {
332                 len = type->bv_len;
333                 len = LDIF_SIZE_NEEDED( len, bv->bv_len ) + 1;
334                 buf = (char *) ch_malloc( len );
335
336                 bufp = buf;
337                 ldif_sput( &bufp, LDIF_PUT_VALUE, type->bv_val,
338                                     bv->bv_val, bv->bv_len );
339                 *bufp = '\0';
340
341                 fputs( buf, fp );
342
343                 free( buf );
344         }
345 }