2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1997-2003
5 Copyright (C) Jelmer Vernooij 2006
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.
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.
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/>.
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"
33 #include "torture/torture.h"
34 #include "lib/util/dlinklist.h"
35 #include "librpc/rpc/dcerpc.h"
36 #include "param/param.h"
38 static bool run_matching(struct torture_context *torture,
41 struct torture_suite *suite,
47 struct torture_suite *o;
49 for (o = torture_root->children; o; o = o->next) {
50 if (gen_fnmatch(expr, o->name) == 0) {
52 reload_charcnv(torture->lp_ctx);
53 ret &= torture_run_suite(torture, o);
57 ret &= run_matching(torture, o->name, expr, o, matched);
61 struct torture_suite *c;
62 struct torture_tcase *t;
64 for (c = suite->children; c; c = c->next) {
65 asprintf(&name, "%s-%s", prefix, c->name);
67 if (gen_fnmatch(expr, name) == 0) {
69 reload_charcnv(torture->lp_ctx);
70 torture->active_testname = talloc_strdup(torture, prefix);
71 ret &= torture_run_suite(torture, c);
76 ret &= run_matching(torture, name, expr, c, matched);
81 for (t = suite->testcases; t; t = t->next) {
82 asprintf(&name, "%s-%s", prefix, t->name);
83 if (gen_fnmatch(expr, name) == 0) {
85 reload_charcnv(torture->lp_ctx);
86 torture->active_testname = talloc_strdup(torture, prefix);
87 ret &= torture_run_tcase(torture, t);
88 talloc_free(torture->active_testname);
97 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
99 /****************************************************************************
100 run a specified test or "ALL"
101 ****************************************************************************/
102 static bool run_test(struct torture_context *torture, const char *name)
105 bool matched = false;
106 struct torture_suite *o;
108 if (strequal(name, "ALL")) {
109 for (o = torture_root->children; o; o = o->next) {
110 ret &= torture_run_suite(torture, o);
115 ret = run_matching(torture, NULL, name, NULL, &matched);
118 printf("Unknown torture operation '%s'\n", name);
125 static bool parse_target(struct loadparm_context *lp_ctx, const char *target)
127 char *host = NULL, *share = NULL;
128 struct dcerpc_binding *binding_struct;
131 /* see if its a RPC transport specifier */
132 if (!smbcli_parse_unc(target, NULL, &host, &share)) {
133 status = dcerpc_parse_binding(talloc_autofree_context(), target, &binding_struct);
134 if (NT_STATUS_IS_ERR(status)) {
135 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", target);
138 lp_set_cmdline(lp_ctx, "torture:host", binding_struct->host);
139 if (lp_parm_string(lp_ctx, NULL, "torture", "share") == NULL)
140 lp_set_cmdline(lp_ctx, "torture:share", "IPC$");
141 lp_set_cmdline(lp_ctx, "torture:binding", target);
143 lp_set_cmdline(lp_ctx, "torture:host", host);
144 lp_set_cmdline(lp_ctx, "torture:share", share);
145 lp_set_cmdline(lp_ctx, "torture:binding", host);
151 static void parse_dns(struct loadparm_context *lp_ctx, const char *dns)
153 char *userdn, *basedn, *secret;
156 /* retrievieng the userdn */
157 p = strchr_m(dns, '#');
159 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", "");
160 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
161 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
164 userdn = strndup(dns, p - dns);
165 lp_set_cmdline(lp_ctx, "torture:ldap_userdn", userdn);
167 /* retrieve the basedn */
169 p = strchr_m(d, '#');
171 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", "");
172 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
175 basedn = strndup(d, p - d);
176 lp_set_cmdline(lp_ctx, "torture:ldap_basedn", basedn);
178 /* retrieve the secret */
181 lp_set_cmdline(lp_ctx, "torture:ldap_secret", "");
185 lp_set_cmdline(lp_ctx, "torture:ldap_secret", secret);
187 printf ("%s - %s - %s\n", userdn, basedn, secret);
191 static void print_test_list(void)
193 struct torture_suite *o;
194 struct torture_suite *s;
195 struct torture_tcase *t;
197 if (torture_root == NULL)
200 for (o = torture_root->children; o; o = o->next) {
201 for (s = o->children; s; s = s->next) {
202 printf("%s-%s\n", o->name, s->name);
205 for (t = o->testcases; t; t = t->next) {
206 printf("%s-%s\n", o->name, t->name);
211 _NORETURN_ static void usage(poptContext pc)
213 struct torture_suite *o;
214 struct torture_suite *s;
215 struct torture_tcase *t;
218 poptPrintUsage(pc, stdout, 0);
221 printf("The binding format is:\n\n");
223 printf(" TRANSPORT:host[flags]\n\n");
225 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
226 printf(" or ncalrpc for local connections.\n\n");
228 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
229 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
230 printf(" string.\n\n");
232 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
233 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
234 printf(" will be auto-determined.\n\n");
236 printf(" other recognised flags are:\n\n");
238 printf(" sign : enable ntlmssp signing\n");
239 printf(" seal : enable ntlmssp sealing\n");
240 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
241 printf(" validate: enable the NDR validator\n");
242 printf(" print: enable debugging of the packets\n");
243 printf(" bigendian: use bigendian RPC\n");
244 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
246 printf(" For example, these all connect to the samr pipe:\n\n");
248 printf(" ncacn_np:myserver\n");
249 printf(" ncacn_np:myserver[samr]\n");
250 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
251 printf(" ncacn_np:myserver[/pipe/samr]\n");
252 printf(" ncacn_np:myserver[samr,sign,print]\n");
253 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
254 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
255 printf(" ncacn_np:\n");
256 printf(" ncacn_np:[/pipe/samr]\n\n");
258 printf(" ncacn_ip_tcp:myserver\n");
259 printf(" ncacn_ip_tcp:myserver[1024]\n");
260 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
262 printf(" ncalrpc:\n\n");
264 printf("The UNC format is:\n\n");
266 printf(" //server/share\n\n");
268 printf("Tests are:");
270 if (torture_root == NULL) {
271 printf("NO TESTS LOADED\n");
275 for (o = torture_root->children; o; o = o->next) {
276 printf("\n%s (%s):\n ", o->description, o->name);
279 for (s = o->children; s; s = s->next) {
280 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
284 i+=printf("%s-%s ", o->name, s->name);
287 for (t = o->testcases; t; t = t->next) {
288 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
292 i+=printf("%s-%s ", o->name, t->name);
298 printf("\nThe default test is ALL.\n");
303 _NORETURN_ static void max_runtime_handler(int sig)
305 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
309 struct timeval last_suite_started;
311 static void simple_suite_start(struct torture_context *ctx,
312 struct torture_suite *suite)
314 last_suite_started = timeval_current();
315 printf("Running %s\n", suite->name);
318 static void simple_suite_finish(struct torture_context *ctx,
319 struct torture_suite *suite)
322 printf("%s took %g secs\n\n", suite->name,
323 timeval_elapsed(&last_suite_started));
326 static void simple_test_result(struct torture_context *context,
327 enum torture_result res, const char *reason)
332 printf("OK: %s\n", reason);
335 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
338 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
341 printf("SKIP: %s - %s\n", context->active_test->name, reason);
346 static void simple_comment(struct torture_context *test,
349 printf("%s", comment);
352 static void simple_warning(struct torture_context *test,
355 fprintf(stderr, "WARNING: %s\n", comment);
358 const static struct torture_ui_ops std_ui_ops = {
359 .comment = simple_comment,
360 .warning = simple_warning,
361 .suite_start = simple_suite_start,
362 .suite_finish = simple_suite_finish,
363 .test_result = simple_test_result
366 static void subunit_init(struct torture_context *ctx)
368 /* FIXME: register segv and bus handler */
371 static void subunit_suite_start(struct torture_context *ctx,
372 struct torture_suite *suite)
376 static void subunit_test_start(struct torture_context *ctx,
377 struct torture_tcase *tcase,
378 struct torture_test *test)
380 printf("test: %s\n", test->name);
383 static void subunit_test_result(struct torture_context *context,
384 enum torture_result res, const char *reason)
388 printf("success: %s", context->active_test->name);
391 printf("failure: %s", context->active_test->name);
394 printf("error: %s", context->active_test->name);
397 printf("skip: %s", context->active_test->name);
401 printf(" [\n%s\n]", reason);
405 static void subunit_comment(struct torture_context *test,
408 fprintf(stderr, "%s", comment);
411 static void subunit_warning(struct torture_context *test,
414 fprintf(stderr, "WARNING!: %s\n", comment);
417 const static struct torture_ui_ops subunit_ui_ops = {
418 .init = subunit_init,
419 .comment = subunit_comment,
420 .warning = subunit_warning,
421 .test_start = subunit_test_start,
422 .test_result = subunit_test_result,
423 .suite_start = subunit_suite_start
426 static void quiet_suite_start(struct torture_context *ctx,
427 struct torture_suite *suite)
431 for (i = 1; i < ctx->level; i++) putchar('\t');
432 printf("%s: ", suite->name);
436 static void quiet_suite_finish(struct torture_context *ctx,
437 struct torture_suite *suite)
442 static void quiet_test_result(struct torture_context *context,
443 enum torture_result res, const char *reason)
447 case TORTURE_OK: putchar('.'); break;
448 case TORTURE_FAIL: putchar('F'); break;
449 case TORTURE_ERROR: putchar('E'); break;
450 case TORTURE_SKIP: putchar('I'); break;
454 const static struct torture_ui_ops quiet_ui_ops = {
455 .suite_start = quiet_suite_start,
456 .suite_finish = quiet_suite_finish,
457 .test_result = quiet_test_result
460 void run_shell(struct torture_context *tctx)
468 cline = smb_readline("torture> ", NULL, NULL);
473 ret = poptParseArgvString(cline, &argc, &argv);
475 fprintf(stderr, "Error parsing line\n");
479 if (!strcmp(argv[0], "quit")) {
481 } else if (!strcmp(argv[0], "set")) {
483 fprintf(stderr, "Usage: set <variable> <value>\n");
485 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
486 lp_set_cmdline(tctx->lp_ctx, name, argv[2]);
489 } else if (!strcmp(argv[0], "help")) {
490 fprintf(stderr, "Available commands:\n"
491 " help - This help command\n"
493 " set - Change variables\n"
495 } else if (!strcmp(argv[0], "run")) {
497 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
499 run_test(tctx, argv[1]);
506 /****************************************************************************
508 ****************************************************************************/
509 int main(int argc,char *argv[])
515 struct torture_context *torture;
516 const struct torture_ui_ops *ui_ops;
519 static const char *target = "other";
522 static const char *ui_ops_name = "simple";
523 const char *basedir = NULL;
524 const char *extra_module = NULL;
525 static int list_tests = 0;
526 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_LIST,
527 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
529 struct poptOption long_options[] = {
531 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit)", NULL },
532 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
533 {"basedir", 0, POPT_ARG_STRING, &basedir, 0, "base directory", "BASEDIR" },
534 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "Seed to use for randomizer", NULL},
535 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
536 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
537 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
538 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "NBench load file to use", NULL},
539 {"list", 0, POPT_ARG_NONE, &list_tests, 0, "List available tests and exit", NULL },
540 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
541 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "Set time limit (in seconds)", NULL},
542 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
543 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
544 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
545 "run dangerous tests (eg. wiping out password database)", NULL},
546 {"load-module", 0, POPT_ARG_STRING, &extra_module, 0, "load tests from DSO file", "SOFILE"},
547 {"shell", 0, POPT_ARG_NONE, &shell, true, "Run shell", NULL},
548 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
549 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
550 "run async tests", NULL},
551 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
552 "number of simultaneous async requests", NULL},
553 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
554 "set maximum time for smbtorture to live", "seconds"},
556 POPT_COMMON_CONNECTION
557 POPT_COMMON_CREDENTIALS
564 /* we are never interested in SIGPIPE */
565 BlockSignals(true, SIGPIPE);
567 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
568 POPT_CONTEXT_KEEP_FIRST);
570 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
572 while((opt = poptGetNextOpt(pc)) != -1) {
575 lp_set_cmdline(cmdline_lp_ctx, "torture:loadfile", poptGetOptArg(pc));
578 lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
581 lp_set_cmdline(cmdline_lp_ctx, "torture:timelimit", poptGetOptArg(pc));
584 lp_set_cmdline(cmdline_lp_ctx, "torture:nprocs", poptGetOptArg(pc));
587 parse_dns(cmdline_lp_ctx, poptGetOptArg(pc));
590 lp_set_cmdline(cmdline_lp_ctx, "torture:dangerous", "Yes");
593 lp_set_cmdline(cmdline_lp_ctx, "torture:async", "Yes");
596 lp_set_cmdline(cmdline_lp_ctx, "smb ports", poptGetOptArg(pc));
601 if (strcmp(target, "samba3") == 0) {
602 lp_set_cmdline(cmdline_lp_ctx, "torture:samba3", "true");
603 } else if (strcmp(target, "samba4") == 0) {
604 lp_set_cmdline(cmdline_lp_ctx, "torture:samba4", "true");
608 /* this will only work if nobody else uses alarm(),
609 which means it won't work for some tests, but we
610 can't use the event context method we use for smbd
611 as so many tests create their own event
612 context. This will at least catch most cases. */
613 signal(SIGALRM, max_runtime_handler);
617 if (extra_module != NULL) {
618 init_module_fn fn = load_module(talloc_autofree_context(), poptGetOptArg(pc));
621 d_printf("Unable to load module from %s\n", poptGetOptArg(pc));
624 if (NT_STATUS_IS_ERR(status)) {
625 d_printf("Error initializing module %s: %s\n",
626 poptGetOptArg(pc), nt_errstr(status));
638 if (torture_seed == 0) {
639 torture_seed = time(NULL);
641 printf("Using seed %d\n", torture_seed);
642 srandom(torture_seed);
644 argv_new = discard_const_p(char *, poptGetArgs(pc));
647 for (i=0; i<argc; i++) {
648 if (argv_new[i] == NULL) {
654 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
659 if (!parse_target(cmdline_lp_ctx, argv_new[1])) {
664 if (!strcmp(ui_ops_name, "simple")) {
665 ui_ops = &std_ui_ops;
666 } else if (!strcmp(ui_ops_name, "subunit")) {
667 ui_ops = &subunit_ui_ops;
668 } else if (!strcmp(ui_ops_name, "quiet")) {
669 ui_ops = &quiet_ui_ops;
671 printf("Unknown output format '%s'\n", ui_ops_name);
675 torture = torture_context_init(talloc_autofree_context(), ui_ops);
676 if (basedir != NULL) {
677 if (basedir[0] != '/') {
678 fprintf(stderr, "Please specify an absolute path to --basedir\n");
681 torture->outputdir = basedir;
683 char *pwd = talloc_size(torture, PATH_MAX);
684 if (!getcwd(pwd, PATH_MAX)) {
685 fprintf(stderr, "Unable to determine current working directory\n");
688 torture->outputdir = pwd;
691 torture->lp_ctx = cmdline_lp_ctx;
694 printf("You must specify a test to run, or 'ALL'\n");
698 for (i=2;i<argc_new;i++) {
699 if (!run_test(torture, argv_new[i])) {
705 if (torture->returncode && correct) {