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)
239 printf("Testing %s\n", tcase->name);
242 static void simple_test_start (struct torture_context *ctx,
243 struct torture_tcase *tcase,
244 struct torture_test *test)
246 printf("Testing %s/%s\n", tcase->name, test->name);
249 static void simple_test_result (struct torture_context *context,
250 enum torture_result res, const char *reason)
255 printf("OK: %s\n", reason);
258 printf("ERROR: %s - %s\n", context->active_test->name, reason);
261 printf("TODO: %s - %s\n", context->active_test->name, reason);
264 printf("SKIP: %s - %s\n", context->active_test->name, reason);
270 static void simple_comment (struct torture_context *test, const char *comment)
272 printf("# %s\n", comment);
275 const static struct torture_ui_ops std_ui_ops = {
276 .comment = simple_comment,
277 .test_start = simple_test_start,
278 .tcase_start = simple_tcase_start,
279 .test_result = simple_test_result
283 static void subunit_test_start (struct torture_context *ctx,
284 struct torture_tcase *tcase,
285 struct torture_test *test)
287 printf("test: %s\n", test->name);
290 static void subunit_test_result (struct torture_context *context,
291 enum torture_result res, const char *reason)
295 printf("success: %s\n", context->active_test->name);
298 printf("failure: %s [ %s ]\n", context->active_test->name, reason);
301 printf("todo: %s\n", context->active_test->name);
304 printf("skip: %s\n", context->active_test->name);
309 static void subunit_comment (struct torture_context *test, const char *comment)
311 printf("# %s\n", comment);
314 const static struct torture_ui_ops subunit_ui_ops = {
315 .comment = subunit_comment,
316 .test_start = subunit_test_start,
317 .test_result = subunit_test_result
320 static void harness_test_start (struct torture_context *ctx,
321 struct torture_tcase *tcase,
322 struct torture_test *test)
326 static void harness_test_result (struct torture_context *context,
327 enum torture_result res, const char *reason)
331 printf("ok %s - %s\n", context->active_test->name, reason);
334 printf("not ok %s - %s\n", context->active_test->name, reason);
337 printf("todo %s - %s\n", context->active_test->name, reason);
340 printf("skip %s - %s\n", context->active_test->name, reason);
345 static void harness_comment (struct torture_context *test, const char *comment)
347 printf("# %s\n", comment);
350 const static struct torture_ui_ops harness_ui_ops = {
351 .comment = harness_comment,
352 .test_start = harness_test_start,
353 .test_result = harness_test_result
356 static void quiet_test_start (struct torture_context *ctx,
357 struct torture_tcase *tcase,
358 struct torture_test *test)
363 const static struct torture_ui_ops quiet_ui_ops = {
364 .test_start = quiet_test_start,
368 /****************************************************************************
370 ****************************************************************************/
371 int main(int argc,char *argv[])
378 struct torture_context *torture;
381 static const char *ui_ops_name = "simple";
382 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS,
383 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC};
385 struct poptOption long_options[] = {
387 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit, harness)", NULL },
388 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
389 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "seed", NULL},
390 {"num-progs", 0, POPT_ARG_INT, &torture_nprocs, 0, "num progs", NULL},
391 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
392 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
393 {"use-oplocks", 'L', POPT_ARG_NONE, &use_oplocks, 0, "use oplocks", NULL},
394 {"show-all", 0, POPT_ARG_NONE, &torture_showall, 0, "show all", NULL},
395 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "loadfile", NULL},
396 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
397 {"timelimit", 't', POPT_ARG_STRING, NULL, OPT_TIMELIMIT, "timelimit", NULL},
398 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
399 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
400 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
401 "run dangerous tests (eg. wiping out password database)", NULL},
402 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
403 "run async tests", NULL},
404 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
405 "number of simultaneous async requests", NULL},
406 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
407 "set maximum time for smbtorture to live", "seconds"},
409 POPT_COMMON_CONNECTION
410 POPT_COMMON_CREDENTIALS
415 #ifdef HAVE_SETBUFFER
416 setbuffer(stdout, NULL, 0);
419 /* we are never interested in SIGPIPE */
420 BlockSignals(True,SIGPIPE);
422 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
423 POPT_CONTEXT_KEEP_FIRST);
425 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
427 while((opt = poptGetNextOpt(pc)) != -1) {
430 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
433 lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
436 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
439 parse_dns(poptGetOptArg(pc));
442 lp_set_cmdline("torture:dangerous", "Yes");
445 lp_set_cmdline("torture:async", "Yes");
448 lp_set_cmdline("smb ports", poptGetOptArg(pc));
451 d_printf("Invalid option %s: %s\n",
452 poptBadOption(pc, 0), poptStrerror(opt));
460 /* this will only work if nobody else uses alarm(),
461 which means it won't work for some tests, but we
462 can't use the event context method we use for smbd
463 as so many tests create their own event
464 context. This will at least catch most cases. */
465 signal(SIGALRM, max_runtime_handler);
472 if (torture_seed == 0) {
473 torture_seed = time(NULL);
475 printf("Using seed %d\n", torture_seed);
476 srandom(torture_seed);
478 argv_new = discard_const_p(char *, poptGetArgs(pc));
481 for (i=0; i<argc; i++) {
482 if (argv_new[i] == NULL) {
493 for(p = argv_new[1]; *p; p++) {
498 /* see if its a RPC transport specifier */
499 if (is_binding_string(argv_new[1])) {
500 lp_set_cmdline("torture:binding", argv_new[1]);
502 char *binding = NULL;
503 char *host = NULL, *share = NULL;
505 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
506 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
510 lp_set_cmdline("torture:host", host);
511 lp_set_cmdline("torture:share", share);
512 asprintf(&binding, "ncacn_np:%s", host);
513 lp_set_cmdline("torture:binding", binding);
516 torture = talloc_zero(NULL, struct torture_context);
517 if (!strcmp(ui_ops_name, "simple")) {
518 torture->ui_ops = &std_ui_ops;
519 } else if (!strcmp(ui_ops_name, "subunit")) {
520 torture->ui_ops = &subunit_ui_ops;
521 } else if (!strcmp(ui_ops_name, "harness")) {
522 torture->ui_ops = &harness_ui_ops;
523 } else if (!strcmp(ui_ops_name, "quiet")) {
524 torture->ui_ops = &quiet_ui_ops;
526 printf("Unknown output format '%s'\n", ui_ops_name);
531 printf("You must specify a test to run, or 'ALL'\n");
533 for (i=2;i<argc_new;i++) {
534 if (!run_test(torture, argv_new[i])) {
540 talloc_free(torture);