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"
52 #define TSEARCHFILE "do_search.0"
53 #define TREADFILE "do_read.0"
54 #define TADDFILE "do_add."
55 #define TMODRDNFILE "do_modrdn.0"
56 #define TMODIFYFILE "do_modify.0"
57 #define TBINDFILE "do_bind.0"
59 static char *get_file_name( char *dirname, char *filename );
60 static int get_search_filters( char *filename, char *filters[], char *bases[] );
61 static int get_read_entries( char *filename, char *entries[] );
62 static void fork_child( char *prog, char **args );
63 static void wait4kids( int nkidval );
65 static int maxkids = 20;
69 static HANDLE *children;
70 static char argbuf[BUFSIZ];
71 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
73 #define ArgDup(x) strdup(x)
81 "-H <uri> | ([-h <host>] -p <port>) "
96 main( int argc, char **argv )
100 char *host = "localhost";
102 char *manager = NULL;
104 char *dirname = NULL;
105 char *progdir = NULL;
107 char *retries = RETRIES;
114 char *sreqs[MAXREQS];
115 char *sbase[MAXREQS];
117 char *sargs[MAXARGS];
119 char scmd[MAXPATHLEN];
122 char *rreqs[MAXREQS];
124 char *rargs[MAXARGS];
126 char rcmd[MAXPATHLEN];
128 char *afiles[MAXREQS];
130 char *aargs[MAXARGS];
132 char acmd[MAXPATHLEN];
135 char *mreqs[MAXREQS];
137 char *margs[MAXARGS];
139 char mcmd[MAXPATHLEN];
141 char *modfile = NULL;
142 char *modreqs[MAXREQS];
143 char *moddn[MAXREQS];
145 char *modargs[MAXARGS];
147 char modcmd[MAXPATHLEN];
150 char *breqs[MAXREQS];
151 char *bcreds[MAXREQS];
153 char *bargs[MAXARGS];
155 char bcmd[MAXPATHLEN];
157 char *friendlyOpt = NULL;
159 tester_init( "slapd-tester" );
161 while ( (i = getopt( argc, argv, "D:d:FH:h:j:l:P:p:r:t:w:" )) != EOF ) {
163 case 'D': /* slapd manager */
164 manager = ArgDup( optarg );
167 case 'd': /* data directory */
168 dirname = strdup( optarg );
175 case 'H': /* slapd uri */
176 uri = strdup( optarg );
179 case 'h': /* slapd host */
180 host = strdup( optarg );
183 case 'j': /* the number of parallel clients */
184 if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
189 case 'l': /* the number of loops per client */
190 loops = strdup( optarg );
193 case 'P': /* prog directory */
194 progdir = strdup( optarg );
197 case 'p': /* the servers port number */
198 port = strdup( optarg );
201 case 'r': /* the number of retries in case of error */
202 retries = strdup( optarg );
205 case 't': /* the delay in seconds between each retry */
206 delay = strdup( optarg );
209 case 'w': /* the managers passwd */
210 passwd = ArgDup( optarg );
219 if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
220 ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
224 children = malloc( maxkids * sizeof(HANDLE) );
226 /* get the file list */
227 if ( ( datadir = opendir( dirname )) == NULL ) {
229 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
231 exit( EXIT_FAILURE );
235 /* look for search, read, modrdn, and add/delete files */
236 for ( file = readdir( datadir ); file; file = readdir( datadir )) {
238 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
239 sfile = get_file_name( dirname, file->d_name );
241 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
242 rfile = get_file_name( dirname, file->d_name );
244 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
245 mfile = get_file_name( dirname, file->d_name );
247 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
248 modfile = get_file_name( dirname, file->d_name );
250 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
251 && ( anum < MAXREQS )) {
252 afiles[anum++] = get_file_name( dirname, file->d_name );
254 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
255 bfile = get_file_name( dirname, file->d_name );
262 /* look for search requests */
264 snum = get_search_filters( sfile, sreqs, sbase );
267 /* look for read requests */
269 rnum = get_read_entries( rfile, rreqs );
272 /* look for modrdn requests */
274 mnum = get_read_entries( mfile, mreqs );
277 /* look for modify requests */
279 modnum = get_search_filters( modfile, modreqs, moddn );
282 /* look for bind requests */
284 bnum = get_search_filters( bfile, bcreds, breqs );
287 /* setup friendly option */
289 switch ( friendly ) {
298 /* NOTE: right now we don't need it more than twice */
305 * generate the search clients
309 snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
311 sargs[sanum++] = scmd;
313 sargs[sanum++] = "-H";
314 sargs[sanum++] = uri;
316 sargs[sanum++] = "-h";
317 sargs[sanum++] = host;
318 sargs[sanum++] = "-p";
319 sargs[sanum++] = port;
321 sargs[sanum++] = "-D";
322 sargs[sanum++] = manager;
323 sargs[sanum++] = "-w";
324 sargs[sanum++] = passwd;
325 sargs[sanum++] = "-l";
326 sargs[sanum++] = loops;
327 sargs[sanum++] = "-r";
328 sargs[sanum++] = retries;
329 sargs[sanum++] = "-t";
330 sargs[sanum++] = delay;
331 sargs[sanum++] = "-b";
332 sargs[sanum++] = NULL; /* will hold the search base */
333 sargs[sanum++] = "-f";
334 sargs[sanum++] = NULL; /* will hold the search request */
335 sargs[sanum++] = NULL;
338 * generate the read clients
342 snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
344 rargs[ranum++] = rcmd;
346 rargs[ranum++] = "-H";
347 rargs[ranum++] = uri;
349 rargs[ranum++] = "-h";
350 rargs[ranum++] = host;
351 rargs[ranum++] = "-p";
352 rargs[ranum++] = port;
354 rargs[ranum++] = "-l";
355 rargs[ranum++] = loops;
356 rargs[ranum++] = "-r";
357 rargs[ranum++] = retries;
358 rargs[ranum++] = "-t";
359 rargs[ranum++] = delay;
360 rargs[ranum++] = "-e";
361 rargs[ranum++] = NULL; /* will hold the read entry */
362 rargs[ranum++] = NULL;
365 * generate the modrdn clients
369 snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
371 margs[manum++] = mcmd;
373 margs[manum++] = "-H";
374 margs[manum++] = uri;
376 margs[manum++] = "-h";
377 margs[manum++] = host;
378 margs[manum++] = "-p";
379 margs[manum++] = port;
381 margs[manum++] = "-D";
382 margs[manum++] = manager;
383 margs[manum++] = "-w";
384 margs[manum++] = passwd;
385 margs[manum++] = "-l";
386 margs[manum++] = loops;
387 margs[manum++] = "-r";
388 margs[manum++] = retries;
389 margs[manum++] = "-t";
390 margs[manum++] = delay;
392 margs[manum++] = friendlyOpt;
394 margs[manum++] = "-e";
395 margs[manum++] = NULL; /* will hold the modrdn entry */
396 margs[manum++] = NULL;
399 * generate the modify clients
403 snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
405 modargs[modanum++] = modcmd;
407 modargs[modanum++] = "-H";
408 modargs[modanum++] = uri;
410 modargs[modanum++] = "-h";
411 modargs[modanum++] = host;
412 modargs[modanum++] = "-p";
413 modargs[modanum++] = port;
415 modargs[modanum++] = "-D";
416 modargs[modanum++] = manager;
417 modargs[modanum++] = "-w";
418 modargs[modanum++] = passwd;
419 modargs[modanum++] = "-l";
420 modargs[modanum++] = loops;
421 modargs[modanum++] = "-r";
422 modargs[modanum++] = retries;
423 modargs[modanum++] = "-t";
424 modargs[modanum++] = delay;
426 modargs[modanum++] = friendlyOpt;
428 modargs[modanum++] = "-e";
429 modargs[modanum++] = NULL; /* will hold the modify entry */
430 modargs[modanum++] = "-a";;
431 modargs[modanum++] = NULL; /* will hold the ava */
432 modargs[modanum++] = NULL;
435 * generate the add/delete clients
439 snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
441 aargs[aanum++] = acmd;
443 aargs[aanum++] = "-H";
444 aargs[aanum++] = uri;
446 aargs[aanum++] = "-h";
447 aargs[aanum++] = host;
448 aargs[aanum++] = "-p";
449 aargs[aanum++] = port;
451 aargs[aanum++] = "-D";
452 aargs[aanum++] = manager;
453 aargs[aanum++] = "-w";
454 aargs[aanum++] = passwd;
455 aargs[aanum++] = "-l";
456 aargs[aanum++] = loops;
457 aargs[aanum++] = "-r";
458 aargs[aanum++] = retries;
459 aargs[aanum++] = "-t";
460 aargs[aanum++] = delay;
462 aargs[aanum++] = friendlyOpt;
464 aargs[aanum++] = "-f";
465 aargs[aanum++] = NULL; /* will hold the add data file */
466 aargs[aanum++] = NULL;
469 * generate the bind clients
473 snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
475 bargs[banum++] = bcmd;
477 bargs[banum++] = "-H";
478 bargs[banum++] = uri;
480 bargs[banum++] = "-h";
481 bargs[banum++] = host;
482 bargs[banum++] = "-p";
483 bargs[banum++] = port;
485 bargs[banum++] = "-l";
486 bargs[banum++] = loops;
488 bargs[banum++] = "-r";
489 bargs[banum++] = retries;
490 bargs[banum++] = "-t";
491 bargs[banum++] = delay;
494 bargs[banum++] = friendlyOpt;
496 bargs[banum++] = "-D";
497 bargs[banum++] = NULL;
498 bargs[banum++] = "-w";
499 bargs[banum++] = NULL;
500 bargs[banum++] = NULL;
502 for ( j = 0; j < MAXREQS; j++ ) {
505 sargs[sanum - 2] = sreqs[j];
506 sargs[sanum - 4] = sbase[j];
507 fork_child( scmd, sargs );
513 rargs[ranum - 2] = rreqs[j];
514 fork_child( rcmd, rargs );
520 margs[manum - 2] = mreqs[j];
521 fork_child( mcmd, margs );
526 modargs[modanum - 4] = moddn[j];
527 modargs[modanum - 2] = modreqs[j];
528 fork_child( modcmd, modargs );
534 aargs[aanum - 2] = afiles[j];
535 fork_child( acmd, aargs );
541 bargs[banum - 4] = breqs[j];
542 bargs[banum - 2] = bcreds[j];
543 fork_child( bcmd, bargs );
551 exit( EXIT_SUCCESS );
555 get_file_name( char *dirname, char *filename )
557 char buf[MAXPATHLEN];
559 snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
561 return( strdup( buf ));
566 get_search_filters( char *filename, char *filters[], char *bases[] )
571 if ( (fp = fopen( filename, "r" )) != NULL ) {
574 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
577 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
579 bases[filter] = ArgDup( line );
580 fgets( line, BUFSIZ, fp );
581 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
584 filters[filter++] = ArgDup( line );
595 get_read_entries( char *filename, char *entries[] )
600 if ( (fp = fopen( filename, "r" )) != NULL ) {
603 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
606 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
608 entries[entry++] = ArgDup( line );
619 fork_child( char *prog, char **args )
623 wait4kids( maxkids );
625 switch ( pid = fork() ) {
628 /* The __LIBASCII execvp only handles ASCII "prog",
629 * we still need to translate the arg vec ourselves.
631 { char *arg2[MAXREQS];
634 for (i=0; args[i]; i++) {
635 arg2[i] = ArgDup(args[i]);
641 execvp( prog, args );
642 tester_perror( "execvp" );
643 exit( EXIT_FAILURE );
646 case -1: /* trouble */
647 tester_perror( "fork" );
650 default: /* parent */
657 wait4kids( int nkidval )
661 while ( nkids >= nkidval ) {
664 if ( WIFSTOPPED(status) ) {
666 "stopping: child stopped with signal %d\n",
667 (int) WSTOPSIG(status) );
669 } else if ( WIFSIGNALED(status) ) {
671 "stopping: child terminated with signal %d%s\n",
672 (int) WTERMSIG(status),
674 WCOREDUMP(status) ? ", core dumped" : ""
679 exit( WEXITSTATUS(status) );
681 } else if ( WEXITSTATUS(status) != 0 ) {
683 "stopping: child exited with status %d\n",
684 (int) WEXITSTATUS(status) );
685 exit( WEXITSTATUS(status) );
695 wait4kids( int nkidval )
699 while ( nkids >= nkidval ) {
700 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
701 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
702 children[i] = children[i+1];
708 fork_child( char *prog, char **args )
712 wait4kids( maxkids );
714 rc = _spawnvp( _P_NOWAIT, prog, args );
717 tester_perror( "_spawnvp" );
719 children[nkids++] = (HANDLE)rc;