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