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