]> git.sur5r.net Git - openldap/blob - servers/slapd/tools/ldbmtest.c
a1c0282290a1c3e01e4aa26a289b53e049aac726
[openldap] / servers / slapd / tools / ldbmtest.c
1 /*
2  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5 #include "portable.h"
6
7 #include <stdio.h>
8 #include <limits.h>
9
10 #include <ac/stdlib.h>
11 #include <ac/socket.h>
12 #include <ac/string.h>
13 #include <ac/ctype.h>
14 #include <ac/time.h>
15 #include <ac/unistd.h>
16 #include <ac/wait.h>
17
18 #ifdef HAVE_SYS_RESOURCE_H
19 #include <sys/resource.h>
20 #endif
21 #ifdef HAVE_SYS_PARAM_H
22 #include <sys/param.h>
23 #endif
24 #include <sys/stat.h>
25
26 #ifdef HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29
30 #ifdef HAVE_IO_H
31 #include <io.h>
32 #endif
33
34 #include "ldap_defaults.h"
35 #include "../slap.h"
36 #include "../back-ldbm/back-ldbm.h"
37
38 static DBCache  *openchoice(char c, int mode, int verbose, char **fname);
39 static void             print_entry(FILE *fp, char c, Datum *key, char *klabel, Datum *data, char *dlabel);
40 static void             free_and_close(DBCache *dbc, Datum key, Datum data);
41 static void             edit_entry(char c, Datum *data);
42 static void             get_keydata(FILE *fp, char c, Datum *key, Datum *data);
43
44 static DBCache *dbc;
45 static LDBM           dbp;
46 static Backend          *be = NULL;
47
48 int
49 main( int argc, char **argv )
50 {
51         char            buf[256];
52         Datum           savekey, key, data, last;
53         char            *fname;
54         ID              id;
55         ID_BLOCK                *idl;
56         Backend         *tbe;
57         int             i;
58         char            *tailorfile;
59
60 #ifdef HAVE_BERKELEY_DB2
61         DBC     *cursorp;
62 #endif
63
64         ldbm_datum_init( savekey );
65         ldbm_datum_init( key );
66         ldbm_datum_init( data );
67         ldbm_datum_init( last );
68
69         tailorfile = SLAPD_DEFAULT_CONFIGFILE;
70         while ( (i = getopt( argc, argv, "d:f:" )) != EOF ) {
71                 switch ( i ) {
72                 case 'd':       /* turn on debugging */
73                         ldap_debug = atoi( optarg );
74                         break;
75
76                 case 'f':       /* specify a tailor file */
77                         tailorfile = strdup( optarg );
78                         break;
79
80                 default:
81                         fprintf( stderr,
82                             "usage: %s [-d level] [-f slapdconfigfile]\n",
83                             argv[0] );
84                         exit( EXIT_FAILURE );
85                 }
86         }
87
88         /*
89          * initialize stuff and figure out which backend we're dealing with
90          */
91
92         slap_init(SLAP_TOOL_MODE, "ldbmtest");
93         read_config( tailorfile );
94         slap_startup(-1);
95
96         while ( 1 ) {
97                 printf( "dbtest: " );
98
99                 if ( fgets( buf, sizeof(buf), stdin ) == NULL )
100                         break;
101
102                 switch ( buf[0] ) {
103                 case 'c':       /* create an index */
104                         fname = NULL;
105                         if ( (dbc = openchoice( buf[1], LDBM_READER, 0,
106                             &fname )) != NULL ) {
107                                 printf( "Already exists\n" );
108                                 ldbm_close( dbc->dbc_db );
109                                 break;
110                         }
111                         if ( (dbc = openchoice( buf[1], LDBM_WRCREAT, 1,
112                             &fname )) != NULL ) {
113                                 ldbm_close( dbc->dbc_db );
114                         }
115                         break;
116
117                 case 'l':       /* lookup somethig in an index */
118                         if ( (dbc = openchoice( buf[1], LDBM_READER, 1, NULL ))
119                             == NULL ) {
120                                 continue;
121                         }
122
123                         get_keydata( stdin, buf[1], &key, NULL );
124                         data = ldbm_fetch( dbc->dbc_db, key );
125                         print_entry( stdout, buf[1], &key, "key: ", &data,
126                             "data:\n" );
127
128                         free_and_close( dbc, key, data );
129                         break;
130
131                 case 'L':       /* get all blocks for a key from an index */
132                         if ( (dbc = openchoice( buf[1], LDBM_READER, 1, NULL ))
133                             == NULL ) {
134                                 continue;
135                         }
136
137                         get_keydata( stdin, buf[1], &key, NULL );
138                         if ( (idl = idl_fetch( be, dbc, key )) != NULL ) {
139                                 data.dptr = (char *) idl;
140                                 data.dsize = (ID_BLOCK_NMAX(idl) + 1) * sizeof(ID);
141                                 print_entry( stdout, buf[1], &key, "key: ",
142                                     &data, "data:\n" );
143                         }
144                         free_and_close( dbc, key, data );
145                         break;
146
147                 case 't':       /* traverse */
148                 case 'T':       /* traverse - keys only */
149                         if ( (dbc = openchoice( buf[1], LDBM_READER, 1, NULL ))
150                             == NULL ) {
151                                 perror( "openchoice" );
152                                 continue;
153                         }
154
155                         savekey.dptr = NULL;
156 #ifdef HAVE_BERKELEY_DB2
157                         for ( key = ldbm_firstkey( dbc->dbc_db, &cursorp );
158                             key.dptr != NULL;
159                             key = ldbm_nextkey( dbc->dbc_db, key, cursorp ) )
160 #else
161                         for ( key = ldbm_firstkey( dbc->dbc_db );
162                             key.dptr != NULL;
163                             key = ldbm_nextkey( dbc->dbc_db, key ) )
164 #endif
165                         {
166                                 if ( savekey.dptr != NULL )
167                                         ldbm_datum_free( dbc->dbc_db, savekey );
168                                 savekey = key;
169
170                                 data = ldbm_fetch( dbc->dbc_db, key );
171
172                                 if ( buf[0] == 't' ) {
173                                         print_entry( stdout, buf[1], &key,
174                                             "key: ", &data, "data:\n" );
175                                 } else {
176                                         print_entry( stdout, buf[1], &key,
177                                             "key: ", NULL, NULL );
178                                 }
179
180                 if ( data.dptr != NULL ) {
181                                     ldbm_datum_free( dbc->dbc_db, data );
182                 }
183                         }
184                         if ( savekey.dptr != NULL )
185                                 ldbm_datum_free( dbc->dbc_db, savekey );
186
187                         ldbm_close( dbc->dbc_db );
188                         break;
189
190                 case 'x':       /* delete an entry */
191                         if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL ))
192                             == NULL ) {
193                                 continue;
194                         }
195
196                         get_keydata( stdin, buf[1], &key, NULL );
197
198                         if ( ldbm_delete( dbc->dbc_db, key ) != 0 ) {
199                                 if ( ldbm_errno( dbc->dbc_db ) == 0 ) {
200                                         perror( "ldbm_delete" );
201                                 } else {
202                                         fprintf( stderr, "db_errno %d",
203                                             ldbm_errno( dbc->dbc_db ) );
204                                 }
205                         }
206
207                         data.dptr = NULL;
208                         free_and_close( dbc, key, data );
209                         break;
210
211 #ifndef HAVE_WINSOCK
212                 case 'e':       /* edit an entry */
213                         if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL ))
214                             == NULL ) {
215                                 continue;
216                         }
217
218                         get_keydata( stdin, buf[1], &key, NULL );
219
220                         data = ldbm_fetch( dbc->dbc_db, key );
221                         if ( data.dptr == NULL ) {
222                                 if ( ldbm_errno( dbc->dbc_db ) == 0 ) {
223                                         perror( "ldbm_fetch" );
224                                 } else {
225                                         fprintf( stderr, "db_errno %d\n",
226                                             ldbm_errno( dbc->dbc_db ) );
227                                 }
228                                 free_and_close( dbc, key, data );
229                                 break;
230                         }
231
232                         edit_entry( buf[1], &data );
233
234                         if ( data.dptr == NULL ) {
235                                 if ( ldbm_delete( dbc->dbc_db, key ) != 0 ) {
236                                         perror( "ldbm_delete" );
237                                 }
238                         } else if ( ldbm_store( dbc->dbc_db, key, data,
239                             LDBM_REPLACE ) != 0 ) {
240                                 if ( ldbm_errno( dbc->dbc_db ) == 0 ) {
241                                         perror( "ldbm_store" );
242                                 } else {
243                                         fprintf( stderr, "db_errno %d\n",
244                                             ldbm_errno( dbc->dbc_db ) );
245                                 }
246                         }
247
248                         free_and_close( dbc, key, data );
249                         break;
250 #endif
251
252                 case 'a':       /* add an entry */
253                         if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL ))
254                             == NULL ) {
255                                 continue;
256                         }
257
258                         get_keydata( stdin, buf[1], &key, &data );
259
260                         if ( ldbm_store( dbc->dbc_db, key, data, LDBM_INSERT )
261                             != 0 ) {
262                                 if ( ldbm_errno( dbc->dbc_db ) == 0 ) {
263                                         perror( "ldbm_store" );
264                                 } else {
265                                         fprintf( stderr, "db_errno %d\n",
266                                             ldbm_errno( dbc->dbc_db ) );
267                                 }
268                         }
269
270                         free_and_close( dbc, key, data );
271                         break;
272
273                 case 'i':       /* insert an id into an index entry */
274                         if ( (dbc = openchoice( buf[1], LDBM_WRITER, 1, NULL ))
275                             == NULL ) {
276                                 continue;
277                         }
278
279                         get_keydata( stdin, buf[1], &key, &data );
280
281                         idl = (ID_BLOCK *) data.dptr;
282                         for ( id = idl_firstid( idl ); id != NOID;
283                             id = idl_nextid( idl, id ) ) {
284                                 if ( idl_insert_key( be, dbc, key, id )
285                                     != 0 ) {
286                                         fprintf( stderr,
287                                             "idl_insert_key (%s) %ld failed\n",
288                                             key.dptr, id );
289                                         continue;
290                                 }
291                         }
292
293                         free_and_close( dbc, key, data );
294                         break;
295
296                 case 'b':       /* select a backend by suffix */
297                         printf( "suffix: " );
298                         fflush( stdout );
299                         if ( fgets( buf, sizeof(buf), stdin ) == NULL ) {
300                                 exit( EXIT_SUCCESS );
301                         } else {
302                                 buf[strlen( buf ) - 1] = '\0';
303                         }
304                         (void) dn_normalize_case( buf );
305                         if ( (tbe = select_backend( buf )) == NULL ) {
306                                 fprintf( stderr, "unknown suffix \"%s\"\n",
307                                     buf );
308                         } else {
309                                 be = tbe;
310                         }
311                         break;
312
313                 case 'B':       /* print current suffix */
314                         if ( be == NULL ) {
315                                 printf( "no current backend\n" );
316                         } else {
317                                 printf( "current backend has suffix \"%s\"\n",
318                                     be->be_suffix[0] );
319                         }
320                         break;
321
322                 case 'C':       /* produce concordance of an index */
323                         if ( (dbc = openchoice( 'i', LDBM_READER, 1, NULL ))
324                             == NULL ) {
325                                 continue;
326                         }
327
328                         last.dptr = NULL;
329
330 #ifdef HAVE_BERKELEY_DB2
331                         for ( key = ldbm_firstkey( dbp, &cursorp );
332                                 key.dptr != NULL;
333                                 key = ldbm_nextkey( dbp, last, cursorp ) )
334 #else
335                         for ( key = ldbm_firstkey( dbp ); key.dptr != NULL;
336                             key = ldbm_nextkey( dbp, last ) )
337 #endif
338                         {
339                                 if ( last.dptr != NULL ) {
340                                         ldbm_datum_free( dbp, last );
341                                 }
342                                 last = key;
343                                 printf( "key(%d): (%s)\n", key.dsize,
344                                     key.dptr );
345                         }
346
347                         free_and_close( dbc, key, last );
348                         break;
349
350                 default:
351                         printf( "commands: l<c> => lookup index\n" );
352                         printf( "          L<c> => lookup index (all)\n" );
353                         printf( "          t<c> => traverse index\n" );
354                         printf( "          T<c> => traverse index keys\n" );
355                         printf( "          x<c> => delete from index\n" );
356                         printf( "          e<c> => edit index entry\n" );
357                         printf( "          a<c> => add index entry\n" );
358                         printf( "          c<c> => create index\n" );
359                         printf( "          i<c> => insert ids into index\n" );
360                         printf( "          b    => change default backend\n" );
361                         printf( "          B    => print default backend\n" );
362                         printf( "where <c> is a char selecting the index:\n" );
363                         printf( "          c => id2children\n" );
364                         printf( "          d => dn2id\n" );
365                         printf( "          e => id2entry\n" );
366                         printf( "          f => arbitrary file\n" );
367                         printf( "          i => attribute index\n" );
368                         break;
369                 }
370         }
371
372         slap_shutdown(-1);
373         slap_destroy();
374
375         return( EXIT_SUCCESS );
376 }
377
378 static void
379 free_and_close( DBCache *dbc, Datum key, Datum data )
380 {
381         ldbm_cache_really_close( be, dbc );
382         if ( key.dptr != NULL )
383                 ldbm_datum_free( dbp, key );
384         if ( data.dptr != NULL )
385                 ldbm_datum_free( dbp, data );
386 }
387
388 static int
389 dnid_cmp( const void *a, const void *b )
390 {
391         return( *(const long int *)a - *(const long int *)b );
392 }
393
394 static char *
395 myrealloc( char *p, int size )
396 {
397         if ( p == NULL )
398                 return( (char *) malloc( size ) );
399         else
400                 return( (char *) realloc( p, size ) );
401 }
402
403 static void
404 get_idlist( FILE *fp, Datum *data )
405 {
406         char    buf[20];
407         int     i, fd, tty;
408         ID_BLOCK        *p;
409         unsigned int    psize, pmax;
410         unsigned int    nmax, nids;
411
412         fd = fileno( fp );
413         tty = isatty( fd );
414
415         p = NULL;
416         psize = 2 * sizeof(ID);
417         pmax = 0;
418         nmax = 0;
419         nids = 0;
420         i = 0;
421         while ( 1 ) {
422                 if ( tty )
423                         printf( "id? " );
424                 if ( fgets( buf, sizeof(buf), fp ) == NULL || buf[0] == '\n' )
425                         break;
426                 if ( strncmp( buf, "nmax=", 5 ) == 0 ) {
427                         nmax = atol( buf + 5 );
428                         continue;
429                 }
430
431                 if ( psize + sizeof(ID) > pmax ) {
432                         pmax += BUFSIZ;
433                         p = (ID_BLOCK *) myrealloc( (char *) p, pmax );
434                 }
435
436                 if ( strncmp( buf, "nids=0", 6 ) == 0 ) {
437                         nids = NOID;
438                         continue;
439                 }
440
441                 ID_BLOCK_ID(p,i++) = atol( buf );
442                 psize += sizeof(ID);
443         }
444         if ( nmax == 0 ) {
445                 if ( tty ) {
446                         nmax = i;
447                         printf( "%d IDs entered.  Max number of ids? [%d] ", i,
448                             i );
449                         if ( fgets( buf, sizeof(buf), fp ) != NULL &&
450                              isdigit( (unsigned char) buf[0] ) ) {
451                                 nmax = atol( buf );
452                         }
453                 } else {
454                         nmax = i;
455                 }
456         }
457         if ( i > 0 ) {
458                 ID_BLOCK_NMAX(p) = nmax;
459                 if ( nids != 0 ) {
460                         ID_BLOCK_NIDS(p) = 0;
461                         ID_BLOCK_ID(p,i) = NOID;
462                 } else {
463                         ID_BLOCK_NIDS(p) = i;
464                 }
465
466                 qsort( (void *) &ID_BLOCK_ID(p, 0), i, sizeof(ID), dnid_cmp );
467         }
468
469         data->dptr = (char *) p;
470         data->dsize = (nmax + ID_BLOCK_IDS_OFFSET) * sizeof(ID);
471 }
472
473 static void
474 get_entry( FILE *fp, Datum *data )
475 {
476         char    buf[BUFSIZ];
477         char    *p;
478         unsigned int    pmax, psize, len;
479         int     fd;
480
481         fd = fileno( fp );
482         if ( isatty( fd ) )
483                 printf( "Enter entry, <cr><cr> to end:\n" );
484
485         p = NULL;
486         pmax = psize = 0;
487         while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
488                 len = strlen( buf );
489                 if ( psize + strlen( buf ) > pmax ) {
490                         pmax += BUFSIZ;
491                         p = myrealloc( p, pmax );
492                 }
493                 if ( psize == 0 )
494                         strcpy( p, buf );
495                 else
496                         strcat( p, buf );
497                 psize += len;
498
499                 if ( buf[0] == '\n' )
500                         break;
501         }
502
503         data->dptr = p;
504         data->dsize = psize + 1;
505 }
506
507 #ifndef HAVE_WINSOCK
508 static void
509 edit_entry( char c, Datum *data )
510 {
511         int             fd, pid;
512         char            tmpname[20];
513         FILE            *fp;
514 #ifndef HAVE_WAITPID
515         WAITSTATUSTYPE  status;
516 #endif
517
518         strcpy( tmpname, "/tmp/dbtestXXXXXX" );
519 #ifndef HAVE_MKSTEMP
520         if ( (fd = open( mktemp( tmpname ), O_RDWR, 0600 )) == -1 ) {
521                 perror( tmpname );
522                 return;
523         }
524 #else
525         if ( (fd = mkstemp( tmpname )) == -1 ) {
526                 perror( tmpname );
527                 return;
528         }
529 #endif
530
531         fp = fdopen( fd, "w" );
532         print_entry( fp, c, NULL, NULL, data, NULL );
533         fflush( fp );
534
535         pid = fork();
536
537         if ( pid == -1 ) {
538                 perror( "fork" );
539                 return;
540         } else if ( pid == 0 ) {
541                 char    *editor;
542
543                 if ( (editor = getenv( "EDITOR" )) == NULL ) {
544                         editor = LDAP_EDITOR;
545                 }
546                 execl( editor, editor, tmpname, NULL );
547                 perror( "execl" );
548                 exit( EXIT_FAILURE );
549         }
550
551         fclose( fp );
552  
553 #ifdef HAVE_WAITPID
554         if ( waitpid( (pid_t) -1, NULL, WAIT_FLAGS ) < 0 )
555 #else
556         if ( wait3( (pid_t) -1, &status, WAIT_FLAGS, 0 ) < 0 )
557 #endif
558         {
559                 perror( "wait" );
560                 return;
561         }
562
563         if ( (fp = fopen( tmpname, "r" )) == NULL ) {
564                 perror( tmpname );
565                 return;
566         }
567     if ( data->dptr != NULL ) {
568             ldbm_datum_free( NULL, *data );
569     }
570         get_keydata( fp, c, NULL, data );
571         fclose( fp );
572         unlink( tmpname );
573 }
574 #endif
575
576 static DBCache *
577 openfile( char *name, int namesiz, int mode, int verbose, char c )
578 {
579         DBCache *dbc;
580
581         if ( name == NULL || *name == '\0' ) {
582                 if ( c == 'f' ) {
583                         printf( "  file: " );
584                         if ( fgets( name, namesiz, stdin ) == NULL )
585                                 exit( EXIT_SUCCESS );
586                         name[strlen( name ) - 1] = '\0';
587                 } else {
588                         printf( "  attr: " );
589                         if ( fgets( name, namesiz, stdin ) == NULL )
590                                 exit( EXIT_SUCCESS );
591                         name[strlen( name ) - 1] = '\0';
592                 }
593         }
594
595         if ( (dbc = ldbm_cache_open( be, name, (c == 'f') ? "" : LDBM_SUFFIX,
596             LDBM_READER )) == NULL ) {
597                 perror( name );
598         } else {
599                 dbp = dbc->dbc_db;
600         }
601
602         return( dbc );
603 }
604
605 static DBCache *
606 openchoice( char c, int mode, int verbose, char **fname )
607 {
608         static char     name[MAXPATHLEN];
609
610         switch ( c ) {
611         case 'c':       /* id2children */
612                 sprintf( name, "id2children" );
613                 break;
614         case 'd':       /* dn2id */
615                 sprintf( name, "dn2id" );
616                 break;
617         case 'e':       /* id2entry */
618                 sprintf( name, "id2entry" );
619                 break;
620         case 'f':       /* arbitrary file */
621         case 'i':       /* index */
622                 if ( fname != NULL && *fname != NULL ) {
623                         strcpy( name, *fname );
624                 } else {
625                         name[0] = '\0';
626                 }
627                 break;
628         default:
629                 printf( "specify one of [fdeci] to select file\n" );
630                 return( NULL );
631                 break;
632         }
633         if ( fname != NULL ) {
634                 *fname = name;
635         }
636
637         return( openfile( name, MAXPATHLEN, mode, verbose, c ) );
638 }
639
640 static void
641 print_entry(
642         FILE    *fp,
643         char    c,
644         Datum   *key,
645         char    *klabel,
646         Datum   *data,
647         char    *dlabel
648 )
649 {
650         ID      id;
651         ID_BLOCK        *idl;
652         unsigned int    i;
653         char    msg[2];
654
655         if ( data != NULL && data->dptr == NULL ) {
656                 msg[0] = c;
657                 msg[1] = '\0';
658
659                 if ( ldbm_errno( dbp ) == 0 )
660                         perror( msg );
661                 else
662                         fprintf( stderr, "%s: db_errno %d\n", msg,
663                             ldbm_errno( dbp ) );
664                 return;
665         }
666
667         switch ( c ) {
668         case 'd':       /* dn2id - key is dn, data is dnid */
669                 if ( key != NULL )
670                         fprintf( fp, "%s%s (len %d)\n", klabel, key->dptr,
671                             key->dsize );
672                 if ( data != NULL ) {
673                         SAFEMEMCPY( (char *) &id, data->dptr, sizeof(ID) );
674                         fprintf( fp, "%s%ld\n", dlabel ? dlabel : "", id );
675                 }
676                 break;
677
678         case 'e':       /* id2entry - key is dnid, data is entry */
679                 if ( key != NULL ) {
680                         SAFEMEMCPY( (char *) &id, key->dptr, sizeof(ID) );
681                         fprintf( fp, "%s %ld\n", klabel, id );
682                 }
683                 if ( data != NULL ) {
684                         if ( dlabel ) {
685                                 fprintf( fp, "data length: %d\n", data->dsize );
686                                 fputs( dlabel, fp );
687                         }
688                         fputs( data->dptr, fp );
689                 }
690                 break;
691
692         case 'c':
693         case 'i':       /* index - key is string, data is dnid[] */
694                 if ( key != NULL )
695                         fprintf( fp, "%s%s (len %d)\n", klabel, key->dptr,
696                             key->dsize );
697                 if ( data != NULL ) {
698                         idl = (ID_BLOCK *) data->dptr;
699
700                         if ( dlabel )
701                                 fprintf( fp, "%s\tnmax=%ld\n\tncur=%ld\n", dlabel,
702                                     ID_BLOCK_NMAX(idl), ID_BLOCK_NIDS(idl) );
703
704                         if ( ID_BLOCK_INDIRECT( idl ) ) {
705                                 for ( i = 0; !ID_BLOCK_NOID(idl, i); i++ ) {
706                                         fprintf( fp, "\t%ld\n", ID_BLOCK_ID(idl, i) );
707                                 }
708                         } else if ( ID_BLOCK_ALLIDS( idl ) ) {
709                                 fprintf( fp, "\tALLIDS (1..%ld)\n",
710                                     ID_BLOCK_NIDS(idl) - 1 );
711                         } else {
712                                 for ( i = 0; i < ID_BLOCK_NIDS(idl); i++ ) {
713                                         fprintf( fp, "\t%ld\n", ID_BLOCK_ID(idl,i) );
714                                 }
715                         }
716                 }
717                 break;
718
719         case 'f':       /* arbitrary file - assume key & data are strings */
720                 if ( key != NULL )
721                         fprintf( fp, "%s%s\n", klabel, key->dptr );
722                 if ( data != NULL ) {
723                         fprintf( fp, "%s%s\n", dlabel ? dlabel : "",
724                             data->dptr );
725                 }
726                 break;
727
728         default:
729                 fprintf( stderr, "specify [deci] to select a file\n" );
730                 break;
731         }
732 }
733
734 static void
735 get_keydata( FILE *fp, char c, Datum *key, Datum *data )
736 {
737         static char     kbuf[BUFSIZ], dbuf[BUFSIZ];
738         long            n;
739         int             fd, tty;
740
741         fd = fileno( fp );
742         tty = isatty( fd );
743
744         switch ( c ) {
745         case 'd':       /* dn2id - key is dn, data is dnid */
746                 if ( key != NULL ) {
747                         if ( tty )
748                                 printf( "  dn: " );
749                         if ( fgets( kbuf, sizeof(kbuf), fp ) == NULL ) {
750                                 exit( EXIT_SUCCESS );
751                         }
752                         kbuf[strlen( kbuf ) - 1] = '\0';
753                         key->dptr = strdup( kbuf );
754                         key->dsize = strlen( kbuf ) + 1;
755                 }
756
757                 if ( data != NULL ) {
758                         if ( tty )
759                                 printf( "  dnid: " );
760                         if ( fgets( dbuf, sizeof(dbuf), fp ) == NULL ) {
761                                 exit( EXIT_SUCCESS );
762                         }
763                         n = atol( dbuf );
764                         data->dptr = (char *) malloc( sizeof(n) );
765                         memcpy( data->dptr, (char *) &n, sizeof(n) );
766                         data->dsize = sizeof(n);
767                 }
768                 break;
769
770         case 'e':       /* id2entry - key is dnid, data is entry */
771                 if ( key != NULL ) {
772                         if ( tty )
773                                 printf( "  dnid: " );
774                         if ( fgets( kbuf, sizeof(kbuf), fp ) == NULL ) {
775                                 exit( EXIT_SUCCESS );
776                         }
777                         n = atol( kbuf );
778                         key->dptr = (char *) malloc( sizeof(n) );
779                         memcpy( key->dptr, (char *) &n, sizeof(n) );
780                         key->dsize = sizeof(n);
781                 }
782
783                 if ( data != NULL ) {
784                         get_entry( fp, data );
785                 }
786                 break;
787
788         case 'c':       /* id2children - key is string dnid, data is dnid[] */
789         case 'i':       /* index - key is string, data is dnid[] */
790                 if ( key != NULL ) {
791                         if ( tty )
792                                 printf( "  key: " );
793                         if ( fgets( kbuf, sizeof(kbuf), fp ) == NULL ) {
794                                 exit( EXIT_SUCCESS );
795                         }
796                         kbuf[strlen( kbuf ) - 1] = '\0';
797                         key->dptr = strdup( kbuf );
798                         key->dsize = strlen( kbuf ) + 1;
799                 }
800
801                 if ( data != NULL ) {
802                         get_idlist( fp, data );
803                 }
804                 break;
805
806         default:
807                 fprintf(stderr, "specify [deci] to select file type\n");
808                 break;
809         }
810 }
811