]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
-FF means: log just once
[openldap] / tests / progs / slapd-tester.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2006 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 #include "ldap.h"
39 #include "slapd-common.h"
40
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"
47 #define MAXARGS                 100
48 #define MAXREQS                 5000
49 #define LOOPS                   "100"
50 #define RETRIES                 "0"
51
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"
58
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 );
64
65 static int      maxkids = 20;
66 static int      nkids;
67
68 #ifdef HAVE_WINSOCK
69 static HANDLE   *children;
70 static char argbuf[BUFSIZ];
71 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
72 #else
73 #define ArgDup(x) strdup(x)
74 #endif
75
76 static void
77 usage( char *name )
78 {
79         fprintf( stderr,
80                 "usage: %s "
81                 "-H <uri> | ([-h <host>] -p <port>) "
82                 "-D <manager> "
83                 "-w <passwd> "
84                 "-d <datadir> "
85                 "[-j <maxchild>] "
86                 "[-l <loops>] "
87                 "-P <progdir> "
88                 "[-r <maxretries>] "
89                 "[-t <delay>] "
90                 "[-F]\n",
91                 name );
92         exit( EXIT_FAILURE );
93 }
94
95 int
96 main( int argc, char **argv )
97 {
98         int             i, j;
99         char            *uri = NULL;
100         char            *host = "localhost";
101         char            *port = NULL;
102         char            *manager = NULL;
103         char            *passwd = NULL;
104         char            *dirname = NULL;
105         char            *progdir = NULL;
106         char            *loops = LOOPS;
107         char            *retries = RETRIES;
108         char            *delay = "0";
109         DIR             *datadir;
110         struct dirent   *file;
111         int             friendly = 0;
112         /* search */
113         char            *sfile = NULL;
114         char            *sreqs[MAXREQS];
115         char            *sbase[MAXREQS];
116         int             snum = 0;
117         char            *sargs[MAXARGS];
118         int             sanum;
119         char            scmd[MAXPATHLEN];
120         /* read */
121         char            *rfile = NULL;
122         char            *rreqs[MAXREQS];
123         int             rnum = 0;
124         char            *rargs[MAXARGS];
125         int             ranum;
126         char            rcmd[MAXPATHLEN];
127         /* addel */
128         char            *afiles[MAXREQS];
129         int             anum = 0;
130         char            *aargs[MAXARGS];
131         int             aanum;
132         char            acmd[MAXPATHLEN];
133         /* modrdn */
134         char            *mfile = NULL;
135         char            *mreqs[MAXREQS];
136         int             mnum = 0;
137         char            *margs[MAXARGS];
138         int             manum;
139         char            mcmd[MAXPATHLEN];
140         /* modify */
141         char            *modfile = NULL;
142         char            *modreqs[MAXREQS];
143         char            *moddn[MAXREQS];
144         int             modnum = 0;
145         char            *modargs[MAXARGS];
146         int             modanum;
147         char            modcmd[MAXPATHLEN];
148         /* bind */
149         char            *bfile = NULL;
150         char            *breqs[MAXREQS];
151         char            *bcreds[MAXREQS];
152         int             bnum = 0;
153         char            *bargs[MAXARGS];
154         int             banum;
155         char            bcmd[MAXPATHLEN];
156
157         char            *friendlyOpt = NULL;
158
159         tester_init( "slapd-tester" );
160
161         while ( (i = getopt( argc, argv, "D:d:FH:h:j:l:P:p:r:t:w:" )) != EOF ) {
162                 switch( i ) {
163                 case 'D':               /* slapd manager */
164                         manager = ArgDup( optarg );
165                         break;
166
167                 case 'd':               /* data directory */
168                         dirname = strdup( optarg );
169                         break;
170
171                 case 'F':
172                         friendly++;
173                         break;
174
175                 case 'H':               /* slapd uri */
176                         uri = strdup( optarg );
177                         break;
178
179                 case 'h':               /* slapd host */
180                         host = strdup( optarg );
181                         break;
182
183                 case 'j':               /* the number of parallel clients */
184                         if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
185                                 usage( argv[0] );
186                         }
187                         break;
188
189                 case 'l':               /* the number of loops per client */
190                         loops = strdup( optarg );
191                         break;
192
193                 case 'P':               /* prog directory */
194                         progdir = strdup( optarg );
195                         break;
196
197                 case 'p':               /* the servers port number */
198                         port = strdup( optarg );
199                         break;
200
201                 case 'r':               /* the number of retries in case of error */
202                         retries = strdup( optarg );
203                         break;
204
205                 case 't':               /* the delay in seconds between each retry */
206                         delay = strdup( optarg );
207                         break;
208
209                 case 'w':               /* the managers passwd */
210                         passwd = ArgDup( optarg );
211                         break;
212
213                 default:
214                         usage( argv[0] );
215                         break;
216                 }
217         }
218
219         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
220                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
221                 usage( argv[0] );
222
223 #ifdef HAVE_WINSOCK
224         children = malloc( maxkids * sizeof(HANDLE) );
225 #endif
226         /* get the file list */
227         if ( ( datadir = opendir( dirname )) == NULL ) {
228
229                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
230                                         argv[0], dirname );
231                 exit( EXIT_FAILURE );
232
233         }
234
235         /*  look for search, read, modrdn, and add/delete files */
236         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
237
238                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
239                         sfile = get_file_name( dirname, file->d_name );
240                         continue;
241                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
242                         rfile = get_file_name( dirname, file->d_name );
243                         continue;
244                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
245                         mfile = get_file_name( dirname, file->d_name );
246                         continue;
247                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
248                         modfile = get_file_name( dirname, file->d_name );
249                         continue;
250                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
251                         && ( anum < MAXREQS )) {
252                         afiles[anum++] = get_file_name( dirname, file->d_name );
253                         continue;
254                 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
255                         bfile = get_file_name( dirname, file->d_name );
256                         continue;
257                 }
258         }
259
260         closedir( datadir );
261
262         /* look for search requests */
263         if ( sfile ) {
264                 snum = get_search_filters( sfile, sreqs, sbase );
265         }
266
267         /* look for read requests */
268         if ( rfile ) {
269                 rnum = get_read_entries( rfile, rreqs );
270         }
271
272         /* look for modrdn requests */
273         if ( mfile ) {
274                 mnum = get_read_entries( mfile, mreqs );
275         }
276
277         /* look for modify requests */
278         if ( modfile ) {
279                 modnum = get_search_filters( modfile, modreqs, moddn );
280         }
281
282         /* look for bind requests */
283         if ( bfile ) {
284                 bnum = get_search_filters( bfile, bcreds, breqs );
285         }
286
287         /* setup friendly option */
288
289         switch ( friendly ) {
290         case 0:
291                 break;
292
293         case 1:
294                 friendlyOpt = "-F";
295                 break;
296
297         default:
298                 /* NOTE: right now we don't need it more than twice */
299         case 2:
300                 friendlyOpt = "-FF";
301                 break;
302         }
303
304         /*
305          * generate the search clients
306          */
307
308         sanum = 0;
309         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
310                 progdir );
311         sargs[sanum++] = scmd;
312         if ( uri ) {
313                 sargs[sanum++] = "-H";
314                 sargs[sanum++] = uri;
315         } else {
316                 sargs[sanum++] = "-h";
317                 sargs[sanum++] = host;
318                 sargs[sanum++] = "-p";
319                 sargs[sanum++] = port;
320         }
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;
336
337         /*
338          * generate the read clients
339          */
340
341         ranum = 0;
342         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
343                 progdir );
344         rargs[ranum++] = rcmd;
345         if ( uri ) {
346                 rargs[ranum++] = "-H";
347                 rargs[ranum++] = uri;
348         } else {
349                 rargs[ranum++] = "-h";
350                 rargs[ranum++] = host;
351                 rargs[ranum++] = "-p";
352                 rargs[ranum++] = port;
353         }
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;
363
364         /*
365          * generate the modrdn clients
366          */
367
368         manum = 0;
369         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
370                 progdir );
371         margs[manum++] = mcmd;
372         if ( uri ) {
373                 margs[manum++] = "-H";
374                 margs[manum++] = uri;
375         } else {
376                 margs[manum++] = "-h";
377                 margs[manum++] = host;
378                 margs[manum++] = "-p";
379                 margs[manum++] = port;
380         }
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;
391         if ( friendly ) {
392                 margs[manum++] = friendlyOpt;
393         }
394         margs[manum++] = "-e";
395         margs[manum++] = NULL;          /* will hold the modrdn entry */
396         margs[manum++] = NULL;
397         
398         /*
399          * generate the modify clients
400          */
401
402         modanum = 0;
403         snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
404                 progdir );
405         modargs[modanum++] = modcmd;
406         if ( uri ) {
407                 modargs[modanum++] = "-H";
408                 modargs[modanum++] = uri;
409         } else {
410                 modargs[modanum++] = "-h";
411                 modargs[modanum++] = host;
412                 modargs[modanum++] = "-p";
413                 modargs[modanum++] = port;
414         }
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;
425         if ( friendly ) {
426                 modargs[modanum++] = friendlyOpt;
427         }
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;
433
434         /*
435          * generate the add/delete clients
436          */
437
438         aanum = 0;
439         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
440                 progdir );
441         aargs[aanum++] = acmd;
442         if ( uri ) {
443                 aargs[aanum++] = "-H";
444                 aargs[aanum++] = uri;
445         } else {
446                 aargs[aanum++] = "-h";
447                 aargs[aanum++] = host;
448                 aargs[aanum++] = "-p";
449                 aargs[aanum++] = port;
450         }
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;
461         if ( friendly ) {
462                 aargs[aanum++] = friendlyOpt;
463         }
464         aargs[aanum++] = "-f";
465         aargs[aanum++] = NULL;          /* will hold the add data file */
466         aargs[aanum++] = NULL;
467
468         /*
469          * generate the bind clients
470          */
471
472         banum = 0;
473         snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
474                 progdir );
475         bargs[banum++] = bcmd;
476         if ( uri ) {
477                 bargs[banum++] = "-H";
478                 bargs[banum++] = uri;
479         } else {
480                 bargs[banum++] = "-h";
481                 bargs[banum++] = host;
482                 bargs[banum++] = "-p";
483                 bargs[banum++] = port;
484         }
485         bargs[banum++] = "-l";
486         bargs[banum++] = loops;
487 #if 0
488         bargs[banum++] = "-r";
489         bargs[banum++] = retries;
490         bargs[banum++] = "-t";
491         bargs[banum++] = delay;
492 #endif
493         if ( friendly ) {
494                 bargs[banum++] = friendlyOpt;
495         }
496         bargs[banum++] = "-D";
497         bargs[banum++] = NULL;
498         bargs[banum++] = "-w";
499         bargs[banum++] = NULL;
500         bargs[banum++] = NULL;
501
502         for ( j = 0; j < MAXREQS; j++ ) {
503                 if ( j < snum ) {
504
505                         sargs[sanum - 2] = sreqs[j];
506                         sargs[sanum - 4] = sbase[j];
507                         fork_child( scmd, sargs );
508
509                 }
510
511                 if ( j < rnum ) {
512
513                         rargs[ranum - 2] = rreqs[j];
514                         fork_child( rcmd, rargs );
515
516                 }
517
518                 if ( j < mnum ) {
519
520                         margs[manum - 2] = mreqs[j];
521                         fork_child( mcmd, margs );
522
523                 }
524                 if ( j < modnum ) {
525
526                         modargs[modanum - 4] = moddn[j];
527                         modargs[modanum - 2] = modreqs[j];
528                         fork_child( modcmd, modargs );
529
530                 }
531
532                 if ( j < anum ) {
533
534                         aargs[aanum - 2] = afiles[j];
535                         fork_child( acmd, aargs );
536
537                 }
538
539                 if ( j < bnum ) {
540
541                         bargs[banum - 4] = breqs[j];
542                         bargs[banum - 2] = bcreds[j];
543                         fork_child( bcmd, bargs );
544
545                 }
546
547         }
548
549         wait4kids( -1 );
550
551         exit( EXIT_SUCCESS );
552 }
553
554 static char *
555 get_file_name( char *dirname, char *filename )
556 {
557         char buf[MAXPATHLEN];
558
559         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
560                 dirname, filename );
561         return( strdup( buf ));
562 }
563
564
565 static int
566 get_search_filters( char *filename, char *filters[], char *bases[] )
567 {
568         FILE    *fp;
569         int     filter = 0;
570
571         if ( (fp = fopen( filename, "r" )) != NULL ) {
572                 char  line[BUFSIZ];
573
574                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
575                         char *nl;
576
577                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
578                                 *nl = '\0';
579                         bases[filter] = ArgDup( line );
580                         fgets( line, BUFSIZ, fp );
581                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
582                                 *nl = '\0';
583
584                         filters[filter++] = ArgDup( line );
585
586                 }
587                 fclose( fp );
588         }
589
590         return( filter );
591 }
592
593
594 static int
595 get_read_entries( char *filename, char *entries[] )
596 {
597         FILE    *fp;
598         int     entry = 0;
599
600         if ( (fp = fopen( filename, "r" )) != NULL ) {
601                 char  line[BUFSIZ];
602
603                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
604                         char *nl;
605
606                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
607                                 *nl = '\0';
608                         entries[entry++] = ArgDup( line );
609
610                 }
611                 fclose( fp );
612         }
613
614         return( entry );
615 }
616
617 #ifndef HAVE_WINSOCK
618 static void
619 fork_child( char *prog, char **args )
620 {
621         pid_t   pid;
622
623         wait4kids( maxkids );
624
625         switch ( pid = fork() ) {
626         case 0:         /* child */
627 #ifdef HAVE_EBCDIC
628                 /* The __LIBASCII execvp only handles ASCII "prog",
629                  * we still need to translate the arg vec ourselves.
630                  */
631                 { char *arg2[MAXREQS];
632                 int i;
633
634                 for (i=0; args[i]; i++) {
635                         arg2[i] = ArgDup(args[i]);
636                         __atoe(arg2[i]);
637                 }
638                 arg2[i] = NULL;
639                 args = arg2; }
640 #endif
641                 execvp( prog, args );
642                 tester_perror( "execvp" );
643                 exit( EXIT_FAILURE );
644                 break;
645
646         case -1:        /* trouble */
647                 tester_perror( "fork" );
648                 break;
649
650         default:        /* parent */
651                 nkids++;
652                 break;
653         }
654 }
655
656 static void
657 wait4kids( int nkidval )
658 {
659         int             status;
660
661         while ( nkids >= nkidval ) {
662                 wait( &status );
663
664                 if ( WIFSTOPPED(status) ) {
665                         fprintf( stderr,
666                             "stopping: child stopped with signal %d\n",
667                             (int) WSTOPSIG(status) );
668
669                 } else if ( WIFSIGNALED(status) ) {
670                         fprintf( stderr, 
671                             "stopping: child terminated with signal %d%s\n",
672                             (int) WTERMSIG(status),
673 #ifdef WCOREDUMP
674                                 WCOREDUMP(status) ? ", core dumped" : ""
675 #else
676                                 ""
677 #endif
678                                 );
679                         exit( WEXITSTATUS(status)  );
680
681                 } else if ( WEXITSTATUS(status) != 0 ) {
682                         fprintf( stderr, 
683                             "stopping: child exited with status %d\n",
684                             (int) WEXITSTATUS(status) );
685                         exit( WEXITSTATUS(status) );
686
687                 } else {
688                         nkids--;
689                 }
690         }
691 }
692 #else
693
694 static void
695 wait4kids( int nkidval )
696 {
697         int rc, i;
698
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];
703                 nkids--;
704         }
705 }
706
707 static void
708 fork_child( char *prog, char **args )
709 {
710         int rc;
711
712         wait4kids( maxkids );
713
714         rc = _spawnvp( _P_NOWAIT, prog, args );
715
716         if ( rc == -1 ) {
717                 tester_perror( "_spawnvp" );
718         } else {
719                 children[nkids++] = (HANDLE)rc;
720         }
721 }
722 #endif