]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
Have slapd-bind reuse LDAP session (no init).
[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         int             bnum = 0;
166         char            *bargs[MAXARGS];
167         int             banum;
168         char            bcmd[MAXPATHLEN];
169         char            bloops[] = "18446744073709551615UL";
170
171         char            *friendlyOpt = NULL;
172
173         tester_init( "slapd-tester" );
174
175         while ( (i = getopt( argc, argv, "ACD:d:FH:h:j:l:L:P:p:r:t:w:" )) != EOF ) {
176                 switch( i ) {
177                 case 'A':
178                         noattrs++;
179                         break;
180
181                 case 'C':
182                         chaserefs++;
183                         break;
184
185                 case 'D':               /* slapd manager */
186                         manager = ArgDup( optarg );
187                         break;
188
189                 case 'd':               /* data directory */
190                         dirname = strdup( optarg );
191                         break;
192
193                 case 'F':
194                         friendly++;
195                         break;
196
197                 case 'H':               /* slapd uri */
198                         uri = strdup( optarg );
199                         break;
200
201                 case 'h':               /* slapd host */
202                         host = strdup( optarg );
203                         break;
204
205                 case 'j':               /* the number of parallel clients */
206                         if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
207                                 usage( argv[0] );
208                         }
209                         break;
210
211                 case 'l':               /* the number of loops per client */
212                         if ( lutil_atoi( &loops, optarg ) != 0 ) {
213                                 usage( argv[0] );
214                         }
215                         break;
216
217                 case 'L':               /* the number of outerloops per client */
218                         outerloops = strdup( optarg );
219                         break;
220
221                 case 'P':               /* prog directory */
222                         progdir = strdup( optarg );
223                         break;
224
225                 case 'p':               /* the servers port number */
226                         port = strdup( optarg );
227                         break;
228
229                 case 'r':               /* the number of retries in case of error */
230                         retries = strdup( optarg );
231                         break;
232
233                 case 't':               /* the delay in seconds between each retry */
234                         delay = strdup( optarg );
235                         break;
236
237                 case 'w':               /* the managers passwd */
238                         passwd = ArgDup( optarg );
239                         break;
240
241                 default:
242                         usage( argv[0] );
243                         break;
244                 }
245         }
246
247         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
248                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
249                 usage( argv[0] );
250
251 #ifdef HAVE_WINSOCK
252         children = malloc( maxkids * sizeof(HANDLE) );
253 #endif
254         /* get the file list */
255         if ( ( datadir = opendir( dirname )) == NULL ) {
256
257                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
258                                         argv[0], dirname );
259                 exit( EXIT_FAILURE );
260
261         }
262
263         /*  look for search, read, modrdn, and add/delete files */
264         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
265
266                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
267                         sfile = get_file_name( dirname, file->d_name );
268                         continue;
269                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
270                         rfile = get_file_name( dirname, file->d_name );
271                         continue;
272                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
273                         mfile = get_file_name( dirname, file->d_name );
274                         continue;
275                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
276                         modfile = get_file_name( dirname, file->d_name );
277                         continue;
278                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
279                         && ( anum < MAXREQS )) {
280                         afiles[anum++] = get_file_name( dirname, file->d_name );
281                         continue;
282                 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
283                         bfile = get_file_name( dirname, file->d_name );
284                         continue;
285                 }
286         }
287
288         closedir( datadir );
289
290         /* look for search requests */
291         if ( sfile ) {
292                 snum = get_search_filters( sfile, sreqs, sattrs, sbase );
293         }
294
295         /* look for read requests */
296         if ( rfile ) {
297                 rnum = get_read_entries( rfile, rreqs, rflts );
298         }
299
300         /* look for modrdn requests */
301         if ( mfile ) {
302                 mnum = get_read_entries( mfile, mreqs, NULL );
303         }
304
305         /* look for modify requests */
306         if ( modfile ) {
307                 modnum = get_search_filters( modfile, modreqs, NULL, moddn );
308         }
309
310         /* look for bind requests */
311         if ( bfile ) {
312                 bnum = get_search_filters( bfile, bcreds, NULL, breqs );
313         }
314
315         /* setup friendly option */
316
317         switch ( friendly ) {
318         case 0:
319                 break;
320
321         case 1:
322                 friendlyOpt = "-F";
323                 break;
324
325         default:
326                 /* NOTE: right now we don't need it more than twice */
327         case 2:
328                 friendlyOpt = "-FF";
329                 break;
330         }
331
332         snprintf( sloops, sizeof( sloops ), "%d", 10 * loops );
333         snprintf( rloops, sizeof( rloops ), "%d", 20 * loops );
334         snprintf( aloops, sizeof( aloops ), "%d", loops );
335         snprintf( mloops, sizeof( mloops ), "%d", loops );
336         snprintf( modloops, sizeof( modloops ), "%d", loops );
337         snprintf( bloops, sizeof( bloops ), "%d", 20 * loops );
338
339         /*
340          * generate the search clients
341          */
342
343         sanum = 0;
344         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
345                 progdir );
346         sargs[sanum++] = scmd;
347         if ( uri ) {
348                 sargs[sanum++] = "-H";
349                 sargs[sanum++] = uri;
350         } else {
351                 sargs[sanum++] = "-h";
352                 sargs[sanum++] = host;
353                 sargs[sanum++] = "-p";
354                 sargs[sanum++] = port;
355         }
356         sargs[sanum++] = "-D";
357         sargs[sanum++] = manager;
358         sargs[sanum++] = "-w";
359         sargs[sanum++] = passwd;
360         sargs[sanum++] = "-l";
361         sargs[sanum++] = sloops;
362         sargs[sanum++] = "-L";
363         sargs[sanum++] = outerloops;
364         sargs[sanum++] = "-r";
365         sargs[sanum++] = retries;
366         sargs[sanum++] = "-t";
367         sargs[sanum++] = delay;
368         if ( friendly ) {
369                 sargs[sanum++] = friendlyOpt;
370         }
371         if ( chaserefs ) {
372                 sargs[sanum++] = "-C";
373         }
374         if ( noattrs ) {
375                 sargs[sanum++] = "-A";
376         }
377         sargs[sanum++] = "-b";
378         sargs[sanum++] = NULL;          /* will hold the search base */
379         sargs[sanum++] = "-f";
380         sargs[sanum++] = NULL;          /* will hold the search request */
381
382         sargs[sanum++] = NULL;
383         sargs[sanum] = NULL;            /* might hold the "attr" request */
384
385         sargs[sanum + 1] = NULL;
386
387         /*
388          * generate the read clients
389          */
390
391         ranum = 0;
392         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
393                 progdir );
394         rargs[ranum++] = rcmd;
395         if ( uri ) {
396                 rargs[ranum++] = "-H";
397                 rargs[ranum++] = uri;
398         } else {
399                 rargs[ranum++] = "-h";
400                 rargs[ranum++] = host;
401                 rargs[ranum++] = "-p";
402                 rargs[ranum++] = port;
403         }
404         rargs[ranum++] = "-D";
405         rargs[ranum++] = manager;
406         rargs[ranum++] = "-w";
407         rargs[ranum++] = passwd;
408         rargs[ranum++] = "-l";
409         rargs[ranum++] = rloops;
410         rargs[ranum++] = "-L";
411         rargs[ranum++] = outerloops;
412         rargs[ranum++] = "-r";
413         rargs[ranum++] = retries;
414         rargs[ranum++] = "-t";
415         rargs[ranum++] = delay;
416         if ( friendly ) {
417                 rargs[ranum++] = friendlyOpt;
418         }
419         if ( chaserefs ) {
420                 rargs[ranum++] = "-C";
421         }
422         if ( noattrs ) {
423                 rargs[ranum++] = "-A";
424         }
425         rargs[ranum++] = "-e";
426         rargs[ranum++] = NULL;          /* will hold the read entry */
427
428         rargs[ranum++] = NULL;
429         rargs[ranum] = NULL;            /* might hold the filter arg */
430
431         rargs[ranum + 1] = NULL;
432
433         /*
434          * generate the modrdn clients
435          */
436
437         manum = 0;
438         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
439                 progdir );
440         margs[manum++] = mcmd;
441         if ( uri ) {
442                 margs[manum++] = "-H";
443                 margs[manum++] = uri;
444         } else {
445                 margs[manum++] = "-h";
446                 margs[manum++] = host;
447                 margs[manum++] = "-p";
448                 margs[manum++] = port;
449         }
450         margs[manum++] = "-D";
451         margs[manum++] = manager;
452         margs[manum++] = "-w";
453         margs[manum++] = passwd;
454         margs[manum++] = "-l";
455         margs[manum++] = mloops;
456         margs[manum++] = "-L";
457         margs[manum++] = outerloops;
458         margs[manum++] = "-r";
459         margs[manum++] = retries;
460         margs[manum++] = "-t";
461         margs[manum++] = delay;
462         if ( friendly ) {
463                 margs[manum++] = friendlyOpt;
464         }
465         if ( chaserefs ) {
466                 margs[manum++] = "-C";
467         }
468         margs[manum++] = "-e";
469         margs[manum++] = NULL;          /* will hold the modrdn entry */
470         margs[manum++] = NULL;
471         
472         /*
473          * generate the modify clients
474          */
475
476         modanum = 0;
477         snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
478                 progdir );
479         modargs[modanum++] = modcmd;
480         if ( uri ) {
481                 modargs[modanum++] = "-H";
482                 modargs[modanum++] = uri;
483         } else {
484                 modargs[modanum++] = "-h";
485                 modargs[modanum++] = host;
486                 modargs[modanum++] = "-p";
487                 modargs[modanum++] = port;
488         }
489         modargs[modanum++] = "-D";
490         modargs[modanum++] = manager;
491         modargs[modanum++] = "-w";
492         modargs[modanum++] = passwd;
493         modargs[modanum++] = "-l";
494         modargs[modanum++] = modloops;
495         modargs[modanum++] = "-L";
496         modargs[modanum++] = outerloops;
497         modargs[modanum++] = "-r";
498         modargs[modanum++] = retries;
499         modargs[modanum++] = "-t";
500         modargs[modanum++] = delay;
501         if ( friendly ) {
502                 modargs[modanum++] = friendlyOpt;
503         }
504         if ( chaserefs ) {
505                 modargs[modanum++] = "-C";
506         }
507         modargs[modanum++] = "-e";
508         modargs[modanum++] = NULL;              /* will hold the modify entry */
509         modargs[modanum++] = "-a";;
510         modargs[modanum++] = NULL;              /* will hold the ava */
511         modargs[modanum++] = NULL;
512
513         /*
514          * generate the add/delete clients
515          */
516
517         aanum = 0;
518         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
519                 progdir );
520         aargs[aanum++] = acmd;
521         if ( uri ) {
522                 aargs[aanum++] = "-H";
523                 aargs[aanum++] = uri;
524         } else {
525                 aargs[aanum++] = "-h";
526                 aargs[aanum++] = host;
527                 aargs[aanum++] = "-p";
528                 aargs[aanum++] = port;
529         }
530         aargs[aanum++] = "-D";
531         aargs[aanum++] = manager;
532         aargs[aanum++] = "-w";
533         aargs[aanum++] = passwd;
534         aargs[aanum++] = "-l";
535         aargs[aanum++] = aloops;
536         aargs[aanum++] = "-L";
537         aargs[aanum++] = outerloops;
538         aargs[aanum++] = "-r";
539         aargs[aanum++] = retries;
540         aargs[aanum++] = "-t";
541         aargs[aanum++] = delay;
542         if ( friendly ) {
543                 aargs[aanum++] = friendlyOpt;
544         }
545         if ( chaserefs ) {
546                 aargs[aanum++] = "-C";
547         }
548         aargs[aanum++] = "-f";
549         aargs[aanum++] = NULL;          /* will hold the add data file */
550         aargs[aanum++] = NULL;
551
552         /*
553          * generate the bind clients
554          */
555
556         banum = 0;
557         snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
558                 progdir );
559         bargs[banum++] = bcmd;
560         bargs[banum++] = "-I";  /* don't init on each bind */
561         if ( uri ) {
562                 bargs[banum++] = "-H";
563                 bargs[banum++] = uri;
564         } else {
565                 bargs[banum++] = "-h";
566                 bargs[banum++] = host;
567                 bargs[banum++] = "-p";
568                 bargs[banum++] = port;
569         }
570         bargs[banum++] = "-l";
571         bargs[banum++] = bloops;
572         bargs[banum++] = "-L";
573         bargs[banum++] = outerloops;
574 #if 0
575         bargs[banum++] = "-r";
576         bargs[banum++] = retries;
577         bargs[banum++] = "-t";
578         bargs[banum++] = delay;
579 #endif
580         if ( friendly ) {
581                 bargs[banum++] = friendlyOpt;
582         }
583         if ( chaserefs ) {
584                 bargs[banum++] = "-C";
585         }
586         bargs[banum++] = "-D";
587         bargs[banum++] = NULL;
588         bargs[banum++] = "-w";
589         bargs[banum++] = NULL;
590         bargs[banum++] = NULL;
591
592 #define DOREQ(n,j) ((n) && ((maxkids > (n)) ? ((j) < maxkids ) : ((j) < (n))))
593
594         for ( j = 0; j < MAXREQS; j++ ) {
595                 if ( DOREQ( snum, j ) ) {
596                         int     jj = j % snum;
597
598                         sargs[sanum - 2] = sreqs[jj];
599                         sargs[sanum - 4] = sbase[jj];
600                         if ( sattrs[jj] != NULL ) {
601                                 sargs[sanum - 1] = "-a";
602                                 sargs[sanum] = sattrs[jj];
603
604                         } else {
605                                 sargs[sanum - 1] = NULL;
606                         }
607                         fork_child( scmd, sargs );
608                 }
609
610                 if ( DOREQ( rnum, j ) ) {
611                         int     jj = j % rnum;
612
613                         rargs[ranum - 2] = rreqs[jj];
614                         if ( rflts[jj] != NULL ) {
615                                 rargs[ranum - 1] = "-f";
616                                 rargs[ranum] = rflts[jj];
617
618                         } else {
619                                 rargs[ranum - 1] = NULL;
620                         }
621                         fork_child( rcmd, rargs );
622                 }
623
624                 if ( j < mnum ) {
625                         margs[manum - 2] = mreqs[j];
626                         fork_child( mcmd, margs );
627                 }
628
629                 if ( j < modnum ) {
630                         modargs[modanum - 4] = moddn[j];
631                         modargs[modanum - 2] = modreqs[j];
632                         fork_child( modcmd, modargs );
633                 }
634
635                 if ( j < anum ) {
636                         aargs[aanum - 2] = afiles[j];
637                         fork_child( acmd, aargs );
638                 }
639
640                 if ( DOREQ( bnum, j ) ) {
641                         int     jj = j % bnum;
642
643                         bargs[banum - 4] = breqs[jj];
644                         bargs[banum - 2] = bcreds[jj];
645                         fork_child( bcmd, bargs );
646                 }
647         }
648
649         wait4kids( -1 );
650
651         exit( EXIT_SUCCESS );
652 }
653
654 static char *
655 get_file_name( char *dirname, char *filename )
656 {
657         char buf[MAXPATHLEN];
658
659         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
660                 dirname, filename );
661         return( strdup( buf ));
662 }
663
664
665 static int
666 get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[] )
667 {
668         FILE    *fp;
669         int     filter = 0;
670
671         if ( (fp = fopen( filename, "r" )) != NULL ) {
672                 char  line[BUFSIZ];
673
674                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
675                         char *nl;
676
677                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
678                                 *nl = '\0';
679                         bases[filter] = ArgDup( line );
680                         fgets( line, BUFSIZ, fp );
681                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
682                                 *nl = '\0';
683
684                         filters[filter] = ArgDup( line );
685                         if ( attrs ) {
686                                 if ( filters[filter][0] == '+') {
687                                         char    *sep = strchr( filters[filter], ':' );
688
689                                         if ( sep != NULL ) {
690                                                 attrs[ filter ] = &filters[ filter ][ 1 ];
691                                                 sep[ 0 ] = '\0';
692                                                 /* NOTE: don't free this! */
693                                                 filters[ filter ] = &sep[ 1 ];
694                                         }
695
696                                 } else {
697                                         attrs[ filter] = NULL;
698                                 }
699                         }
700                         filter++;
701
702                 }
703                 fclose( fp );
704         }
705
706         return( filter );
707 }
708
709
710 static int
711 get_read_entries( char *filename, char *entries[], char *filters[] )
712 {
713         FILE    *fp;
714         int     entry = 0;
715
716         if ( (fp = fopen( filename, "r" )) != NULL ) {
717                 char  line[BUFSIZ];
718
719                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
720                         char *nl;
721
722                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
723                                 *nl = '\0';
724                         if ( filters != NULL && line[0] == '+' ) {
725                                 LDAPURLDesc     *lud;
726
727                                 if ( ldap_url_parse( &line[1], &lud ) != LDAP_URL_SUCCESS ) {
728                                         entry = -1;
729                                         break;
730                                 }
731
732                                 if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
733                                         ldap_free_urldesc( lud );
734                                         entry = -1;
735                                         break;
736                                 }
737
738                                 entries[entry] = ArgDup( lud->lud_dn );
739
740                                 if ( lud->lud_filter ) {
741                                         filters[entry] = ArgDup( lud->lud_filter );
742
743                                 } else {
744                                         filters[entry] = ArgDup( "(objectClass=*)" );
745                                 }
746                                 ldap_free_urldesc( lud );
747
748                         } else {
749                                 entries[entry] = ArgDup( line );
750                         }
751
752                         entry++;
753
754                 }
755                 fclose( fp );
756         }
757
758         return( entry );
759 }
760
761 #ifndef HAVE_WINSOCK
762 static void
763 fork_child( char *prog, char **args )
764 {
765         pid_t   pid;
766
767         wait4kids( maxkids );
768
769         switch ( pid = fork() ) {
770         case 0:         /* child */
771 #ifdef HAVE_EBCDIC
772                 /* The __LIBASCII execvp only handles ASCII "prog",
773                  * we still need to translate the arg vec ourselves.
774                  */
775                 { char *arg2[MAXREQS];
776                 int i;
777
778                 for (i=0; args[i]; i++) {
779                         arg2[i] = ArgDup(args[i]);
780                         __atoe(arg2[i]);
781                 }
782                 arg2[i] = NULL;
783                 args = arg2; }
784 #endif
785                 execvp( prog, args );
786                 tester_perror( "execvp" );
787                 exit( EXIT_FAILURE );
788                 break;
789
790         case -1:        /* trouble */
791                 tester_perror( "fork" );
792                 break;
793
794         default:        /* parent */
795                 nkids++;
796                 break;
797         }
798 }
799
800 static void
801 wait4kids( int nkidval )
802 {
803         int             status;
804
805         while ( nkids >= nkidval ) {
806                 wait( &status );
807
808                 if ( WIFSTOPPED(status) ) {
809                         fprintf( stderr,
810                             "stopping: child stopped with signal %d\n",
811                             (int) WSTOPSIG(status) );
812
813                 } else if ( WIFSIGNALED(status) ) {
814                         fprintf( stderr, 
815                             "stopping: child terminated with signal %d%s\n",
816                             (int) WTERMSIG(status),
817 #ifdef WCOREDUMP
818                                 WCOREDUMP(status) ? ", core dumped" : ""
819 #else
820                                 ""
821 #endif
822                                 );
823                         exit( WEXITSTATUS(status)  );
824
825                 } else if ( WEXITSTATUS(status) != 0 ) {
826                         fprintf( stderr, 
827                             "stopping: child exited with status %d\n",
828                             (int) WEXITSTATUS(status) );
829                         exit( WEXITSTATUS(status) );
830
831                 } else {
832                         nkids--;
833                 }
834         }
835 }
836 #else
837
838 static void
839 wait4kids( int nkidval )
840 {
841         int rc, i;
842
843         while ( nkids >= nkidval ) {
844                 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
845                 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
846                         children[i] = children[i+1];
847                 nkids--;
848         }
849 }
850
851 static void
852 fork_child( char *prog, char **args )
853 {
854         int rc;
855
856         wait4kids( maxkids );
857
858         rc = _spawnvp( _P_NOWAIT, prog, args );
859
860         if ( rc == -1 ) {
861                 tester_perror( "_spawnvp" );
862         } else {
863                 children[nkids++] = (HANDLE)rc;
864         }
865 }
866 #endif