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[] );
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;
119 char *sreqs[MAXREQS];
120 char *sattrs[MAXREQS];
121 char *sbase[MAXREQS];
123 char *sargs[MAXARGS];
125 char scmd[MAXPATHLEN];
126 char sloops[] = "18446744073709551615UL";
129 char *rreqs[MAXREQS];
131 char *rargs[MAXARGS];
133 char rcmd[MAXPATHLEN];
134 char rloops[] = "18446744073709551615UL";
136 char *afiles[MAXREQS];
138 char *aargs[MAXARGS];
140 char acmd[MAXPATHLEN];
141 char aloops[] = "18446744073709551615UL";
144 char *mreqs[MAXREQS];
146 char *margs[MAXARGS];
148 char mcmd[MAXPATHLEN];
149 char mloops[] = "18446744073709551615UL";
151 char *modfile = NULL;
152 char *modreqs[MAXREQS];
153 char *moddn[MAXREQS];
155 char *modargs[MAXARGS];
157 char modcmd[MAXPATHLEN];
158 char modloops[] = "18446744073709551615UL";
161 char *breqs[MAXREQS];
162 char *bcreds[MAXREQS];
164 char *bargs[MAXARGS];
166 char bcmd[MAXPATHLEN];
167 char bloops[] = "18446744073709551615UL";
169 char *friendlyOpt = NULL;
171 tester_init( "slapd-tester" );
173 while ( (i = getopt( argc, argv, "CD:d:FH:h:j:l:L:P:p:r:t:w:" )) != EOF ) {
179 case 'D': /* slapd manager */
180 manager = ArgDup( optarg );
183 case 'd': /* data directory */
184 dirname = strdup( optarg );
191 case 'H': /* slapd uri */
192 uri = strdup( optarg );
195 case 'h': /* slapd host */
196 host = strdup( optarg );
199 case 'j': /* the number of parallel clients */
200 if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
205 case 'l': /* the number of loops per client */
206 if ( lutil_atoi( &loops, optarg ) != 0 ) {
211 case 'L': /* the number of outerloops per client */
212 outerloops = strdup( optarg );
215 case 'P': /* prog directory */
216 progdir = strdup( optarg );
219 case 'p': /* the servers port number */
220 port = strdup( optarg );
223 case 'r': /* the number of retries in case of error */
224 retries = strdup( optarg );
227 case 't': /* the delay in seconds between each retry */
228 delay = strdup( optarg );
231 case 'w': /* the managers passwd */
232 passwd = ArgDup( optarg );
241 if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
242 ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
246 children = malloc( maxkids * sizeof(HANDLE) );
248 /* get the file list */
249 if ( ( datadir = opendir( dirname )) == NULL ) {
251 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
253 exit( EXIT_FAILURE );
257 /* look for search, read, modrdn, and add/delete files */
258 for ( file = readdir( datadir ); file; file = readdir( datadir )) {
260 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
261 sfile = get_file_name( dirname, file->d_name );
263 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
264 rfile = get_file_name( dirname, file->d_name );
266 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
267 mfile = get_file_name( dirname, file->d_name );
269 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
270 modfile = get_file_name( dirname, file->d_name );
272 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
273 && ( anum < MAXREQS )) {
274 afiles[anum++] = get_file_name( dirname, file->d_name );
276 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
277 bfile = get_file_name( dirname, file->d_name );
284 /* look for search requests */
286 snum = get_search_filters( sfile, sreqs, sattrs, sbase );
289 /* look for read requests */
291 rnum = get_read_entries( rfile, rreqs );
294 /* look for modrdn requests */
296 mnum = get_read_entries( mfile, mreqs );
299 /* look for modify requests */
301 modnum = get_search_filters( modfile, modreqs, NULL, moddn );
304 /* look for bind requests */
306 bnum = get_search_filters( bfile, bcreds, NULL, breqs );
309 /* setup friendly option */
311 switch ( friendly ) {
320 /* NOTE: right now we don't need it more than twice */
326 snprintf( sloops, sizeof( sloops ), "%d", 10 * loops );
327 snprintf( rloops, sizeof( rloops ), "%d", 20 * loops );
328 snprintf( aloops, sizeof( aloops ), "%d", loops );
329 snprintf( mloops, sizeof( mloops ), "%d", loops );
330 snprintf( modloops, sizeof( modloops ), "%d", loops );
331 snprintf( bloops, sizeof( bloops ), "%d", 20 * loops );
334 * generate the search clients
338 snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
340 sargs[sanum++] = scmd;
342 sargs[sanum++] = "-H";
343 sargs[sanum++] = uri;
345 sargs[sanum++] = "-h";
346 sargs[sanum++] = host;
347 sargs[sanum++] = "-p";
348 sargs[sanum++] = port;
350 sargs[sanum++] = "-D";
351 sargs[sanum++] = manager;
352 sargs[sanum++] = "-w";
353 sargs[sanum++] = passwd;
354 sargs[sanum++] = "-l";
355 sargs[sanum++] = sloops;
356 sargs[sanum++] = "-L";
357 sargs[sanum++] = outerloops;
358 sargs[sanum++] = "-r";
359 sargs[sanum++] = retries;
360 sargs[sanum++] = "-t";
361 sargs[sanum++] = delay;
363 sargs[sanum++] = friendlyOpt;
366 sargs[sanum++] = "-C";
368 sargs[sanum++] = "-b";
369 sargs[sanum++] = NULL; /* will hold the search base */
370 sargs[sanum++] = "-f";
371 sargs[sanum++] = NULL; /* will hold the search request */
373 sargs[sanum++] = NULL;
374 sargs[sanum] = NULL; /* might hold the "attr" request */
376 sargs[sanum + 1] = NULL;
379 * generate the read clients
383 snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
385 rargs[ranum++] = rcmd;
387 rargs[ranum++] = "-H";
388 rargs[ranum++] = uri;
390 rargs[ranum++] = "-h";
391 rargs[ranum++] = host;
392 rargs[ranum++] = "-p";
393 rargs[ranum++] = port;
395 rargs[ranum++] = "-l";
396 rargs[ranum++] = rloops;
397 rargs[ranum++] = "-L";
398 rargs[ranum++] = outerloops;
399 rargs[ranum++] = "-r";
400 rargs[ranum++] = retries;
401 rargs[ranum++] = "-t";
402 rargs[ranum++] = delay;
404 rargs[ranum++] = friendlyOpt;
407 rargs[ranum++] = "-C";
409 rargs[ranum++] = "-e";
410 rargs[ranum++] = NULL; /* will hold the read entry */
411 rargs[ranum++] = NULL;
414 * generate the modrdn clients
418 snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
420 margs[manum++] = mcmd;
422 margs[manum++] = "-H";
423 margs[manum++] = uri;
425 margs[manum++] = "-h";
426 margs[manum++] = host;
427 margs[manum++] = "-p";
428 margs[manum++] = port;
430 margs[manum++] = "-D";
431 margs[manum++] = manager;
432 margs[manum++] = "-w";
433 margs[manum++] = passwd;
434 margs[manum++] = "-l";
435 margs[manum++] = mloops;
436 margs[manum++] = "-L";
437 margs[manum++] = outerloops;
438 margs[manum++] = "-r";
439 margs[manum++] = retries;
440 margs[manum++] = "-t";
441 margs[manum++] = delay;
443 margs[manum++] = friendlyOpt;
446 margs[manum++] = "-C";
448 margs[manum++] = "-e";
449 margs[manum++] = NULL; /* will hold the modrdn entry */
450 margs[manum++] = NULL;
453 * generate the modify clients
457 snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
459 modargs[modanum++] = modcmd;
461 modargs[modanum++] = "-H";
462 modargs[modanum++] = uri;
464 modargs[modanum++] = "-h";
465 modargs[modanum++] = host;
466 modargs[modanum++] = "-p";
467 modargs[modanum++] = port;
469 modargs[modanum++] = "-D";
470 modargs[modanum++] = manager;
471 modargs[modanum++] = "-w";
472 modargs[modanum++] = passwd;
473 modargs[modanum++] = "-l";
474 modargs[modanum++] = modloops;
475 modargs[modanum++] = "-L";
476 modargs[modanum++] = outerloops;
477 modargs[modanum++] = "-r";
478 modargs[modanum++] = retries;
479 modargs[modanum++] = "-t";
480 modargs[modanum++] = delay;
482 modargs[modanum++] = friendlyOpt;
485 modargs[modanum++] = "-C";
487 modargs[modanum++] = "-e";
488 modargs[modanum++] = NULL; /* will hold the modify entry */
489 modargs[modanum++] = "-a";;
490 modargs[modanum++] = NULL; /* will hold the ava */
491 modargs[modanum++] = NULL;
494 * generate the add/delete clients
498 snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
500 aargs[aanum++] = acmd;
502 aargs[aanum++] = "-H";
503 aargs[aanum++] = uri;
505 aargs[aanum++] = "-h";
506 aargs[aanum++] = host;
507 aargs[aanum++] = "-p";
508 aargs[aanum++] = port;
510 aargs[aanum++] = "-D";
511 aargs[aanum++] = manager;
512 aargs[aanum++] = "-w";
513 aargs[aanum++] = passwd;
514 aargs[aanum++] = "-l";
515 aargs[aanum++] = aloops;
516 aargs[aanum++] = "-L";
517 aargs[aanum++] = outerloops;
518 aargs[aanum++] = "-r";
519 aargs[aanum++] = retries;
520 aargs[aanum++] = "-t";
521 aargs[aanum++] = delay;
523 aargs[aanum++] = friendlyOpt;
526 aargs[aanum++] = "-C";
528 aargs[aanum++] = "-f";
529 aargs[aanum++] = NULL; /* will hold the add data file */
530 aargs[aanum++] = NULL;
533 * generate the bind clients
537 snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
539 bargs[banum++] = bcmd;
541 bargs[banum++] = "-H";
542 bargs[banum++] = uri;
544 bargs[banum++] = "-h";
545 bargs[banum++] = host;
546 bargs[banum++] = "-p";
547 bargs[banum++] = port;
549 bargs[banum++] = "-l";
550 bargs[banum++] = bloops;
551 bargs[banum++] = "-L";
552 bargs[banum++] = outerloops;
554 bargs[banum++] = "-r";
555 bargs[banum++] = retries;
556 bargs[banum++] = "-t";
557 bargs[banum++] = delay;
560 bargs[banum++] = friendlyOpt;
563 bargs[banum++] = "-C";
565 bargs[banum++] = "-D";
566 bargs[banum++] = NULL;
567 bargs[banum++] = "-w";
568 bargs[banum++] = NULL;
569 bargs[banum++] = NULL;
571 for ( j = 0; j < MAXREQS; j++ ) {
574 sargs[sanum - 2] = sreqs[j];
575 sargs[sanum - 4] = sbase[j];
576 if ( sattrs[j] != NULL ) {
577 sargs[sanum - 1] = "-a";
578 sargs[sanum] = sattrs[j];
581 sargs[sanum - 1] = NULL;
583 fork_child( scmd, sargs );
589 rargs[ranum - 2] = rreqs[j];
590 fork_child( rcmd, rargs );
596 margs[manum - 2] = mreqs[j];
597 fork_child( mcmd, margs );
602 modargs[modanum - 4] = moddn[j];
603 modargs[modanum - 2] = modreqs[j];
604 fork_child( modcmd, modargs );
610 aargs[aanum - 2] = afiles[j];
611 fork_child( acmd, aargs );
617 bargs[banum - 4] = breqs[j];
618 bargs[banum - 2] = bcreds[j];
619 fork_child( bcmd, bargs );
627 exit( EXIT_SUCCESS );
631 get_file_name( char *dirname, char *filename )
633 char buf[MAXPATHLEN];
635 snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
637 return( strdup( buf ));
642 get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[] )
647 if ( (fp = fopen( filename, "r" )) != NULL ) {
650 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
653 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
655 bases[filter] = ArgDup( line );
656 fgets( line, BUFSIZ, fp );
657 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
660 filters[filter] = ArgDup( line );
662 if ( filters[filter][0] == '+') {
663 char *sep = strchr( filters[filter], ':' );
666 attrs[ filter ] = &filters[ filter ][ 1 ];
668 /* NOTE: don't free this! */
669 filters[ filter ] = &sep[ 1 ];
673 attrs[ filter] = NULL;
687 get_read_entries( char *filename, char *entries[] )
692 if ( (fp = fopen( filename, "r" )) != NULL ) {
695 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
698 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
700 entries[entry++] = ArgDup( line );
711 fork_child( char *prog, char **args )
715 wait4kids( maxkids );
717 switch ( pid = fork() ) {
720 /* The __LIBASCII execvp only handles ASCII "prog",
721 * we still need to translate the arg vec ourselves.
723 { char *arg2[MAXREQS];
726 for (i=0; args[i]; i++) {
727 arg2[i] = ArgDup(args[i]);
733 execvp( prog, args );
734 tester_perror( "execvp" );
735 exit( EXIT_FAILURE );
738 case -1: /* trouble */
739 tester_perror( "fork" );
742 default: /* parent */
749 wait4kids( int nkidval )
753 while ( nkids >= nkidval ) {
756 if ( WIFSTOPPED(status) ) {
758 "stopping: child stopped with signal %d\n",
759 (int) WSTOPSIG(status) );
761 } else if ( WIFSIGNALED(status) ) {
763 "stopping: child terminated with signal %d%s\n",
764 (int) WTERMSIG(status),
766 WCOREDUMP(status) ? ", core dumped" : ""
771 exit( WEXITSTATUS(status) );
773 } else if ( WEXITSTATUS(status) != 0 ) {
775 "stopping: child exited with status %d\n",
776 (int) WEXITSTATUS(status) );
777 exit( WEXITSTATUS(status) );
787 wait4kids( int nkidval )
791 while ( nkids >= nkidval ) {
792 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
793 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
794 children[i] = children[i+1];
800 fork_child( char *prog, char **args )
804 wait4kids( maxkids );
806 rc = _spawnvp( _P_NOWAIT, prog, args );
809 tester_perror( "_spawnvp" );
811 children[nkids++] = (HANDLE)rc;