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