]> git.sur5r.net Git - openldap/blob - servers/slapd/slapmodify.c
ITS#7256 Rework entry retrieval and cleanup.
[openldap] / servers / slapd / slapmodify.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2014 The OpenLDAP Foundation.
5  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
6  * Portions Copyright 2003 IBM Corporation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25
26 #include "ac/stdlib.h"
27
28 #include "ac/ctype.h"
29 #include "ac/string.h"
30 #include "ac/socket.h"
31 #include "ac/unistd.h"
32
33 #include "lber.h"
34 #include "ldif.h"
35 #include "lutil.h"
36 #include "lutil_meter.h"
37 #include <sys/stat.h>
38
39 #include "slapcommon.h"
40
41 static char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
42
43 int
44 slapmodify( int argc, char **argv )
45 {
46         char *buf = NULL;
47         const char *text;
48         char textbuf[SLAP_TEXT_BUFLEN] = { '\0' };
49         size_t textlen = sizeof textbuf;
50         const char *progname = "slapmodify";
51
52         struct berval csn;
53         unsigned long sid;
54         struct berval bvtext;
55         ID id;
56         OperationBuffer opbuf;
57         Operation *op;
58
59         int checkvals, ldifrc;
60         unsigned long lineno, nextline;
61         int lmax;
62         int rc = EXIT_SUCCESS;
63
64         int enable_meter = 0;
65         lutil_meter_t meter;
66         struct stat stat_buf;
67
68         /* default "000" */
69         csnsid = 0;
70
71         if ( isatty (2) ) enable_meter = 1;
72         slap_tool_init( progname, SLAPMODIFY, argc, argv );
73
74         memset( &opbuf, 0, sizeof(opbuf) );
75         op = &opbuf.ob_op;
76         op->o_hdr = &opbuf.ob_hdr;
77         op->o_bd = be;
78
79         if ( !be->be_entry_open ||
80                 !be->be_entry_close ||
81                 !be->be_entry_put ||
82                 !be->be_dn2id_get ||
83                 !be->be_entry_get ||
84                 !be->be_entry_modify )
85         {
86                 fprintf( stderr, "%s: database doesn't support necessary operations.\n",
87                         progname );
88                 if ( dryrun ) {
89                         fprintf( stderr, "\t(dry) continuing...\n" );
90
91                 } else {
92                         exit( EXIT_FAILURE );
93                 }
94         }
95
96         checkvals = (slapMode & SLAP_TOOL_QUICK) ? 0 : 1;
97
98         lmax = 0;
99         nextline = 0;
100
101         /* enforce schema checking unless not disabled */
102         if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) {
103                 SLAP_DBFLAGS(be) &= ~(SLAP_DBFLAG_NO_SCHEMA_CHECK);
104         }
105
106         if( !dryrun && be->be_entry_open( be, 1 ) != 0 ) {
107                 fprintf( stderr, "%s: could not open database.\n",
108                         progname );
109                 exit( EXIT_FAILURE );
110         }
111
112         (void)slap_tool_update_ctxcsn_init();
113
114         if ( enable_meter 
115 #ifdef LDAP_DEBUG
116                 /* tools default to "none" */
117                 && slap_debug == LDAP_DEBUG_NONE
118 #endif
119                 && !fstat ( fileno ( ldiffp->fp ), &stat_buf )
120                 && S_ISREG(stat_buf.st_mode) ) {
121                 enable_meter = !lutil_meter_open(
122                         &meter,
123                         &lutil_meter_text_display,
124                         &lutil_meter_linear_estimator,
125                         stat_buf.st_size);
126         } else {
127                 enable_meter = 0;
128         }
129
130         /* nextline is the line number of the end of the current entry */
131         for( lineno=1; ( ldifrc = ldif_read_record( ldiffp, &nextline, &buf, &lmax )) > 0;
132                 lineno=nextline+1 )
133         {
134                 BackendDB *bd;
135                 Entry *e_orig = NULL, *e = NULL;
136                 struct berval rbuf;
137                 LDIFRecord lr;
138                 struct berval ndn;
139                 int n;
140                 int is_oc = 0;
141                 int local_rc;
142                 int mod_err = 0;
143                 char *request = "(unknown)";
144
145                 ber_str2bv( buf, 0, 0, &rbuf );
146
147                 if ( lineno < jumpline )
148                         continue;
149
150                 if ( enable_meter )
151                         lutil_meter_update( &meter,
152                                          ftell( ldiffp->fp ),
153                                          0);
154
155                 /*
156                  * Initialize text buffer
157                  */
158                 bvtext.bv_len = textlen;
159                 bvtext.bv_val = textbuf;
160                 bvtext.bv_val[0] = '\0';
161
162                 local_rc = ldap_parse_ldif_record( &rbuf, lineno, &lr,
163                         "slapmodify", LDIF_NO_CONTROLS );
164
165                 if ( local_rc != LDAP_SUCCESS ) {
166                         fprintf( stderr, "%s: could not parse entry (line=%lu)\n",
167                                 progname, lineno );
168                         rc = EXIT_FAILURE;
169                         if( continuemode ) continue;
170                         break;
171                 }
172
173                 switch ( lr.lr_op ) {
174                 case LDAP_REQ_ADD:
175                         request = "add";
176                         break;
177
178                 case LDAP_REQ_MODIFY:
179                         request = "modify";
180                         break;
181
182                 case LDAP_REQ_DELETE:
183                         if ( be->be_entry_delete )
184                         {
185                                 request = "delete";
186                                 break;
187                         }
188                         /* backend does not support delete, fallthrough */
189
190                 case LDAP_REQ_MODRDN:
191                         fprintf( stderr, "%s: request 0x%lx not supported (line=%lu)\n",
192                                 progname, (unsigned long)lr.lr_op, lineno );
193                         rc = EXIT_FAILURE;
194                         if( continuemode ) continue;
195                         goto done;
196
197                 default:
198                         /* record skipped e.g. version: or comment or something we don't handle yet */
199                         continue;
200                 }
201
202                 local_rc = dnNormalize( 0, NULL, NULL, &lr.lr_dn, &ndn, NULL );
203                 if ( local_rc != LDAP_SUCCESS ) {
204                         fprintf( stderr, "%s: DN=\"%s\" normalization failed (line=%lu)\n",
205                                 progname, lr.lr_dn.bv_val, lineno );
206                         rc = EXIT_FAILURE;
207                         if( continuemode ) continue;
208                         break;
209                 }
210
211                 /* make sure the DN is not empty */
212                 if( BER_BVISEMPTY( &ndn ) &&
213                         !BER_BVISEMPTY( be->be_nsuffix ))
214                 {
215                         fprintf( stderr, "%s: line %lu: "
216                                 "%s entry with empty dn=\"\"",
217                                 progname, lineno, request );
218                         bd = select_backend( &ndn, nosubordinates );
219                         if ( bd ) {
220                                 BackendDB *bdtmp;
221                                 int dbidx = 0;
222                                 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
223                                         if ( bdtmp == bd ) break;
224                                         dbidx++;
225                                 }
226
227                                 assert( bdtmp != NULL );
228                                 
229                                 fprintf( stderr, "; did you mean to use database #%d (%s)?",
230                                         dbidx,
231                                         bd->be_suffix[0].bv_val );
232
233                         }
234                         fprintf( stderr, "\n" );
235                         rc = EXIT_FAILURE;
236                         SLAP_FREE( ndn.bv_val );
237                         ldap_ldif_record_done( &lr );
238                         if( continuemode ) continue;
239                         break;
240                 }
241
242                 /* check backend */
243                 bd = select_backend( &ndn, nosubordinates );
244                 if ( bd != be ) {
245                         fprintf( stderr, "%s: line %lu: "
246                                 "database #%d (%s) not configured to hold \"%s\"",
247                                 progname, lineno,
248                                 dbnum,
249                                 be->be_suffix[0].bv_val,
250                                 lr.lr_dn.bv_val );
251                         if ( bd ) {
252                                 BackendDB *bdtmp;
253                                 int dbidx = 0;
254                                 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
255                                         if ( bdtmp == bd ) break;
256                                         dbidx++;
257                                 }
258
259                                 assert( bdtmp != NULL );
260                                 
261                                 fprintf( stderr, "; did you mean to use database #%d (%s)?",
262                                         dbidx,
263                                         bd->be_suffix[0].bv_val );
264
265                         } else {
266                                 fprintf( stderr, "; no database configured for that naming context" );
267                         }
268                         fprintf( stderr, "\n" );
269                         rc = EXIT_FAILURE;
270                         SLAP_FREE( ndn.bv_val );
271                         ldap_ldif_record_done( &lr );
272                         if( continuemode ) continue;
273                         break;
274                 }
275
276                 /* get id and/or entry */
277                 switch ( lr.lr_op ) {
278                         case LDAP_REQ_ADD:
279                                 e = entry_alloc();
280                                 ber_dupbv( &e->e_name, &lr.lr_dn );
281                                 ber_dupbv( &e->e_nname, &ndn );
282                                 break;
283
284                         //case LDAP_REQ_MODRDN:
285                         case LDAP_REQ_DELETE:
286                         case LDAP_REQ_MODIFY:
287                                 id = be->be_dn2id_get( be, &ndn );
288                                 rc = (id == NOID);
289                                 if ( rc == LDAP_SUCCESS && lr.lr_op != LDAP_REQ_DELETE ) {
290                                         e_orig = be->be_entry_get( be, id );
291                                         e = entry_dup( e_orig );
292                                 }
293                                 break;
294                 }
295
296                 if ( rc != LDAP_SUCCESS ) {
297                         fprintf( stderr, "%s: no such entry \"%s\" in database (lineno=%d)\n",
298                                 progname, ndn.bv_val, lineno );
299                         rc = EXIT_FAILURE;
300                         SLAP_FREE( ndn.bv_val );
301                         if( continuemode ) continue;
302                         goto done;
303                 }
304
305                 if ( lr.lrop_mods ) {
306                         for ( n = 0; lr.lrop_mods && lr.lrop_mods[ n ] != NULL; n++ ) {
307                                 LDAPMod *mod = lr.lrop_mods[ n ];
308                                 Modification mods = { 0 };
309                                 unsigned i = 0;
310                                 int bin = (mod->mod_op & LDAP_MOD_BVALUES);
311                                 int pretty = 0;
312                                 int normalize = 0;
313
314                                 local_rc = slap_str2ad( mod->mod_type, &mods.sm_desc, &text );
315                                 if ( local_rc != LDAP_SUCCESS ) {
316                                         fprintf( stderr, "%s: slap_str2ad(\"%s\") failed for entry \"%s\" (%d: %s, lineno=%lu)\n",
317                                                 progname, mod->mod_type, lr.lr_dn.bv_val, local_rc, text, lineno );
318                                         rc = EXIT_FAILURE;
319                                         mod_err = 1;
320                                         if( continuemode ) continue;
321                                         SLAP_FREE( ndn.bv_val );
322                                         ldap_ldif_record_done( &lr );
323                                         entry_free( e );
324                                         be_entry_release_w( op, e_orig );
325                                         goto done;
326                                 }
327
328                                 mods.sm_type = mods.sm_desc->ad_cname;
329
330                                 if ( mods.sm_desc->ad_type->sat_syntax->ssyn_pretty ) {
331                                         pretty = 1;
332
333                                 } else {
334                                         assert( mods.sm_desc->ad_type->sat_syntax->ssyn_validate != NULL );
335                                 }
336
337                                 if ( mods.sm_desc->ad_type->sat_equality &&
338                                         mods.sm_desc->ad_type->sat_equality->smr_normalize )
339                                 {
340                                         normalize = 1;
341                                 }
342
343                                 if ( bin && mod->mod_bvalues ) {
344                                         for ( i = 0; mod->mod_bvalues[ i ] != NULL; i++ )
345                                                 ;
346
347                                 } else if ( !bin && mod->mod_values ) {
348                                         for ( i = 0; mod->mod_values[ i ] != NULL; i++ )
349                                                 ;
350                                 }
351
352                                 if ( i != 0 )
353                                 {
354                                         mods.sm_values = SLAP_CALLOC( sizeof( struct berval ), i + 1 );
355                                         if ( normalize ) {
356                                                 mods.sm_nvalues = SLAP_CALLOC( sizeof( struct berval ), i + 1 );
357                                         } else {
358                                                 mods.sm_nvalues = NULL;
359                                         }
360                                 }
361                                 mods.sm_numvals = i;
362
363                                 for ( i = 0; i < mods.sm_numvals; i++ ) {
364                                         struct berval bv;
365
366                                         if ( bin ) {
367                                                 bv = *mod->mod_bvalues[ i ];
368                                         } else {
369                                                 ber_str2bv( mod->mod_values[ i ], 0, 0, &bv );
370                                         }
371
372                                         if ( pretty ) {
373                                                 local_rc = ordered_value_pretty( mods.sm_desc,
374                                                 &bv, &mods.sm_values[i], NULL );
375
376                                         } else {
377                                                 local_rc = ordered_value_validate( mods.sm_desc,
378                                                         &bv, 0 );
379                                         }
380
381                                         if ( local_rc != LDAP_SUCCESS ) {
382                                                 fprintf( stderr, "%s: DN=\"%s\": unable to %s attr=%s value #%d\n",
383                                                         progname, e->e_dn, pretty ? "prettify" : "validate",
384                                                         mods.sm_desc->ad_cname.bv_val, i );
385                                                 /* handle error */
386                                                 mod_err = 1;
387                                                 rc = EXIT_FAILURE;
388                                                 ber_bvarray_free( mods.sm_values );
389                                                 ber_bvarray_free( mods.sm_nvalues );
390                                                 if( continuemode ) continue;
391                                                 SLAP_FREE( ndn.bv_val );
392                                                 ldap_ldif_record_done( &lr );
393                                                 entry_free( e );
394                                                 be_entry_release_w( op, e_orig );
395                                                 goto done;
396                                         }
397
398                                         if ( !pretty ) {
399                                                 ber_dupbv( &mods.sm_values[i], &bv );
400                                         }
401
402                                         if ( normalize ) {
403                                                 local_rc = ordered_value_normalize(
404                                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
405                                                         mods.sm_desc,
406                                                         mods.sm_desc->ad_type->sat_equality,
407                                                         &mods.sm_values[i], &mods.sm_nvalues[i],
408                                                         NULL );
409                                                 if ( local_rc != LDAP_SUCCESS ) {
410                                                         fprintf( stderr, "%s: DN=\"%s\": unable to normalize attr=%s value #%d\n",
411                                                                 progname, e->e_dn, mods.sm_desc->ad_cname.bv_val, i );
412                                                         /* handle error */
413                                                         mod_err = 1;
414                                                         rc = EXIT_FAILURE;
415                                                         ber_bvarray_free( mods.sm_values );
416                                                         ber_bvarray_free( mods.sm_nvalues );
417                                                         if( continuemode ) continue;
418                                                         SLAP_FREE( ndn.bv_val );
419                                                         ldap_ldif_record_done( &lr );
420                                                         entry_free( e );
421                                                         be_entry_release_w( op, e_orig );
422                                                         goto done;
423                                                 }
424                                         }
425                                 }
426
427                                 mods.sm_op = (mod->mod_op & ~LDAP_MOD_BVALUES);
428                                 mods.sm_flags = 0;
429
430                                 if ( mods.sm_desc == slap_schema.si_ad_objectClass ) {
431                                         is_oc = 1;
432                                 }
433
434                                 switch ( mods.sm_op ) {
435                                 case LDAP_MOD_ADD:
436                                         local_rc = modify_add_values( e, &mods,
437                                                 0, &text, textbuf, textlen );
438                                         break;
439
440                                 case LDAP_MOD_DELETE:
441                                         local_rc = modify_delete_values( e, &mods,
442                                                 0, &text, textbuf, textlen );
443                                         break;
444
445                                 case LDAP_MOD_REPLACE:
446                                         local_rc = modify_replace_values( e, &mods,
447                                                 0, &text, textbuf, textlen );
448                                         break;
449
450                                 case LDAP_MOD_INCREMENT:
451                                         local_rc = modify_increment_values( e, &mods,
452                                                 0, &text, textbuf, textlen );
453                                         break;
454                                 }
455
456                                 if ( local_rc != LDAP_SUCCESS ) {
457                                         fprintf( stderr, "%s: DN=\"%s\": unable to modify attr=%s\n",
458                                                 progname, e->e_dn, mods.sm_desc->ad_cname.bv_val );
459                                         rc = EXIT_FAILURE;
460                                         ber_bvarray_free( mods.sm_values );
461                                         ber_bvarray_free( mods.sm_nvalues );
462                                         if( continuemode ) continue;
463                                         SLAP_FREE( ndn.bv_val );
464                                         ldap_ldif_record_done( &lr );
465                                         entry_free( e );
466                                         be_entry_release_w( op, e_orig );
467                                         goto done;
468                                 }
469                         }
470
471                         rc = slap_tool_entry_check( progname, op, e, lineno, &text, textbuf, textlen );
472                         if ( rc != LDAP_SUCCESS ) {
473                                 rc = EXIT_FAILURE;
474                                 SLAP_FREE( ndn.bv_val );
475                                 ldap_ldif_record_done( &lr );
476                                 if( continuemode ) continue;
477                                 entry_free( e );
478                                 break;
479                         }
480                 }
481
482                 if ( SLAP_LASTMOD(be) && e != NULL ) {
483                         time_t now = slap_get_time();
484                         char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
485                         struct berval vals[ 2 ];
486
487                         struct berval name, timestamp;
488
489                         struct berval nvals[ 2 ];
490                         struct berval nname;
491                         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
492
493                         Attribute *a;
494
495                         vals[1].bv_len = 0;
496                         vals[1].bv_val = NULL;
497
498                         nvals[1].bv_len = 0;
499                         nvals[1].bv_val = NULL;
500
501                         csn.bv_len = ldap_pvt_csnstr( csnbuf, sizeof( csnbuf ), csnsid, 0 );
502                         csn.bv_val = csnbuf;
503
504                         timestamp.bv_val = timebuf;
505                         timestamp.bv_len = sizeof(timebuf);
506
507                         slap_timestamp( &now, &timestamp );
508
509                         if ( BER_BVISEMPTY( &be->be_rootndn ) ) {
510                                 BER_BVSTR( &name, SLAPD_ANONYMOUS );
511                                 nname = name;
512                         } else {
513                                 name = be->be_rootdn;
514                                 nname = be->be_rootndn;
515                         }
516
517                         a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
518                         if ( a != NULL ) {
519                                 vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
520                                 vals[0].bv_val = uuidbuf;
521                                 if ( a->a_vals != a->a_nvals ) {
522                                         SLAP_FREE( a->a_nvals[0].bv_val );
523                                         SLAP_FREE( a->a_nvals );
524                                 }
525                                 SLAP_FREE( a->a_vals[0].bv_val );
526                                 SLAP_FREE( a->a_vals );
527                                 a->a_vals = NULL;
528                                 a->a_nvals = NULL;
529                                 a->a_numvals = 0;
530                         }
531                         attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, vals, NULL );
532
533                         a = attr_find( e->e_attrs, slap_schema.si_ad_creatorsName );
534                         if ( a == NULL ) {
535                                 vals[0] = name;
536                                 nvals[0] = nname;
537                                 attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals );
538
539                         } else {
540                                 ber_bvreplace( &a->a_vals[0], &name );
541                                 ber_bvreplace( &a->a_nvals[0], &nname );
542                         }
543
544                         a = attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp );
545                         if ( a == NULL ) {
546                                 vals[0] = timestamp;
547                                 attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL );
548
549                         } else {
550                                 ber_bvreplace( &a->a_vals[0], &timestamp );
551                         }
552
553                         a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
554                         if ( a == NULL ) {
555                                 vals[0] = csn;
556                                 attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL );
557
558                         } else {
559                                 ber_bvreplace( &a->a_vals[0], &csn );
560                         }
561
562                         a = attr_find( e->e_attrs, slap_schema.si_ad_modifiersName );
563                         if ( a == NULL ) {
564                                 vals[0] = name;
565                                 nvals[0] = nname;
566                                 attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals );
567
568                         } else {
569                                 ber_bvreplace( &a->a_vals[0], &name );
570                                 ber_bvreplace( &a->a_nvals[0], &nname );
571                         }
572
573                         a = attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp );
574                         if ( a == NULL ) {
575                                 vals[0] = timestamp;
576                                 attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL );
577
578                         } else {
579                                 ber_bvreplace( &a->a_vals[0], &timestamp );
580                         }
581                 }
582
583                 if ( mod_err ) break;
584
585                 /* check schema, objectClass etc */
586
587                 if ( !dryrun ) {
588                         switch ( lr.lr_op ) {
589                         case LDAP_REQ_ADD:
590                                 id = be->be_entry_put( be, e, &bvtext );
591                                 rc = (id == NOID);
592                                 break;
593
594                         case LDAP_REQ_MODIFY:
595                                 id = be->be_entry_modify( be, e, &bvtext );
596                                 rc = (id == NOID);
597                                 break;
598
599                         case LDAP_REQ_DELETE:
600                                 rc = be->be_entry_delete( be, id, &bvtext );
601                                 e_orig = NULL;
602                                 break;
603
604                         }
605
606                         if( rc != LDAP_SUCCESS ) {
607                                 fprintf( stderr, "%s: could not %s entry dn=\"%s\" "
608                                         "(line=%lu): %s\n", progname, request, e->e_dn,
609                                         lineno, bvtext.bv_val );
610                                 rc = EXIT_FAILURE;
611                                 entry_free( e );
612                                 if( continuemode ) continue;
613                                 break;
614                         }
615
616                         sid = slap_tool_update_ctxcsn_check( progname, e );
617
618                         if ( verbose )
619                                 fprintf( stderr, "%s: \"%s\" (%08lx)\n",
620                                         request, e->e_dn, (long) id );
621                 } else {
622                         if ( verbose )
623                                 fprintf( stderr, "%s: \"%s\"\n",
624                                         request, e->e_dn );
625                 }
626
627                 ldap_ldif_record_done( &lr );
628                 if ( e ) entry_free( e );
629                 if ( e_orig ) be_entry_release_w( op, e_orig );
630                 if ( rc != LDAP_SUCCESS && !continuemode ) break;
631         }
632
633 done:;
634         if ( ldifrc < 0 )
635                 rc = EXIT_FAILURE;
636
637         bvtext.bv_len = textlen;
638         bvtext.bv_val = textbuf;
639         bvtext.bv_val[0] = '\0';
640
641         if ( enable_meter ) {
642                 lutil_meter_update( &meter, ftell( ldiffp->fp ), 1);
643                 lutil_meter_close( &meter );
644         }
645
646         if ( rc == EXIT_SUCCESS ) {
647                 rc = slap_tool_update_ctxcsn( progname, sid, &bvtext );
648         }
649
650         ch_free( buf );
651
652         if ( !dryrun ) {
653                 if ( enable_meter ) {
654                         fprintf( stderr, "Closing DB..." );
655                 }
656                 if( be->be_entry_close( be ) ) {
657                         rc = EXIT_FAILURE;
658                 }
659
660                 if( be->be_sync ) {
661                         be->be_sync( be );
662                 }
663                 if ( enable_meter ) {
664                         fprintf( stderr, "\n" );
665                 }
666         }
667
668         if ( slap_tool_destroy())
669                 rc = EXIT_FAILURE;
670
671         return rc;
672 }
673