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