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>) "
100 main( int argc, char **argv )
104 char *host = "localhost";
106 char *manager = NULL;
108 char *dirname = NULL;
109 char *progdir = NULL;
111 char *outerloops = OUTERLOOPS;
112 char *retries = RETRIES;
122 char *sreqs[MAXREQS];
123 char *sattrs[MAXREQS];
124 char *sbase[MAXREQS];
126 char *sargs[MAXARGS];
128 char scmd[MAXPATHLEN];
129 char sloops[] = "18446744073709551615UL";
132 char *rreqs[MAXREQS];
134 char *rargs[MAXARGS];
135 char *rflts[MAXREQS];
137 char rcmd[MAXPATHLEN];
138 char rloops[] = "18446744073709551615UL";
140 char *afiles[MAXREQS];
142 char *aargs[MAXARGS];
144 char acmd[MAXPATHLEN];
145 char aloops[] = "18446744073709551615UL";
148 char *mreqs[MAXREQS];
150 char *margs[MAXARGS];
152 char mcmd[MAXPATHLEN];
153 char mloops[] = "18446744073709551615UL";
155 char *modfile = NULL;
156 char *modreqs[MAXREQS];
157 char *moddn[MAXREQS];
159 char *modargs[MAXARGS];
161 char modcmd[MAXPATHLEN];
162 char modloops[] = "18446744073709551615UL";
165 char *breqs[MAXREQS];
166 char *bcreds[MAXREQS];
167 char *battrs[MAXREQS];
169 char *bargs[MAXARGS];
171 char bcmd[MAXPATHLEN];
172 char bloops[] = "18446744073709551615UL";
174 char *friendlyOpt = NULL;
176 char *pw_file = NULL;
178 tester_init( "slapd-tester", TESTER_TESTER );
180 while ( (i = getopt( argc, argv, "ACD:d:FH:h:i:j:l:L:P:p:r:t:w:Wy:" )) != EOF ) {
190 case 'D': /* slapd manager */
191 manager = ArgDup( optarg );
194 case 'd': /* data directory */
195 dirname = strdup( optarg );
202 case 'H': /* slapd uri */
203 uri = strdup( optarg );
206 case 'h': /* slapd host */
207 host = strdup( optarg );
214 case 'j': /* the number of parallel clients */
215 if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
220 case 'l': /* the number of loops per client */
221 if ( lutil_atoi( &loops, optarg ) != 0 ) {
226 case 'L': /* the number of outerloops per client */
227 outerloops = strdup( optarg );
230 case 'P': /* prog directory */
231 progdir = strdup( optarg );
234 case 'p': /* the servers port number */
235 port = strdup( optarg );
238 case 'r': /* the number of retries in case of error */
239 retries = strdup( optarg );
242 case 't': /* the delay in seconds between each retry */
243 delay = strdup( optarg );
246 case 'w': /* the managers passwd */
247 passwd = ArgDup( optarg );
248 memset( optarg, '*', strlen( optarg ) );
265 if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
266 ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
270 children = malloc( maxkids * sizeof(HANDLE) );
272 /* get the file list */
273 if ( ( datadir = opendir( dirname )) == NULL ) {
274 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
276 exit( EXIT_FAILURE );
279 /* look for search, read, modrdn, and add/delete files */
280 for ( file = readdir( datadir ); file; file = readdir( datadir )) {
282 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
283 sfile = get_file_name( dirname, file->d_name );
285 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
286 rfile = get_file_name( dirname, file->d_name );
288 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
289 mfile = get_file_name( dirname, file->d_name );
291 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
292 modfile = get_file_name( dirname, file->d_name );
294 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
295 && ( anum < MAXREQS )) {
296 afiles[anum++] = get_file_name( dirname, file->d_name );
298 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
299 bfile = get_file_name( dirname, file->d_name );
307 passwd = getpassphrase( _("Enter LDAP Password: ") );
309 } else if ( pw_file ) {
312 if ( lutil_get_filed_password( pw_file, &pw ) ) {
313 exit( EXIT_FAILURE );
319 /* look for search requests */
321 snum = get_search_filters( sfile, sreqs, sattrs, sbase );
324 /* look for read requests */
326 rnum = get_read_entries( rfile, rreqs, rflts );
329 /* look for modrdn requests */
331 mnum = get_read_entries( mfile, mreqs, NULL );
334 /* look for modify requests */
336 modnum = get_search_filters( modfile, modreqs, NULL, moddn );
339 /* look for bind requests */
341 bnum = get_search_filters( bfile, bcreds, battrs, breqs );
344 /* setup friendly option */
346 switch ( friendly ) {
355 /* NOTE: right now we don't need it more than twice */
361 snprintf( sloops, sizeof( sloops ), "%d", 10 * loops );
362 snprintf( rloops, sizeof( rloops ), "%d", 20 * loops );
363 snprintf( aloops, sizeof( aloops ), "%d", loops );
364 snprintf( mloops, sizeof( mloops ), "%d", loops );
365 snprintf( modloops, sizeof( modloops ), "%d", loops );
366 snprintf( bloops, sizeof( bloops ), "%d", 20 * loops );
369 * generate the search clients
373 snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
375 sargs[sanum++] = scmd;
377 sargs[sanum++] = "-H";
378 sargs[sanum++] = uri;
380 sargs[sanum++] = "-h";
381 sargs[sanum++] = host;
382 sargs[sanum++] = "-p";
383 sargs[sanum++] = port;
385 sargs[sanum++] = "-D";
386 sargs[sanum++] = manager;
387 sargs[sanum++] = "-w";
388 sargs[sanum++] = passwd;
389 sargs[sanum++] = "-l";
390 sargs[sanum++] = sloops;
391 sargs[sanum++] = "-L";
392 sargs[sanum++] = outerloops;
393 sargs[sanum++] = "-r";
394 sargs[sanum++] = retries;
395 sargs[sanum++] = "-t";
396 sargs[sanum++] = delay;
398 sargs[sanum++] = friendlyOpt;
401 sargs[sanum++] = "-C";
404 sargs[sanum++] = "-A";
407 sargs[sanum++] = "-i";
408 sargs[sanum++] = ignore;
410 sargs[sanum++] = "-b";
411 sargs[sanum++] = NULL; /* will hold the search base */
412 sargs[sanum++] = "-f";
413 sargs[sanum++] = NULL; /* will hold the search request */
415 sargs[sanum++] = NULL;
416 sargs[sanum] = NULL; /* might hold the "attr" request */
418 sargs[sanum + 1] = NULL;
421 * generate the read clients
425 snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
427 rargs[ranum++] = rcmd;
429 rargs[ranum++] = "-H";
430 rargs[ranum++] = uri;
432 rargs[ranum++] = "-h";
433 rargs[ranum++] = host;
434 rargs[ranum++] = "-p";
435 rargs[ranum++] = port;
437 rargs[ranum++] = "-D";
438 rargs[ranum++] = manager;
439 rargs[ranum++] = "-w";
440 rargs[ranum++] = passwd;
441 rargs[ranum++] = "-l";
442 rargs[ranum++] = rloops;
443 rargs[ranum++] = "-L";
444 rargs[ranum++] = outerloops;
445 rargs[ranum++] = "-r";
446 rargs[ranum++] = retries;
447 rargs[ranum++] = "-t";
448 rargs[ranum++] = delay;
450 rargs[ranum++] = friendlyOpt;
453 rargs[ranum++] = "-C";
456 rargs[ranum++] = "-A";
459 rargs[ranum++] = "-i";
460 rargs[ranum++] = ignore;
462 rargs[ranum++] = "-e";
463 rargs[ranum++] = NULL; /* will hold the read entry */
465 rargs[ranum++] = NULL;
466 rargs[ranum] = NULL; /* might hold the filter arg */
468 rargs[ranum + 1] = NULL;
471 * generate the modrdn clients
475 snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
477 margs[manum++] = mcmd;
479 margs[manum++] = "-H";
480 margs[manum++] = uri;
482 margs[manum++] = "-h";
483 margs[manum++] = host;
484 margs[manum++] = "-p";
485 margs[manum++] = port;
487 margs[manum++] = "-D";
488 margs[manum++] = manager;
489 margs[manum++] = "-w";
490 margs[manum++] = passwd;
491 margs[manum++] = "-l";
492 margs[manum++] = mloops;
493 margs[manum++] = "-L";
494 margs[manum++] = outerloops;
495 margs[manum++] = "-r";
496 margs[manum++] = retries;
497 margs[manum++] = "-t";
498 margs[manum++] = delay;
500 margs[manum++] = friendlyOpt;
503 margs[manum++] = "-C";
506 margs[manum++] = "-i";
507 margs[manum++] = ignore;
509 margs[manum++] = "-e";
510 margs[manum++] = NULL; /* will hold the modrdn entry */
511 margs[manum++] = NULL;
514 * generate the modify clients
518 snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
520 modargs[modanum++] = modcmd;
522 modargs[modanum++] = "-H";
523 modargs[modanum++] = uri;
525 modargs[modanum++] = "-h";
526 modargs[modanum++] = host;
527 modargs[modanum++] = "-p";
528 modargs[modanum++] = port;
530 modargs[modanum++] = "-D";
531 modargs[modanum++] = manager;
532 modargs[modanum++] = "-w";
533 modargs[modanum++] = passwd;
534 modargs[modanum++] = "-l";
535 modargs[modanum++] = modloops;
536 modargs[modanum++] = "-L";
537 modargs[modanum++] = outerloops;
538 modargs[modanum++] = "-r";
539 modargs[modanum++] = retries;
540 modargs[modanum++] = "-t";
541 modargs[modanum++] = delay;
543 modargs[modanum++] = friendlyOpt;
546 modargs[modanum++] = "-C";
549 modargs[modanum++] = "-i";
550 modargs[modanum++] = ignore;
552 modargs[modanum++] = "-e";
553 modargs[modanum++] = NULL; /* will hold the modify entry */
554 modargs[modanum++] = "-a";;
555 modargs[modanum++] = NULL; /* will hold the ava */
556 modargs[modanum++] = NULL;
559 * generate the add/delete clients
563 snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
565 aargs[aanum++] = acmd;
567 aargs[aanum++] = "-H";
568 aargs[aanum++] = uri;
570 aargs[aanum++] = "-h";
571 aargs[aanum++] = host;
572 aargs[aanum++] = "-p";
573 aargs[aanum++] = port;
575 aargs[aanum++] = "-D";
576 aargs[aanum++] = manager;
577 aargs[aanum++] = "-w";
578 aargs[aanum++] = passwd;
579 aargs[aanum++] = "-l";
580 aargs[aanum++] = aloops;
581 aargs[aanum++] = "-L";
582 aargs[aanum++] = outerloops;
583 aargs[aanum++] = "-r";
584 aargs[aanum++] = retries;
585 aargs[aanum++] = "-t";
586 aargs[aanum++] = delay;
588 aargs[aanum++] = friendlyOpt;
591 aargs[aanum++] = "-C";
594 aargs[aanum++] = "-i";
595 aargs[aanum++] = ignore;
597 aargs[aanum++] = "-f";
598 aargs[aanum++] = NULL; /* will hold the add data file */
599 aargs[aanum++] = NULL;
602 * generate the bind clients
606 snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
608 bargs[banum++] = bcmd;
609 bargs[banum++] = "-I"; /* don't init on each bind */
611 bargs[banum++] = "-H";
612 bargs[banum++] = uri;
614 bargs[banum++] = "-h";
615 bargs[banum++] = host;
616 bargs[banum++] = "-p";
617 bargs[banum++] = port;
619 bargs[banum++] = "-l";
620 bargs[banum++] = bloops;
621 bargs[banum++] = "-L";
622 bargs[banum++] = outerloops;
624 bargs[banum++] = "-r";
625 bargs[banum++] = retries;
626 bargs[banum++] = "-t";
627 bargs[banum++] = delay;
630 bargs[banum++] = friendlyOpt;
633 bargs[banum++] = "-C";
636 bargs[banum++] = "-i";
637 bargs[banum++] = ignore;
639 bargs[banum++] = "-D";
640 bargs[banum++] = NULL;
641 bargs[banum++] = "-w";
642 bargs[banum++] = NULL;
643 bargs[banum++] = NULL;
645 #define DOREQ(n,j) ((n) && ((maxkids > (n)) ? ((j) < maxkids ) : ((j) < (n))))
647 for ( j = 0; j < MAXREQS; j++ ) {
648 if ( DOREQ( snum, j ) ) {
651 sargs[sanum - 2] = sreqs[jj];
652 sargs[sanum - 4] = sbase[jj];
653 if ( sattrs[jj] != NULL ) {
654 sargs[sanum - 1] = "-a";
655 sargs[sanum] = sattrs[jj];
658 sargs[sanum - 1] = NULL;
660 fork_child( scmd, sargs );
663 if ( DOREQ( rnum, j ) ) {
666 rargs[ranum - 2] = rreqs[jj];
667 if ( rflts[jj] != NULL ) {
668 rargs[ranum - 1] = "-f";
669 rargs[ranum] = rflts[jj];
672 rargs[ranum - 1] = NULL;
674 fork_child( rcmd, rargs );
678 margs[manum - 2] = mreqs[j];
679 fork_child( mcmd, margs );
683 modargs[modanum - 4] = moddn[j];
684 modargs[modanum - 2] = modreqs[j];
685 fork_child( modcmd, modargs );
689 aargs[aanum - 2] = afiles[j];
690 fork_child( acmd, aargs );
693 if ( DOREQ( bnum, j ) ) {
696 if ( battrs[jj] != NULL ) {
697 bargs[banum - 4] = manager ? manager : "";
698 bargs[banum - 2] = passwd ? passwd : "";
700 bargs[banum - 1] = "-b";
701 bargs[banum] = breqs[jj];
702 bargs[banum + 1] = "-f";
703 bargs[banum + 2] = bcreds[jj];
704 bargs[banum + 3] = "-a";
705 bargs[banum + 4] = battrs[jj];
707 bargs[banum - 4] = breqs[jj];
708 bargs[banum - 2] = bcreds[jj];
709 bargs[banum - 1] = NULL;
712 fork_child( bcmd, bargs );
713 bargs[banum - 1] = NULL;
719 exit( EXIT_SUCCESS );
723 get_file_name( char *dirname, char *filename )
725 char buf[MAXPATHLEN];
727 snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
729 return( strdup( buf ));
734 get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[] )
739 if ( (fp = fopen( filename, "r" )) != NULL ) {
742 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
745 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
747 bases[filter] = ArgDup( line );
748 fgets( line, BUFSIZ, fp );
749 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
752 filters[filter] = ArgDup( line );
754 if ( filters[filter][0] == '+') {
755 char *sep = strchr( filters[filter], ':' );
758 attrs[ filter ] = &filters[ filter ][ 1 ];
760 /* NOTE: don't free this! */
761 filters[ filter ] = &sep[ 1 ];
765 attrs[ filter] = NULL;
779 get_read_entries( char *filename, char *entries[], char *filters[] )
784 if ( (fp = fopen( filename, "r" )) != NULL ) {
787 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
790 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
792 if ( filters != NULL && line[0] == '+' ) {
795 if ( ldap_url_parse( &line[1], &lud ) != LDAP_URL_SUCCESS ) {
800 if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
801 ldap_free_urldesc( lud );
806 entries[entry] = ArgDup( lud->lud_dn );
808 if ( lud->lud_filter ) {
809 filters[entry] = ArgDup( lud->lud_filter );
812 filters[entry] = ArgDup( "(objectClass=*)" );
814 ldap_free_urldesc( lud );
817 entries[entry] = ArgDup( line );
831 fork_child( char *prog, char **args )
835 wait4kids( maxkids );
837 switch ( pid = fork() ) {
840 /* The __LIBASCII execvp only handles ASCII "prog",
841 * we still need to translate the arg vec ourselves.
843 { char *arg2[MAXREQS];
846 for (i=0; args[i]; i++) {
847 arg2[i] = ArgDup(args[i]);
853 execvp( prog, args );
854 tester_perror( "execvp", NULL );
855 exit( EXIT_FAILURE );
858 case -1: /* trouble */
859 tester_perror( "fork", NULL );
862 default: /* parent */
869 wait4kids( int nkidval )
873 while ( nkids >= nkidval ) {
876 if ( WIFSTOPPED(status) ) {
878 "stopping: child stopped with signal %d\n",
879 (int) WSTOPSIG(status) );
881 } else if ( WIFSIGNALED(status) ) {
883 "stopping: child terminated with signal %d%s\n",
884 (int) WTERMSIG(status),
886 WCOREDUMP(status) ? ", core dumped" : ""
891 exit( WEXITSTATUS(status) );
893 } else if ( WEXITSTATUS(status) != 0 ) {
895 "stopping: child exited with status %d\n",
896 (int) WEXITSTATUS(status) );
897 exit( WEXITSTATUS(status) );
907 wait4kids( int nkidval )
911 while ( nkids >= nkidval ) {
912 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
913 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
914 children[i] = children[i+1];
920 fork_child( char *prog, char **args )
924 wait4kids( maxkids );
926 rc = _spawnvp( _P_NOWAIT, prog, args );
929 tester_perror( "_spawnvp", NULL );
931 children[nkids++] = (HANDLE)rc;