r25513: don't hide warnings in subunit mode
[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
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 static void subunit_warning(struct torture_context *test,
384                             const char *comment)
385 {
386         fprintf(stderr, "WARNING!: %s\n", comment);
387 }
388
389 const static struct torture_ui_ops subunit_ui_ops = {
390         .init = subunit_init,
391         .comment = subunit_comment,
392         .warning = subunit_warning,
393         .test_start = subunit_test_start,
394         .test_result = subunit_test_result,
395         .suite_start = subunit_suite_start
396 };
397
398 static void quiet_suite_start(struct torture_context *ctx,
399                               struct torture_suite *suite)
400 {
401         int i;
402         ctx->quiet = true;
403         for (i = 1; i < ctx->level; i++) putchar('\t');
404         printf("%s: ", suite->name);
405         fflush(stdout);
406 }
407
408 static void quiet_suite_finish(struct torture_context *ctx,
409                                struct torture_suite *suite)
410 {
411         putchar('\n');
412 }
413
414 static void quiet_test_result(struct torture_context *context, 
415                               enum torture_result res, const char *reason)
416 {
417         fflush(stdout);
418         switch (res) {
419         case TORTURE_OK: putchar('.'); break;
420         case TORTURE_FAIL: putchar('F'); break;
421         case TORTURE_ERROR: putchar('E'); break;
422         case TORTURE_SKIP: putchar('I'); break;
423         }
424 }
425
426 const static struct torture_ui_ops quiet_ui_ops = {
427         .suite_start = quiet_suite_start,
428         .suite_finish = quiet_suite_finish,
429         .test_result = quiet_test_result
430 };
431
432 void run_shell(struct torture_context *tctx)
433 {
434         char *cline;
435         int argc;
436         const char **argv;
437         int ret;
438
439         while (1) {
440                 cline = smb_readline("torture> ", NULL, NULL);
441
442                 if (cline == NULL)
443                         return;
444         
445                 ret = poptParseArgvString(cline, &argc, &argv);
446                 if (ret != 0) {
447                         fprintf(stderr, "Error parsing line\n");
448                         continue;
449                 }
450
451                 if (!strcmp(argv[0], "quit")) {
452                         return;
453                 } else if (!strcmp(argv[0], "set")) {
454                         if (argc < 3) {
455                                 fprintf(stderr, "Usage: set <variable> <value>\n");
456                         } else {
457                                 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
458                                 lp_set_cmdline(global_loadparm, name, argv[2]);
459                                 talloc_free(name);
460                         }
461                 } else if (!strcmp(argv[0], "help")) {
462                         fprintf(stderr, "Available commands:\n"
463                                                         " help - This help command\n"
464                                                         " run - Run test\n"
465                                                         " set - Change variables\n"
466                                                         "\n");
467                 } else if (!strcmp(argv[0], "run")) {
468                         if (argc < 2) {
469                                 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
470                         } else {
471                                 run_test(tctx, argv[1]);
472                         }
473                 }
474         }
475 }
476
477 /****************************************************************************
478   main program
479 ****************************************************************************/
480 int main(int argc,char *argv[])
481 {
482         int opt, i;
483         bool correct = true;
484         int max_runtime=0;
485         int argc_new;
486         struct torture_context *torture;
487         const struct torture_ui_ops *ui_ops;
488         char **argv_new;
489         poptContext pc;
490         static const char *target = "other";
491         struct dcerpc_binding *binding_struct;
492         NTSTATUS status;
493         int shell = False;
494         static const char *ui_ops_name = "simple";
495         const char *basedir = NULL;
496         const char *extra_module = NULL;
497         static int list_tests = 0;
498         char *host = NULL, *share = NULL;
499         enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
500               OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
501         
502         struct poptOption long_options[] = {
503                 POPT_AUTOHELP
504                 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
505                 {"smb-ports",   'p', POPT_ARG_STRING, NULL,     OPT_SMB_PORTS,  "SMB ports",    NULL},
506                 {"basedir",       0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
507                 {"seed",          0, POPT_ARG_INT,  &torture_seed,      0,      "seed",         NULL},
508                 {"num-progs",     0, POPT_ARG_INT,  NULL,       OPT_NUMPROGS,   "num progs",    NULL},
509                 {"num-ops",       0, POPT_ARG_INT,  &torture_numops,    0,      "num ops",      NULL},
510                 {"entries",       0, POPT_ARG_INT,  &torture_entries,   0,      "entries",      NULL},
511                 {"loadfile",      0, POPT_ARG_STRING,   NULL,   OPT_LOADFILE,   "loadfile",     NULL},
512                 {"list",          0, POPT_ARG_NONE, &list_tests, 0, NULL, NULL },
513                 {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
514                 {"timelimit",   't', POPT_ARG_INT,      NULL,   OPT_TIMELIMIT,  "timelimit",    NULL},
515                 {"failures",    'f', POPT_ARG_INT,  &torture_failures,  0,      "failures",     NULL},
516                 {"parse-dns",   'D', POPT_ARG_STRING,   NULL,   OPT_DNS,        "parse-dns",    NULL},
517                 {"dangerous",   'X', POPT_ARG_NONE,     NULL,   OPT_DANGEROUS,
518                  "run dangerous tests (eg. wiping out password database)", NULL},
519                 {"load-module",  0,  POPT_ARG_STRING, &extra_module,     0, "load tests from DSO file",    "SOFILE"},
520                 {"shell",               0, POPT_ARG_NONE, &shell, True, "Run shell", NULL},
521                 {"target",              'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
522                 {"async",       'a', POPT_ARG_NONE,     NULL,   OPT_ASYNC,
523                  "run async tests", NULL},
524                 {"num-async",    0, POPT_ARG_INT,  &torture_numasync,  0,
525                  "number of simultaneous async requests", NULL},
526                 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0, 
527                  "set maximum time for smbtorture to live", "seconds"},
528                 POPT_COMMON_SAMBA
529                 POPT_COMMON_CONNECTION
530                 POPT_COMMON_CREDENTIALS
531                 POPT_COMMON_VERSION
532                 { NULL }
533         };
534
535         setlinebuf(stdout);
536
537         /* we are never interested in SIGPIPE */
538         BlockSignals(true, SIGPIPE);
539
540         pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options, 
541                             POPT_CONTEXT_KEEP_FIRST);
542
543         poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
544
545         while((opt = poptGetNextOpt(pc)) != -1) {
546                 switch (opt) {
547                 case OPT_LOADFILE:
548                         lp_set_cmdline(global_loadparm, "torture:loadfile", poptGetOptArg(pc));
549                         break;
550                 case OPT_UNCLIST:
551                         lp_set_cmdline(global_loadparm, "torture:unclist", poptGetOptArg(pc));
552                         break;
553                 case OPT_TIMELIMIT:
554                         lp_set_cmdline(global_loadparm, "torture:timelimit", poptGetOptArg(pc));
555                         break;
556                 case OPT_NUMPROGS:
557                         lp_set_cmdline(global_loadparm, "torture:nprocs", poptGetOptArg(pc));
558                         break;
559                 case OPT_DNS:
560                         parse_dns(poptGetOptArg(pc));
561                         break;
562                 case OPT_DANGEROUS:
563                         lp_set_cmdline(global_loadparm, "torture:dangerous", "Yes");
564                         break;
565                 case OPT_ASYNC:
566                         lp_set_cmdline(global_loadparm, "torture:async", "Yes");
567                         break;
568                 case OPT_SMB_PORTS:
569                         lp_set_cmdline(global_loadparm, "smb ports", poptGetOptArg(pc));
570                         break;
571                 }
572         }
573
574         if (strcmp(target, "samba3") == 0) {
575                 lp_set_cmdline(global_loadparm, "torture:samba3", "true");
576         } else if (strcmp(target, "samba4") == 0) {
577                 lp_set_cmdline(global_loadparm, "torture:samba4", "true");
578         }
579
580         if (max_runtime) {
581                 /* this will only work if nobody else uses alarm(),
582                    which means it won't work for some tests, but we
583                    can't use the event context method we use for smbd
584                    as so many tests create their own event
585                    context. This will at least catch most cases. */
586                 signal(SIGALRM, max_runtime_handler);
587                 alarm(max_runtime);
588         }
589
590         ldb_global_init();
591
592         if (extra_module != NULL) {
593             init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
594
595             if (fn == NULL) 
596                 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
597             else {
598                 status = fn();
599                 if (NT_STATUS_IS_ERR(status)) {
600                     d_printf("Error initializing module %s: %s\n", 
601                              poptGetOptArg(pc), nt_errstr(status));
602                 }
603             }
604         } else { 
605                 torture_init();
606         }
607
608         if (list_tests) {
609                 print_test_list();
610                 return 0;
611         }
612
613         if (torture_seed == 0) {
614                 torture_seed = time(NULL);
615         } 
616         printf("Using seed %d\n", torture_seed);
617         srandom(torture_seed);
618
619         argv_new = discard_const_p(char *, poptGetArgs(pc));
620
621         argc_new = argc;
622         for (i=0; i<argc; i++) {
623                 if (argv_new[i] == NULL) {
624                         argc_new = i;
625                         break;
626                 }
627         }
628
629         if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
630                 usage(pc);
631                 exit(1);
632         }
633
634         /* see if its a RPC transport specifier */
635         if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
636                 status = dcerpc_parse_binding(talloc_autofree_context(), argv_new[1], &binding_struct);
637                 if (NT_STATUS_IS_ERR(status)) {
638                         d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
639                         usage(pc);
640                         return false;
641                 }
642                 lp_set_cmdline(global_loadparm, "torture:host", binding_struct->host);
643                 if (lp_parm_string(global_loadparm, NULL, "torture", "share") == NULL)
644                         lp_set_cmdline(global_loadparm, "torture:share", "IPC$");
645                 lp_set_cmdline(global_loadparm, "torture:binding", argv_new[1]);
646         } else {
647                 lp_set_cmdline(global_loadparm, "torture:host", host);
648                 lp_set_cmdline(global_loadparm, "torture:share", share);
649                 lp_set_cmdline(global_loadparm, "torture:binding", host);
650         }
651
652         if (!strcmp(ui_ops_name, "simple")) {
653                 ui_ops = &std_ui_ops;
654         } else if (!strcmp(ui_ops_name, "subunit")) {
655                 ui_ops = &subunit_ui_ops;
656         } else if (!strcmp(ui_ops_name, "quiet")) {
657                 ui_ops = &quiet_ui_ops;
658         } else {
659                 printf("Unknown output format '%s'\n", ui_ops_name);
660                 exit(1);
661         }
662
663         torture = torture_context_init(talloc_autofree_context(), ui_ops);
664         if (basedir != NULL) {
665                 if (basedir[0] != '/') {
666                         fprintf(stderr, "Please specify an absolute path to --basedir\n");
667                         return 1;
668                 }
669                 torture->outputdir = basedir;
670         } else {
671                 char *pwd = talloc_size(torture, PATH_MAX);
672                 if (!getcwd(pwd, PATH_MAX)) {
673                         fprintf(stderr, "Unable to determine current working directory\n");
674                         return 1;
675                 }
676                 torture->outputdir = pwd;
677         }
678
679         if (argc_new == 0) {
680                 printf("You must specify a test to run, or 'ALL'\n");
681         } else if (shell) {
682                 run_shell(torture);
683         } else {
684                 for (i=2;i<argc_new;i++) {
685                         if (!run_test(torture, argv_new[i])) {
686                                 correct = false;
687                         }
688                 }
689         }
690
691         if (torture->returncode && correct) {
692                 return(0);
693         } else {
694                 return(1);
695         }
696 }