2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2008 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 #define SEARCHCMD "slapd-search"
40 #define READCMD "slapd-read"
41 #define ADDCMD "slapd-addel"
42 #define MODRDNCMD "slapd-modrdn"
43 #define MODIFYCMD "slapd-modify"
49 #define TSEARCHFILE "do_search.0"
50 #define TREADFILE "do_read.0"
51 #define TADDFILE "do_add."
52 #define TMODRDNFILE "do_modrdn.0"
53 #define TMODIFYFILE "do_modify.0"
55 static char *get_file_name( char *dirname, char *filename );
56 static int get_search_filters( char *filename, char *filters[], char *bases[] );
57 static int get_read_entries( char *filename, char *entries[] );
58 static void fork_child( char *prog, char **args );
59 static void wait4kids( int nkidval );
61 static int maxkids = 20;
65 static HANDLE *children;
66 static char argbuf[BUFSIZ];
67 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
69 #define ArgDup(x) strdup(x)
77 "-H <uri> | ([-h <host>] -p <port>) "
92 main( int argc, char **argv )
96 char *host = "localhost";
100 char *dirname = NULL;
101 char *progdir = NULL;
103 char *retries = RETRIES;
108 char *sreqs[MAXREQS];
109 char *sbase[MAXREQS];
112 char *rreqs[MAXREQS];
114 char *afiles[MAXREQS];
117 char *mreqs[MAXREQS];
119 char *sargs[MAXARGS];
121 char scmd[MAXPATHLEN];
122 char *rargs[MAXARGS];
124 char rcmd[MAXPATHLEN];
125 char *aargs[MAXARGS];
127 char acmd[MAXPATHLEN];
128 char *margs[MAXARGS];
130 char mcmd[MAXPATHLEN];
131 char *modargs[MAXARGS];
133 char modcmd[MAXPATHLEN];
134 char *modfile = NULL;
135 char *modreqs[MAXREQS];
136 char *moddn[MAXREQS];
140 while ( (i = getopt( argc, argv, "D:d:FH:h:j:l:P:p:r:t:w:" )) != EOF ) {
142 case 'D': /* slapd manager */
143 manager = ArgDup( optarg );
146 case 'd': /* data directory */
147 dirname = strdup( optarg );
154 case 'H': /* slapd uri */
155 uri = strdup( optarg );
158 case 'h': /* slapd host */
159 host = strdup( optarg );
162 case 'j': /* the number of parallel clients */
163 if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
168 case 'l': /* the number of loops per client */
169 loops = strdup( optarg );
172 case 'P': /* prog directory */
173 progdir = strdup( optarg );
176 case 'p': /* the servers port number */
177 port = strdup( optarg );
180 case 'r': /* the number of retries in case of error */
181 retries = strdup( optarg );
184 case 't': /* the delay in seconds between each retry */
185 delay = strdup( optarg );
188 case 'w': /* the managers passwd */
189 passwd = ArgDup( optarg );
198 if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
199 ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
203 children = malloc( maxkids * sizeof(HANDLE) );
205 /* get the file list */
206 if ( ( datadir = opendir( dirname )) == NULL ) {
208 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
210 exit( EXIT_FAILURE );
214 /* look for search, read, modrdn, and add/delete files */
215 for ( file = readdir( datadir ); file; file = readdir( datadir )) {
217 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
218 sfile = get_file_name( dirname, file->d_name );
220 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
221 rfile = get_file_name( dirname, file->d_name );
223 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
224 mfile = get_file_name( dirname, file->d_name );
226 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
227 modfile = get_file_name( dirname, file->d_name );
229 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
230 && ( anum < MAXREQS )) {
231 afiles[anum++] = get_file_name( dirname, file->d_name );
238 /* look for search requests */
240 snum = get_search_filters( sfile, sreqs, sbase );
243 /* look for read requests */
245 rnum = get_read_entries( rfile, rreqs );
248 /* look for modrdn requests */
250 mnum = get_read_entries( mfile, mreqs );
252 /* look for modify requests */
254 modnum = get_search_filters( modfile, modreqs, moddn );
258 * generate the search clients
262 snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
264 sargs[sanum++] = scmd;
266 sargs[sanum++] = "-H";
267 sargs[sanum++] = uri;
269 sargs[sanum++] = "-h";
270 sargs[sanum++] = host;
271 sargs[sanum++] = "-p";
272 sargs[sanum++] = port;
274 sargs[sanum++] = "-D";
275 sargs[sanum++] = manager;
276 sargs[sanum++] = "-w";
277 sargs[sanum++] = passwd;
278 sargs[sanum++] = "-l";
279 sargs[sanum++] = loops;
280 sargs[sanum++] = "-r";
281 sargs[sanum++] = retries;
282 sargs[sanum++] = "-t";
283 sargs[sanum++] = delay;
284 sargs[sanum++] = "-b";
285 sargs[sanum++] = NULL; /* will hold the search base */
286 sargs[sanum++] = "-f";
287 sargs[sanum++] = NULL; /* will hold the search request */
288 sargs[sanum++] = NULL;
291 * generate the read clients
295 snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
297 rargs[ranum++] = rcmd;
299 rargs[ranum++] = "-H";
300 rargs[ranum++] = uri;
302 rargs[ranum++] = "-h";
303 rargs[ranum++] = host;
304 rargs[ranum++] = "-p";
305 rargs[ranum++] = port;
307 rargs[ranum++] = "-l";
308 rargs[ranum++] = loops;
309 rargs[ranum++] = "-r";
310 rargs[ranum++] = retries;
311 rargs[ranum++] = "-t";
312 rargs[ranum++] = delay;
313 rargs[ranum++] = "-e";
314 rargs[ranum++] = NULL; /* will hold the read entry */
315 rargs[ranum++] = NULL;
318 * generate the modrdn clients
322 snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
324 margs[manum++] = mcmd;
326 margs[manum++] = "-H";
327 margs[manum++] = uri;
329 margs[manum++] = "-h";
330 margs[manum++] = host;
331 margs[manum++] = "-p";
332 margs[manum++] = port;
334 margs[manum++] = "-D";
335 margs[manum++] = manager;
336 margs[manum++] = "-w";
337 margs[manum++] = passwd;
338 margs[manum++] = "-l";
339 margs[manum++] = loops;
340 margs[manum++] = "-r";
341 margs[manum++] = retries;
342 margs[manum++] = "-t";
343 margs[manum++] = delay;
345 margs[manum++] = "-F";
347 margs[manum++] = "-e";
348 margs[manum++] = NULL; /* will hold the modrdn entry */
349 margs[manum++] = NULL;
352 * generate the modify clients
356 snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
358 modargs[modanum++] = modcmd;
360 modargs[modanum++] = "-H";
361 modargs[modanum++] = uri;
363 modargs[modanum++] = "-h";
364 modargs[modanum++] = host;
365 modargs[modanum++] = "-p";
366 modargs[modanum++] = port;
368 modargs[modanum++] = "-D";
369 modargs[modanum++] = manager;
370 modargs[modanum++] = "-w";
371 modargs[modanum++] = passwd;
372 modargs[modanum++] = "-l";
373 modargs[modanum++] = loops;
374 modargs[modanum++] = "-r";
375 modargs[modanum++] = retries;
376 modargs[modanum++] = "-t";
377 modargs[modanum++] = delay;
379 modargs[modanum++] = "-F";
381 modargs[modanum++] = "-e";
382 modargs[modanum++] = NULL; /* will hold the modify entry */
383 modargs[modanum++] = "-a";;
384 modargs[modanum++] = NULL; /* will hold the ava */
385 modargs[modanum++] = NULL;
388 * generate the add/delete clients
392 snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
394 aargs[aanum++] = acmd;
396 aargs[aanum++] = "-H";
397 aargs[aanum++] = uri;
399 aargs[aanum++] = "-h";
400 aargs[aanum++] = host;
401 aargs[aanum++] = "-p";
402 aargs[aanum++] = port;
404 aargs[aanum++] = "-D";
405 aargs[aanum++] = manager;
406 aargs[aanum++] = "-w";
407 aargs[aanum++] = passwd;
408 aargs[aanum++] = "-l";
409 aargs[aanum++] = loops;
410 aargs[aanum++] = "-r";
411 aargs[aanum++] = retries;
412 aargs[aanum++] = "-t";
413 aargs[aanum++] = delay;
415 aargs[aanum++] = "-F";
417 aargs[aanum++] = "-f";
418 aargs[aanum++] = NULL; /* will hold the add data file */
419 aargs[aanum++] = NULL;
421 for ( j = 0; j < MAXREQS; j++ ) {
425 sargs[sanum - 2] = sreqs[j];
426 sargs[sanum - 4] = sbase[j];
427 fork_child( scmd, sargs );
433 rargs[ranum - 2] = rreqs[j];
434 fork_child( rcmd, rargs );
440 margs[manum - 2] = mreqs[j];
441 fork_child( mcmd, margs );
446 modargs[modanum - 4] = moddn[j];
447 modargs[modanum - 2] = modreqs[j];
448 fork_child( modcmd, modargs );
454 aargs[aanum - 2] = afiles[j];
455 fork_child( acmd, aargs );
463 exit( EXIT_SUCCESS );
467 get_file_name( char *dirname, char *filename )
469 char buf[MAXPATHLEN];
471 snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
473 return( strdup( buf ));
478 get_search_filters( char *filename, char *filters[], char *bases[] )
483 if ( (fp = fopen( filename, "r" )) != NULL ) {
486 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
489 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
491 bases[filter] = ArgDup( line );
492 fgets( line, BUFSIZ, fp );
493 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
496 filters[filter++] = ArgDup( line );
507 get_read_entries( char *filename, char *entries[] )
512 if ( (fp = fopen( filename, "r" )) != NULL ) {
515 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
518 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
520 entries[entry++] = ArgDup( line );
531 fork_child( char *prog, char **args )
535 wait4kids( maxkids );
537 switch ( pid = fork() ) {
540 /* The __LIBASCII execvp only handles ASCII "prog",
541 * we still need to translate the arg vec ourselves.
543 { char *arg2[MAXREQS];
546 for (i=0; args[i]; i++) {
547 arg2[i] = ArgDup(args[i]);
553 execvp( prog, args );
554 fprintf( stderr, "%s: ", prog );
556 exit( EXIT_FAILURE );
559 case -1: /* trouble */
560 fprintf( stderr, "Could not fork to run %s\n", prog );
564 default: /* parent */
571 wait4kids( int nkidval )
575 while ( nkids >= nkidval ) {
578 if ( WIFSTOPPED(status) ) {
580 "stopping: child stopped with signal %d\n",
581 (int) WSTOPSIG(status) );
583 } else if ( WIFSIGNALED(status) ) {
585 "stopping: child terminated with signal %d%s\n",
586 (int) WTERMSIG(status),
588 WCOREDUMP(status) ? ", core dumped" : ""
593 exit( WEXITSTATUS(status) );
595 } else if ( WEXITSTATUS(status) != 0 ) {
597 "stopping: child exited with status %d\n",
598 (int) WEXITSTATUS(status) );
599 exit( WEXITSTATUS(status) );
609 wait4kids( int nkidval )
613 while ( nkids >= nkidval ) {
614 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
615 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
616 children[i] = children[i+1];
622 fork_child( char *prog, char **args )
626 wait4kids( maxkids );
628 rc = _spawnvp( _P_NOWAIT, prog, args );
631 fprintf( stderr, "%s: ", prog );
634 children[nkids++] = (HANDLE)rc;