]> git.sur5r.net Git - openldap/blob - servers/slapd/tools/edb2ldif.c
Add OpenLDAP RCSid to *.[ch] in clients, libraries, and servers.
[openldap] / servers / slapd / tools / edb2ldif.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright (c) 1995 Regents of the University of Michigan.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted
7  * provided that this notice is preserved and that due credit is given
8  * to the University of Michigan at Ann Arbor. The name of the University
9  * may not be used to endorse or promote products derived from this
10  * software without specific prior written permission. This software
11  * is provided ``as is'' without express or implied warranty.
12  */
13
14 #include "portable.h"
15
16 #include <stdio.h>
17
18 #include <ac/stdlib.h>
19
20 #include <ac/ctype.h>
21 #include <ac/errno.h>
22 #include <ac/dirent.h>
23 #include <ac/string.h>
24 #include <ac/unistd.h>
25
26 #include <sys/stat.h>
27
28 #include <quipu/config.h>
29 #include <quipu/entry.h>
30 #include <quipu/commonarg.h>
31 #include <quipu/attrvalue.h>
32
33 #if ICRELEASE > 1
34 #define HAVE_FILE_ATTR_DIR
35 #endif
36
37 #ifdef TURBO_DISK
38 #define HAVE_PARSE_ENTRY
39 #endif
40
41 #define DEF_EDBFILENAME         "EDB"
42 #define EDB_ROOT_FILENAME       "EDB.root"
43 #define DEF_BASEDN              ""
44 #define EDBMAP_FILENAME         "EDB.map"
45 #define ADDVALS_FILENAME        ".add"
46
47 #define MAX_LINE_SIZE   2048
48
49 #define VERBOSE_ENTRY_REPORT_THRESHOLD  250
50
51
52 /* data structures */
53 struct edbmap {
54     char                *edbm_filename;
55     char                *edbm_rdn;
56     struct edbmap       *edbm_next;
57 };
58
59 /* prototypes */
60 static int edb2ldif( FILE *outfp, char *edbfile, char *basedn, int recurse );
61 static int convert_entry( FILE *fp, char *edbname, FILE *outfp,
62         char *basedn, char *loc_addvals, int loc_addlen, char *linebuf );
63 static int add_rdn_values (Attr_Sequence entryas, RDN rdn);
64 static int read_edbmap( char *mapfile, struct edbmap **edbmapp );
65 static char *file2rdn( struct edbmap *edbmap, char *filename );
66 static void free_edbmap( struct edbmap *edbmap );
67 static char *read_file( char *filename, int *lenp );
68 static void print_err( char *msg );
69
70
71 /* globals */
72 #ifdef LDAP_DEBUG
73 static int      debugflg;
74 #endif
75 static int      verboseflg;
76 static int      override_add = 0;
77 static int      entrycount;
78 static char     **ignore_attr = NULL;
79 static char     *always_addvals = NULL;
80 static int      always_addlen;
81 static char     *last_dn;
82 static char     *edb_home = ".";
83 char            *progname;
84 int             ldap_syslog = 0;
85 int             ldap_syslog_level = 0;
86
87
88 int
89 main( int argc, char **argv )
90 {
91     char        *usage = "usage: %s [-d] [-o] [-r] [-v] [-b basedn] [-a addvalsfile] [-f fileattrdir] [-i ignoreattr...] [edbfile...]\n";
92     char        edbfile[ MAXNAMLEN ], *basedn;
93     int         c, rc, errflg, ignore_count, recurse;
94     extern char dsa_mode;
95 #ifdef HAVE_FILE_ATTR_DIR
96     extern char *file_attr_directory;
97 #endif
98
99     if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
100         progname = argv[ 0 ];
101     } else {
102         ++progname;
103     }
104
105     errflg = recurse = 0;
106 #ifdef LDAP_DEBUG
107     debugflg = 0;
108 #endif
109     ignore_count = 0;
110     always_addvals = NULL;
111     basedn = NULL;
112
113     while (( c = getopt( argc, argv, "dorva:b:f:h:i:" )) != EOF ) {
114         switch( c ) {
115         case 'd':
116 #ifdef LDAP_DEBUG
117             ++debugflg;
118 #else
119             fprintf( stderr, "Ignoring -d:  compile with -DLDAP_DEBUG to enable this option.\n" );
120 #endif
121             break;
122
123         case 'o':
124             ++override_add;     
125             break;
126
127         case 'r':
128             ++recurse;  
129             break;
130
131         case 'v':
132             ++verboseflg;
133             break;
134
135         case 'a':
136             if ( always_addvals != NULL ) {
137                 ++errflg;
138             } else if (( always_addvals = read_file( optarg, &always_addlen ))
139                     == NULL ) {
140                 print_err( optarg );
141                 exit( EXIT_FAILURE );
142             }
143             break;
144
145         case 'b':
146             if ( basedn != NULL ) {
147                 ++errflg;
148             } else {
149                 basedn = optarg;
150             }
151             break;
152
153         case 'f':
154 #ifdef HAVE_FILE_ATTR_DIR
155             /* add trailing slash to directory name if missing */
156             if ( *( optarg + strlen( optarg ) - 1 ) == '/' ) {
157                 file_attr_directory = strdup( optarg );
158             } else if (( file_attr_directory = (char *)malloc( strlen( optarg )
159                     + 2 )) != NULL ) {
160                 sprintf( file_attr_directory, "%s/", optarg );
161         
162             }
163             if ( file_attr_directory == NULL ) {
164                 print_err( "malloc" );
165                 exit( EXIT_FAILURE );
166             }
167 #else /* HAVE_FILE_ATTR_DIR */
168             fprintf( stderr, "Ignoring -f:  this option requires a newer version of ISODE.\n" );
169 #endif /* HAVE_FILE_ATTR_DIR */
170             break;
171
172         case 'h':
173             edb_home = optarg;
174             break;
175
176         case 'i':
177             if ( ignore_count == 0 ) {
178                 ignore_attr = (char **)malloc( 2 * sizeof( char * ));
179             } else {
180                 ignore_attr = (char **)realloc( ignore_attr,
181                     ( ignore_count + 2 ) * sizeof( char * ));
182             }
183             if ( ignore_attr == NULL ) {
184                 print_err( "malloc/realloc" );
185                 exit( EXIT_FAILURE );
186             }
187             ignore_attr[ ignore_count ] = optarg;
188             ignore_attr[ ++ignore_count ] = NULL;
189             break;
190
191         default:
192             ++errflg;
193         }
194     }
195
196     if ( errflg ) {
197         fprintf( stderr, usage, progname );
198         exit( EXIT_FAILURE );
199     }
200
201     if ( basedn == NULL ) {
202         basedn = DEF_BASEDN;
203     }
204
205     /* load & initialize quipu syntax handlers */
206     quipu_syntaxes();
207 #ifdef LDAP_USE_PP
208     pp_quipu_init( progname );
209 #endif
210     dsap_init( NULL, NULL );
211
212     dsa_mode = 1;       /* so {CRYPT} is accepted by EDB parse routines */
213
214     if ( init_syntaxes() < 0 ) {
215         fprintf( stderr, "%s: init_syntaxes failed -- check your oid tables \n",
216             progname );
217         exit( EXIT_FAILURE );
218     }
219
220
221     entrycount = 0;
222
223     /* process EDB file(s) */
224     if ( optind >= argc ) {
225         *edbfile = '\0';
226         rc = edb2ldif( stdout, edbfile, basedn, recurse );
227     } else {
228         for ( rc = 0; rc >= 0 && optind < argc; ++optind ) {
229             if ( argv[ optind ][ 0 ] == '/' ) {
230                 strcpy( edbfile, argv[ optind ] );
231             } else {
232                 sprintf( edbfile, "%s/%s", edb_home, argv[ optind ] );
233             }
234             rc = edb2ldif( stdout, edbfile, basedn, recurse );
235         }
236     }
237
238     if ( last_dn != NULL ) {
239         free( last_dn );
240     }
241
242 #ifdef LDAP_DEBUG
243     fprintf( stderr, "edb2ldif: exit( %d )\n", ( rc < 0 ) ? 1 : 0 );
244 #endif
245
246     exit( ( rc < 0 ) ? EXIT_FAILURE : EXIT_SUCCESS );
247 }
248
249
250 static int
251 edb2ldif( FILE *outfp, char *edbfile, char *basedn, int recurse )
252 {
253     FILE        *fp;
254     char        *addvals, *p, *rdn, line[ MAX_LINE_SIZE + 1 ];
255     char        dirname[ MAXNAMLEN ], filename[ MAXNAMLEN ];
256     int         err, startcount, addvals_len;
257     struct stat st;
258
259 #ifdef LDAP_DEBUG
260     if ( debugflg ) {
261         fprintf( stderr, "edb2ldif( 0x%X, \"%s\", \"%s\", %d)\n",
262                 outfp, edbfile, basedn, recurse );
263     }
264 #endif
265
266     if ( *edbfile == '\0' ) {
267         sprintf( filename, "%s/%s", edb_home, EDB_ROOT_FILENAME );
268         if ( stat( filename, &st ) == 0 ) {
269             if (( err = edb2ldif( outfp, filename, basedn, 0 )) < 0 ) {
270 #ifdef LDAP_DEBUG
271                 if ( debugflg ) {
272                     fprintf( stderr, "edb2ldif: 0 return( %d )\n", err );
273                 }
274 #endif
275                 return( err );
276             }
277             if (( basedn = strdup( last_dn )) == NULL ) {
278                 print_err( "strdup" );
279 #ifdef LDAP_DEBUG
280                 if ( debugflg ) {
281                     fprintf( stderr, "edb2ldif: 1 return( -1 )\n" );
282                 }
283 #endif
284                 return( -1 );
285             }
286         }
287         sprintf( edbfile, "%s/%s", edb_home, DEF_EDBFILENAME );
288     }
289
290     if ( verboseflg ) {
291         fprintf( stderr, "%s: converting EDB file: \"%s\"\n\tbasedn: \"%s\"\n",
292                 progname, edbfile, basedn );
293     }
294
295     startcount = entrycount;
296     err = 0;
297
298
299     /* construct name of directory we are working in */
300     if (( p = strrchr( edbfile, '/' )) == NULL ) {
301         dirname[ 0 ] = '.';
302         dirname[ 1 ] = '\0';
303     } else {
304         strncpy( dirname, edbfile, p - edbfile );
305         dirname[ p - edbfile ] = '\0';
306     }
307
308     /* load local ".add" file (if any) */
309     sprintf( filename, "%s/%s", dirname, ADDVALS_FILENAME );
310     addvals_len = 0;
311     addvals = read_file( filename, &addvals_len );
312
313     /* read and convert this EDB file */
314     if (( fp = fopen( edbfile, "r" )) == NULL ) {
315         print_err( edbfile );
316         if ( addvals != NULL ) {
317             free( addvals );
318         }
319 #ifdef LDAP_DEBUG
320         if ( debugflg ) {
321             fprintf( stderr, "edb2ldif: 2 return( -1 )\n" );
322         }
323 #endif
324         return( -1 );
325     }
326
327     /* skip first two lines (type and timestamp) if they are present */
328     if ( fgets( line, MAX_LINE_SIZE, fp ) == NULL ) {
329         err = -1;
330     } else {
331         line[ strlen( line ) - 1 ] = '\0';
332         if ( strcmp( line, "MASTER" ) == 0 || strcmp( line, "SLAVE" ) == 0 ||
333                 strcmp( line, "CACHE" ) == 0 ) {
334             if ( fgets( line, MAX_LINE_SIZE, fp ) == NULL ) {
335                 err = -1;
336             }
337         } else {
338             rewind( fp );
339         }
340     }
341
342     if ( err != 0 ) {
343         fprintf( stderr, "%s: skipping empty EDB file %s\n", progname,
344                 edbfile );
345         err = 0;        /* treat as a non-fatal error */
346     } else {
347         while ( !feof( fp ) && ( err = convert_entry( fp, edbfile, outfp,
348                 basedn, addvals, addvals_len, line )) > 0 ) {
349             if ( verboseflg && (( entrycount - startcount ) %
350                     VERBOSE_ENTRY_REPORT_THRESHOLD ) == 0 ) {
351                 fprintf( stderr, "\tworking... %d entries done...\n", 
352                         entrycount - startcount );
353             }
354         }
355     }
356
357     fclose( fp );
358     if ( addvals != NULL ) {
359         free( addvals );
360     }
361
362     if ( err < 0 ) {
363 #ifdef LDAP_DEBUG
364         if ( debugflg ) {
365             fprintf( stderr, "edb2ldif: 3 return( %d )\n", err );
366         }
367 #endif
368         return( err );
369     }
370
371     if ( verboseflg ) {
372         fprintf( stderr, "\t%d entries converted\n\n", 
373                 entrycount - startcount );
374     }
375
376     /* optionally convert EDB file within sub-directories */
377     if ( recurse ) {
378         char            *newbase;
379         DIR             *dp;
380         struct dirent   *dep;
381         struct edbmap   *edbmap;
382
383         /* open this directory */
384         if (( dp = opendir( dirname )) == NULL ) {
385             print_err( dirname );
386 #ifdef LDAP_DEBUG
387             if ( debugflg ) {
388                 fprintf( stderr, "edb2ldif: 4 return( -1 )\n" );
389             }
390 #endif
391             return( -1 );
392         }
393
394         /* check for EDB.map file and record contents for future reference */
395         sprintf( filename, "%s/%s", dirname, EDBMAP_FILENAME );
396         if ( read_edbmap( filename, &edbmap ) < 0 ) {
397             print_err( "read_edbmap" );
398             closedir( dp );
399 #ifdef LDAP_DEBUG
400             if ( debugflg ) {
401                 fprintf( stderr, "edb2ldif: 5 return( -1 )\n" );
402             }
403 #endif
404             return( -1 );
405         }
406
407         p = dirname + strlen( dirname );
408         *p++ = '/';
409         *p = '\0';
410
411         /* scan looking for sub-directories w/EDB files in them */
412         err = 0;
413         while ( err >= 0 && ( dep = readdir( dp )) != NULL ) {
414             if ( dep->d_name[ 0 ] == '.' && ( dep->d_name[ 1 ] == '\0' ||
415                     ( dep->d_name[ 1 ] == '.' && dep->d_name[ 2 ] == '\0' ))) {
416                 continue;       /* skip "." and ".." */
417             }
418
419             strcpy( p, dep->d_name );
420 #ifdef LDAP_DEBUG
421             if ( debugflg ) {
422                 fprintf( stderr, "edb2ldif: checking directory \"%s\"\n",
423                         dirname );
424             }
425 #endif
426
427             if ( stat( dirname, &st ) != 0 ) {
428                 print_err( dirname );
429             } else if ( S_ISDIR( st.st_mode )) {
430                 sprintf( filename, "%s/%s", dirname, DEF_EDBFILENAME );
431
432                 if ( stat( filename, &st ) == 0 && S_ISREG( st.st_mode )) {
433                     if (( newbase = malloc( strlen( basedn ) +
434                             strlen( dep->d_name ) + 3 )) == NULL ) {
435                         print_err( "malloc" );
436                         err = -1;
437                         continue;
438                     }
439
440                     sprintf( newbase, "%s@%s", basedn,
441                             file2rdn( edbmap, dep->d_name ));
442
443                     /* recurse */
444                     err = edb2ldif( outfp, filename, newbase, recurse );
445
446                     free( newbase );
447                 }
448             }
449         }
450
451         free_edbmap( edbmap );
452         closedir( dp );
453
454         if ( verboseflg ) {
455             fprintf( stderr, "%s: %d total entries converted under \"%s\"\n\n",
456                     progname, entrycount - startcount, basedn );
457         }
458     }
459
460 #ifdef LDAP_DEBUG
461     if ( debugflg ) {
462         fprintf( stderr, "edb2ldif: 6 return( %d )\n", err );
463     }
464 #endif
465     return( err );
466 }
467
468
469 /*
470  * read one entry from fp and write to outfp.
471  * return > 0 if entry converted, 0 if end of file, < 0 if error occurs
472  */
473 static int
474 convert_entry(
475     FILE        *fp,
476     char        *edbname,
477     FILE        *outfp,
478     char        *basedn,
479     char        *loc_addvals,
480     int         loc_addlen,
481     char        *linebuf
482 )
483 {
484     Attr_Sequence       as, tmpas;
485     AV_Sequence         av;
486     PS                  attrtype_ps, val_ps;
487     char                *dnstr;
488     DN                  dn;
489     RDN                 rdn;
490     int                 valcnt;
491     extern int          parse_status;
492     extern char         *parse_file;
493     extern RDN          parse_rdn;
494 #ifdef HAVE_PARSE_ENTRY
495     extern char         *parse_entry;
496     extern Attr_Sequence        fget_attributes();
497 #else /* HAVE_PARSE_ENTRY */
498     extern Attr_Sequence        get_attributes();
499 #endif /* HAVE_PARSE_ENTRY */
500
501 #ifdef LDAP_DEBUG
502     if ( debugflg ) {
503         fprintf( stderr, "convert_entry( 0x%X, \"%s\", 0x%X, \"%s\", ...)\n",
504                 fp, edbname, outfp, basedn );
505     }
506 #endif
507
508     while (( dnstr = fgets( linebuf, MAX_LINE_SIZE, fp )) != NULL &&
509             *linebuf == '\n' ) {
510         ;
511     }
512
513     if ( dnstr == NULL ) {
514         return( feof( fp ) ? 0 : -1 );  /* end of file or error */
515     }
516
517     linebuf[ strlen( linebuf ) - 1 ] = '\0';
518
519     if (( dnstr = malloc( strlen( basedn ) + strlen( linebuf ) + 2 ))
520             == NULL ) {
521         print_err( "convert_entry" );
522         return( -1 );
523     }
524     sprintf( dnstr, "%s@%s", basedn, linebuf );
525     if ( last_dn != NULL ) {
526         free( last_dn );
527     }
528     last_dn = dnstr;
529
530     if ( entrycount > 0 ) {
531         fputc( '\n', outfp );
532     }
533
534     /*
535      * parse_entry, parse_file and parse_rdn are needed inside the
536      * libisode decoding routines, so we set it here.
537      */
538     parse_file = edbname;
539 #ifdef HAVE_PARSE_ENTRY
540     parse_entry = dnstr;
541 #endif
542     parse_rdn = rdn = str2rdn( linebuf );
543
544     if (( val_ps = ps_alloc( str_open )) == NULLPS ||
545             str_setup( val_ps, NULLCP, 0, 0 ) == NOTOK ) {
546         fprintf( stderr, "%s: ps_alloc/setup failed (EDB file %s)\n", progname,
547                 edbname );
548         if ( rdn != NULLRDN ) {
549             rdn_free( rdn );
550         }
551         return( -1 );
552     }
553
554     if (( dn = str2dn( dnstr )) == NULLDN || av2ldif( outfp, NULL, dn,
555             0, "dn", val_ps ) < 0 ) {
556         sprintf( linebuf,
557                 "str2dn or av2ldif of DN failed (EDB file %s, entry %s)\n", 
558                 edbname, dnstr );
559         print_err( linebuf );
560         if ( dn != NULLDN ) {
561             dn_free( dn );
562         }
563         ps_free( val_ps );
564         if ( rdn != NULLRDN ) {
565             rdn_free( rdn );
566         }
567         return( -1 );
568     }
569     dn_free( dn );
570
571     ++entrycount;
572
573     if ( always_addvals != NULL && ( loc_addvals == NULL || !override_add )
574             && fwrite( always_addvals, always_addlen, 1, outfp ) != 1 ) {
575         sprintf( linebuf,
576                 "write of additional values failed (EDB file %s, entry %s)\n", 
577                 edbname, dnstr );
578         print_err( linebuf );
579         ps_free( val_ps );
580         if ( rdn != NULLRDN ) {
581             rdn_free( rdn );
582         }
583         return( -1 );
584     }
585
586     if ( loc_addvals != NULL && fwrite( loc_addvals, loc_addlen, 1,
587             outfp ) != 1 ) {
588         sprintf( linebuf,
589                 "write of additional values failed (EDB file %s, entry %s)\n", 
590                 edbname, dnstr );
591         print_err( linebuf );
592         ps_free( val_ps );
593         if ( rdn != NULLRDN ) {
594             rdn_free( rdn );
595         }
596         return( -1 );
597     }
598
599
600 #ifdef HAVE_PARSE_ENTRY
601     as = fget_attributes( fp );
602 #else /* HAVE_PARSE_ENTRY */
603     as = get_attributes( fp );
604 #endif /* HAVE_PARSE_ENTRY */
605
606     if ( parse_status != 0 ) {
607         fprintf( stderr, "%s: problem parsing entry (EDB file %s)\n", progname,
608                 edbname );
609         ps_free( val_ps );
610         if ( as != NULLATTR ) {
611             as_free( as );
612         }
613         if ( rdn != NULLRDN ) {
614             rdn_free( rdn );
615         }
616         return( -1 );
617     }
618
619     if ( add_rdn_values( as, rdn ) != 0 ) {
620         sprintf( linebuf,
621             "adding RDN values(s) failed (EDB file %s, entry %s)\n", 
622             edbname, dnstr );
623         print_err( linebuf );
624         if ( as != NULLATTR ) {
625             as_free( as );
626         }
627         if ( rdn != NULLRDN ) {
628             rdn_free( rdn );
629         }
630         return( -1 );
631     }
632
633     if (( attrtype_ps = ps_alloc( str_open )) == NULLPS ||
634             str_setup( attrtype_ps, NULLCP, 0, 0 ) == NOTOK ) {
635         fprintf( stderr, "%s: ps_alloc/setup failed (EDB file %s)\n", progname,
636                 edbname );
637         if ( as != NULLATTR ) {
638             as_free( as );
639         }
640         if ( rdn != NULLRDN ) {
641             rdn_free( rdn );
642         }
643         return( -1 );
644     }
645
646     for ( tmpas = as; tmpas != NULLATTR; tmpas = tmpas->attr_link ) {
647         attrtype_ps->ps_ptr = attrtype_ps->ps_base;
648         AttrT_print( attrtype_ps, tmpas->attr_type, EDBOUT );
649         *attrtype_ps->ps_ptr = '\0';
650
651         if ( ignore_attr != NULL ) {
652             int i;
653
654             for ( i = 0; ignore_attr[ i ] != NULL; ++i ) {
655                 if ( strcasecmp( attrtype_ps->ps_base, ignore_attr[ i ] )
656                         == 0 ) {
657                     break;
658                 }
659             }
660             if ( ignore_attr[ i ] != NULL ) {
661                 continue;       /* skip this attribute */
662             }
663         }
664
665         valcnt = 0;
666         for ( av = tmpas->attr_value; av != NULLAV; av = av->avseq_next ) {
667             ++valcnt;
668             if ( av2ldif( outfp, av, NULL, tmpas->attr_type->oa_syntax,
669                     attrtype_ps->ps_base, val_ps ) < 0 ) {
670                 sprintf( linebuf,
671                         "av2ldif failed (EDB file %s, entry %s, attribute %s, value no. %d)\n", 
672                         edbname, dnstr, attrtype_ps->ps_base, valcnt );
673                 print_err( linebuf );
674                 ps_free( attrtype_ps );
675                 ps_free( val_ps );
676                 as_free( as );
677                 if ( rdn != NULLRDN ) {
678                     rdn_free( rdn );
679                 }
680                 return( -1 );
681             }
682         }
683     }
684
685     ps_free( attrtype_ps );
686     ps_free( val_ps );
687     as_free( as );
688     if ( rdn != NULLRDN ) {
689         rdn_free( rdn );
690     }
691
692     return( 1 );
693 }
694
695
696 static int
697 add_rdn_values( Attr_Sequence entryas, RDN rdn )
698 {
699 /*
700  * this routine is based on code from the real_unravel_attribute() routine
701  * found in isode-8.0/.dsap/common/attribute.c
702  */
703     AttributeType       at;
704     AV_Sequence         avs;
705     Attr_Sequence       as;
706
707     for (; rdn != NULLRDN; rdn = rdn->rdn_next ) {
708         if (( as = as_find_type( entryas, rdn->rdn_at )) == NULLATTR ) {
709             at = AttrT_cpy( rdn->rdn_at );
710             avs = avs_comp_new( AttrV_cpy(&rdn->rdn_av ));
711             as  = as_comp_new( at, avs, NULLACL_INFO );
712             entryas = as_merge( entryas, as );
713         } else {
714             for ( avs = as->attr_value; avs != NULLAV; avs = avs->avseq_next ) {
715                 if ( AttrV_cmp( &rdn->rdn_av, &avs->avseq_av ) == 0 ) {
716                     break;
717                 }
718             }
719
720             if ( avs == NULLAV ) {
721                 avs = avs_comp_new( AttrV_cpy( &rdn->rdn_av ));
722                 as->attr_value = avs_merge( as->attr_value, avs );
723             }
724         }
725     }
726
727     return( 0 );
728 }
729
730
731 /* read the EDB.map file and return a linked list of translations */
732 static int
733 read_edbmap( char *mapfile, struct edbmap **edbmapp )
734 {
735     FILE                *fp;
736     char                *p, *filename, *rdn, line[ MAX_LINE_SIZE + 1 ];
737     int                 err;
738     struct edbmap       *emp, *tmpemp;
739
740 #ifdef LDAP_DEBUG
741     if ( debugflg ) {
742         fprintf( stderr, "read_edbmap( \"%s\", ...)\n", mapfile );
743     }
744 #endif
745
746     if (( fp = fopen( mapfile, "r" )) == NULL ) {
747         *edbmapp = NULL;
748         return( 0 );    /* soft error -- no EDB.map file */
749     }
750
751     emp = NULL;
752
753     /*
754      * read all the lines in the file, looking for lines of the form:
755      *  RDN # filename
756      */
757     err = 0;
758     while ( err == 0 && fgets( line, MAX_LINE_SIZE, fp ) != NULL ) {
759         line[ strlen( line ) - 1 ] = '\0';      /* remove trailing newline */
760         if (( filename = strchr( line, '#' )) == NULL ) {
761             continue;
762         }
763
764         *filename++ = '\0';
765         while ( isspace((unsigned char) *filename) ) { /* strip leading whitespace */
766             ++filename;
767         }
768
769         if ( *filename == '\0' ) {
770             continue;
771         }
772
773         p = filename + strlen( filename ) - 1;
774         while ( isspace((unsigned char) *p) ) { /* strip trailing whitespace */
775             *p-- = '\0';
776         }
777
778         rdn = line;
779         while ( isspace((unsigned char) *rdn)) { /* strip leading whitespace */
780             ++rdn;
781         }
782
783         if ( *rdn == '\0' ) {
784             continue;
785         }
786
787         p = rdn + strlen( rdn ) - 1;
788         while ( isspace((unsigned char) *p)) { /* strip trailing whitespace */
789             *p-- = '\0';
790         }
791
792         if (( tmpemp = (struct edbmap *)calloc( 1, sizeof( struct edbmap )))
793                 == NULL ||
794                 ( tmpemp->edbm_filename = strdup( filename )) == NULL ||
795                 ( tmpemp->edbm_rdn = strdup( rdn )) == NULL ) {
796             err = -1;
797         } else {
798             tmpemp->edbm_next = emp;
799             emp = tmpemp;
800         }
801     }
802
803     fclose( fp );
804
805     if ( err == 0 ) {
806         *edbmapp = emp;
807     } else {
808         free_edbmap( emp );
809     }
810
811     return( err );
812 }
813
814
815 static char *
816 file2rdn( struct edbmap *edbmap, char *filename )
817 {
818 #ifdef LDAP_DEBUG
819     if ( debugflg ) {
820         fprintf( stderr, "file2rdn( 0x%X, \"%s\" )\n", edbmap, filename );
821     }
822 #endif
823
824     while ( edbmap != NULL ) {
825         if ( strcmp( filename, edbmap->edbm_filename ) == 0 ) {
826             break;
827         }
828         edbmap = edbmap->edbm_next;
829     }
830
831     return(( edbmap == NULL ) ? filename : edbmap->edbm_rdn );
832 }
833
834
835 /* free the edbmap list */
836 static void
837 free_edbmap( struct edbmap *edbmap )
838 {
839     struct edbmap       *tmp;
840
841 #ifdef LDAP_DEBUG
842     if ( debugflg ) {
843         fprintf( stderr, "free_edbmap( 0x%X )\n", edbmap );
844     }
845 #endif
846
847     while ( edbmap != NULL ) {
848         if ( edbmap->edbm_filename != NULL ) free( edbmap->edbm_filename );
849         if ( edbmap->edbm_rdn != NULL ) free( edbmap->edbm_rdn );
850         tmp = edbmap;
851         edbmap = edbmap->edbm_next;
852         free( tmp );
853     }
854 }
855
856
857 static void
858 print_err( char *msg )
859 {
860 #ifdef LDAP_DEBUG
861     if ( debugflg ) {
862         fprintf( stderr, "print_err( \"%s\" )\n", msg );
863     }
864 #endif
865
866     if ( errno > sys_nerr ) {
867         fprintf( stderr, "%s: %s: errno=%d\n", progname, msg, errno );
868     } else {
869         fprintf( stderr, "%s: %s: %s\n", progname, msg, sys_errlist[ errno ] );
870     }
871 }
872
873
874 static char *
875 read_file( char *filename, int *lenp )
876 {
877     FILE        *fp;
878     struct stat st;
879     char        *buf;
880
881 #ifdef LDAP_DEBUG
882     if ( debugflg ) {
883         fprintf( stderr, "read_file( \"%s\", 0x%X )\n", filename, lenp );
884     }
885 #endif
886
887     if ( stat( filename, &st ) != 0 || !S_ISREG( st.st_mode ) ||
888             ( fp = fopen( filename, "r" )) == NULL ) {
889         return( NULL );
890     }
891
892     if (( buf = (char *)malloc( st.st_size )) == NULL ) {
893         fclose( fp );
894         return( NULL );
895     }
896
897     if ( fread( buf, st.st_size, 1, fp ) != 1 ) {
898         fclose( fp );
899         free( buf );
900         return( NULL );
901     }
902
903     fclose( fp );
904     *lenp = st.st_size;
905     return( buf );
906 }