]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
rework tester common error logging and so
[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         tester_init( "slapd-tester" );
158
159         while ( (i = getopt( argc, argv, "D:d:FH:h:j:l:P:p:r:t:w:" )) != EOF ) {
160                 switch( i ) {
161                 case 'D':               /* slapd manager */
162                         manager = ArgDup( optarg );
163                         break;
164
165                 case 'd':               /* data directory */
166                         dirname = strdup( optarg );
167                         break;
168
169                 case 'F':
170                         friendly++;
171                         break;
172
173                 case 'H':               /* slapd uri */
174                         uri = strdup( optarg );
175                         break;
176
177                 case 'h':               /* slapd host */
178                         host = strdup( optarg );
179                         break;
180
181                 case 'j':               /* the number of parallel clients */
182                         if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
183                                 usage( argv[0] );
184                         }
185                         break;
186
187                 case 'l':               /* the number of loops per client */
188                         loops = strdup( optarg );
189                         break;
190
191                 case 'P':               /* prog directory */
192                         progdir = strdup( optarg );
193                         break;
194
195                 case 'p':               /* the servers port number */
196                         port = strdup( optarg );
197                         break;
198
199                 case 'r':               /* the number of retries in case of error */
200                         retries = strdup( optarg );
201                         break;
202
203                 case 't':               /* the delay in seconds between each retry */
204                         delay = strdup( optarg );
205                         break;
206
207                 case 'w':               /* the managers passwd */
208                         passwd = ArgDup( optarg );
209                         break;
210
211                 default:
212                         usage( argv[0] );
213                         break;
214                 }
215         }
216
217         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
218                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
219                 usage( argv[0] );
220
221 #ifdef HAVE_WINSOCK
222         children = malloc( maxkids * sizeof(HANDLE) );
223 #endif
224         /* get the file list */
225         if ( ( datadir = opendir( dirname )) == NULL ) {
226
227                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
228                                         argv[0], dirname );
229                 exit( EXIT_FAILURE );
230
231         }
232
233         /*  look for search, read, modrdn, and add/delete files */
234         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
235
236                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
237                         sfile = get_file_name( dirname, file->d_name );
238                         continue;
239                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
240                         rfile = get_file_name( dirname, file->d_name );
241                         continue;
242                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
243                         mfile = get_file_name( dirname, file->d_name );
244                         continue;
245                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
246                         modfile = get_file_name( dirname, file->d_name );
247                         continue;
248                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
249                         && ( anum < MAXREQS )) {
250                         afiles[anum++] = get_file_name( dirname, file->d_name );
251                         continue;
252                 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
253                         bfile = get_file_name( dirname, file->d_name );
254                         continue;
255                 }
256         }
257
258         closedir( datadir );
259
260         /* look for search requests */
261         if ( sfile ) {
262                 snum = get_search_filters( sfile, sreqs, sbase );
263         }
264
265         /* look for read requests */
266         if ( rfile ) {
267                 rnum = get_read_entries( rfile, rreqs );
268         }
269
270         /* look for modrdn requests */
271         if ( mfile ) {
272                 mnum = get_read_entries( mfile, mreqs );
273         }
274
275         /* look for modify requests */
276         if ( modfile ) {
277                 modnum = get_search_filters( modfile, modreqs, moddn );
278         }
279
280         /* look for bind requests */
281         if ( bfile ) {
282                 bnum = get_search_filters( bfile, bcreds, breqs );
283         }
284
285         /*
286          * generate the search clients
287          */
288
289         sanum = 0;
290         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
291                 progdir );
292         sargs[sanum++] = scmd;
293         if ( uri ) {
294                 sargs[sanum++] = "-H";
295                 sargs[sanum++] = uri;
296         } else {
297                 sargs[sanum++] = "-h";
298                 sargs[sanum++] = host;
299                 sargs[sanum++] = "-p";
300                 sargs[sanum++] = port;
301         }
302         sargs[sanum++] = "-D";
303         sargs[sanum++] = manager;
304         sargs[sanum++] = "-w";
305         sargs[sanum++] = passwd;
306         sargs[sanum++] = "-l";
307         sargs[sanum++] = loops;
308         sargs[sanum++] = "-r";
309         sargs[sanum++] = retries;
310         sargs[sanum++] = "-t";
311         sargs[sanum++] = delay;
312         sargs[sanum++] = "-b";
313         sargs[sanum++] = NULL;          /* will hold the search base */
314         sargs[sanum++] = "-f";
315         sargs[sanum++] = NULL;          /* will hold the search request */
316         sargs[sanum++] = NULL;
317
318         /*
319          * generate the read clients
320          */
321
322         ranum = 0;
323         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
324                 progdir );
325         rargs[ranum++] = rcmd;
326         if ( uri ) {
327                 rargs[ranum++] = "-H";
328                 rargs[ranum++] = uri;
329         } else {
330                 rargs[ranum++] = "-h";
331                 rargs[ranum++] = host;
332                 rargs[ranum++] = "-p";
333                 rargs[ranum++] = port;
334         }
335         rargs[ranum++] = "-l";
336         rargs[ranum++] = loops;
337         rargs[ranum++] = "-r";
338         rargs[ranum++] = retries;
339         rargs[ranum++] = "-t";
340         rargs[ranum++] = delay;
341         rargs[ranum++] = "-e";
342         rargs[ranum++] = NULL;          /* will hold the read entry */
343         rargs[ranum++] = NULL;
344
345         /*
346          * generate the modrdn clients
347          */
348
349         manum = 0;
350         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
351                 progdir );
352         margs[manum++] = mcmd;
353         if ( uri ) {
354                 margs[manum++] = "-H";
355                 margs[manum++] = uri;
356         } else {
357                 margs[manum++] = "-h";
358                 margs[manum++] = host;
359                 margs[manum++] = "-p";
360                 margs[manum++] = port;
361         }
362         margs[manum++] = "-D";
363         margs[manum++] = manager;
364         margs[manum++] = "-w";
365         margs[manum++] = passwd;
366         margs[manum++] = "-l";
367         margs[manum++] = loops;
368         margs[manum++] = "-r";
369         margs[manum++] = retries;
370         margs[manum++] = "-t";
371         margs[manum++] = delay;
372         if ( friendly ) {
373                 margs[manum++] = "-F";
374         }
375         margs[manum++] = "-e";
376         margs[manum++] = NULL;          /* will hold the modrdn entry */
377         margs[manum++] = NULL;
378         
379         /*
380          * generate the modify clients
381          */
382
383         modanum = 0;
384         snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
385                 progdir );
386         modargs[modanum++] = modcmd;
387         if ( uri ) {
388                 modargs[modanum++] = "-H";
389                 modargs[modanum++] = uri;
390         } else {
391                 modargs[modanum++] = "-h";
392                 modargs[modanum++] = host;
393                 modargs[modanum++] = "-p";
394                 modargs[modanum++] = port;
395         }
396         modargs[modanum++] = "-D";
397         modargs[modanum++] = manager;
398         modargs[modanum++] = "-w";
399         modargs[modanum++] = passwd;
400         modargs[modanum++] = "-l";
401         modargs[modanum++] = loops;
402         modargs[modanum++] = "-r";
403         modargs[modanum++] = retries;
404         modargs[modanum++] = "-t";
405         modargs[modanum++] = delay;
406         if ( friendly ) {
407                 modargs[modanum++] = "-F";
408         }
409         modargs[modanum++] = "-e";
410         modargs[modanum++] = NULL;              /* will hold the modify entry */
411         modargs[modanum++] = "-a";;
412         modargs[modanum++] = NULL;              /* will hold the ava */
413         modargs[modanum++] = NULL;
414
415         /*
416          * generate the add/delete clients
417          */
418
419         aanum = 0;
420         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
421                 progdir );
422         aargs[aanum++] = acmd;
423         if ( uri ) {
424                 aargs[aanum++] = "-H";
425                 aargs[aanum++] = uri;
426         } else {
427                 aargs[aanum++] = "-h";
428                 aargs[aanum++] = host;
429                 aargs[aanum++] = "-p";
430                 aargs[aanum++] = port;
431         }
432         aargs[aanum++] = "-D";
433         aargs[aanum++] = manager;
434         aargs[aanum++] = "-w";
435         aargs[aanum++] = passwd;
436         aargs[aanum++] = "-l";
437         aargs[aanum++] = loops;
438         aargs[aanum++] = "-r";
439         aargs[aanum++] = retries;
440         aargs[aanum++] = "-t";
441         aargs[aanum++] = delay;
442         if ( friendly ) {
443                 aargs[aanum++] = "-F";
444         }
445         aargs[aanum++] = "-f";
446         aargs[aanum++] = NULL;          /* will hold the add data file */
447         aargs[aanum++] = NULL;
448
449         /*
450          * generate the bind clients
451          */
452
453         banum = 0;
454         snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
455                 progdir );
456         bargs[banum++] = bcmd;
457         if ( uri ) {
458                 bargs[banum++] = "-H";
459                 bargs[banum++] = uri;
460         } else {
461                 bargs[banum++] = "-h";
462                 bargs[banum++] = host;
463                 bargs[banum++] = "-p";
464                 bargs[banum++] = port;
465         }
466         bargs[banum++] = "-l";
467         bargs[banum++] = loops;
468 #if 0
469         bargs[banum++] = "-r";
470         bargs[banum++] = retries;
471         bargs[banum++] = "-t";
472         bargs[banum++] = delay;
473 #endif
474         if ( friendly ) {
475                 bargs[banum++] = "-F";
476         }
477         bargs[banum++] = "-D";
478         bargs[banum++] = NULL;
479         bargs[banum++] = "-w";
480         bargs[banum++] = NULL;
481         bargs[banum++] = NULL;
482
483         for ( j = 0; j < MAXREQS; j++ ) {
484                 if ( j < snum ) {
485
486                         sargs[sanum - 2] = sreqs[j];
487                         sargs[sanum - 4] = sbase[j];
488                         fork_child( scmd, sargs );
489
490                 }
491
492                 if ( j < rnum ) {
493
494                         rargs[ranum - 2] = rreqs[j];
495                         fork_child( rcmd, rargs );
496
497                 }
498
499                 if ( j < mnum ) {
500
501                         margs[manum - 2] = mreqs[j];
502                         fork_child( mcmd, margs );
503
504                 }
505                 if ( j < modnum ) {
506
507                         modargs[modanum - 4] = moddn[j];
508                         modargs[modanum - 2] = modreqs[j];
509                         fork_child( modcmd, modargs );
510
511                 }
512
513                 if ( j < anum ) {
514
515                         aargs[aanum - 2] = afiles[j];
516                         fork_child( acmd, aargs );
517
518                 }
519
520                 if ( j < bnum ) {
521
522                         bargs[banum - 4] = breqs[j];
523                         bargs[banum - 2] = bcreds[j];
524                         fork_child( bcmd, bargs );
525
526                 }
527
528         }
529
530         wait4kids( -1 );
531
532         exit( EXIT_SUCCESS );
533 }
534
535 static char *
536 get_file_name( char *dirname, char *filename )
537 {
538         char buf[MAXPATHLEN];
539
540         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
541                 dirname, filename );
542         return( strdup( buf ));
543 }
544
545
546 static int
547 get_search_filters( char *filename, char *filters[], char *bases[] )
548 {
549         FILE    *fp;
550         int     filter = 0;
551
552         if ( (fp = fopen( filename, "r" )) != NULL ) {
553                 char  line[BUFSIZ];
554
555                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
556                         char *nl;
557
558                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
559                                 *nl = '\0';
560                         bases[filter] = ArgDup( line );
561                         fgets( line, BUFSIZ, fp );
562                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
563                                 *nl = '\0';
564
565                         filters[filter++] = ArgDup( line );
566
567                 }
568                 fclose( fp );
569         }
570
571         return( filter );
572 }
573
574
575 static int
576 get_read_entries( char *filename, char *entries[] )
577 {
578         FILE    *fp;
579         int     entry = 0;
580
581         if ( (fp = fopen( filename, "r" )) != NULL ) {
582                 char  line[BUFSIZ];
583
584                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
585                         char *nl;
586
587                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
588                                 *nl = '\0';
589                         entries[entry++] = ArgDup( line );
590
591                 }
592                 fclose( fp );
593         }
594
595         return( entry );
596 }
597
598 #ifndef HAVE_WINSOCK
599 static void
600 fork_child( char *prog, char **args )
601 {
602         pid_t   pid;
603
604         wait4kids( maxkids );
605
606         switch ( pid = fork() ) {
607         case 0:         /* child */
608 #ifdef HAVE_EBCDIC
609                 /* The __LIBASCII execvp only handles ASCII "prog",
610                  * we still need to translate the arg vec ourselves.
611                  */
612                 { char *arg2[MAXREQS];
613                 int i;
614
615                 for (i=0; args[i]; i++) {
616                         arg2[i] = ArgDup(args[i]);
617                         __atoe(arg2[i]);
618                 }
619                 arg2[i] = NULL;
620                 args = arg2; }
621 #endif
622                 execvp( prog, args );
623                 tester_perror( "execvp" );
624                 exit( EXIT_FAILURE );
625                 break;
626
627         case -1:        /* trouble */
628                 tester_perror( "fork" );
629                 break;
630
631         default:        /* parent */
632                 nkids++;
633                 break;
634         }
635 }
636
637 static void
638 wait4kids( int nkidval )
639 {
640         int             status;
641
642         while ( nkids >= nkidval ) {
643                 wait( &status );
644
645                 if ( WIFSTOPPED(status) ) {
646                         fprintf( stderr,
647                             "stopping: child stopped with signal %d\n",
648                             (int) WSTOPSIG(status) );
649
650                 } else if ( WIFSIGNALED(status) ) {
651                         fprintf( stderr, 
652                             "stopping: child terminated with signal %d%s\n",
653                             (int) WTERMSIG(status),
654 #ifdef WCOREDUMP
655                                 WCOREDUMP(status) ? ", core dumped" : ""
656 #else
657                                 ""
658 #endif
659                                 );
660                         exit( WEXITSTATUS(status)  );
661
662                 } else if ( WEXITSTATUS(status) != 0 ) {
663                         fprintf( stderr, 
664                             "stopping: child exited with status %d\n",
665                             (int) WEXITSTATUS(status) );
666                         exit( WEXITSTATUS(status) );
667
668                 } else {
669                         nkids--;
670                 }
671         }
672 }
673 #else
674
675 static void
676 wait4kids( int nkidval )
677 {
678         int rc, i;
679
680         while ( nkids >= nkidval ) {
681                 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
682                 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
683                         children[i] = children[i+1];
684                 nkids--;
685         }
686 }
687
688 static void
689 fork_child( char *prog, char **args )
690 {
691         int rc;
692
693         wait4kids( maxkids );
694
695         rc = _spawnvp( _P_NOWAIT, prog, args );
696
697         if ( rc == -1 ) {
698                 tester_perror( "_spawnvp" );
699         } else {
700                 children[nkids++] = (HANDLE)rc;
701         }
702 }
703 #endif