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