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];
165 char *battrs[MAXREQS];
167 char *bargs[MAXARGS];
169 char bcmd[MAXPATHLEN];
170 char bloops[] = "18446744073709551615UL";
172 char *friendlyOpt = NULL;
174 tester_init( "slapd-tester" );
176 while ( (i = getopt( argc, argv, "ACD:d:FH:h:j:l:L:P:p:r:t:w:" )) != EOF ) {
186 case 'D': /* slapd manager */
187 manager = ArgDup( optarg );
190 case 'd': /* data directory */
191 dirname = strdup( optarg );
198 case 'H': /* slapd uri */
199 uri = strdup( optarg );
202 case 'h': /* slapd host */
203 host = strdup( optarg );
206 case 'j': /* the number of parallel clients */
207 if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
212 case 'l': /* the number of loops per client */
213 if ( lutil_atoi( &loops, optarg ) != 0 ) {
218 case 'L': /* the number of outerloops per client */
219 outerloops = strdup( optarg );
222 case 'P': /* prog directory */
223 progdir = strdup( optarg );
226 case 'p': /* the servers port number */
227 port = strdup( optarg );
230 case 'r': /* the number of retries in case of error */
231 retries = strdup( optarg );
234 case 't': /* the delay in seconds between each retry */
235 delay = strdup( optarg );
238 case 'w': /* the managers passwd */
239 passwd = ArgDup( optarg );
248 if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
249 ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
253 children = malloc( maxkids * sizeof(HANDLE) );
255 /* get the file list */
256 if ( ( datadir = opendir( dirname )) == NULL ) {
258 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
260 exit( EXIT_FAILURE );
264 /* look for search, read, modrdn, and add/delete files */
265 for ( file = readdir( datadir ); file; file = readdir( datadir )) {
267 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
268 sfile = get_file_name( dirname, file->d_name );
270 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
271 rfile = get_file_name( dirname, file->d_name );
273 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
274 mfile = get_file_name( dirname, file->d_name );
276 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
277 modfile = get_file_name( dirname, file->d_name );
279 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
280 && ( anum < MAXREQS )) {
281 afiles[anum++] = get_file_name( dirname, file->d_name );
283 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
284 bfile = get_file_name( dirname, file->d_name );
291 /* look for search requests */
293 snum = get_search_filters( sfile, sreqs, sattrs, sbase );
296 /* look for read requests */
298 rnum = get_read_entries( rfile, rreqs, rflts );
301 /* look for modrdn requests */
303 mnum = get_read_entries( mfile, mreqs, NULL );
306 /* look for modify requests */
308 modnum = get_search_filters( modfile, modreqs, NULL, moddn );
311 /* look for bind requests */
313 bnum = get_search_filters( bfile, bcreds, battrs, breqs );
316 /* setup friendly option */
318 switch ( friendly ) {
327 /* NOTE: right now we don't need it more than twice */
333 snprintf( sloops, sizeof( sloops ), "%d", 10 * loops );
334 snprintf( rloops, sizeof( rloops ), "%d", 20 * loops );
335 snprintf( aloops, sizeof( aloops ), "%d", loops );
336 snprintf( mloops, sizeof( mloops ), "%d", loops );
337 snprintf( modloops, sizeof( modloops ), "%d", loops );
338 snprintf( bloops, sizeof( bloops ), "%d", 20 * loops );
341 * generate the search clients
345 snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
347 sargs[sanum++] = scmd;
349 sargs[sanum++] = "-H";
350 sargs[sanum++] = uri;
352 sargs[sanum++] = "-h";
353 sargs[sanum++] = host;
354 sargs[sanum++] = "-p";
355 sargs[sanum++] = port;
357 sargs[sanum++] = "-D";
358 sargs[sanum++] = manager;
359 sargs[sanum++] = "-w";
360 sargs[sanum++] = passwd;
361 sargs[sanum++] = "-l";
362 sargs[sanum++] = sloops;
363 sargs[sanum++] = "-L";
364 sargs[sanum++] = outerloops;
365 sargs[sanum++] = "-r";
366 sargs[sanum++] = retries;
367 sargs[sanum++] = "-t";
368 sargs[sanum++] = delay;
370 sargs[sanum++] = friendlyOpt;
373 sargs[sanum++] = "-C";
376 sargs[sanum++] = "-A";
378 sargs[sanum++] = "-b";
379 sargs[sanum++] = NULL; /* will hold the search base */
380 sargs[sanum++] = "-f";
381 sargs[sanum++] = NULL; /* will hold the search request */
383 sargs[sanum++] = NULL;
384 sargs[sanum] = NULL; /* might hold the "attr" request */
386 sargs[sanum + 1] = NULL;
389 * generate the read clients
393 snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
395 rargs[ranum++] = rcmd;
397 rargs[ranum++] = "-H";
398 rargs[ranum++] = uri;
400 rargs[ranum++] = "-h";
401 rargs[ranum++] = host;
402 rargs[ranum++] = "-p";
403 rargs[ranum++] = port;
405 rargs[ranum++] = "-D";
406 rargs[ranum++] = manager;
407 rargs[ranum++] = "-w";
408 rargs[ranum++] = passwd;
409 rargs[ranum++] = "-l";
410 rargs[ranum++] = rloops;
411 rargs[ranum++] = "-L";
412 rargs[ranum++] = outerloops;
413 rargs[ranum++] = "-r";
414 rargs[ranum++] = retries;
415 rargs[ranum++] = "-t";
416 rargs[ranum++] = delay;
418 rargs[ranum++] = friendlyOpt;
421 rargs[ranum++] = "-C";
424 rargs[ranum++] = "-A";
426 rargs[ranum++] = "-e";
427 rargs[ranum++] = NULL; /* will hold the read entry */
429 rargs[ranum++] = NULL;
430 rargs[ranum] = NULL; /* might hold the filter arg */
432 rargs[ranum + 1] = NULL;
435 * generate the modrdn clients
439 snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
441 margs[manum++] = mcmd;
443 margs[manum++] = "-H";
444 margs[manum++] = uri;
446 margs[manum++] = "-h";
447 margs[manum++] = host;
448 margs[manum++] = "-p";
449 margs[manum++] = port;
451 margs[manum++] = "-D";
452 margs[manum++] = manager;
453 margs[manum++] = "-w";
454 margs[manum++] = passwd;
455 margs[manum++] = "-l";
456 margs[manum++] = mloops;
457 margs[manum++] = "-L";
458 margs[manum++] = outerloops;
459 margs[manum++] = "-r";
460 margs[manum++] = retries;
461 margs[manum++] = "-t";
462 margs[manum++] = delay;
464 margs[manum++] = friendlyOpt;
467 margs[manum++] = "-C";
469 margs[manum++] = "-e";
470 margs[manum++] = NULL; /* will hold the modrdn entry */
471 margs[manum++] = NULL;
474 * generate the modify clients
478 snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
480 modargs[modanum++] = modcmd;
482 modargs[modanum++] = "-H";
483 modargs[modanum++] = uri;
485 modargs[modanum++] = "-h";
486 modargs[modanum++] = host;
487 modargs[modanum++] = "-p";
488 modargs[modanum++] = port;
490 modargs[modanum++] = "-D";
491 modargs[modanum++] = manager;
492 modargs[modanum++] = "-w";
493 modargs[modanum++] = passwd;
494 modargs[modanum++] = "-l";
495 modargs[modanum++] = modloops;
496 modargs[modanum++] = "-L";
497 modargs[modanum++] = outerloops;
498 modargs[modanum++] = "-r";
499 modargs[modanum++] = retries;
500 modargs[modanum++] = "-t";
501 modargs[modanum++] = delay;
503 modargs[modanum++] = friendlyOpt;
506 modargs[modanum++] = "-C";
508 modargs[modanum++] = "-e";
509 modargs[modanum++] = NULL; /* will hold the modify entry */
510 modargs[modanum++] = "-a";;
511 modargs[modanum++] = NULL; /* will hold the ava */
512 modargs[modanum++] = NULL;
515 * generate the add/delete clients
519 snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
521 aargs[aanum++] = acmd;
523 aargs[aanum++] = "-H";
524 aargs[aanum++] = uri;
526 aargs[aanum++] = "-h";
527 aargs[aanum++] = host;
528 aargs[aanum++] = "-p";
529 aargs[aanum++] = port;
531 aargs[aanum++] = "-D";
532 aargs[aanum++] = manager;
533 aargs[aanum++] = "-w";
534 aargs[aanum++] = passwd;
535 aargs[aanum++] = "-l";
536 aargs[aanum++] = aloops;
537 aargs[aanum++] = "-L";
538 aargs[aanum++] = outerloops;
539 aargs[aanum++] = "-r";
540 aargs[aanum++] = retries;
541 aargs[aanum++] = "-t";
542 aargs[aanum++] = delay;
544 aargs[aanum++] = friendlyOpt;
547 aargs[aanum++] = "-C";
549 aargs[aanum++] = "-f";
550 aargs[aanum++] = NULL; /* will hold the add data file */
551 aargs[aanum++] = NULL;
554 * generate the bind clients
558 snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
560 bargs[banum++] = bcmd;
561 bargs[banum++] = "-I"; /* don't init on each bind */
563 bargs[banum++] = "-H";
564 bargs[banum++] = uri;
566 bargs[banum++] = "-h";
567 bargs[banum++] = host;
568 bargs[banum++] = "-p";
569 bargs[banum++] = port;
571 bargs[banum++] = "-l";
572 bargs[banum++] = bloops;
573 bargs[banum++] = "-L";
574 bargs[banum++] = outerloops;
576 bargs[banum++] = "-r";
577 bargs[banum++] = retries;
578 bargs[banum++] = "-t";
579 bargs[banum++] = delay;
582 bargs[banum++] = friendlyOpt;
585 bargs[banum++] = "-C";
587 bargs[banum++] = "-D";
588 bargs[banum++] = NULL;
589 bargs[banum++] = "-w";
590 bargs[banum++] = NULL;
591 bargs[banum++] = NULL;
593 #define DOREQ(n,j) ((n) && ((maxkids > (n)) ? ((j) < maxkids ) : ((j) < (n))))
595 for ( j = 0; j < MAXREQS; j++ ) {
596 if ( DOREQ( snum, j ) ) {
599 sargs[sanum - 2] = sreqs[jj];
600 sargs[sanum - 4] = sbase[jj];
601 if ( sattrs[jj] != NULL ) {
602 sargs[sanum - 1] = "-a";
603 sargs[sanum] = sattrs[jj];
606 sargs[sanum - 1] = NULL;
608 fork_child( scmd, sargs );
611 if ( DOREQ( rnum, j ) ) {
614 rargs[ranum - 2] = rreqs[jj];
615 if ( rflts[jj] != NULL ) {
616 rargs[ranum - 1] = "-f";
617 rargs[ranum] = rflts[jj];
620 rargs[ranum - 1] = NULL;
622 fork_child( rcmd, rargs );
626 margs[manum - 2] = mreqs[j];
627 fork_child( mcmd, margs );
631 modargs[modanum - 4] = moddn[j];
632 modargs[modanum - 2] = modreqs[j];
633 fork_child( modcmd, modargs );
637 aargs[aanum - 2] = afiles[j];
638 fork_child( acmd, aargs );
641 if ( DOREQ( bnum, j ) ) {
644 bargs[banum - 4] = breqs[jj];
645 bargs[banum - 2] = bcreds[jj];
646 if ( battrs[jj] != NULL ) {
647 bargs[banum - 1] = "-a";
648 bargs[banum] = battrs[jj];
651 sargs[sanum - 1] = NULL;
653 fork_child( bcmd, bargs );
659 exit( EXIT_SUCCESS );
663 get_file_name( char *dirname, char *filename )
665 char buf[MAXPATHLEN];
667 snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
669 return( strdup( buf ));
674 get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[] )
679 if ( (fp = fopen( filename, "r" )) != NULL ) {
682 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
685 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
687 bases[filter] = ArgDup( line );
688 fgets( line, BUFSIZ, fp );
689 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
692 filters[filter] = ArgDup( line );
694 if ( filters[filter][0] == '+') {
695 char *sep = strchr( filters[filter], ':' );
698 attrs[ filter ] = &filters[ filter ][ 1 ];
700 /* NOTE: don't free this! */
701 filters[ filter ] = &sep[ 1 ];
705 attrs[ filter] = NULL;
719 get_read_entries( char *filename, char *entries[], char *filters[] )
724 if ( (fp = fopen( filename, "r" )) != NULL ) {
727 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
730 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
732 if ( filters != NULL && line[0] == '+' ) {
735 if ( ldap_url_parse( &line[1], &lud ) != LDAP_URL_SUCCESS ) {
740 if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
741 ldap_free_urldesc( lud );
746 entries[entry] = ArgDup( lud->lud_dn );
748 if ( lud->lud_filter ) {
749 filters[entry] = ArgDup( lud->lud_filter );
752 filters[entry] = ArgDup( "(objectClass=*)" );
754 ldap_free_urldesc( lud );
757 entries[entry] = ArgDup( line );
771 fork_child( char *prog, char **args )
775 wait4kids( maxkids );
777 switch ( pid = fork() ) {
780 /* The __LIBASCII execvp only handles ASCII "prog",
781 * we still need to translate the arg vec ourselves.
783 { char *arg2[MAXREQS];
786 for (i=0; args[i]; i++) {
787 arg2[i] = ArgDup(args[i]);
793 execvp( prog, args );
794 tester_perror( "execvp", NULL );
795 exit( EXIT_FAILURE );
798 case -1: /* trouble */
799 tester_perror( "fork", NULL );
802 default: /* parent */
809 wait4kids( int nkidval )
813 while ( nkids >= nkidval ) {
816 if ( WIFSTOPPED(status) ) {
818 "stopping: child stopped with signal %d\n",
819 (int) WSTOPSIG(status) );
821 } else if ( WIFSIGNALED(status) ) {
823 "stopping: child terminated with signal %d%s\n",
824 (int) WTERMSIG(status),
826 WCOREDUMP(status) ? ", core dumped" : ""
831 exit( WEXITSTATUS(status) );
833 } else if ( WEXITSTATUS(status) != 0 ) {
835 "stopping: child exited with status %d\n",
836 (int) WEXITSTATUS(status) );
837 exit( WEXITSTATUS(status) );
847 wait4kids( int nkidval )
851 while ( nkids >= nkidval ) {
852 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
853 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
854 children[i] = children[i+1];
860 fork_child( char *prog, char **args )
864 wait4kids( maxkids );
866 rc = _spawnvp( _P_NOWAIT, prog, args );
869 tester_perror( "_spawnvp", NULL );
871 children[nkids++] = (HANDLE)rc;