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