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