2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2006 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
16 * This work was initially developed by Kurt Spanier for inclusion
17 * in OpenLDAP Software.
24 #include <ac/stdlib.h>
27 #include <ac/dirent.h>
29 #include <ac/socket.h>
30 #include <ac/string.h>
31 #include <ac/unistd.h>
35 #include "ldap_defaults.h"
39 #include "slapd-common.h"
41 #define SEARCHCMD "slapd-search"
42 #define READCMD "slapd-read"
43 #define ADDCMD "slapd-addel"
44 #define MODRDNCMD "slapd-modrdn"
45 #define MODIFYCMD "slapd-modify"
46 #define BINDCMD "slapd-bind"
50 #define OUTERLOOPS "1"
53 #define TSEARCHFILE "do_search.0"
54 #define TREADFILE "do_read.0"
55 #define TADDFILE "do_add."
56 #define TMODRDNFILE "do_modrdn.0"
57 #define TMODIFYFILE "do_modify.0"
58 #define TBINDFILE "do_bind.0"
60 static char *get_file_name( char *dirname, char *filename );
61 static int get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[] );
62 static int get_read_entries( char *filename, char *entries[], char *filters[] );
63 static void fork_child( char *prog, char **args );
64 static void wait4kids( int nkidval );
66 static int maxkids = 20;
70 static HANDLE *children;
71 static char argbuf[BUFSIZ];
72 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
74 #define ArgDup(x) strdup(x)
82 "-H <uri> | ([-h <host>] -p <port>) "
99 main( int argc, char **argv )
103 char *host = "localhost";
105 char *manager = NULL;
107 char *dirname = NULL;
108 char *progdir = NULL;
110 char *outerloops = OUTERLOOPS;
111 char *retries = RETRIES;
120 char *sreqs[MAXREQS];
121 char *sattrs[MAXREQS];
122 char *sbase[MAXREQS];
124 char *sargs[MAXARGS];
126 char scmd[MAXPATHLEN];
127 char sloops[] = "18446744073709551615UL";
130 char *rreqs[MAXREQS];
132 char *rargs[MAXARGS];
133 char *rflts[MAXREQS];
135 char rcmd[MAXPATHLEN];
136 char rloops[] = "18446744073709551615UL";
138 char *afiles[MAXREQS];
140 char *aargs[MAXARGS];
142 char acmd[MAXPATHLEN];
143 char aloops[] = "18446744073709551615UL";
146 char *mreqs[MAXREQS];
148 char *margs[MAXARGS];
150 char mcmd[MAXPATHLEN];
151 char mloops[] = "18446744073709551615UL";
153 char *modfile = NULL;
154 char *modreqs[MAXREQS];
155 char *moddn[MAXREQS];
157 char *modargs[MAXARGS];
159 char modcmd[MAXPATHLEN];
160 char modloops[] = "18446744073709551615UL";
163 char *breqs[MAXREQS];
164 char *bcreds[MAXREQS];
166 char *bargs[MAXARGS];
168 char bcmd[MAXPATHLEN];
169 char bloops[] = "18446744073709551615UL";
171 char *friendlyOpt = NULL;
173 tester_init( "slapd-tester" );
175 while ( (i = getopt( argc, argv, "ACD:d:FH:h:j:l:L:P:p:r:t:w:" )) != EOF ) {
185 case 'D': /* slapd manager */
186 manager = ArgDup( optarg );
189 case 'd': /* data directory */
190 dirname = strdup( optarg );
197 case 'H': /* slapd uri */
198 uri = strdup( optarg );
201 case 'h': /* slapd host */
202 host = strdup( optarg );
205 case 'j': /* the number of parallel clients */
206 if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
211 case 'l': /* the number of loops per client */
212 if ( lutil_atoi( &loops, optarg ) != 0 ) {
217 case 'L': /* the number of outerloops per client */
218 outerloops = strdup( optarg );
221 case 'P': /* prog directory */
222 progdir = strdup( optarg );
225 case 'p': /* the servers port number */
226 port = strdup( optarg );
229 case 'r': /* the number of retries in case of error */
230 retries = strdup( optarg );
233 case 't': /* the delay in seconds between each retry */
234 delay = strdup( optarg );
237 case 'w': /* the managers passwd */
238 passwd = ArgDup( optarg );
247 if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
248 ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
252 children = malloc( maxkids * sizeof(HANDLE) );
254 /* get the file list */
255 if ( ( datadir = opendir( dirname )) == NULL ) {
257 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
259 exit( EXIT_FAILURE );
263 /* look for search, read, modrdn, and add/delete files */
264 for ( file = readdir( datadir ); file; file = readdir( datadir )) {
266 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
267 sfile = get_file_name( dirname, file->d_name );
269 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
270 rfile = get_file_name( dirname, file->d_name );
272 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
273 mfile = get_file_name( dirname, file->d_name );
275 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
276 modfile = get_file_name( dirname, file->d_name );
278 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
279 && ( anum < MAXREQS )) {
280 afiles[anum++] = get_file_name( dirname, file->d_name );
282 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
283 bfile = get_file_name( dirname, file->d_name );
290 /* look for search requests */
292 snum = get_search_filters( sfile, sreqs, sattrs, sbase );
295 /* look for read requests */
297 rnum = get_read_entries( rfile, rreqs, rflts );
300 /* look for modrdn requests */
302 mnum = get_read_entries( mfile, mreqs, NULL );
305 /* look for modify requests */
307 modnum = get_search_filters( modfile, modreqs, NULL, moddn );
310 /* look for bind requests */
312 bnum = get_search_filters( bfile, bcreds, NULL, breqs );
315 /* setup friendly option */
317 switch ( friendly ) {
326 /* NOTE: right now we don't need it more than twice */
332 snprintf( sloops, sizeof( sloops ), "%d", 10 * loops );
333 snprintf( rloops, sizeof( rloops ), "%d", 20 * loops );
334 snprintf( aloops, sizeof( aloops ), "%d", loops );
335 snprintf( mloops, sizeof( mloops ), "%d", loops );
336 snprintf( modloops, sizeof( modloops ), "%d", loops );
337 snprintf( bloops, sizeof( bloops ), "%d", 20 * loops );
340 * generate the search clients
344 snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
346 sargs[sanum++] = scmd;
348 sargs[sanum++] = "-H";
349 sargs[sanum++] = uri;
351 sargs[sanum++] = "-h";
352 sargs[sanum++] = host;
353 sargs[sanum++] = "-p";
354 sargs[sanum++] = port;
356 sargs[sanum++] = "-D";
357 sargs[sanum++] = manager;
358 sargs[sanum++] = "-w";
359 sargs[sanum++] = passwd;
360 sargs[sanum++] = "-l";
361 sargs[sanum++] = sloops;
362 sargs[sanum++] = "-L";
363 sargs[sanum++] = outerloops;
364 sargs[sanum++] = "-r";
365 sargs[sanum++] = retries;
366 sargs[sanum++] = "-t";
367 sargs[sanum++] = delay;
369 sargs[sanum++] = friendlyOpt;
372 sargs[sanum++] = "-C";
375 sargs[sanum++] = "-A";
377 sargs[sanum++] = "-b";
378 sargs[sanum++] = NULL; /* will hold the search base */
379 sargs[sanum++] = "-f";
380 sargs[sanum++] = NULL; /* will hold the search request */
382 sargs[sanum++] = NULL;
383 sargs[sanum] = NULL; /* might hold the "attr" request */
385 sargs[sanum + 1] = NULL;
388 * generate the read clients
392 snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
394 rargs[ranum++] = rcmd;
396 rargs[ranum++] = "-H";
397 rargs[ranum++] = uri;
399 rargs[ranum++] = "-h";
400 rargs[ranum++] = host;
401 rargs[ranum++] = "-p";
402 rargs[ranum++] = port;
404 rargs[ranum++] = "-D";
405 rargs[ranum++] = manager;
406 rargs[ranum++] = "-w";
407 rargs[ranum++] = passwd;
408 rargs[ranum++] = "-l";
409 rargs[ranum++] = rloops;
410 rargs[ranum++] = "-L";
411 rargs[ranum++] = outerloops;
412 rargs[ranum++] = "-r";
413 rargs[ranum++] = retries;
414 rargs[ranum++] = "-t";
415 rargs[ranum++] = delay;
417 rargs[ranum++] = friendlyOpt;
420 rargs[ranum++] = "-C";
423 rargs[ranum++] = "-A";
425 rargs[ranum++] = "-e";
426 rargs[ranum++] = NULL; /* will hold the read entry */
428 rargs[ranum++] = NULL;
429 rargs[ranum] = NULL; /* might hold the filter arg */
431 rargs[ranum + 1] = NULL;
434 * generate the modrdn clients
438 snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
440 margs[manum++] = mcmd;
442 margs[manum++] = "-H";
443 margs[manum++] = uri;
445 margs[manum++] = "-h";
446 margs[manum++] = host;
447 margs[manum++] = "-p";
448 margs[manum++] = port;
450 margs[manum++] = "-D";
451 margs[manum++] = manager;
452 margs[manum++] = "-w";
453 margs[manum++] = passwd;
454 margs[manum++] = "-l";
455 margs[manum++] = mloops;
456 margs[manum++] = "-L";
457 margs[manum++] = outerloops;
458 margs[manum++] = "-r";
459 margs[manum++] = retries;
460 margs[manum++] = "-t";
461 margs[manum++] = delay;
463 margs[manum++] = friendlyOpt;
466 margs[manum++] = "-C";
468 margs[manum++] = "-e";
469 margs[manum++] = NULL; /* will hold the modrdn entry */
470 margs[manum++] = NULL;
473 * generate the modify clients
477 snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
479 modargs[modanum++] = modcmd;
481 modargs[modanum++] = "-H";
482 modargs[modanum++] = uri;
484 modargs[modanum++] = "-h";
485 modargs[modanum++] = host;
486 modargs[modanum++] = "-p";
487 modargs[modanum++] = port;
489 modargs[modanum++] = "-D";
490 modargs[modanum++] = manager;
491 modargs[modanum++] = "-w";
492 modargs[modanum++] = passwd;
493 modargs[modanum++] = "-l";
494 modargs[modanum++] = modloops;
495 modargs[modanum++] = "-L";
496 modargs[modanum++] = outerloops;
497 modargs[modanum++] = "-r";
498 modargs[modanum++] = retries;
499 modargs[modanum++] = "-t";
500 modargs[modanum++] = delay;
502 modargs[modanum++] = friendlyOpt;
505 modargs[modanum++] = "-C";
507 modargs[modanum++] = "-e";
508 modargs[modanum++] = NULL; /* will hold the modify entry */
509 modargs[modanum++] = "-a";;
510 modargs[modanum++] = NULL; /* will hold the ava */
511 modargs[modanum++] = NULL;
514 * generate the add/delete clients
518 snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
520 aargs[aanum++] = acmd;
522 aargs[aanum++] = "-H";
523 aargs[aanum++] = uri;
525 aargs[aanum++] = "-h";
526 aargs[aanum++] = host;
527 aargs[aanum++] = "-p";
528 aargs[aanum++] = port;
530 aargs[aanum++] = "-D";
531 aargs[aanum++] = manager;
532 aargs[aanum++] = "-w";
533 aargs[aanum++] = passwd;
534 aargs[aanum++] = "-l";
535 aargs[aanum++] = aloops;
536 aargs[aanum++] = "-L";
537 aargs[aanum++] = outerloops;
538 aargs[aanum++] = "-r";
539 aargs[aanum++] = retries;
540 aargs[aanum++] = "-t";
541 aargs[aanum++] = delay;
543 aargs[aanum++] = friendlyOpt;
546 aargs[aanum++] = "-C";
548 aargs[aanum++] = "-f";
549 aargs[aanum++] = NULL; /* will hold the add data file */
550 aargs[aanum++] = NULL;
553 * generate the bind clients
557 snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
559 bargs[banum++] = bcmd;
560 bargs[banum++] = "-I"; /* don't init on each bind */
562 bargs[banum++] = "-H";
563 bargs[banum++] = uri;
565 bargs[banum++] = "-h";
566 bargs[banum++] = host;
567 bargs[banum++] = "-p";
568 bargs[banum++] = port;
570 bargs[banum++] = "-l";
571 bargs[banum++] = bloops;
572 bargs[banum++] = "-L";
573 bargs[banum++] = outerloops;
575 bargs[banum++] = "-r";
576 bargs[banum++] = retries;
577 bargs[banum++] = "-t";
578 bargs[banum++] = delay;
581 bargs[banum++] = friendlyOpt;
584 bargs[banum++] = "-C";
586 bargs[banum++] = "-D";
587 bargs[banum++] = NULL;
588 bargs[banum++] = "-w";
589 bargs[banum++] = NULL;
590 bargs[banum++] = NULL;
592 #define DOREQ(n,j) ((n) && ((maxkids > (n)) ? ((j) < maxkids ) : ((j) < (n))))
594 for ( j = 0; j < MAXREQS; j++ ) {
595 if ( DOREQ( snum, j ) ) {
598 sargs[sanum - 2] = sreqs[jj];
599 sargs[sanum - 4] = sbase[jj];
600 if ( sattrs[jj] != NULL ) {
601 sargs[sanum - 1] = "-a";
602 sargs[sanum] = sattrs[jj];
605 sargs[sanum - 1] = NULL;
607 fork_child( scmd, sargs );
610 if ( DOREQ( rnum, j ) ) {
613 rargs[ranum - 2] = rreqs[jj];
614 if ( rflts[jj] != NULL ) {
615 rargs[ranum - 1] = "-f";
616 rargs[ranum] = rflts[jj];
619 rargs[ranum - 1] = NULL;
621 fork_child( rcmd, rargs );
625 margs[manum - 2] = mreqs[j];
626 fork_child( mcmd, margs );
630 modargs[modanum - 4] = moddn[j];
631 modargs[modanum - 2] = modreqs[j];
632 fork_child( modcmd, modargs );
636 aargs[aanum - 2] = afiles[j];
637 fork_child( acmd, aargs );
640 if ( DOREQ( bnum, j ) ) {
643 bargs[banum - 4] = breqs[jj];
644 bargs[banum - 2] = bcreds[jj];
645 fork_child( bcmd, bargs );
651 exit( EXIT_SUCCESS );
655 get_file_name( char *dirname, char *filename )
657 char buf[MAXPATHLEN];
659 snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
661 return( strdup( buf ));
666 get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[] )
671 if ( (fp = fopen( filename, "r" )) != NULL ) {
674 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
677 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
679 bases[filter] = ArgDup( line );
680 fgets( line, BUFSIZ, fp );
681 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
684 filters[filter] = ArgDup( line );
686 if ( filters[filter][0] == '+') {
687 char *sep = strchr( filters[filter], ':' );
690 attrs[ filter ] = &filters[ filter ][ 1 ];
692 /* NOTE: don't free this! */
693 filters[ filter ] = &sep[ 1 ];
697 attrs[ filter] = NULL;
711 get_read_entries( char *filename, char *entries[], char *filters[] )
716 if ( (fp = fopen( filename, "r" )) != NULL ) {
719 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
722 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
724 if ( filters != NULL && line[0] == '+' ) {
727 if ( ldap_url_parse( &line[1], &lud ) != LDAP_URL_SUCCESS ) {
732 if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
733 ldap_free_urldesc( lud );
738 entries[entry] = ArgDup( lud->lud_dn );
740 if ( lud->lud_filter ) {
741 filters[entry] = ArgDup( lud->lud_filter );
744 filters[entry] = ArgDup( "(objectClass=*)" );
746 ldap_free_urldesc( lud );
749 entries[entry] = ArgDup( line );
763 fork_child( char *prog, char **args )
767 wait4kids( maxkids );
769 switch ( pid = fork() ) {
772 /* The __LIBASCII execvp only handles ASCII "prog",
773 * we still need to translate the arg vec ourselves.
775 { char *arg2[MAXREQS];
778 for (i=0; args[i]; i++) {
779 arg2[i] = ArgDup(args[i]);
785 execvp( prog, args );
786 tester_perror( "execvp" );
787 exit( EXIT_FAILURE );
790 case -1: /* trouble */
791 tester_perror( "fork" );
794 default: /* parent */
801 wait4kids( int nkidval )
805 while ( nkids >= nkidval ) {
808 if ( WIFSTOPPED(status) ) {
810 "stopping: child stopped with signal %d\n",
811 (int) WSTOPSIG(status) );
813 } else if ( WIFSIGNALED(status) ) {
815 "stopping: child terminated with signal %d%s\n",
816 (int) WTERMSIG(status),
818 WCOREDUMP(status) ? ", core dumped" : ""
823 exit( WEXITSTATUS(status) );
825 } else if ( WEXITSTATUS(status) != 0 ) {
827 "stopping: child exited with status %d\n",
828 (int) WEXITSTATUS(status) );
829 exit( WEXITSTATUS(status) );
839 wait4kids( int nkidval )
843 while ( nkids >= nkidval ) {
844 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
845 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
846 children[i] = children[i+1];
852 fork_child( char *prog, char **args )
856 wait4kids( maxkids );
858 rc = _spawnvp( _P_NOWAIT, prog, args );
861 tester_perror( "_spawnvp" );
863 children[nkids++] = (HANDLE)rc;