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