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