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