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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "lib/cmdline/popt_common.h"
24 #include "system/time.h"
25 #include "system/wait.h"
26 #include "system/filesys.h"
27 #include "libcli/libcli.h"
28 #include "lib/ldb/include/ldb.h"
29 #include "lib/events/events.h"
31 #include "torture/torture.h"
32 #include "torture/ui.h"
34 #include "dlinklist.h"
35 #include "librpc/rpc/dcerpc.h"
37 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
39 /****************************************************************************
40 run a specified test or "ALL"
41 ****************************************************************************/
42 static BOOL run_test(struct torture_context *torture, const char *name)
48 if (strequal(name,"ALL")) {
49 for (o = torture_ops; o; o = o->next) {
50 if (!run_test(torture, o->name)) {
57 for (o = torture_ops; o; o = o->next) {
58 if (gen_fnmatch(name, o->name) == 0) {
62 printf("Running %s\n", o->name);
65 t = torture_create_procs(o->multi_fn,
69 printf("TEST %s FAILED!\n", o->name);
73 struct timeval tv = timeval_current();
74 if (!o->fn(torture)) {
76 printf("TEST %s FAILED!\n", o->name);
78 t = timeval_elapsed(&tv);
80 printf("%s took %g secs\n\n", o->name, t);
85 printf("Unknown torture operation '%s'\n", name);
92 static void parse_dns(const char *dns)
94 char *userdn, *basedn, *secret;
97 /* retrievieng the userdn */
98 p = strchr_m(dns, '#');
100 lp_set_cmdline("torture:ldap_userdn", "");
101 lp_set_cmdline("torture:ldap_basedn", "");
102 lp_set_cmdline("torture:ldap_secret", "");
105 userdn = strndup(dns, p - dns);
106 lp_set_cmdline("torture:ldap_userdn", userdn);
108 /* retrieve the basedn */
110 p = strchr_m(d, '#');
112 lp_set_cmdline("torture:ldap_basedn", "");
113 lp_set_cmdline("torture:ldap_secret", "");
116 basedn = strndup(d, p - d);
117 lp_set_cmdline("torture:ldap_basedn", basedn);
119 /* retrieve the secret */
122 lp_set_cmdline("torture:ldap_secret", "");
126 lp_set_cmdline("torture:ldap_secret", secret);
128 printf ("%s - %s - %s\n", userdn, basedn, secret);
132 static void usage(poptContext pc)
134 struct torture_op *o;
135 char last_prefix[64];
138 poptPrintUsage(pc, stdout, 0);
141 printf("The binding format is:\n\n");
143 printf(" TRANSPORT:host[flags]\n\n");
145 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
146 printf(" or ncalrpc for local connections.\n\n");
148 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
149 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
150 printf(" string.\n\n");
152 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
153 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
154 printf(" will be auto-determined.\n\n");
156 printf(" other recognised flags are:\n\n");
158 printf(" sign : enable ntlmssp signing\n");
159 printf(" seal : enable ntlmssp sealing\n");
160 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
161 printf(" validate: enable the NDR validator\n");
162 printf(" print: enable debugging of the packets\n");
163 printf(" bigendian: use bigendian RPC\n");
164 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
166 printf(" For example, these all connect to the samr pipe:\n\n");
168 printf(" ncacn_np:myserver\n");
169 printf(" ncacn_np:myserver[samr]\n");
170 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
171 printf(" ncacn_np:myserver[/pipe/samr]\n");
172 printf(" ncacn_np:myserver[samr,sign,print]\n");
173 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
174 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
175 printf(" ncacn_np:\n");
176 printf(" ncacn_np:[/pipe/samr]\n\n");
178 printf(" ncacn_ip_tcp:myserver\n");
179 printf(" ncacn_ip_tcp:myserver[1024]\n");
180 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
182 printf(" ncalrpc:\n\n");
184 printf("The UNC format is:\n\n");
186 printf(" //server/share\n\n");
188 printf("Tests are:");
191 last_prefix[0] = '\0';
192 for (o = torture_ops; o; o = o->next) {
195 if ((sep = strchr(o->name, '-'))) {
196 if (strncmp(o->name, last_prefix, sep - o->name) != 0) {
197 strncpy(last_prefix, o->name,
198 MIN(sizeof(last_prefix),
205 if (i + strlen(o->name) >= (MAX_COLS - 2)) {
209 i+=printf("%s ", o->name);
213 printf("The default test is ALL.\n");
218 static BOOL is_binding_string(const char *binding_string)
220 TALLOC_CTX *mem_ctx = talloc_init("is_binding_string");
221 struct dcerpc_binding *binding_struct;
224 status = dcerpc_parse_binding(mem_ctx, binding_string, &binding_struct);
226 talloc_free(mem_ctx);
227 return NT_STATUS_IS_OK(status);
230 static void max_runtime_handler(int sig)
232 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
236 static void simple_tcase_start (struct torture_context *ctx,
237 struct torture_tcase *tcase,
238 struct torture_test *test)
240 printf("Testing %s...\n", tcase->name);
243 static void simple_test_start (struct torture_context *ctx,
244 struct torture_tcase *tcase,
245 struct torture_test *test)
247 printf("Testing %s/%s...\n", tcase->name, test->name);
250 static void simple_test_result (struct torture_context *context,
251 enum torture_result res, const char *reason)
256 printf("OK: %s\n", reason);
259 printf("ERROR: %s - %s\n", context->active_test->name, reason);
262 printf("TODO: %s - %s\n", context->active_test->name, reason);
265 printf("SKIP: %s - %s\n", context->active_test->name, reason);
271 static void simple_comment (struct torture_context *test, const char *comment)
273 printf("# %s\n", comment);
276 const static struct torture_ui_ops std_ui_ops = {
277 .comment = simple_comment,
278 .test_start = simple_test_start,
279 .tcase_start = simple_tcase_start,
280 .test_result = simple_test_result
284 static void subunit_test_start (struct torture_context *ctx,
285 struct torture_tcase *tcase,
286 struct torture_test *test)
288 printf("test: %s\n", test->name);
291 static void subunit_test_result (struct torture_context *context,
292 enum torture_result res, const char *reason)
296 printf("success: %s\n", context->active_test->name);
299 printf("failure: %s [ %s ]\n", context->active_test->name, reason);
302 printf("todo: %s\n", context->active_test->name);
305 printf("skip: %s\n", context->active_test->name);
310 static void subunit_comment (struct torture_context *test, const char *comment)
312 printf("# %s\n", comment);
315 const static struct torture_ui_ops subunit_ui_ops = {
316 .comment = subunit_comment,
317 .test_start = subunit_test_start,
318 .test_result = subunit_test_result
321 static void harness_test_start (struct torture_context *ctx,
322 struct torture_tcase *tcase,
323 struct torture_test *test)
327 static void harness_test_result (struct torture_context *context,
328 enum torture_result res, const char *reason)
332 printf("ok %s - %s\n", context->active_test->name, reason);
335 printf("not ok %s - %s\n", context->active_test->name, reason);
338 printf("todo %s - %s\n", context->active_test->name, reason);
341 printf("skip %s - %s\n", context->active_test->name, reason);
346 static void harness_comment (struct torture_context *test, const char *comment)
348 printf("# %s\n", comment);
351 const static struct torture_ui_ops harness_ui_ops = {
352 .comment = harness_comment,
353 .test_start = harness_test_start,
354 .test_result = harness_test_result
357 /****************************************************************************
359 ****************************************************************************/
360 int main(int argc,char *argv[])
367 struct torture_context *torture;
370 static const char *ui_ops_name = "simple";
371 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS,
372 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC};
374 struct poptOption long_options[] = {
376 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit, harness)", NULL },
377 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
378 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "seed", NULL},
379 {"num-progs", 0, POPT_ARG_INT, &torture_nprocs, 0, "num progs", NULL},
380 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
381 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
382 {"use-oplocks", 'L', POPT_ARG_NONE, &use_oplocks, 0, "use oplocks", NULL},
383 {"show-all", 0, POPT_ARG_NONE, &torture_showall, 0, "show all", NULL},
384 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "loadfile", NULL},
385 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
386 {"timelimit", 't', POPT_ARG_STRING, NULL, OPT_TIMELIMIT, "timelimit", NULL},
387 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
388 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
389 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
390 "run dangerous tests (eg. wiping out password database)", NULL},
391 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
392 "run async tests", NULL},
393 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
394 "number of simultaneous async requests", NULL},
395 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
396 "set maximum time for smbtorture to live", "seconds"},
398 POPT_COMMON_CONNECTION
399 POPT_COMMON_CREDENTIALS
404 #ifdef HAVE_SETBUFFER
405 setbuffer(stdout, NULL, 0);
408 /* we are never interested in SIGPIPE */
409 BlockSignals(True,SIGPIPE);
411 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
412 POPT_CONTEXT_KEEP_FIRST);
414 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
416 while((opt = poptGetNextOpt(pc)) != -1) {
419 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
422 lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
425 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
428 parse_dns(poptGetOptArg(pc));
431 lp_set_cmdline("torture:dangerous", "Yes");
434 lp_set_cmdline("torture:async", "Yes");
437 lp_set_cmdline("smb ports", poptGetOptArg(pc));
440 d_printf("Invalid option %s: %s\n",
441 poptBadOption(pc, 0), poptStrerror(opt));
449 /* this will only work if nobody else uses alarm(),
450 which means it won't work for some tests, but we
451 can't use the event context method we use for smbd
452 as so many tests create their own event
453 context. This will at least catch most cases. */
454 signal(SIGALRM, max_runtime_handler);
461 if (torture_seed == 0) {
462 torture_seed = time(NULL);
464 printf("Using seed %d\n", torture_seed);
465 srandom(torture_seed);
467 argv_new = discard_const_p(char *, poptGetArgs(pc));
470 for (i=0; i<argc; i++) {
471 if (argv_new[i] == NULL) {
482 for(p = argv_new[1]; *p; p++) {
487 /* see if its a RPC transport specifier */
488 if (is_binding_string(argv_new[1])) {
489 lp_set_cmdline("torture:binding", argv_new[1]);
491 char *binding = NULL;
492 char *host = NULL, *share = NULL;
494 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
495 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
499 lp_set_cmdline("torture:host", host);
500 lp_set_cmdline("torture:share", share);
501 asprintf(&binding, "ncacn_np:%s", host);
502 lp_set_cmdline("torture:binding", binding);
505 torture = talloc_zero(NULL, struct torture_context);
506 if (!strcmp(ui_ops_name, "simple")) {
507 torture->ui_ops = &std_ui_ops;
508 } else if (!strcmp(ui_ops_name, "subunit")) {
509 torture->ui_ops = &subunit_ui_ops;
510 } else if (!strcmp(ui_ops_name, "harness")) {
511 torture->ui_ops = &harness_ui_ops;
513 printf("Unknown output format '%s'\n", ui_ops_name);
518 printf("You must specify a test to run, or 'ALL'\n");
520 for (i=2;i<argc_new;i++) {
521 if (!run_test(torture, argv_new[i])) {
527 talloc_free(torture);