]> git.sur5r.net Git - openldap/blob - servers/slapd/tools/edb2ldif.c
Misc header cleanup
[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 "portable.h"
14
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 #include <ac/ctype.h>
19 #include <ac/errno.h>
20 #include <ac/dirent.h>
21 #include <ac/string.h>
22 #include <ac/unistd.h>
23
24 #include <sys/stat.h>
25
26 #include <quipu/config.h>
27 #include <quipu/entry.h>
28 #include <quipu/commonarg.h>
29 #include <quipu/attrvalue.h>
30
31 #if ICRELEASE > 1
32 #define HAVE_FILE_ATTR_DIR
33 #endif
34
35 #ifdef TURBO_DISK
36 #define HAVE_PARSE_ENTRY
37 #endif
38
39 #define DEF_EDBFILENAME         "EDB"
40 #define EDB_ROOT_FILENAME       "EDB.root"
41 #define DEF_BASEDN              ""
42 #define EDBMAP_FILENAME         "EDB.map"
43 #define ADDVALS_FILENAME        ".add"
44
45 #define MAX_LINE_SIZE   2048
46
47 #define VERBOSE_ENTRY_REPORT_THRESHOLD  250
48
49
50 /* data structures */
51 struct edbmap {
52     char                *edbm_filename;
53     char                *edbm_rdn;
54     struct edbmap       *edbm_next;
55 };
56
57 /* prototypes */
58 static int edb2ldif( FILE *outfp, char *edbfile, char *basedn, int recurse );
59 static int convert_entry( FILE *fp, char *edbname, FILE *outfp,
60         char *basedn, char *loc_addvals, int loc_addlen, char *linebuf );
61 static int add_rdn_values (Attr_Sequence entryas, RDN rdn);
62 static int read_edbmap( char *mapfile, struct edbmap **edbmapp );
63 static char *file2rdn( struct edbmap *edbmap, char *filename );
64 static void free_edbmap( struct edbmap *edbmap );
65 static char *read_file( char *filename, int *lenp );
66 static void print_err( char *msg );
67
68
69 /* globals */
70 #ifdef LDAP_DEBUG
71 static int      debugflg;
72 #endif
73 static int      verboseflg;
74 static int      override_add = 0;
75 static int      entrycount;
76 static char     **ignore_attr = NULL;
77 static char     *always_addvals = NULL;
78 static int      always_addlen;
79 static char     *last_dn;
80 static char     *edb_home = ".";
81 char            *progname;
82 int             ldap_syslog = 0;
83 int             ldap_syslog_level = 0;
84
85
86 int
87 main( int argc, char **argv )
88 {
89     char        *usage = "usage: %s [-d] [-o] [-r] [-v] [-b basedn] [-a addvalsfile] [-f fileattrdir] [-i ignoreattr...] [edbfile...]\n";
90     char        edbfile[ MAXNAMLEN ], *basedn;
91     int         c, rc, errflg, ignore_count, recurse;
92     extern char dsa_mode;
93 #ifdef HAVE_FILE_ATTR_DIR
94     extern char *file_attr_directory;
95 #endif
96
97     if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
98         progname = argv[ 0 ];
99     } else {
100         ++progname;
101     }
102
103     errflg = recurse = 0;
104 #ifdef LDAP_DEBUG
105     debugflg = 0;
106 #endif
107     ignore_count = 0;
108     always_addvals = NULL;
109     basedn = NULL;
110
111     while (( c = getopt( argc, argv, "dorva:b:f:h:i:" )) != -1 ) {
112         switch( c ) {
113         case 'd':
114 #ifdef LDAP_DEBUG
115             ++debugflg;
116 #else
117             fprintf( stderr, "Ignoring -d:  compile with -DLDAP_DEBUG to enable this option.\n" );
118 #endif
119             break;
120
121         case 'o':
122             ++override_add;     
123             break;
124
125         case 'r':
126             ++recurse;  
127             break;
128
129         case 'v':
130             ++verboseflg;
131             break;
132
133         case 'a':
134             if ( always_addvals != NULL ) {
135                 ++errflg;
136             } else if (( always_addvals = read_file( optarg, &always_addlen ))
137                     == NULL ) {
138                 print_err( optarg );
139                 exit( 1 );
140             }
141             break;
142
143         case 'b':
144             if ( basedn != NULL ) {
145                 ++errflg;
146             } else {
147                 basedn = optarg;
148             }
149             break;
150
151         case 'f':
152 #ifdef HAVE_FILE_ATTR_DIR
153             /* add trailing slash to directory name if missing */
154             if ( *( optarg + strlen( optarg ) - 1 ) == '/' ) {
155                 file_attr_directory = strdup( optarg );
156             } else if (( file_attr_directory = (char *)malloc( strlen( optarg )
157                     + 2 )) != NULL ) {
158                 sprintf( file_attr_directory, "%s/", optarg );
159         
160             }
161             if ( file_attr_directory == NULL ) {
162                 print_err( "malloc" );
163                 exit( 1 );
164             }
165 #else /* HAVE_FILE_ATTR_DIR */
166             fprintf( stderr, "Ignoring -f:  this option requires a newer version of ISODE.\n" );
167 #endif /* HAVE_FILE_ATTR_DIR */
168             break;
169
170         case 'h':
171             edb_home = optarg;
172             break;
173
174         case 'i':
175             if ( ignore_count == 0 ) {
176                 ignore_attr = (char **)malloc( 2 * sizeof( char * ));
177             } else {
178                 ignore_attr = (char **)realloc( ignore_attr,
179                     ( ignore_count + 2 ) * sizeof( char * ));
180             }
181             if ( ignore_attr == NULL ) {
182                 print_err( "malloc/realloc" );
183                 exit( 1 );
184             }
185             ignore_attr[ ignore_count ] = optarg;
186             ignore_attr[ ++ignore_count ] = NULL;
187             break;
188
189         default:
190             ++errflg;
191         }
192     }
193
194     if ( errflg ) {
195         fprintf( stderr, usage, progname );
196         exit( 1 );
197     }
198
199     if ( basedn == NULL ) {
200         basedn = DEF_BASEDN;
201     }
202
203     /* load & initialize quipu syntax handlers */
204     quipu_syntaxes();
205 #ifdef LDAP_USE_PP
206     pp_quipu_init( progname );
207 #endif
208     dsap_init( NULL, NULL );
209
210     dsa_mode = 1;       /* so {CRYPT} is accepted by EDB parse routines */
211
212     if ( init_syntaxes() < 0 ) {
213         fprintf( stderr, "%s: init_syntaxes failed -- check your oid tables \n",
214             progname );
215         exit( 1 );
216     }
217
218
219     entrycount = 0;
220
221     /* process EDB file(s) */
222     if ( optind >= argc ) {
223         *edbfile = '\0';
224         rc = edb2ldif( stdout, edbfile, basedn, recurse );
225     } else {
226         for ( rc = 0; rc >= 0 && optind < argc; ++optind ) {
227             if ( argv[ optind ][ 0 ] == '/' ) {
228                 strcpy( edbfile, argv[ optind ] );
229             } else {
230                 sprintf( edbfile, "%s/%s", edb_home, argv[ optind ] );
231             }
232             rc = edb2ldif( stdout, edbfile, basedn, recurse );
233         }
234     }
235
236     if ( last_dn != NULL ) {
237         free( last_dn );
238     }
239
240 #ifdef LDAP_DEBUG
241     fprintf( stderr, "edb2ldif: exit( %d )\n", ( rc < 0 ) ? 1 : 0 );
242 #endif
243
244     exit( ( rc < 0 ) ? 1 : 0 );
245 }
246
247
248 static int
249 edb2ldif( FILE *outfp, char *edbfile, char *basedn, int recurse )
250 {
251     FILE        *fp;
252     char        *addvals, *p, *rdn, line[ MAX_LINE_SIZE + 1 ];
253     char        dirname[ MAXNAMLEN ], filename[ MAXNAMLEN ];
254     int         err, startcount, addvals_len;
255     struct stat st;
256
257 #ifdef LDAP_DEBUG
258     if ( debugflg ) {
259         fprintf( stderr, "edb2ldif( 0x%X, \"%s\", \"%s\", %d)\n",
260                 outfp, edbfile, basedn, recurse );
261     }
262 #endif
263
264     if ( *edbfile == '\0' ) {
265         sprintf( filename, "%s/%s", edb_home, EDB_ROOT_FILENAME );
266         if ( stat( filename, &st ) == 0 ) {
267             if (( err = edb2ldif( outfp, filename, basedn, 0 )) < 0 ) {
268 #ifdef LDAP_DEBUG
269                 if ( debugflg ) {
270                     fprintf( stderr, "edb2ldif: 0 return( %d )\n", err );
271                 }
272 #endif
273                 return( err );
274             }
275             if (( basedn = strdup( last_dn )) == NULL ) {
276                 print_err( "strdup" );
277 #ifdef LDAP_DEBUG
278                 if ( debugflg ) {
279                     fprintf( stderr, "edb2ldif: 1 return( -1 )\n" );
280                 }
281 #endif
282                 return( -1 );
283             }
284         }
285         sprintf( edbfile, "%s/%s", edb_home, DEF_EDBFILENAME );
286     }
287
288     if ( verboseflg ) {
289         fprintf( stderr, "%s: converting EDB file: \"%s\"\n\tbasedn: \"%s\"\n",
290                 progname, edbfile, basedn );
291     }
292
293     startcount = entrycount;
294     err = 0;
295
296
297     /* construct name of directory we are working in */
298     if (( p = strrchr( edbfile, '/' )) == NULL ) {
299         dirname[ 0 ] = '.';
300         dirname[ 1 ] = '\0';
301     } else {
302         strncpy( dirname, edbfile, p - edbfile );
303         dirname[ p - edbfile ] = '\0';
304     }
305
306     /* load local ".add" file (if any) */
307     sprintf( filename, "%s/%s", dirname, ADDVALS_FILENAME );
308     addvals_len = 0;
309     addvals = read_file( filename, &addvals_len );
310
311     /* read and convert this EDB file */
312     if (( fp = fopen( edbfile, "r" )) == NULL ) {
313         print_err( edbfile );
314         if ( addvals != NULL ) {
315             free( addvals );
316         }
317 #ifdef LDAP_DEBUG
318         if ( debugflg ) {
319             fprintf( stderr, "edb2ldif: 2 return( -1 )\n" );
320         }
321 #endif
322         return( -1 );
323     }
324
325     /* skip first two lines (type and timestamp) if they are present */
326     if ( fgets( line, MAX_LINE_SIZE, fp ) == NULL ) {
327         err = -1;
328     } else {
329         line[ strlen( line ) - 1 ] = '\0';
330         if ( strcmp( line, "MASTER" ) == 0 || strcmp( line, "SLAVE" ) == 0 ||
331                 strcmp( line, "CACHE" ) == 0 ) {
332             if ( fgets( line, MAX_LINE_SIZE, fp ) == NULL ) {
333                 err = -1;
334             }
335         } else {
336             rewind( fp );
337         }
338     }
339
340     if ( err != 0 ) {
341         fprintf( stderr, "%s: skipping empty EDB file %s\n", progname,
342                 edbfile );
343         err = 0;        /* treat as a non-fatal error */
344     } else {
345         while ( !feof( fp ) && ( err = convert_entry( fp, edbfile, outfp,
346                 basedn, addvals, addvals_len, line )) > 0 ) {
347             if ( verboseflg && (( entrycount - startcount ) %
348                     VERBOSE_ENTRY_REPORT_THRESHOLD ) == 0 ) {
349                 fprintf( stderr, "\tworking... %d entries done...\n", 
350                         entrycount - startcount );
351             }
352         }
353     }
354
355     fclose( fp );
356     if ( addvals != NULL ) {
357         free( addvals );
358     }
359
360     if ( err < 0 ) {
361 #ifdef LDAP_DEBUG
362         if ( debugflg ) {
363             fprintf( stderr, "edb2ldif: 3 return( %d )\n", err );
364         }
365 #endif
366         return( err );
367     }
368
369     if ( verboseflg ) {
370         fprintf( stderr, "\t%d entries converted\n\n", 
371                 entrycount - startcount );
372     }
373
374     /* optionally convert EDB file within sub-directories */
375     if ( recurse ) {
376         char            *newbase;
377         DIR             *dp;
378         struct dirent   *dep;
379         struct edbmap   *edbmap;
380
381         /* open this directory */
382         if (( dp = opendir( dirname )) == NULL ) {
383             print_err( dirname );
384 #ifdef LDAP_DEBUG
385             if ( debugflg ) {
386                 fprintf( stderr, "edb2ldif: 4 return( -1 )\n" );
387             }
388 #endif
389             return( -1 );
390         }
391
392         /* check for EDB.map file and record contents for future reference */
393         sprintf( filename, "%s/%s", dirname, EDBMAP_FILENAME );
394         if ( read_edbmap( filename, &edbmap ) < 0 ) {
395             print_err( "read_edbmap" );
396             closedir( dp );
397 #ifdef LDAP_DEBUG
398             if ( debugflg ) {
399                 fprintf( stderr, "edb2ldif: 5 return( -1 )\n" );
400             }
401 #endif
402             return( -1 );
403         }
404
405         p = dirname + strlen( dirname );
406         *p++ = '/';
407         *p = '\0';
408
409         /* scan looking for sub-directories w/EDB files in them */
410         err = 0;
411         while ( err >= 0 && ( dep = readdir( dp )) != NULL ) {
412             if ( dep->d_name[ 0 ] == '.' && ( dep->d_name[ 1 ] == '\0' ||
413                     ( dep->d_name[ 1 ] == '.' && dep->d_name[ 2 ] == '\0' ))) {
414                 continue;       /* skip "." and ".." */
415             }
416
417             strcpy( p, dep->d_name );
418 #ifdef LDAP_DEBUG
419             if ( debugflg ) {
420                 fprintf( stderr, "edb2ldif: checking directory \"%s\"\n",
421                         dirname );
422             }
423 #endif
424
425             if ( stat( dirname, &st ) != 0 ) {
426                 print_err( dirname );
427             } else if ( S_ISDIR( st.st_mode )) {
428                 sprintf( filename, "%s/%s", dirname, DEF_EDBFILENAME );
429
430                 if ( stat( filename, &st ) == 0 && S_ISREG( st.st_mode )) {
431                     if (( newbase = malloc( strlen( basedn ) +
432                             strlen( dep->d_name ) + 3 )) == NULL ) {
433                         print_err( "malloc" );
434                         err = -1;
435                         continue;
436                     }
437
438                     sprintf( newbase, "%s@%s", basedn,
439                             file2rdn( edbmap, dep->d_name ));
440
441                     /* recurse */
442                     err = edb2ldif( outfp, filename, newbase, recurse );
443
444                     free( newbase );
445                 }
446             }
447         }
448
449         free_edbmap( edbmap );
450         closedir( dp );
451
452         if ( verboseflg ) {
453             fprintf( stderr, "%s: %d total entries converted under \"%s\"\n\n",
454                     progname, entrycount - startcount, basedn );
455         }
456     }
457
458 #ifdef LDAP_DEBUG
459     if ( debugflg ) {
460         fprintf( stderr, "edb2ldif: 6 return( %d )\n", err );
461     }
462 #endif
463     return( err );
464 }
465
466
467 /*
468  * read one entry from fp and write to outfp.
469  * return > 0 if entry converted, 0 if end of file, < 0 if error occurs
470  */
471 static int
472 convert_entry(
473     FILE        *fp,
474     char        *edbname,
475     FILE        *outfp,
476     char        *basedn,
477     char        *loc_addvals,
478     int         loc_addlen,
479     char        *linebuf
480 )
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 static int
695 add_rdn_values( Attr_Sequence entryas, RDN rdn )
696 {
697 /*
698  * this routine is based on code from the real_unravel_attribute() routine
699  * found in isode-8.0/.dsap/common/attribute.c
700  */
701     AttributeType       at;
702     AV_Sequence         avs;
703     Attr_Sequence       as;
704
705     for (; rdn != NULLRDN; rdn = rdn->rdn_next ) {
706         if (( as = as_find_type( entryas, rdn->rdn_at )) == NULLATTR ) {
707             at = AttrT_cpy( rdn->rdn_at );
708             avs = avs_comp_new( AttrV_cpy(&rdn->rdn_av ));
709             as  = as_comp_new( at, avs, NULLACL_INFO );
710             entryas = as_merge( entryas, as );
711         } else {
712             for ( avs = as->attr_value; avs != NULLAV; avs = avs->avseq_next ) {
713                 if ( AttrV_cmp( &rdn->rdn_av, &avs->avseq_av ) == 0 ) {
714                     break;
715                 }
716             }
717
718             if ( avs == NULLAV ) {
719                 avs = avs_comp_new( AttrV_cpy( &rdn->rdn_av ));
720                 as->attr_value = avs_merge( as->attr_value, avs );
721             }
722         }
723     }
724
725     return( 0 );
726 }
727
728
729 /* read the EDB.map file and return a linked list of translations */
730 static int
731 read_edbmap( char *mapfile, struct edbmap **edbmapp )
732 {
733     FILE                *fp;
734     char                *p, *filename, *rdn, line[ MAX_LINE_SIZE + 1 ];
735     int                 err;
736     struct edbmap       *emp, *tmpemp;
737
738 #ifdef LDAP_DEBUG
739     if ( debugflg ) {
740         fprintf( stderr, "read_edbmap( \"%s\", ...)\n", mapfile );
741     }
742 #endif
743
744     if (( fp = fopen( mapfile, "r" )) == NULL ) {
745         *edbmapp = NULL;
746         return( 0 );    /* soft error -- no EDB.map file */
747     }
748
749     emp = NULL;
750
751     /*
752      * read all the lines in the file, looking for lines of the form:
753      *  RDN # filename
754      */
755     err = 0;
756     while ( err == 0 && fgets( line, MAX_LINE_SIZE, fp ) != NULL ) {
757         line[ strlen( line ) - 1 ] = '\0';      /* remove trailing newline */
758         if (( filename = strchr( line, '#' )) == NULL ) {
759             continue;
760         }
761
762         *filename++ = '\0';
763         while ( isspace((unsigned char) *filename) ) { /* strip leading whitespace */
764             ++filename;
765         }
766
767         if ( *filename == '\0' ) {
768             continue;
769         }
770
771         p = filename + strlen( filename ) - 1;
772         while ( isspace((unsigned char) *p) ) { /* strip trailing whitespace */
773             *p-- = '\0';
774         }
775
776         rdn = line;
777         while ( isspace((unsigned char) *rdn)) { /* strip leading whitespace */
778             ++rdn;
779         }
780
781         if ( *rdn == '\0' ) {
782             continue;
783         }
784
785         p = rdn + strlen( rdn ) - 1;
786         while ( isspace((unsigned char) *p)) { /* strip trailing whitespace */
787             *p-- = '\0';
788         }
789
790         if (( tmpemp = (struct edbmap *)calloc( 1, sizeof( struct edbmap )))
791                 == NULL ||
792                 ( tmpemp->edbm_filename = strdup( filename )) == NULL ||
793                 ( tmpemp->edbm_rdn = strdup( rdn )) == NULL ) {
794             err = -1;
795         } else {
796             tmpemp->edbm_next = emp;
797             emp = tmpemp;
798         }
799     }
800
801     fclose( fp );
802
803     if ( err == 0 ) {
804         *edbmapp = emp;
805     } else {
806         free_edbmap( emp );
807     }
808
809     return( err );
810 }
811
812
813 static char *
814 file2rdn( struct edbmap *edbmap, char *filename )
815 {
816 #ifdef LDAP_DEBUG
817     if ( debugflg ) {
818         fprintf( stderr, "file2rdn( 0x%X, \"%s\" )\n", edbmap, filename );
819     }
820 #endif
821
822     while ( edbmap != NULL ) {
823         if ( strcmp( filename, edbmap->edbm_filename ) == 0 ) {
824             break;
825         }
826         edbmap = edbmap->edbm_next;
827     }
828
829     return(( edbmap == NULL ) ? filename : edbmap->edbm_rdn );
830 }
831
832
833 /* free the edbmap list */
834 static void
835 free_edbmap( struct edbmap *edbmap )
836 {
837     struct edbmap       *tmp;
838
839 #ifdef LDAP_DEBUG
840     if ( debugflg ) {
841         fprintf( stderr, "free_edbmap( 0x%X )\n", edbmap );
842     }
843 #endif
844
845     while ( edbmap != NULL ) {
846         if ( edbmap->edbm_filename != NULL ) free( edbmap->edbm_filename );
847         if ( edbmap->edbm_rdn != NULL ) free( edbmap->edbm_rdn );
848         tmp = edbmap;
849         edbmap = edbmap->edbm_next;
850         free( tmp );
851     }
852 }
853
854
855 static void
856 print_err( char *msg )
857 {
858 #ifdef LDAP_DEBUG
859     if ( debugflg ) {
860         fprintf( stderr, "print_err( \"%s\" )\n", msg );
861     }
862 #endif
863
864     if ( errno > sys_nerr ) {
865         fprintf( stderr, "%s: %s: error %d\n", progname, msg, errno );
866     } else {
867         fprintf( stderr, "%s: %s: %s\n", progname, msg, sys_errlist[ errno ] );
868     }
869 }
870
871
872 static char *
873 read_file( char *filename, int *lenp )
874 {
875     FILE        *fp;
876     struct stat st;
877     char        *buf;
878
879 #ifdef LDAP_DEBUG
880     if ( debugflg ) {
881         fprintf( stderr, "read_file( \"%s\", 0x%X )\n", filename, lenp );
882     }
883 #endif
884
885     if ( stat( filename, &st ) != 0 || !S_ISREG( st.st_mode ) ||
886             ( fp = fopen( filename, "r" )) == NULL ) {
887         return( NULL );
888     }
889
890     if (( buf = (char *)malloc( st.st_size )) == NULL ) {
891         fclose( fp );
892         return( NULL );
893     }
894
895     if ( fread( buf, st.st_size, 1, fp ) != 1 ) {
896         fclose( fp );
897         free( buf );
898         return( NULL );
899     }
900
901     fclose( fp );
902     *lenp = st.st_size;
903     return( buf );
904 }