Fix the build.
[jra/samba/.git] / source4 / torture / smbtorture.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester
4    Copyright (C) Andrew Tridgell 1997-2003
5    Copyright (C) Jelmer Vernooij 2006-2008
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "lib/cmdline/popt_common.h"
23 #include "system/time.h"
24 #include "system/wait.h"
25 #include "system/filesys.h"
26 #include "system/readline.h"
27 #include "lib/smbreadline/smbreadline.h"
28 #include "libcli/libcli.h"
29 #include "lib/ldb/include/ldb.h"
30 #include "lib/events/events.h"
31 #include "dynconfig/dynconfig.h"
32
33 #include "torture/smbtorture.h"
34 #include "../lib/util/dlinklist.h"
35 #include "librpc/rpc/dcerpc.h"
36 #include "auth/gensec/gensec.h"
37 #include "param/param.h"
38
39 #include "auth/credentials/credentials.h"
40
41 static bool run_matching(struct torture_context *torture,
42                                                  const char *prefix, 
43                                                  const char *expr,
44                                                  struct torture_suite *suite,
45                                                  bool *matched)
46 {
47         bool ret = true;
48
49         if (suite == NULL) {
50                 struct torture_suite *o;
51
52                 for (o = torture_root->children; o; o = o->next) {
53                         if (gen_fnmatch(expr, o->name) == 0) {
54                                 *matched = true;
55                                 reload_charcnv(torture->lp_ctx);
56                                 ret &= torture_run_suite(torture, o);
57                                 continue;
58                         }
59
60                         ret &= run_matching(torture, o->name, expr, o, matched);
61                 }
62         } else {
63                 char *name;
64                 struct torture_suite *c;
65                 struct torture_tcase *t;
66
67                 for (c = suite->children; c; c = c->next) {
68                         asprintf(&name, "%s-%s", prefix, c->name);
69
70                         if (gen_fnmatch(expr, name) == 0) {
71                                 *matched = true;
72                                 reload_charcnv(torture->lp_ctx);
73                                 torture->active_testname = talloc_strdup(torture, prefix);
74                                 ret &= torture_run_suite(torture, c);
75                                 free(name);
76                                 continue;
77                         }
78                         
79                         ret &= run_matching(torture, name, expr, c, matched);
80
81                         free(name);
82                 }
83
84                 for (t = suite->testcases; t; t = t->next) {
85                         asprintf(&name, "%s-%s", prefix, t->name);
86                         if (gen_fnmatch(expr, name) == 0) {
87                                 *matched = true;
88                                 reload_charcnv(torture->lp_ctx);
89                                 torture->active_testname = talloc_strdup(torture, prefix);
90                                 ret &= torture_run_tcase(torture, t);
91                                 talloc_free(torture->active_testname);
92                         }
93                         free(name);
94                 }
95         }
96
97         return ret;
98 }
99
100 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
101
102 /****************************************************************************
103 run a specified test or "ALL"
104 ****************************************************************************/
105 static bool run_test(struct torture_context *torture, const char *name)
106 {
107         bool ret = true;
108         bool matched = false;
109         struct torture_suite *o;
110
111         if (strequal(name, "ALL")) {
112                 for (o = torture_root->children; o; o = o->next) {
113                         ret &= torture_run_suite(torture, o);
114                 }
115                 return ret;
116         }
117
118         ret = run_matching(torture, NULL, name, NULL, &matched);
119
120         if (!matched) {
121                 printf("Unknown torture operation '%s'\n", name);
122                 return false;
123         }
124
125         return ret;
126 }
127
128 static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
129 {
130         char *host = NULL, *share = NULL;
131         struct dcerpc_binding *binding_struct;
132         NTSTATUS status;
133
134         /* see if its a RPC transport specifier */
135         if (!smbcli_parse_unc(target, NULL, &host, &share)) {
136                 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
137                 if (NT_STATUS_IS_ERR(status)) {
138                         d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
139                         return false;
140                 }
141                 lp_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
142                 if (lp_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
143                         lp_set_cmdline(lp_ctx, "torture:share", "IPC$");
144                 lp_set_cmdline(lp_ctx, "torture:binding", target);
145         } else {
146                 lp_set_cmdline(lp_ctx, "torture:host", host);
147                 lp_set_cmdline(lp_ctx, "torture:share", share);
148                 lp_set_cmdline(lp_ctx, "torture:binding", host);
149         }
150
151         return true;
152 }
153
154 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
155 {
156         char *userdn, *basedn, *secret;
157         char *p, *d;
158
159         /* retrievieng the userdn */
160         p = strchr_m(dns, '#');
161         if (!p) {
162                 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
163                 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
164                 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
165                 return;
166         }
167         userdn = strndup(dns, p - dns);
168         lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
169
170         /* retrieve the basedn */
171         d = p + 1;
172         p = strchr_m(d, '#');
173         if (!p) {
174                 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
175                 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
176                 return;
177         }
178         basedn = strndup(d, p - d);
179         lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
180
181         /* retrieve the secret */
182         p = p + 1;
183         if (!p) {
184                 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
185                 return;
186         }
187         secret = strdup(p);
188         lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
189
190         printf ("%s - %s - %s\n", userdn, basedn, secret);
191
192 }
193
194 static void print_test_list(void)
195 {
196         struct torture_suite *o;
197         struct torture_suite *s;
198         struct torture_tcase *t;
199
200         if (torture_root == NULL)
201                 return;
202
203         for (o = torture_root->children; o; o = o->next) {
204                 for (s = o->children; s; s = s->next) {
205                         printf("%s-%s\n", o->name, s->name);
206                 }
207
208                 for (t = o->testcases; t; t = t->next) {
209                         printf("%s-%s\n", o->name, t->name);
210                 }
211         }
212 }
213
214 _NORETURN_ static void usage(poptContext pc)
215 {
216         struct torture_suite *o;
217         struct torture_suite *s;
218         struct torture_tcase *t;
219         int i;
220
221         poptPrintUsage(pc, stdout, 0);
222         printf("\n");
223
224         printf("The binding format is:\n\n");
225
226         printf("  TRANSPORT:host[flags]\n\n");
227
228         printf("  where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
229         printf("  or ncalrpc for local connections.\n\n");
230
231         printf("  'host' is an IP or hostname or netbios name. If the binding string\n");
232         printf("  identifies the server side of an endpoint, 'host' may be an empty\n");
233         printf("  string.\n\n");
234
235         printf("  'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
236         printf("  a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
237         printf("  will be auto-determined.\n\n");
238
239         printf("  other recognised flags are:\n\n");
240
241         printf("    sign : enable ntlmssp signing\n");
242         printf("    seal : enable ntlmssp sealing\n");
243         printf("    connect : enable rpc connect level auth (auth, but no sign or seal)\n");
244         printf("    validate: enable the NDR validator\n");
245         printf("    print: enable debugging of the packets\n");
246         printf("    bigendian: use bigendian RPC\n");
247         printf("    padcheck: check reply data for non-zero pad bytes\n\n");
248
249         printf("  For example, these all connect to the samr pipe:\n\n");
250
251         printf("    ncacn_np:myserver\n");
252         printf("    ncacn_np:myserver[samr]\n");
253         printf("    ncacn_np:myserver[\\pipe\\samr]\n");
254         printf("    ncacn_np:myserver[/pipe/samr]\n");
255         printf("    ncacn_np:myserver[samr,sign,print]\n");
256         printf("    ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
257         printf("    ncacn_np:myserver[/pipe/samr,seal,validate]\n");
258         printf("    ncacn_np:\n");
259         printf("    ncacn_np:[/pipe/samr]\n\n");
260
261         printf("    ncacn_ip_tcp:myserver\n");
262         printf("    ncacn_ip_tcp:myserver[1024]\n");
263         printf("    ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
264
265         printf("    ncalrpc:\n\n");
266
267         printf("The UNC format is:\n\n");
268
269         printf("  //server/share\n\n");
270
271         printf("Tests are:");
272
273         if (torture_root == NULL) {
274             printf("NO TESTS LOADED\n");
275             exit(1);
276         }
277
278         for (o = torture_root->children; o; o = o->next) {
279                 printf("\n%s (%s):\n  ", o->description, o->name);
280
281                 i = 0;
282                 for (s = o->children; s; s = s->next) {
283                         if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
284                                 printf("\n  ");
285                                 i = 0;
286                         }
287                         i+=printf("%s-%s ", o->name, s->name);
288                 }
289
290                 for (t = o->testcases; t; t = t->next) {
291                         if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
292                                 printf("\n  ");
293                                 i = 0;
294                         }
295                         i+=printf("%s-%s ", o->name, t->name);
296                 }
297
298                 if (i) printf("\n");
299         }
300
301         printf("\nThe default test is ALL.\n");
302
303         exit(1);
304 }
305
306 _NORETURN_ static void max_runtime_handler(int sig)
307 {
308         DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
309         exit(1);
310 }
311
312 struct timeval last_suite_started;
313
314 static void simple_suite_start(struct torture_context *ctx,
315                                struct torture_suite *suite)
316 {
317         last_suite_started = timeval_current();
318         printf("Running %s\n", suite->name);
319 }
320
321 static void simple_suite_finish(struct torture_context *ctx,
322                                 struct torture_suite *suite)
323 {
324
325         printf("%s took %g secs\n\n", suite->name, 
326                    timeval_elapsed(&last_suite_started));
327 }
328
329 static void simple_test_result(struct torture_context *context, 
330                                enum torture_result res, const char *reason)
331 {
332         switch (res) {
333         case TORTURE_OK:
334                 if (reason)
335                         printf("OK: %s\n", reason);
336                 break;
337         case TORTURE_FAIL:
338                 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
339                 break;
340         case TORTURE_ERROR:
341                 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason); 
342                 break;
343         case TORTURE_SKIP:
344                 printf("SKIP: %s - %s\n", context->active_test->name, reason);
345                 break;
346         }
347 }
348
349 static void simple_comment(struct torture_context *test, 
350                            const char *comment)
351 {
352         printf("%s", comment);
353 }
354
355 static void simple_warning(struct torture_context *test, 
356                            const char *comment)
357 {
358         fprintf(stderr, "WARNING: %s\n", comment);
359 }
360
361 const static struct torture_ui_ops std_ui_ops = {
362         .comment = simple_comment,
363         .warning = simple_warning,
364         .suite_start = simple_suite_start,
365         .suite_finish = simple_suite_finish,
366         .test_result = simple_test_result
367 };
368
369
370 static void quiet_suite_start(struct torture_context *ctx,
371                               struct torture_suite *suite)
372 {
373         int i;
374         ctx->results->quiet = true;
375         for (i = 1; i < ctx->level; i++) putchar('\t');
376         printf("%s: ", suite->name);
377         fflush(stdout);
378 }
379
380 static void quiet_suite_finish(struct torture_context *ctx,
381                                struct torture_suite *suite)
382 {
383         putchar('\n');
384 }
385
386 static void quiet_test_result(struct torture_context *context, 
387                               enum torture_result res, const char *reason)
388 {
389         fflush(stdout);
390         switch (res) {
391         case TORTURE_OK: putchar('.'); break;
392         case TORTURE_FAIL: putchar('F'); break;
393         case TORTURE_ERROR: putchar('E'); break;
394         case TORTURE_SKIP: putchar('I'); break;
395         }
396 }
397
398 const static struct torture_ui_ops quiet_ui_ops = {
399         .suite_start = quiet_suite_start,
400         .suite_finish = quiet_suite_finish,
401         .test_result = quiet_test_result
402 };
403
404 static void run_shell(struct torture_context *tctx)
405 {
406         char *cline;
407         int argc;
408         const char **argv;
409         int ret;
410
411         while (1) {
412                 cline = smb_readline("torture> ", NULL, NULL);
413
414                 if (cline == NULL)
415                         return;
416         
417                 ret = poptParseArgvString(cline, &argc, &argv);
418                 if (ret != 0) {
419                         fprintf(stderr, "Error parsing line\n");
420                         continue;
421                 }
422
423                 if (!strcmp(argv[0], "quit")) {
424                         return;
425                 } else if (!strcmp(argv[0], "set")) {
426                         if (argc < 3) {
427                                 fprintf(stderr, "Usage: set <variable> <value>\n");
428                         } else {
429                                 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
430                                 lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
431                                 talloc_free(name);
432                         }
433                 } else if (!strcmp(argv[0], "help")) {
434                         fprintf(stderr, "Available commands:\n"
435                                                         " help - This help command\n"
436                                                         " run - Run test\n"
437                                                         " set - Change variables\n"
438                                                         "\n");
439                 } else if (!strcmp(argv[0], "run")) {
440                         if (argc < 2) {
441                                 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
442                         } else {
443                                 run_test(tctx, argv[1]);
444                         }
445                 }
446                 free(cline);
447         }
448 }
449
450 /****************************************************************************
451   main program
452 ****************************************************************************/
453 int main(int argc,char *argv[])
454 {
455         int opt, i;
456         bool correct = true;
457         int max_runtime=0;
458         int argc_new;
459         struct torture_context *torture;
460         struct torture_results *results;
461         const struct torture_ui_ops *ui_ops;
462         char **argv_new;
463         poptContext pc;
464         static const char *target = "other";
465         NTSTATUS status;
466         int shell = false;
467         static const char *ui_ops_name = "simple";
468         const char *basedir = NULL;
469         const char *extra_module = NULL;
470         static int list_tests = 0;
471         int num_extra_users = 0;
472         enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
473               OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS,OPT_EXTRA_USER};
474         
475         struct poptOption long_options[] = {
476                 POPT_AUTOHELP
477                 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
478                 {"smb-ports",   'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,  "SMB ports",    NULL},
479                 {"basedir",       0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
480                 {"seed",          0, POPT_ARG_INT,  &torture_seed,      0,      "Seed to use for randomizer",   NULL},
481                 {"num-progs",     0, POPT_ARG_INT,  NULL,       OPT_NUMPROGS,   "num progs",    NULL},
482                 {"num-ops",       0, POPT_ARG_INT,  &torture_numops,    0,      "num ops",      NULL},
483                 {"entries",       0, POPT_ARG_INT,  &torture_entries,   0,      "entries",      NULL},
484                 {"loadfile",      0, POPT_ARG_STRING,   NULL,   OPT_LOADFILE,   "NBench load file to use",      NULL},
485                 {"list",          0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
486                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
487                 {"timelimit",   't', POPT_ARG_INT,      NULL,   OPT_TIMELIMIT,  "Set time limit (in seconds)",  NULL},
488                 {"failures",    'f', POPT_ARG_INT,  &torture_failures,  0,      "failures",     NULL},
489                 {"parse-dns",   'D', POPT_ARG_STRING,   NULL,   OPT_DNS,        "parse-dns",    NULL},
490                 {"dangerous",   'X', POPT_ARG_NONE,     NULL,   OPT_DANGEROUS,
491                  "run dangerous tests (eg. wiping out password database)", NULL},
492                 {"load-module",  0,  POPT_ARG_STRING, &extra_module,     0, "load tests from DSO file",    "SOFILE"},
493                 {"shell",               0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
494                 {"target",              'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
495                 {"async",       'a', POPT_ARG_NONE,     NULL,   OPT_ASYNC,
496                  "run async tests", NULL},
497                 {"num-async",    0, POPT_ARG_INT,  &torture_numasync,  0,
498                  "number of simultaneous async requests", NULL},
499                 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, 
500                  "set maximum time for smbtorture to live", "seconds"},
501                 {"extra-user",   0, POPT_ARG_STRING, NULL, OPT_EXTRA_USER,
502                  "extra user credentials", NULL},
503                 POPT_COMMON_SAMBA
504                 POPT_COMMON_CONNECTION
505                 POPT_COMMON_CREDENTIALS
506                 POPT_COMMON_VERSION
507                 { NULL }
508         };
509
510         setlinebuf(stdout);
511
512         /* we are never interested in SIGPIPE */
513         BlockSignals(true, SIGPIPE);
514
515         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
516                             POPT_CONTEXT_KEEP_FIRST);
517
518         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
519
520         while((opt = poptGetNextOpt(pc)) != -1) {
521                 switch (opt) {
522                 case OPT_LOADFILE:
523                         lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
524                         break;
525                 case OPT_UNCLIST:
526                         lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
527                         break;
528                 case OPT_TIMELIMIT:
529                         lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
530                         break;
531                 case OPT_NUMPROGS:
532                         lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
533                         break;
534                 case OPT_DNS:
535                         parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
536                         break;
537                 case OPT_DANGEROUS:
538                         lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
539                         break;
540                 case OPT_ASYNC:
541                         lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
542                         break;
543                 case OPT_SMB_PORTS:
544                         lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
545                         break;
546                 case OPT_EXTRA_USER:
547                         {
548                                 char *option = talloc_asprintf(NULL, "torture:extra_user%u",
549                                                                ++num_extra_users);
550                                 char *value = poptGetOptArg(pc);
551                                 lp_set_cmdline(cmdline_lp_ctx, option, value);
552                                 talloc_free(option);
553                         }
554                         break;
555                 }
556         }
557
558         if (strcmp(target, "samba3") == 0) {
559                 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
560         } else if (strcmp(target, "samba4") == 0) {
561                 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
562         }
563
564         if (max_runtime) {
565                 /* this will only work if nobody else uses alarm(),
566                    which means it won't work for some tests, but we
567                    can't use the event context method we use for smbd
568                    as so many tests create their own event
569                    context. This will at least catch most cases. */
570                 signal(SIGALRM, max_runtime_handler);
571                 alarm(max_runtime);
572         }
573
574         if (extra_module != NULL) {
575             init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
576
577             if (fn == NULL) 
578                 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
579             else {
580                 status = fn();
581                 if (NT_STATUS_IS_ERR(status)) {
582                     d_printf("Error initializing module %s: %s\n", 
583                              poptGetOptArg(pc), nt_errstr(status));
584                 }
585             }
586         } else { 
587                 torture_init();
588         }
589
590         if (list_tests) {
591                 print_test_list();
592                 return 0;
593         }
594
595         if (torture_seed == 0) {
596                 torture_seed = time(NULL);
597         } 
598         printf("Using seed %d\n", torture_seed);
599         srandom(torture_seed);
600
601         argv_new = discard_const_p(char *, poptGetArgs(pc));
602
603         argc_new = argc;
604         for (i=0; i<argc; i++) {
605                 if (argv_new[i] == NULL) {
606                         argc_new = i;
607                         break;
608                 }
609         }
610
611         if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
612                 usage(pc);
613                 exit(1);
614         }
615
616         if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
617                 usage(pc);
618                 exit(1);
619         }
620
621         if (!strcmp(ui_ops_name, "simple")) {
622                 ui_ops = &std_ui_ops;
623         } else if (!strcmp(ui_ops_name, "subunit")) {
624                 ui_ops = &torture_subunit_ui_ops;
625         } else if (!strcmp(ui_ops_name, "quiet")) {
626                 ui_ops = &quiet_ui_ops;
627         } else {
628                 printf("Unknown output format '%s'\n", ui_ops_name);
629                 exit(1);
630         }
631
632         results = torture_results_init(talloc_autofree_context(), ui_ops);
633
634         torture = torture_context_init(s4_event_context_init(NULL), results);
635         if (basedir != NULL) {
636                 if (basedir[0] != '/') {
637                         fprintf(stderr, "Please specify an absolute path to --basedir\n");
638                         return 1;
639                 }
640                 torture->outputdir = basedir;
641         } else {
642                 char *pwd = talloc_size(torture, PATH_MAX);
643                 if (!getcwd(pwd, PATH_MAX)) {
644                         fprintf(stderr, "Unable to determine current working directory\n");
645                         return 1;
646                 }
647                 torture->outputdir = pwd;
648         }
649
650         torture->lp_ctx = cmdline_lp_ctx;
651
652         gensec_init(cmdline_lp_ctx);
653
654         if (argc_new == 0) {
655                 printf("You must specify a test to run, or 'ALL'\n");
656         } else if (shell) {
657                 run_shell(torture);
658         } else {
659                 for (i=2;i<argc_new;i++) {
660                         if (!run_test(torture, argv_new[i])) {
661                                 correct = false;
662                         }
663                 }
664         }
665
666         if (torture->results->returncode && correct) {
667                 return(0);
668         } else {
669                 return(1);
670         }
671 }