]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
use lutil_ato*() whenever appropriate
[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 #include "lutil.h"
37
38
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"
44 #define MAXARGS                 100
45 #define MAXREQS                 5000
46 #define LOOPS                   "100"
47 #define RETRIES                 "0"
48
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"
54
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 );
60
61 static int      maxkids = 20;
62 static int      nkids;
63
64 #ifdef HAVE_WINSOCK
65 static HANDLE   *children;
66 static char argbuf[BUFSIZ];
67 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
68 #else
69 #define ArgDup(x) strdup(x)
70 #endif
71
72 static void
73 usage( char *name )
74 {
75         fprintf( stderr,
76                 "usage: %s "
77                 "-H <uri> | ([-h <host>] -p <port>) "
78                 "-D <manager> "
79                 "-w <passwd> "
80                 "-d <datadir> "
81                 "[-j <maxchild>] "
82                 "[-l <loops>] "
83                 "-P <progdir> "
84                 "[-r <maxretries>] "
85                 "[-t <delay>] "
86                 "[-F]\n",
87                 name );
88         exit( EXIT_FAILURE );
89 }
90
91 int
92 main( int argc, char **argv )
93 {
94         int             i, j;
95         char            *uri = NULL;
96         char            *host = "localhost";
97         char            *port = NULL;
98         char            *manager = NULL;
99         char            *passwd = NULL;
100         char            *dirname = NULL;
101         char            *progdir = NULL;
102         char            *loops = LOOPS;
103         char            *retries = RETRIES;
104         char            *delay = "0";
105         DIR                     *datadir;
106         struct dirent   *file;
107         char            *sfile = NULL;
108         char            *sreqs[MAXREQS];
109         char            *sbase[MAXREQS];
110         int         snum = 0;
111         char            *rfile = NULL;
112         char            *rreqs[MAXREQS];
113         int         rnum = 0;
114         char            *afiles[MAXREQS];
115         int         anum = 0;
116         char            *mfile = NULL;
117         char            *mreqs[MAXREQS];
118         int             mnum = 0;
119         char            *sargs[MAXARGS];
120         int                     sanum;
121         char            scmd[MAXPATHLEN];
122         char            *rargs[MAXARGS];
123         int                     ranum;
124         char            rcmd[MAXPATHLEN];
125         char            *aargs[MAXARGS];
126         int                     aanum;
127         char            acmd[MAXPATHLEN];
128         char            *margs[MAXARGS];
129         int             manum;
130         char            mcmd[MAXPATHLEN];
131         char            *modargs[MAXARGS];
132         int             modanum;
133         char            modcmd[MAXPATHLEN];
134         char            *modfile = NULL;
135         char            *modreqs[MAXREQS];
136         char            *moddn[MAXREQS];
137         int             modnum = 0;
138         int             friendly = 0;
139
140         while ( (i = getopt( argc, argv, "D:d:FH:h:j:l:P:p:r:t:w:" )) != EOF ) {
141                 switch( i ) {
142                 case 'D':               /* slapd manager */
143                         manager = ArgDup( optarg );
144                         break;
145
146                 case 'd':               /* data directory */
147                         dirname = strdup( optarg );
148                         break;
149
150                 case 'F':
151                         friendly++;
152                         break;
153
154                 case 'H':               /* slapd uri */
155                         uri = strdup( optarg );
156                         break;
157
158                 case 'h':               /* slapd host */
159                         host = strdup( optarg );
160                         break;
161
162                 case 'j':               /* the number of parallel clients */
163                         if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
164                                 usage( argv[0] );
165                         }
166                         break;
167
168                 case 'l':               /* the number of loops per client */
169                         loops = strdup( optarg );
170                         break;
171
172                 case 'P':               /* prog directory */
173                         progdir = strdup( optarg );
174                         break;
175
176                 case 'p':               /* the servers port number */
177                         port = strdup( optarg );
178                         break;
179
180                 case 'r':               /* the number of retries in case of error */
181                         retries = strdup( optarg );
182                         break;
183
184                 case 't':               /* the delay in seconds between each retry */
185                         delay = strdup( optarg );
186                         break;
187
188                 case 'w':               /* the managers passwd */
189                         passwd = ArgDup( optarg );
190                         break;
191
192                 default:
193                         usage( argv[0] );
194                         break;
195                 }
196         }
197
198         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
199                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
200                 usage( argv[0] );
201
202 #ifdef HAVE_WINSOCK
203         children = malloc( maxkids * sizeof(HANDLE) );
204 #endif
205         /* get the file list */
206         if ( ( datadir = opendir( dirname )) == NULL ) {
207
208                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
209                                         argv[0], dirname );
210                 exit( EXIT_FAILURE );
211
212         }
213
214         /*  look for search, read, modrdn, and add/delete files */
215         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
216
217                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
218                         sfile = get_file_name( dirname, file->d_name );
219                         continue;
220                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
221                         rfile = get_file_name( dirname, file->d_name );
222                         continue;
223                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
224                         mfile = get_file_name( dirname, file->d_name );
225                         continue;
226                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
227                         modfile = get_file_name( dirname, file->d_name );
228                         continue;
229                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
230                         && ( anum < MAXREQS )) {
231                         afiles[anum++] = get_file_name( dirname, file->d_name );
232                         continue;
233                 }
234         }
235
236         closedir( datadir );
237
238         /* look for search requests */
239         if ( sfile ) {
240                 snum = get_search_filters( sfile, sreqs, sbase );
241         }
242
243         /* look for read requests */
244         if ( rfile ) {
245                 rnum = get_read_entries( rfile, rreqs );
246         }
247
248         /* look for modrdn requests */
249         if ( mfile ) {
250                 mnum = get_read_entries( mfile, mreqs );
251         }
252         /* look for modify requests */
253         if ( modfile ) {
254                 modnum = get_search_filters( modfile, modreqs, moddn );
255         }
256
257         /*
258          * generate the search clients
259          */
260
261         sanum = 0;
262         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
263                 progdir );
264         sargs[sanum++] = scmd;
265         if ( uri ) {
266                 sargs[sanum++] = "-H";
267                 sargs[sanum++] = uri;
268         } else {
269                 sargs[sanum++] = "-h";
270                 sargs[sanum++] = host;
271                 sargs[sanum++] = "-p";
272                 sargs[sanum++] = port;
273         }
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;
289
290         /*
291          * generate the read clients
292          */
293
294         ranum = 0;
295         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
296                 progdir );
297         rargs[ranum++] = rcmd;
298         if ( uri ) {
299                 rargs[ranum++] = "-H";
300                 rargs[ranum++] = uri;
301         } else {
302                 rargs[ranum++] = "-h";
303                 rargs[ranum++] = host;
304                 rargs[ranum++] = "-p";
305                 rargs[ranum++] = port;
306         }
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;
316
317         /*
318          * generate the modrdn clients
319          */
320
321         manum = 0;
322         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
323                 progdir );
324         margs[manum++] = mcmd;
325         if ( uri ) {
326                 margs[manum++] = "-H";
327                 margs[manum++] = uri;
328         } else {
329                 margs[manum++] = "-h";
330                 margs[manum++] = host;
331                 margs[manum++] = "-p";
332                 margs[manum++] = port;
333         }
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;
344         if ( friendly ) {
345                 margs[manum++] = "-F";
346         }
347         margs[manum++] = "-e";
348         margs[manum++] = NULL;          /* will hold the modrdn entry */
349         margs[manum++] = NULL;
350         
351         /*
352          * generate the modify clients
353          */
354
355         modanum = 0;
356         snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
357                 progdir );
358         modargs[modanum++] = modcmd;
359         if ( uri ) {
360                 modargs[modanum++] = "-H";
361                 modargs[modanum++] = uri;
362         } else {
363                 modargs[modanum++] = "-h";
364                 modargs[modanum++] = host;
365                 modargs[modanum++] = "-p";
366                 modargs[modanum++] = port;
367         }
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;
378         if ( friendly ) {
379                 modargs[modanum++] = "-F";
380         }
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;
386
387         /*
388          * generate the add/delete clients
389          */
390
391         aanum = 0;
392         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
393                 progdir );
394         aargs[aanum++] = acmd;
395         if ( uri ) {
396                 aargs[aanum++] = "-H";
397                 aargs[aanum++] = uri;
398         } else {
399                 aargs[aanum++] = "-h";
400                 aargs[aanum++] = host;
401                 aargs[aanum++] = "-p";
402                 aargs[aanum++] = port;
403         }
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;
414         if ( friendly ) {
415                 aargs[aanum++] = "-F";
416         }
417         aargs[aanum++] = "-f";
418         aargs[aanum++] = NULL;          /* will hold the add data file */
419         aargs[aanum++] = NULL;
420
421         for ( j = 0; j < MAXREQS; j++ ) {
422
423                 if ( j < snum ) {
424
425                         sargs[sanum - 2] = sreqs[j];
426                         sargs[sanum - 4] = sbase[j];
427                         fork_child( scmd, sargs );
428
429                 }
430
431                 if ( j < rnum ) {
432
433                         rargs[ranum - 2] = rreqs[j];
434                         fork_child( rcmd, rargs );
435
436                 }
437
438                 if ( j < mnum ) {
439
440                         margs[manum - 2] = mreqs[j];
441                         fork_child( mcmd, margs );
442
443                 }
444                 if ( j < modnum ) {
445
446                         modargs[modanum - 4] = moddn[j];
447                         modargs[modanum - 2] = modreqs[j];
448                         fork_child( modcmd, modargs );
449
450                 }
451
452                 if ( j < anum ) {
453
454                         aargs[aanum - 2] = afiles[j];
455                         fork_child( acmd, aargs );
456
457                 }
458
459         }
460
461         wait4kids( -1 );
462
463         exit( EXIT_SUCCESS );
464 }
465
466 static char *
467 get_file_name( char *dirname, char *filename )
468 {
469         char buf[MAXPATHLEN];
470
471         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
472                 dirname, filename );
473         return( strdup( buf ));
474 }
475
476
477 static int
478 get_search_filters( char *filename, char *filters[], char *bases[] )
479 {
480         FILE    *fp;
481         int     filter = 0;
482
483         if ( (fp = fopen( filename, "r" )) != NULL ) {
484                 char  line[BUFSIZ];
485
486                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
487                         char *nl;
488
489                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
490                                 *nl = '\0';
491                         bases[filter] = ArgDup( line );
492                         fgets( line, BUFSIZ, fp );
493                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
494                                 *nl = '\0';
495
496                         filters[filter++] = ArgDup( line );
497
498                 }
499                 fclose( fp );
500         }
501
502         return( filter );
503 }
504
505
506 static int
507 get_read_entries( char *filename, char *entries[] )
508 {
509         FILE    *fp;
510         int     entry = 0;
511
512         if ( (fp = fopen( filename, "r" )) != NULL ) {
513                 char  line[BUFSIZ];
514
515                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
516                         char *nl;
517
518                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
519                                 *nl = '\0';
520                         entries[entry++] = ArgDup( line );
521
522                 }
523                 fclose( fp );
524         }
525
526         return( entry );
527 }
528
529 #ifndef HAVE_WINSOCK
530 static void
531 fork_child( char *prog, char **args )
532 {
533         pid_t   pid;
534
535         wait4kids( maxkids );
536
537         switch ( pid = fork() ) {
538         case 0:         /* child */
539 #ifdef HAVE_EBCDIC
540                 /* The __LIBASCII execvp only handles ASCII "prog",
541                  * we still need to translate the arg vec ourselves.
542                  */
543                 { char *arg2[MAXREQS];
544                 int i;
545
546                 for (i=0; args[i]; i++) {
547                         arg2[i] = ArgDup(args[i]);
548                         __atoe(arg2[i]);
549                 }
550                 arg2[i] = NULL;
551                 args = arg2; }
552 #endif
553                 execvp( prog, args );
554                 fprintf( stderr, "%s: ", prog );
555                 perror( "execv" );
556                 exit( EXIT_FAILURE );
557                 break;
558
559         case -1:        /* trouble */
560                 fprintf( stderr, "Could not fork to run %s\n", prog );
561                 perror( "fork" );
562                 break;
563
564         default:        /* parent */
565                 nkids++;
566                 break;
567         }
568 }
569
570 static void
571 wait4kids( int nkidval )
572 {
573         int             status;
574
575         while ( nkids >= nkidval ) {
576                 wait( &status );
577
578                 if ( WIFSTOPPED(status) ) {
579                         fprintf( stderr,
580                             "stopping: child stopped with signal %d\n",
581                             (int) WSTOPSIG(status) );
582
583                 } else if ( WIFSIGNALED(status) ) {
584                         fprintf( stderr, 
585                             "stopping: child terminated with signal %d%s\n",
586                             (int) WTERMSIG(status),
587 #ifdef WCOREDUMP
588                                 WCOREDUMP(status) ? ", core dumped" : ""
589 #else
590                                 ""
591 #endif
592                                 );
593                         exit( WEXITSTATUS(status)  );
594
595                 } else if ( WEXITSTATUS(status) != 0 ) {
596                         fprintf( stderr, 
597                             "stopping: child exited with status %d\n",
598                             (int) WEXITSTATUS(status) );
599                         exit( WEXITSTATUS(status) );
600
601                 } else {
602                         nkids--;
603                 }
604         }
605 }
606 #else
607
608 static void
609 wait4kids( int nkidval )
610 {
611         int rc, i;
612
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];
617                 nkids--;
618         }
619 }
620
621 static void
622 fork_child( char *prog, char **args )
623 {
624         int rc;
625
626         wait4kids( maxkids );
627
628         rc = _spawnvp( _P_NOWAIT, prog, args );
629
630         if ( rc == -1 ) {
631                 fprintf( stderr, "%s: ", prog );
632                 perror("spawnvp");
633         } else {
634                 children[nkids++] = (HANDLE)rc;
635         }
636 }
637 #endif