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