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