]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
add "retry" switch (currently needed to stress-test back-meta); defaults to old behavior
[openldap] / tests / progs / slapd-tester.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
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>.
14  */
15 /* ACKNOWLEDGEMENTS:
16  * This work was initially developed by Kurt Spanier for inclusion
17  * in OpenLDAP Software.
18  */
19
20 #include "portable.h"
21
22 #include <stdio.h>
23
24 #include <ac/stdlib.h>
25
26 #include <ac/ctype.h>
27 #include <ac/dirent.h>
28 #include <ac/param.h>
29 #include <ac/socket.h>
30 #include <ac/string.h>
31 #include <ac/unistd.h>
32 #include <ac/wait.h>
33
34
35 #include "ldap_defaults.h"
36
37
38 #define SEARCHCMD               "slapd-search"
39 #define READCMD                 "slapd-read"
40 #define ADDCMD                  "slapd-addel"
41 #define MODRDNCMD               "slapd-modrdn"
42 #define MODIFYCMD               "slapd-modify"
43 #define MAXARGS                 100
44 #define MAXREQS                 5000
45 #define LOOPS                   "100"
46 #define RETRIES                 "0"
47
48 #define TSEARCHFILE             "do_search.0"
49 #define TREADFILE               "do_read.0"
50 #define TADDFILE                "do_add."
51 #define TMODRDNFILE             "do_modrdn.0"
52 #define TMODIFYFILE             "do_modify.0"
53
54 static char *get_file_name( char *dirname, char *filename );
55 static int  get_search_filters( char *filename, char *filters[], char *bases[] );
56 static int  get_read_entries( char *filename, char *entries[] );
57 static void fork_child( char *prog, char **args );
58 static void     wait4kids( int nkidval );
59
60 static int      maxkids = 20;
61 static int      nkids;
62
63 #ifdef HAVE_WINSOCK
64 static HANDLE   *children;
65 static char argbuf[BUFSIZ];
66 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
67 #else
68 #define ArgDup(x) strdup(x)
69 #endif
70
71 static void
72 usage( char *name )
73 {
74         fprintf( stderr, "usage: %s -H <uri> | ([-h <host>] -p <port>) -D <manager> -w <passwd> -d <datadir> [-j <maxchild>] [-l <loops>] -P <progdir>\n", name );
75         exit( EXIT_FAILURE );
76 }
77
78 int
79 main( int argc, char **argv )
80 {
81         int             i, j;
82         char            *uri = NULL;
83         char            *host = "localhost";
84         char            *port = NULL;
85         char            *manager = NULL;
86         char            *passwd = NULL;
87         char            *dirname = NULL;
88         char            *progdir = NULL;
89         char            *loops = LOOPS;
90         char            *retries = RETRIES;
91         DIR                     *datadir;
92         struct dirent   *file;
93         char            *sfile = NULL;
94         char            *sreqs[MAXREQS];
95         char            *sbase[MAXREQS];
96         int         snum = 0;
97         char            *rfile = NULL;
98         char            *rreqs[MAXREQS];
99         int         rnum = 0;
100         char            *afiles[MAXREQS];
101         int         anum = 0;
102         char            *mfile = NULL;
103         char            *mreqs[MAXREQS];
104         int             mnum = 0;
105         char            *sargs[MAXARGS];
106         int                     sanum;
107         char            scmd[MAXPATHLEN];
108         char            *rargs[MAXARGS];
109         int                     ranum;
110         char            rcmd[MAXPATHLEN];
111         char            *aargs[MAXARGS];
112         int                     aanum;
113         char            acmd[MAXPATHLEN];
114         char            *margs[MAXARGS];
115         int             manum;
116         char            mcmd[MAXPATHLEN];
117         char            *modargs[MAXARGS];
118         int             modanum;
119         char            modcmd[MAXPATHLEN];
120         char            *modfile = NULL;
121         char            *modreqs[MAXREQS];
122         char            *moddn[MAXREQS];
123         int             modnum = 0;
124
125         while ( (i = getopt( argc, argv, "D:d:H:h:j:l:P:p:r:w:" )) != EOF ) {
126                 switch( i ) {
127                 case 'D':               /* slapd manager */
128                         manager = ArgDup( optarg );
129                         break;
130
131                 case 'd':               /* data directory */
132                         dirname = strdup( optarg );
133                         break;
134
135                 case 'H':               /* slapd uri */
136                         uri = strdup( optarg );
137                         break;
138
139                 case 'h':               /* slapd host */
140                         host = strdup( optarg );
141                         break;
142
143                 case 'j':               /* the number of parallel clients */
144                         maxkids = atoi( optarg );
145                         break;
146
147                 case 'l':               /* the number of loops per client */
148                         loops = strdup( optarg );
149                         break;
150
151                 case 'P':               /* prog directory */
152                         progdir = strdup( optarg );
153                         break;
154
155                 case 'p':               /* the servers port number */
156                         port = strdup( optarg );
157                         break;
158
159                 case 'r':
160                         retries = strdup( optarg );
161                         break;
162
163                 case 'w':               /* the managers passwd */
164                         passwd = ArgDup( optarg );
165                         break;
166
167                 default:
168                         usage( argv[0] );
169                         break;
170                 }
171         }
172
173         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
174                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
175                 usage( argv[0] );
176
177 #ifdef HAVE_WINSOCK
178         children = malloc( maxkids * sizeof(HANDLE) );
179 #endif
180         /* get the file list */
181         if ( ( datadir = opendir( dirname )) == NULL ) {
182
183                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
184                                         argv[0], dirname );
185                 exit( EXIT_FAILURE );
186
187         }
188
189         /*  look for search, read, modrdn, and add/delete files */
190         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
191
192                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
193                         sfile = get_file_name( dirname, file->d_name );
194                         continue;
195                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
196                         rfile = get_file_name( dirname, file->d_name );
197                         continue;
198                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
199                         mfile = get_file_name( dirname, file->d_name );
200                         continue;
201                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
202                         modfile = get_file_name( dirname, file->d_name );
203                         continue;
204                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
205                         && ( anum < MAXREQS )) {
206                         afiles[anum++] = get_file_name( dirname, file->d_name );
207                         continue;
208                 }
209         }
210
211         closedir( datadir );
212
213         /* look for search requests */
214         if ( sfile ) {
215                 snum = get_search_filters( sfile, sreqs, sbase );
216         }
217
218         /* look for read requests */
219         if ( rfile ) {
220                 rnum = get_read_entries( rfile, rreqs );
221         }
222
223         /* look for modrdn requests */
224         if ( mfile ) {
225                 mnum = get_read_entries( mfile, mreqs );
226         }
227         /* look for modify requests */
228         if ( modfile ) {
229                 modnum = get_search_filters( modfile, modreqs, moddn );
230         }
231
232         /*
233          * generate the search clients
234          */
235
236         sanum = 0;
237         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
238                 progdir );
239         sargs[sanum++] = scmd;
240         if ( uri ) {
241                 sargs[sanum++] = "-H";
242                 sargs[sanum++] = uri;
243         } else {
244                 sargs[sanum++] = "-h";
245                 sargs[sanum++] = host;
246                 sargs[sanum++] = "-p";
247                 sargs[sanum++] = port;
248         }
249         sargs[sanum++] = "-D";
250         sargs[sanum++] = manager;
251         sargs[sanum++] = "-w";
252         sargs[sanum++] = passwd;
253         sargs[sanum++] = "-l";
254         sargs[sanum++] = loops;
255         sargs[sanum++] = "-r";
256         sargs[sanum++] = retries;
257         sargs[sanum++] = "-b";
258         sargs[sanum++] = NULL;          /* will hold the search base */
259         sargs[sanum++] = "-f";
260         sargs[sanum++] = NULL;          /* will hold the search request */
261         sargs[sanum++] = NULL;
262
263         /*
264          * generate the read clients
265          */
266
267         ranum = 0;
268         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
269                 progdir );
270         rargs[ranum++] = rcmd;
271         if ( uri ) {
272                 rargs[ranum++] = "-H";
273                 rargs[ranum++] = uri;
274         } else {
275                 rargs[ranum++] = "-h";
276                 rargs[ranum++] = host;
277                 rargs[ranum++] = "-p";
278                 rargs[ranum++] = port;
279         }
280         rargs[ranum++] = "-l";
281         rargs[ranum++] = loops;
282         rargs[ranum++] = "-r";
283         rargs[ranum++] = retries;
284         rargs[ranum++] = "-e";
285         rargs[ranum++] = NULL;          /* will hold the read entry */
286         rargs[ranum++] = NULL;
287
288         /*
289          * generate the modrdn clients
290          */
291
292         manum = 0;
293         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
294                 progdir );
295         margs[manum++] = mcmd;
296         if ( uri ) {
297                 margs[manum++] = "-H";
298                 margs[manum++] = uri;
299         } else {
300                 margs[manum++] = "-h";
301                 margs[manum++] = host;
302                 margs[manum++] = "-p";
303                 margs[manum++] = port;
304         }
305         margs[manum++] = "-D";
306         margs[manum++] = manager;
307         margs[manum++] = "-w";
308         margs[manum++] = passwd;
309         margs[manum++] = "-l";
310         margs[manum++] = loops;
311         margs[manum++] = "-r";
312         margs[manum++] = retries;
313         margs[manum++] = "-e";
314         margs[manum++] = NULL;          /* will hold the modrdn entry */
315         margs[manum++] = NULL;
316         
317         /*
318          * generate the modify clients
319          */
320
321         modanum = 0;
322         snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
323                 progdir );
324         modargs[modanum++] = modcmd;
325         if ( uri ) {
326                 modargs[modanum++] = "-H";
327                 modargs[modanum++] = uri;
328         } else {
329                 modargs[modanum++] = "-h";
330                 modargs[modanum++] = host;
331                 modargs[modanum++] = "-p";
332                 modargs[modanum++] = port;
333         }
334         modargs[modanum++] = "-D";
335         modargs[modanum++] = manager;
336         modargs[modanum++] = "-w";
337         modargs[modanum++] = passwd;
338         modargs[modanum++] = "-l";
339         modargs[modanum++] = loops;
340         modargs[modanum++] = "-r";
341         modargs[modanum++] = retries;
342         modargs[modanum++] = "-e";
343         modargs[modanum++] = NULL;              /* will hold the modify entry */
344         modargs[modanum++] = "-a";;
345         modargs[modanum++] = NULL;              /* will hold the ava */
346         modargs[modanum++] = NULL;
347
348         /*
349          * generate the add/delete clients
350          */
351
352         aanum = 0;
353         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
354                 progdir );
355         aargs[aanum++] = acmd;
356         if ( uri ) {
357                 aargs[aanum++] = "-H";
358                 aargs[aanum++] = uri;
359         } else {
360                 aargs[aanum++] = "-h";
361                 aargs[aanum++] = host;
362                 aargs[aanum++] = "-p";
363                 aargs[aanum++] = port;
364         }
365         aargs[aanum++] = "-D";
366         aargs[aanum++] = manager;
367         aargs[aanum++] = "-w";
368         aargs[aanum++] = passwd;
369         aargs[aanum++] = "-l";
370         aargs[aanum++] = loops;
371         aargs[aanum++] = "-r";
372         aargs[aanum++] = retries;
373         aargs[aanum++] = "-f";
374         aargs[aanum++] = NULL;          /* will hold the add data file */
375         aargs[aanum++] = NULL;
376
377         for ( j = 0; j < MAXREQS; j++ ) {
378
379                 if ( j < snum ) {
380
381                         sargs[sanum - 2] = sreqs[j];
382                         sargs[sanum - 4] = sbase[j];
383                         fork_child( scmd, sargs );
384
385                 }
386
387                 if ( j < rnum ) {
388
389                         rargs[ranum - 2] = rreqs[j];
390                         fork_child( rcmd, rargs );
391
392                 }
393
394                 if ( j < mnum ) {
395
396                         margs[manum - 2] = mreqs[j];
397                         fork_child( mcmd, margs );
398
399                 }
400                 if ( j < modnum ) {
401
402                         modargs[modanum - 4] = moddn[j];
403                         modargs[modanum - 2] = modreqs[j];
404                         fork_child( modcmd, modargs );
405
406                 }
407
408                 if ( j < anum ) {
409
410                         aargs[aanum - 2] = afiles[j];
411                         fork_child( acmd, aargs );
412
413                 }
414
415         }
416
417         wait4kids( -1 );
418
419         exit( EXIT_SUCCESS );
420 }
421
422 static char *
423 get_file_name( char *dirname, char *filename )
424 {
425         char buf[MAXPATHLEN];
426
427         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
428                 dirname, filename );
429         return( strdup( buf ));
430 }
431
432
433 static int
434 get_search_filters( char *filename, char *filters[], char *bases[] )
435 {
436         FILE    *fp;
437         int     filter = 0;
438
439         if ( (fp = fopen( filename, "r" )) != NULL ) {
440                 char  line[BUFSIZ];
441
442                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
443                         char *nl;
444
445                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
446                                 *nl = '\0';
447                         bases[filter] = ArgDup( line );
448                         fgets( line, BUFSIZ, fp );
449                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
450                                 *nl = '\0';
451
452                         filters[filter++] = ArgDup( line );
453
454                 }
455                 fclose( fp );
456         }
457
458         return( filter );
459 }
460
461
462 static int
463 get_read_entries( char *filename, char *entries[] )
464 {
465         FILE    *fp;
466         int     entry = 0;
467
468         if ( (fp = fopen( filename, "r" )) != NULL ) {
469                 char  line[BUFSIZ];
470
471                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
472                         char *nl;
473
474                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
475                                 *nl = '\0';
476                         entries[entry++] = ArgDup( line );
477
478                 }
479                 fclose( fp );
480         }
481
482         return( entry );
483 }
484
485 #ifndef HAVE_WINSOCK
486 static void
487 fork_child( char *prog, char **args )
488 {
489         pid_t   pid;
490
491         wait4kids( maxkids );
492
493         switch ( pid = fork() ) {
494         case 0:         /* child */
495 #ifdef HAVE_EBCDIC
496                 /* The __LIBASCII execvp only handles ASCII "prog",
497                  * we still need to translate the arg vec ourselves.
498                  */
499                 { char *arg2[MAXREQS];
500                 int i;
501
502                 for (i=0; args[i]; i++) {
503                         arg2[i] = ArgDup(args[i]);
504                         __atoe(arg2[i]);
505                 }
506                 arg2[i] = NULL;
507                 args = arg2; }
508 #endif
509                 execvp( prog, args );
510                 fprintf( stderr, "%s: ", prog );
511                 perror( "execv" );
512                 exit( EXIT_FAILURE );
513                 break;
514
515         case -1:        /* trouble */
516                 fprintf( stderr, "Could not fork to run %s\n", prog );
517                 perror( "fork" );
518                 break;
519
520         default:        /* parent */
521                 nkids++;
522                 break;
523         }
524 }
525
526 static void
527 wait4kids( int nkidval )
528 {
529         int             status;
530
531         while ( nkids >= nkidval ) {
532                 wait( &status );
533
534                 if ( WIFSTOPPED(status) ) {
535                         fprintf( stderr,
536                             "stopping: child stopped with signal %d\n",
537                             (int) WSTOPSIG(status) );
538
539                 } else if ( WIFSIGNALED(status) ) {
540                         fprintf( stderr, 
541                             "stopping: child terminated with signal %d%s\n",
542                             (int) WTERMSIG(status),
543 #ifdef WCOREDUMP
544                                 WCOREDUMP(status) ? ", core dumped" : ""
545 #else
546                                 ""
547 #endif
548                                 );
549                         exit( WEXITSTATUS(status)  );
550
551                 } else if ( WEXITSTATUS(status) != 0 ) {
552                         fprintf( stderr, 
553                             "stopping: child exited with status %d\n",
554                             (int) WEXITSTATUS(status) );
555                         exit( WEXITSTATUS(status) );
556
557                 } else {
558                         nkids--;
559                 }
560         }
561 }
562 #else
563
564 static void
565 wait4kids( int nkidval )
566 {
567         int rc, i;
568
569         while ( nkids >= nkidval ) {
570                 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
571                 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
572                         children[i] = children[i+1];
573                 nkids--;
574         }
575 }
576
577 static void
578 fork_child( char *prog, char **args )
579 {
580         int rc;
581
582         wait4kids( maxkids );
583
584         rc = _spawnvp( _P_NOWAIT, prog, args );
585
586         if ( rc == -1 ) {
587                 fprintf( stderr, "%s: ", prog );
588                 perror("spawnvp");
589         } else {
590                 children[nkids++] = (HANDLE)rc;
591         }
592 }
593 #endif