]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
cleanup testers
[openldap] / tests / progs / slapd-tester.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2006 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* ACKNOWLEDGEMENTS:
16  * This work was initially developed by Kurt Spanier for inclusion
17  * in OpenLDAP Software.
18  */
19
20 #include "portable.h"
21
22 #include <stdio.h>
23
24 #include <ac/stdlib.h>
25
26 #include <ac/ctype.h>
27 #include <ac/dirent.h>
28 #include <ac/param.h>
29 #include <ac/socket.h>
30 #include <ac/string.h>
31 #include <ac/unistd.h>
32 #include <ac/wait.h>
33
34
35 #include "ldap_defaults.h"
36 #include "lutil.h"
37
38 #include "ldap.h"
39 #include "slapd-common.h"
40
41 #define SEARCHCMD               "slapd-search"
42 #define READCMD                 "slapd-read"
43 #define ADDCMD                  "slapd-addel"
44 #define MODRDNCMD               "slapd-modrdn"
45 #define MODIFYCMD               "slapd-modify"
46 #define BINDCMD                 "slapd-bind"
47 #define MAXARGS                 100
48 #define MAXREQS                 5000
49 #define LOOPS                   100
50 #define OUTERLOOPS              "1"
51 #define RETRIES                 "0"
52
53 #define TSEARCHFILE             "do_search.0"
54 #define TREADFILE               "do_read.0"
55 #define TADDFILE                "do_add."
56 #define TMODRDNFILE             "do_modrdn.0"
57 #define TMODIFYFILE             "do_modify.0"
58 #define TBINDFILE               "do_bind.0"
59
60 static char *get_file_name( char *dirname, char *filename );
61 static int  get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[] );
62 static int  get_read_entries( char *filename, char *entries[], char *filters[] );
63 static void fork_child( char *prog, char **args );
64 static void     wait4kids( int nkidval );
65
66 static int      maxkids = 20;
67 static int      nkids;
68
69 #ifdef HAVE_WINSOCK
70 static HANDLE   *children;
71 static char argbuf[BUFSIZ];
72 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
73 #else
74 #define ArgDup(x) strdup(x)
75 #endif
76
77 static void
78 usage( char *name )
79 {
80         fprintf( stderr,
81                 "usage: %s "
82                 "-H <uri> | ([-h <host>] -p <port>) "
83                 "-D <manager> "
84                 "-w <passwd> "
85                 "-d <datadir> "
86                 "[-j <maxchild>] "
87                 "[-l <loops>] "
88                 "[-L <outerloops>] "
89                 "-P <progdir> "
90                 "[-r <maxretries>] "
91                 "[-t <delay>] "
92                 "[-F] "
93                 "[-C]\n",
94                 name );
95         exit( EXIT_FAILURE );
96 }
97
98 int
99 main( int argc, char **argv )
100 {
101         int             i, j;
102         char            *uri = NULL;
103         char            *host = "localhost";
104         char            *port = NULL;
105         char            *manager = NULL;
106         char            *passwd = NULL;
107         char            *dirname = NULL;
108         char            *progdir = NULL;
109         int             loops = LOOPS;
110         char            *outerloops = OUTERLOOPS;
111         char            *retries = RETRIES;
112         char            *delay = "0";
113         DIR             *datadir;
114         struct dirent   *file;
115         int             friendly = 0;
116         int             chaserefs = 0;
117         int             noattrs = 0;
118         /* search */
119         char            *sfile = NULL;
120         char            *sreqs[MAXREQS];
121         char            *sattrs[MAXREQS];
122         char            *sbase[MAXREQS];
123         int             snum = 0;
124         char            *sargs[MAXARGS];
125         int             sanum;
126         char            scmd[MAXPATHLEN];
127         char            sloops[] = "18446744073709551615UL";
128         /* read */
129         char            *rfile = NULL;
130         char            *rreqs[MAXREQS];
131         int             rnum = 0;
132         char            *rargs[MAXARGS];
133         char            *rflts[MAXREQS];
134         int             ranum;
135         char            rcmd[MAXPATHLEN];
136         char            rloops[] = "18446744073709551615UL";
137         /* addel */
138         char            *afiles[MAXREQS];
139         int             anum = 0;
140         char            *aargs[MAXARGS];
141         int             aanum;
142         char            acmd[MAXPATHLEN];
143         char            aloops[] = "18446744073709551615UL";
144         /* modrdn */
145         char            *mfile = NULL;
146         char            *mreqs[MAXREQS];
147         int             mnum = 0;
148         char            *margs[MAXARGS];
149         int             manum;
150         char            mcmd[MAXPATHLEN];
151         char            mloops[] = "18446744073709551615UL";
152         /* modify */
153         char            *modfile = NULL;
154         char            *modreqs[MAXREQS];
155         char            *moddn[MAXREQS];
156         int             modnum = 0;
157         char            *modargs[MAXARGS];
158         int             modanum;
159         char            modcmd[MAXPATHLEN];
160         char            modloops[] = "18446744073709551615UL";
161         /* bind */
162         char            *bfile = NULL;
163         char            *breqs[MAXREQS];
164         char            *bcreds[MAXREQS];
165         char            *battrs[MAXREQS];
166         int             bnum = 0;
167         char            *bargs[MAXARGS];
168         int             banum;
169         char            bcmd[MAXPATHLEN];
170         char            bloops[] = "18446744073709551615UL";
171
172         char            *friendlyOpt = NULL;
173
174         tester_init( "slapd-tester" );
175
176         while ( (i = getopt( argc, argv, "ACD:d:FH:h:j:l:L:P:p:r:t:w:" )) != EOF ) {
177                 switch( i ) {
178                 case 'A':
179                         noattrs++;
180                         break;
181
182                 case 'C':
183                         chaserefs++;
184                         break;
185
186                 case 'D':               /* slapd manager */
187                         manager = ArgDup( optarg );
188                         break;
189
190                 case 'd':               /* data directory */
191                         dirname = strdup( optarg );
192                         break;
193
194                 case 'F':
195                         friendly++;
196                         break;
197
198                 case 'H':               /* slapd uri */
199                         uri = strdup( optarg );
200                         break;
201
202                 case 'h':               /* slapd host */
203                         host = strdup( optarg );
204                         break;
205
206                 case 'j':               /* the number of parallel clients */
207                         if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
208                                 usage( argv[0] );
209                         }
210                         break;
211
212                 case 'l':               /* the number of loops per client */
213                         if ( lutil_atoi( &loops, optarg ) != 0 ) {
214                                 usage( argv[0] );
215                         }
216                         break;
217
218                 case 'L':               /* the number of outerloops per client */
219                         outerloops = strdup( optarg );
220                         break;
221
222                 case 'P':               /* prog directory */
223                         progdir = strdup( optarg );
224                         break;
225
226                 case 'p':               /* the servers port number */
227                         port = strdup( optarg );
228                         break;
229
230                 case 'r':               /* the number of retries in case of error */
231                         retries = strdup( optarg );
232                         break;
233
234                 case 't':               /* the delay in seconds between each retry */
235                         delay = strdup( optarg );
236                         break;
237
238                 case 'w':               /* the managers passwd */
239                         passwd = ArgDup( optarg );
240                         break;
241
242                 default:
243                         usage( argv[0] );
244                         break;
245                 }
246         }
247
248         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
249                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
250                 usage( argv[0] );
251
252 #ifdef HAVE_WINSOCK
253         children = malloc( maxkids * sizeof(HANDLE) );
254 #endif
255         /* get the file list */
256         if ( ( datadir = opendir( dirname )) == NULL ) {
257
258                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
259                                         argv[0], dirname );
260                 exit( EXIT_FAILURE );
261
262         }
263
264         /*  look for search, read, modrdn, and add/delete files */
265         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
266
267                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
268                         sfile = get_file_name( dirname, file->d_name );
269                         continue;
270                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
271                         rfile = get_file_name( dirname, file->d_name );
272                         continue;
273                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
274                         mfile = get_file_name( dirname, file->d_name );
275                         continue;
276                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
277                         modfile = get_file_name( dirname, file->d_name );
278                         continue;
279                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
280                         && ( anum < MAXREQS )) {
281                         afiles[anum++] = get_file_name( dirname, file->d_name );
282                         continue;
283                 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
284                         bfile = get_file_name( dirname, file->d_name );
285                         continue;
286                 }
287         }
288
289         closedir( datadir );
290
291         /* look for search requests */
292         if ( sfile ) {
293                 snum = get_search_filters( sfile, sreqs, sattrs, sbase );
294         }
295
296         /* look for read requests */
297         if ( rfile ) {
298                 rnum = get_read_entries( rfile, rreqs, rflts );
299         }
300
301         /* look for modrdn requests */
302         if ( mfile ) {
303                 mnum = get_read_entries( mfile, mreqs, NULL );
304         }
305
306         /* look for modify requests */
307         if ( modfile ) {
308                 modnum = get_search_filters( modfile, modreqs, NULL, moddn );
309         }
310
311         /* look for bind requests */
312         if ( bfile ) {
313                 bnum = get_search_filters( bfile, bcreds, battrs, breqs );
314         }
315
316         /* setup friendly option */
317
318         switch ( friendly ) {
319         case 0:
320                 break;
321
322         case 1:
323                 friendlyOpt = "-F";
324                 break;
325
326         default:
327                 /* NOTE: right now we don't need it more than twice */
328         case 2:
329                 friendlyOpt = "-FF";
330                 break;
331         }
332
333         snprintf( sloops, sizeof( sloops ), "%d", 10 * loops );
334         snprintf( rloops, sizeof( rloops ), "%d", 20 * loops );
335         snprintf( aloops, sizeof( aloops ), "%d", loops );
336         snprintf( mloops, sizeof( mloops ), "%d", loops );
337         snprintf( modloops, sizeof( modloops ), "%d", loops );
338         snprintf( bloops, sizeof( bloops ), "%d", 20 * loops );
339
340         /*
341          * generate the search clients
342          */
343
344         sanum = 0;
345         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
346                 progdir );
347         sargs[sanum++] = scmd;
348         if ( uri ) {
349                 sargs[sanum++] = "-H";
350                 sargs[sanum++] = uri;
351         } else {
352                 sargs[sanum++] = "-h";
353                 sargs[sanum++] = host;
354                 sargs[sanum++] = "-p";
355                 sargs[sanum++] = port;
356         }
357         sargs[sanum++] = "-D";
358         sargs[sanum++] = manager;
359         sargs[sanum++] = "-w";
360         sargs[sanum++] = passwd;
361         sargs[sanum++] = "-l";
362         sargs[sanum++] = sloops;
363         sargs[sanum++] = "-L";
364         sargs[sanum++] = outerloops;
365         sargs[sanum++] = "-r";
366         sargs[sanum++] = retries;
367         sargs[sanum++] = "-t";
368         sargs[sanum++] = delay;
369         if ( friendly ) {
370                 sargs[sanum++] = friendlyOpt;
371         }
372         if ( chaserefs ) {
373                 sargs[sanum++] = "-C";
374         }
375         if ( noattrs ) {
376                 sargs[sanum++] = "-A";
377         }
378         sargs[sanum++] = "-b";
379         sargs[sanum++] = NULL;          /* will hold the search base */
380         sargs[sanum++] = "-f";
381         sargs[sanum++] = NULL;          /* will hold the search request */
382
383         sargs[sanum++] = NULL;
384         sargs[sanum] = NULL;            /* might hold the "attr" request */
385
386         sargs[sanum + 1] = NULL;
387
388         /*
389          * generate the read clients
390          */
391
392         ranum = 0;
393         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
394                 progdir );
395         rargs[ranum++] = rcmd;
396         if ( uri ) {
397                 rargs[ranum++] = "-H";
398                 rargs[ranum++] = uri;
399         } else {
400                 rargs[ranum++] = "-h";
401                 rargs[ranum++] = host;
402                 rargs[ranum++] = "-p";
403                 rargs[ranum++] = port;
404         }
405         rargs[ranum++] = "-D";
406         rargs[ranum++] = manager;
407         rargs[ranum++] = "-w";
408         rargs[ranum++] = passwd;
409         rargs[ranum++] = "-l";
410         rargs[ranum++] = rloops;
411         rargs[ranum++] = "-L";
412         rargs[ranum++] = outerloops;
413         rargs[ranum++] = "-r";
414         rargs[ranum++] = retries;
415         rargs[ranum++] = "-t";
416         rargs[ranum++] = delay;
417         if ( friendly ) {
418                 rargs[ranum++] = friendlyOpt;
419         }
420         if ( chaserefs ) {
421                 rargs[ranum++] = "-C";
422         }
423         if ( noattrs ) {
424                 rargs[ranum++] = "-A";
425         }
426         rargs[ranum++] = "-e";
427         rargs[ranum++] = NULL;          /* will hold the read entry */
428
429         rargs[ranum++] = NULL;
430         rargs[ranum] = NULL;            /* might hold the filter arg */
431
432         rargs[ranum + 1] = NULL;
433
434         /*
435          * generate the modrdn clients
436          */
437
438         manum = 0;
439         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
440                 progdir );
441         margs[manum++] = mcmd;
442         if ( uri ) {
443                 margs[manum++] = "-H";
444                 margs[manum++] = uri;
445         } else {
446                 margs[manum++] = "-h";
447                 margs[manum++] = host;
448                 margs[manum++] = "-p";
449                 margs[manum++] = port;
450         }
451         margs[manum++] = "-D";
452         margs[manum++] = manager;
453         margs[manum++] = "-w";
454         margs[manum++] = passwd;
455         margs[manum++] = "-l";
456         margs[manum++] = mloops;
457         margs[manum++] = "-L";
458         margs[manum++] = outerloops;
459         margs[manum++] = "-r";
460         margs[manum++] = retries;
461         margs[manum++] = "-t";
462         margs[manum++] = delay;
463         if ( friendly ) {
464                 margs[manum++] = friendlyOpt;
465         }
466         if ( chaserefs ) {
467                 margs[manum++] = "-C";
468         }
469         margs[manum++] = "-e";
470         margs[manum++] = NULL;          /* will hold the modrdn entry */
471         margs[manum++] = NULL;
472         
473         /*
474          * generate the modify clients
475          */
476
477         modanum = 0;
478         snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
479                 progdir );
480         modargs[modanum++] = modcmd;
481         if ( uri ) {
482                 modargs[modanum++] = "-H";
483                 modargs[modanum++] = uri;
484         } else {
485                 modargs[modanum++] = "-h";
486                 modargs[modanum++] = host;
487                 modargs[modanum++] = "-p";
488                 modargs[modanum++] = port;
489         }
490         modargs[modanum++] = "-D";
491         modargs[modanum++] = manager;
492         modargs[modanum++] = "-w";
493         modargs[modanum++] = passwd;
494         modargs[modanum++] = "-l";
495         modargs[modanum++] = modloops;
496         modargs[modanum++] = "-L";
497         modargs[modanum++] = outerloops;
498         modargs[modanum++] = "-r";
499         modargs[modanum++] = retries;
500         modargs[modanum++] = "-t";
501         modargs[modanum++] = delay;
502         if ( friendly ) {
503                 modargs[modanum++] = friendlyOpt;
504         }
505         if ( chaserefs ) {
506                 modargs[modanum++] = "-C";
507         }
508         modargs[modanum++] = "-e";
509         modargs[modanum++] = NULL;              /* will hold the modify entry */
510         modargs[modanum++] = "-a";;
511         modargs[modanum++] = NULL;              /* will hold the ava */
512         modargs[modanum++] = NULL;
513
514         /*
515          * generate the add/delete clients
516          */
517
518         aanum = 0;
519         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
520                 progdir );
521         aargs[aanum++] = acmd;
522         if ( uri ) {
523                 aargs[aanum++] = "-H";
524                 aargs[aanum++] = uri;
525         } else {
526                 aargs[aanum++] = "-h";
527                 aargs[aanum++] = host;
528                 aargs[aanum++] = "-p";
529                 aargs[aanum++] = port;
530         }
531         aargs[aanum++] = "-D";
532         aargs[aanum++] = manager;
533         aargs[aanum++] = "-w";
534         aargs[aanum++] = passwd;
535         aargs[aanum++] = "-l";
536         aargs[aanum++] = aloops;
537         aargs[aanum++] = "-L";
538         aargs[aanum++] = outerloops;
539         aargs[aanum++] = "-r";
540         aargs[aanum++] = retries;
541         aargs[aanum++] = "-t";
542         aargs[aanum++] = delay;
543         if ( friendly ) {
544                 aargs[aanum++] = friendlyOpt;
545         }
546         if ( chaserefs ) {
547                 aargs[aanum++] = "-C";
548         }
549         aargs[aanum++] = "-f";
550         aargs[aanum++] = NULL;          /* will hold the add data file */
551         aargs[aanum++] = NULL;
552
553         /*
554          * generate the bind clients
555          */
556
557         banum = 0;
558         snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
559                 progdir );
560         bargs[banum++] = bcmd;
561         bargs[banum++] = "-I";  /* don't init on each bind */
562         if ( uri ) {
563                 bargs[banum++] = "-H";
564                 bargs[banum++] = uri;
565         } else {
566                 bargs[banum++] = "-h";
567                 bargs[banum++] = host;
568                 bargs[banum++] = "-p";
569                 bargs[banum++] = port;
570         }
571         bargs[banum++] = "-l";
572         bargs[banum++] = bloops;
573         bargs[banum++] = "-L";
574         bargs[banum++] = outerloops;
575 #if 0
576         bargs[banum++] = "-r";
577         bargs[banum++] = retries;
578         bargs[banum++] = "-t";
579         bargs[banum++] = delay;
580 #endif
581         if ( friendly ) {
582                 bargs[banum++] = friendlyOpt;
583         }
584         if ( chaserefs ) {
585                 bargs[banum++] = "-C";
586         }
587         bargs[banum++] = "-D";
588         bargs[banum++] = NULL;
589         bargs[banum++] = "-w";
590         bargs[banum++] = NULL;
591         bargs[banum++] = NULL;
592
593 #define DOREQ(n,j) ((n) && ((maxkids > (n)) ? ((j) < maxkids ) : ((j) < (n))))
594
595         for ( j = 0; j < MAXREQS; j++ ) {
596                 if ( DOREQ( snum, j ) ) {
597                         int     jj = j % snum;
598
599                         sargs[sanum - 2] = sreqs[jj];
600                         sargs[sanum - 4] = sbase[jj];
601                         if ( sattrs[jj] != NULL ) {
602                                 sargs[sanum - 1] = "-a";
603                                 sargs[sanum] = sattrs[jj];
604
605                         } else {
606                                 sargs[sanum - 1] = NULL;
607                         }
608                         fork_child( scmd, sargs );
609                 }
610
611                 if ( DOREQ( rnum, j ) ) {
612                         int     jj = j % rnum;
613
614                         rargs[ranum - 2] = rreqs[jj];
615                         if ( rflts[jj] != NULL ) {
616                                 rargs[ranum - 1] = "-f";
617                                 rargs[ranum] = rflts[jj];
618
619                         } else {
620                                 rargs[ranum - 1] = NULL;
621                         }
622                         fork_child( rcmd, rargs );
623                 }
624
625                 if ( j < mnum ) {
626                         margs[manum - 2] = mreqs[j];
627                         fork_child( mcmd, margs );
628                 }
629
630                 if ( j < modnum ) {
631                         modargs[modanum - 4] = moddn[j];
632                         modargs[modanum - 2] = modreqs[j];
633                         fork_child( modcmd, modargs );
634                 }
635
636                 if ( j < anum ) {
637                         aargs[aanum - 2] = afiles[j];
638                         fork_child( acmd, aargs );
639                 }
640
641                 if ( DOREQ( bnum, j ) ) {
642                         int     jj = j % bnum;
643
644                         bargs[banum - 4] = breqs[jj];
645                         bargs[banum - 2] = bcreds[jj];
646                         bargs[banum - 1] = NULL;
647                         if ( battrs[jj] != NULL ) {
648                                 bargs[banum - 5] = "-b";
649                                 bargs[banum - 1] = "-a";
650                                 bargs[banum] = battrs[jj];
651                         }
652                         fork_child( bcmd, bargs );
653                         bargs[banum - 5] = "-D";
654                 }
655         }
656
657         wait4kids( -1 );
658
659         exit( EXIT_SUCCESS );
660 }
661
662 static char *
663 get_file_name( char *dirname, char *filename )
664 {
665         char buf[MAXPATHLEN];
666
667         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
668                 dirname, filename );
669         return( strdup( buf ));
670 }
671
672
673 static int
674 get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[] )
675 {
676         FILE    *fp;
677         int     filter = 0;
678
679         if ( (fp = fopen( filename, "r" )) != NULL ) {
680                 char  line[BUFSIZ];
681
682                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
683                         char *nl;
684
685                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
686                                 *nl = '\0';
687                         bases[filter] = ArgDup( line );
688                         fgets( line, BUFSIZ, fp );
689                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
690                                 *nl = '\0';
691
692                         filters[filter] = ArgDup( line );
693                         if ( attrs ) {
694                                 if ( filters[filter][0] == '+') {
695                                         char    *sep = strchr( filters[filter], ':' );
696
697                                         if ( sep != NULL ) {
698                                                 attrs[ filter ] = &filters[ filter ][ 1 ];
699                                                 sep[ 0 ] = '\0';
700                                                 /* NOTE: don't free this! */
701                                                 filters[ filter ] = &sep[ 1 ];
702                                         }
703
704                                 } else {
705                                         attrs[ filter] = NULL;
706                                 }
707                         }
708                         filter++;
709
710                 }
711                 fclose( fp );
712         }
713
714         return( filter );
715 }
716
717
718 static int
719 get_read_entries( char *filename, char *entries[], char *filters[] )
720 {
721         FILE    *fp;
722         int     entry = 0;
723
724         if ( (fp = fopen( filename, "r" )) != NULL ) {
725                 char  line[BUFSIZ];
726
727                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
728                         char *nl;
729
730                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
731                                 *nl = '\0';
732                         if ( filters != NULL && line[0] == '+' ) {
733                                 LDAPURLDesc     *lud;
734
735                                 if ( ldap_url_parse( &line[1], &lud ) != LDAP_URL_SUCCESS ) {
736                                         entry = -1;
737                                         break;
738                                 }
739
740                                 if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
741                                         ldap_free_urldesc( lud );
742                                         entry = -1;
743                                         break;
744                                 }
745
746                                 entries[entry] = ArgDup( lud->lud_dn );
747
748                                 if ( lud->lud_filter ) {
749                                         filters[entry] = ArgDup( lud->lud_filter );
750
751                                 } else {
752                                         filters[entry] = ArgDup( "(objectClass=*)" );
753                                 }
754                                 ldap_free_urldesc( lud );
755
756                         } else {
757                                 entries[entry] = ArgDup( line );
758                         }
759
760                         entry++;
761
762                 }
763                 fclose( fp );
764         }
765
766         return( entry );
767 }
768
769 #ifndef HAVE_WINSOCK
770 static void
771 fork_child( char *prog, char **args )
772 {
773         pid_t   pid;
774
775         wait4kids( maxkids );
776
777         switch ( pid = fork() ) {
778         case 0:         /* child */
779 #ifdef HAVE_EBCDIC
780                 /* The __LIBASCII execvp only handles ASCII "prog",
781                  * we still need to translate the arg vec ourselves.
782                  */
783                 { char *arg2[MAXREQS];
784                 int i;
785
786                 for (i=0; args[i]; i++) {
787                         arg2[i] = ArgDup(args[i]);
788                         __atoe(arg2[i]);
789                 }
790                 arg2[i] = NULL;
791                 args = arg2; }
792 #endif
793                 execvp( prog, args );
794                 tester_perror( "execvp", NULL );
795                 exit( EXIT_FAILURE );
796                 break;
797
798         case -1:        /* trouble */
799                 tester_perror( "fork", NULL );
800                 break;
801
802         default:        /* parent */
803                 nkids++;
804                 break;
805         }
806 }
807
808 static void
809 wait4kids( int nkidval )
810 {
811         int             status;
812
813         while ( nkids >= nkidval ) {
814                 wait( &status );
815
816                 if ( WIFSTOPPED(status) ) {
817                         fprintf( stderr,
818                             "stopping: child stopped with signal %d\n",
819                             (int) WSTOPSIG(status) );
820
821                 } else if ( WIFSIGNALED(status) ) {
822                         fprintf( stderr, 
823                             "stopping: child terminated with signal %d%s\n",
824                             (int) WTERMSIG(status),
825 #ifdef WCOREDUMP
826                                 WCOREDUMP(status) ? ", core dumped" : ""
827 #else
828                                 ""
829 #endif
830                                 );
831                         exit( WEXITSTATUS(status)  );
832
833                 } else if ( WEXITSTATUS(status) != 0 ) {
834                         fprintf( stderr, 
835                             "stopping: child exited with status %d\n",
836                             (int) WEXITSTATUS(status) );
837                         exit( WEXITSTATUS(status) );
838
839                 } else {
840                         nkids--;
841                 }
842         }
843 }
844 #else
845
846 static void
847 wait4kids( int nkidval )
848 {
849         int rc, i;
850
851         while ( nkids >= nkidval ) {
852                 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
853                 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
854                         children[i] = children[i+1];
855                 nkids--;
856         }
857 }
858
859 static void
860 fork_child( char *prog, char **args )
861 {
862         int rc;
863
864         wait4kids( maxkids );
865
866         rc = _spawnvp( _P_NOWAIT, prog, args );
867
868         if ( rc == -1 ) {
869                 tester_perror( "_spawnvp", NULL );
870         } else {
871                 children[nkids++] = (HANDLE)rc;
872         }
873 }
874 #endif