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