r21439: fix compiler warnings
[Samba/ekacnet.git] / source4 / torture / util_smb.c
blob75fa9648f42404b8eaf73048794ac8019c422cfd
1 /*
2 Unix SMB/CIFS implementation.
3 SMB torture tester utility functions
4 Copyright (C) Andrew Tridgell 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.
22 #include "includes.h"
23 #include "lib/cmdline/popt_common.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/raw/ioctl.h"
26 #include "libcli/libcli.h"
27 #include "system/filesys.h"
28 #include "system/shmem.h"
29 #include "system/wait.h"
30 #include "system/time.h"
31 #include "torture/ui.h"
32 #include "torture/torture.h"
33 #include "util/dlinklist.h"
36 /**
37 setup a directory ready for a test
39 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
41 smb_raw_exit(cli->session);
42 if (smbcli_deltree(cli->tree, dname) == -1 ||
43 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
44 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
45 return False;
47 return True;
51 create a directory, returning a handle to it
53 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
55 NTSTATUS status;
56 union smb_open io;
57 TALLOC_CTX *mem_ctx;
59 mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
61 io.generic.level = RAW_OPEN_NTCREATEX;
62 io.ntcreatex.in.root_fid = 0;
63 io.ntcreatex.in.flags = 0;
64 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
65 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
66 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
67 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
68 io.ntcreatex.in.alloc_size = 0;
69 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
70 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
71 io.ntcreatex.in.security_flags = 0;
72 io.ntcreatex.in.fname = dname;
74 status = smb_raw_open(tree, mem_ctx, &io);
75 talloc_free(mem_ctx);
77 if (NT_STATUS_IS_OK(status)) {
78 *fnum = io.ntcreatex.out.file.fnum;
81 return status;
85 /**
86 sometimes we need a fairly complex file to work with, so we can test
87 all possible attributes.
89 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
91 int fnum;
92 char buf[7] = "abc";
93 union smb_setfileinfo setfile;
94 union smb_fileinfo fileinfo;
95 time_t t = (time(NULL) & ~1);
96 NTSTATUS status;
98 smbcli_unlink(cli->tree, fname);
99 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
100 SEC_RIGHTS_FILE_ALL,
101 FILE_ATTRIBUTE_NORMAL,
102 NTCREATEX_SHARE_ACCESS_DELETE|
103 NTCREATEX_SHARE_ACCESS_READ|
104 NTCREATEX_SHARE_ACCESS_WRITE,
105 NTCREATEX_DISP_OVERWRITE_IF,
106 0, 0);
107 if (fnum == -1) return -1;
109 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
111 if (strchr(fname, ':') == NULL) {
112 /* setup some EAs */
113 setfile.generic.level = RAW_SFILEINFO_EA_SET;
114 setfile.generic.in.file.fnum = fnum;
115 setfile.ea_set.in.num_eas = 2;
116 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
117 setfile.ea_set.in.eas[0].flags = 0;
118 setfile.ea_set.in.eas[0].name.s = "EAONE";
119 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
120 setfile.ea_set.in.eas[1].flags = 0;
121 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
122 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
123 status = smb_raw_setfileinfo(cli->tree, &setfile);
124 if (!NT_STATUS_IS_OK(status)) {
125 printf("Failed to setup EAs\n");
129 /* make sure all the timestamps aren't the same, and are also
130 in different DST zones*/
131 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
132 setfile.generic.in.file.fnum = fnum;
134 setfile.setattre.in.create_time = t + 9*30*24*60*60;
135 setfile.setattre.in.access_time = t + 6*30*24*60*60;
136 setfile.setattre.in.write_time = t + 3*30*24*60*60;
138 status = smb_raw_setfileinfo(cli->tree, &setfile);
139 if (!NT_STATUS_IS_OK(status)) {
140 printf("Failed to setup file times - %s\n", nt_errstr(status));
143 /* make sure all the timestamps aren't the same */
144 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
145 fileinfo.generic.in.file.fnum = fnum;
147 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
148 if (!NT_STATUS_IS_OK(status)) {
149 printf("Failed to query file times - %s\n", nt_errstr(status));
152 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
153 printf("create_time not setup correctly\n");
155 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
156 printf("access_time not setup correctly\n");
158 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
159 printf("write_time not setup correctly\n");
162 return fnum;
167 sometimes we need a fairly complex directory to work with, so we can test
168 all possible attributes.
170 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
172 int fnum;
173 union smb_setfileinfo setfile;
174 union smb_fileinfo fileinfo;
175 time_t t = (time(NULL) & ~1);
176 NTSTATUS status;
178 smbcli_deltree(cli->tree, dname);
179 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
180 SEC_RIGHTS_DIR_ALL,
181 FILE_ATTRIBUTE_DIRECTORY,
182 NTCREATEX_SHARE_ACCESS_READ|
183 NTCREATEX_SHARE_ACCESS_WRITE,
184 NTCREATEX_DISP_OPEN_IF,
185 NTCREATEX_OPTIONS_DIRECTORY, 0);
186 if (fnum == -1) return -1;
188 if (strchr(dname, ':') == NULL) {
189 /* setup some EAs */
190 setfile.generic.level = RAW_SFILEINFO_EA_SET;
191 setfile.generic.in.file.fnum = fnum;
192 setfile.ea_set.in.num_eas = 2;
193 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
194 setfile.ea_set.in.eas[0].flags = 0;
195 setfile.ea_set.in.eas[0].name.s = "EAONE";
196 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
197 setfile.ea_set.in.eas[1].flags = 0;
198 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
199 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
200 status = smb_raw_setfileinfo(cli->tree, &setfile);
201 if (!NT_STATUS_IS_OK(status)) {
202 printf("Failed to setup EAs\n");
206 /* make sure all the timestamps aren't the same, and are also
207 in different DST zones*/
208 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
209 setfile.generic.in.file.fnum = fnum;
211 setfile.setattre.in.create_time = t + 9*30*24*60*60;
212 setfile.setattre.in.access_time = t + 6*30*24*60*60;
213 setfile.setattre.in.write_time = t + 3*30*24*60*60;
215 status = smb_raw_setfileinfo(cli->tree, &setfile);
216 if (!NT_STATUS_IS_OK(status)) {
217 printf("Failed to setup file times - %s\n", nt_errstr(status));
220 /* make sure all the timestamps aren't the same */
221 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
222 fileinfo.generic.in.file.fnum = fnum;
224 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
225 if (!NT_STATUS_IS_OK(status)) {
226 printf("Failed to query file times - %s\n", nt_errstr(status));
229 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
230 printf("create_time not setup correctly\n");
232 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
233 printf("access_time not setup correctly\n");
235 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
236 printf("write_time not setup correctly\n");
239 return fnum;
244 /* return a pointer to a anonymous shared memory segment of size "size"
245 which will persist across fork() but will disappear when all processes
246 exit
248 The memory is not zeroed
250 This function uses system5 shared memory. It takes advantage of a property
251 that the memory is not destroyed if it is attached when the id is removed
253 void *shm_setup(int size)
255 int shmid;
256 void *ret;
258 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
259 if (shmid == -1) {
260 printf("can't get shared memory\n");
261 exit(1);
263 ret = (void *)shmat(shmid, 0, 0);
264 if (!ret || ret == (void *)-1) {
265 printf("can't attach to shared memory\n");
266 return NULL;
268 /* the following releases the ipc, but note that this process
269 and all its children will still have access to the memory, its
270 just that the shmid is no longer valid for other shm calls. This
271 means we don't leave behind lots of shm segments after we exit
273 See Stevens "advanced programming in unix env" for details
275 shmctl(shmid, IPC_RMID, 0);
277 return ret;
282 check that a wire string matches the flags specified
283 not 100% accurate, but close enough for testing
285 bool wire_bad_flags(struct smb_wire_string *str, int flags, struct smbcli_state *cli)
287 bool server_unicode;
288 int len;
289 if (!str || !str->s) return True;
290 len = strlen(str->s);
291 if (flags & STR_TERMINATE) len++;
293 server_unicode = (cli->transport->negotiate.capabilities&CAP_UNICODE)?True:False;
294 if (getenv("CLI_FORCE_ASCII") || !lp_unicode()) {
295 server_unicode = False;
298 if ((flags & STR_UNICODE) || server_unicode) {
299 len *= 2;
300 } else if (flags & STR_TERMINATE_ASCII) {
301 len++;
303 if (str->private_length != len) {
304 printf("Expected wire_length %d but got %d for '%s'\n",
305 len, str->private_length, str->s);
306 return True;
308 return False;
312 dump a all_info QFILEINFO structure
314 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
316 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
317 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
318 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
319 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
320 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
321 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
322 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
323 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
324 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
325 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
326 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
327 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
331 dump file infor by name
333 void torture_all_info(struct smbcli_tree *tree, const char *fname)
335 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
336 union smb_fileinfo finfo;
337 NTSTATUS status;
339 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
340 finfo.generic.in.file.path = fname;
341 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
342 if (!NT_STATUS_IS_OK(status)) {
343 d_printf("%s - %s\n", fname, nt_errstr(status));
344 return;
347 d_printf("%s:\n", fname);
348 dump_all_info(mem_ctx, &finfo);
349 talloc_free(mem_ctx);
354 set a attribute on a file
356 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
358 union smb_setfileinfo sfinfo;
359 NTSTATUS status;
361 ZERO_STRUCT(sfinfo.basic_info.in);
362 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
363 sfinfo.basic_info.in.file.path = fname;
364 sfinfo.basic_info.in.attrib = attrib;
365 status = smb_raw_setpathinfo(tree, &sfinfo);
366 return NT_STATUS_IS_OK(status);
371 set a file descriptor as sparse
373 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
375 union smb_ioctl nt;
376 NTSTATUS status;
377 TALLOC_CTX *mem_ctx;
379 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
380 if (!mem_ctx) {
381 return NT_STATUS_NO_MEMORY;
384 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
385 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
386 nt.ntioctl.in.file.fnum = fnum;
387 nt.ntioctl.in.fsctl = True;
388 nt.ntioctl.in.filter = 0;
389 nt.ntioctl.in.max_data = 0;
390 nt.ntioctl.in.blob = data_blob(NULL, 0);
392 status = smb_raw_ioctl(tree, mem_ctx, &nt);
394 talloc_free(mem_ctx);
396 return status;
400 check that an EA has the right value
402 NTSTATUS torture_check_ea(struct smbcli_state *cli,
403 const char *fname, const char *eaname, const char *value)
405 union smb_fileinfo info;
406 NTSTATUS status;
407 struct ea_name ea;
408 TALLOC_CTX *mem_ctx = talloc_new(cli);
410 info.ea_list.level = RAW_FILEINFO_EA_LIST;
411 info.ea_list.in.file.path = fname;
412 info.ea_list.in.num_names = 1;
413 info.ea_list.in.ea_names = &ea;
415 ea.name.s = eaname;
417 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
418 if (!NT_STATUS_IS_OK(status)) {
419 talloc_free(mem_ctx);
420 return status;
423 if (info.ea_list.out.num_eas != 1) {
424 printf("Expected 1 ea in ea_list\n");
425 talloc_free(mem_ctx);
426 return NT_STATUS_EA_CORRUPT_ERROR;
429 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
430 printf("Expected ea '%s' not '%s' in ea_list\n",
431 eaname, info.ea_list.out.eas[0].name.s);
432 talloc_free(mem_ctx);
433 return NT_STATUS_EA_CORRUPT_ERROR;
436 if (value == NULL) {
437 if (info.ea_list.out.eas[0].value.length != 0) {
438 printf("Expected zero length ea for %s\n", eaname);
439 talloc_free(mem_ctx);
440 return NT_STATUS_EA_CORRUPT_ERROR;
442 talloc_free(mem_ctx);
443 return NT_STATUS_OK;
446 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
447 memcmp(value, info.ea_list.out.eas[0].value.data,
448 info.ea_list.out.eas[0].value.length) == 0) {
449 talloc_free(mem_ctx);
450 return NT_STATUS_OK;
453 printf("Expected value '%s' not '%*.*s' for ea %s\n",
454 value,
455 (int)info.ea_list.out.eas[0].value.length,
456 (int)info.ea_list.out.eas[0].value.length,
457 info.ea_list.out.eas[0].value.data,
458 eaname);
460 talloc_free(mem_ctx);
462 return NT_STATUS_EA_CORRUPT_ERROR;
465 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
466 struct smbcli_state **c,
467 const char *hostname,
468 const char *sharename,
469 struct event_context *ev)
471 NTSTATUS status;
473 status = smbcli_full_connection(mem_ctx, c, hostname,
474 sharename, NULL,
475 cmdline_credentials, ev);
476 if (!NT_STATUS_IS_OK(status)) {
477 printf("Failed to open connection - %s\n", nt_errstr(status));
478 return False;
481 (*c)->transport->options.use_oplocks = lp_parm_bool(-1, "torture",
482 "use_oplocks", False);
483 (*c)->transport->options.use_level2_oplocks = lp_parm_bool(-1, "torture",
484 "use_level2_oplocks", False);
486 return True;
489 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, int conn_index)
491 const char *host = lp_parm_string(-1, "torture", "host");
492 const char *share = lp_parm_string(-1, "torture", "share");
493 char **unc_list = NULL;
494 int num_unc_names = 0;
495 const char *p;
497 p = lp_parm_string(-1, "torture", "unclist");
498 if (p) {
499 char *h, *s;
500 unc_list = file_lines_load(p, &num_unc_names, NULL);
501 if (!unc_list || num_unc_names <= 0) {
502 printf("Failed to load unc names list from '%s'\n", p);
503 exit(1);
506 if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
507 NULL, &h, &s)) {
508 printf("Failed to parse UNC name %s\n",
509 unc_list[conn_index % num_unc_names]);
510 exit(1);
512 host = h;
513 share = s;
516 return torture_open_connection_share(NULL, c, host, share, NULL);
519 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
520 int conn_index,
521 struct event_context *ev)
523 const char *host = lp_parm_string(-1, "torture", "host");
524 const char *share = lp_parm_string(-1, "torture", "share");
525 char **unc_list = NULL;
526 int num_unc_names = 0;
527 const char *p;
529 p = lp_parm_string(-1, "torture", "unclist");
530 if (p) {
531 char *h, *s;
532 unc_list = file_lines_load(p, &num_unc_names, NULL);
533 if (!unc_list || num_unc_names <= 0) {
534 printf("Failed to load unc names list from '%s'\n", p);
535 exit(1);
538 if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
539 NULL, &h, &s)) {
540 printf("Failed to parse UNC name %s\n",
541 unc_list[conn_index % num_unc_names]);
542 exit(1);
544 host = h;
545 share = s;
549 return torture_open_connection_share(NULL, c, host, share, ev);
554 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
556 bool ret = True;
557 if (!c) return True;
558 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
559 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
560 ret = False;
562 talloc_free(c);
563 return ret;
567 /* check if the server produced the expected error code */
568 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
569 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
571 NTSTATUS status;
573 status = smbcli_nt_error(c->tree);
574 if (NT_STATUS_IS_DOS(status)) {
575 int class, num;
576 class = NT_STATUS_DOS_CLASS(status);
577 num = NT_STATUS_DOS_CODE(status);
578 if (eclass != class || ecode != num) {
579 printf("unexpected error code %s\n", nt_errstr(status));
580 printf(" expected %s or %s (at %s)\n",
581 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
582 nt_errstr(nterr), location);
583 return False;
585 } else {
586 if (!NT_STATUS_EQUAL(nterr, status)) {
587 printf("unexpected error code %s\n", nt_errstr(status));
588 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
589 return False;
593 return True;
596 static struct smbcli_state *current_cli;
597 static int procnum; /* records process count number when forking */
599 static void sigcont(int sig)
603 double torture_create_procs(struct torture_context *tctx,
604 bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
606 int i, status;
607 volatile pid_t *child_status;
608 volatile bool *child_status_out;
609 int synccount;
610 int tries = 8;
611 int torture_nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
612 double start_time_limit = 10 + (torture_nprocs * 1.5);
613 struct timeval tv;
615 *result = True;
617 synccount = 0;
619 signal(SIGCONT, sigcont);
621 child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
622 if (!child_status) {
623 printf("Failed to setup shared memory\n");
624 return -1;
627 child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
628 if (!child_status_out) {
629 printf("Failed to setup result status shared memory\n");
630 return -1;
633 for (i = 0; i < torture_nprocs; i++) {
634 child_status[i] = 0;
635 child_status_out[i] = True;
638 tv = timeval_current();
640 for (i=0;i<torture_nprocs;i++) {
641 procnum = i;
642 if (fork() == 0) {
643 char *myname;
645 pid_t mypid = getpid();
646 srandom(((int)mypid) ^ ((int)time(NULL)));
648 asprintf(&myname, "CLIENT%d", i);
649 lp_set_cmdline("netbios name", myname);
650 free(myname);
653 while (1) {
654 if (torture_open_connection(&current_cli, i)) {
655 break;
657 if (tries-- == 0) {
658 printf("pid %d failed to start\n", (int)getpid());
659 _exit(1);
661 msleep(100);
664 child_status[i] = getpid();
666 pause();
668 if (child_status[i]) {
669 printf("Child %d failed to start!\n", i);
670 child_status_out[i] = 1;
671 _exit(1);
674 child_status_out[i] = fn(tctx, current_cli, i);
675 _exit(0);
679 do {
680 synccount = 0;
681 for (i=0;i<torture_nprocs;i++) {
682 if (child_status[i]) synccount++;
684 if (synccount == torture_nprocs) break;
685 msleep(100);
686 } while (timeval_elapsed(&tv) < start_time_limit);
688 if (synccount != torture_nprocs) {
689 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
690 *result = False;
691 return timeval_elapsed(&tv);
694 printf("Starting %d clients\n", torture_nprocs);
696 /* start the client load */
697 tv = timeval_current();
698 for (i=0;i<torture_nprocs;i++) {
699 child_status[i] = 0;
702 printf("%d clients started\n", torture_nprocs);
704 kill(0, SIGCONT);
706 for (i=0;i<torture_nprocs;i++) {
707 int ret;
708 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
709 if (ret == -1 || WEXITSTATUS(status) != 0) {
710 *result = False;
714 printf("\n");
716 for (i=0;i<torture_nprocs;i++) {
717 if (!child_status_out[i]) {
718 *result = False;
721 return timeval_elapsed(&tv);
724 static bool wrap_smb_multi_test(struct torture_context *torture,
725 struct torture_tcase *tcase,
726 struct torture_test *test)
728 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
729 bool result;
731 torture_create_procs(torture, fn, &result);
733 return result;
736 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
737 struct torture_suite *suite,
738 const char *name,
739 bool (*run) (struct torture_context *,
740 struct smbcli_state *,
741 int i))
743 struct torture_test *test;
744 struct torture_tcase *tcase;
746 tcase = torture_suite_add_tcase(suite, name);
748 test = talloc(tcase, struct torture_test);
750 test->name = talloc_strdup(test, name);
751 test->description = NULL;
752 test->run = wrap_smb_multi_test;
753 test->fn = run;
754 test->dangerous = false;
756 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
758 return test;
762 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
763 struct torture_tcase *tcase,
764 struct torture_test *test)
766 bool (*fn) (struct torture_context *, struct smbcli_state *,
767 struct smbcli_state *);
768 bool ret;
770 struct smbcli_state *cli1, *cli2;
772 if (!torture_open_connection(&cli1, 0) ||
773 !torture_open_connection(&cli2, 1))
774 return false;
776 fn = test->fn;
778 ret = fn(torture_ctx, cli1, cli2);
780 talloc_free(cli1);
781 talloc_free(cli2);
783 return ret;
788 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
789 struct torture_suite *suite,
790 const char *name,
791 bool (*run) (struct torture_context *,
792 struct smbcli_state *,
793 struct smbcli_state *))
795 struct torture_test *test;
796 struct torture_tcase *tcase;
798 tcase = torture_suite_add_tcase(suite, name);
800 test = talloc(tcase, struct torture_test);
802 test->name = talloc_strdup(test, name);
803 test->description = NULL;
804 test->run = wrap_simple_2smb_test;
805 test->fn = run;
806 test->dangerous = false;
808 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
810 return test;
814 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
815 struct torture_tcase *tcase,
816 struct torture_test *test)
818 bool (*fn) (struct torture_context *, struct smbcli_state *);
819 bool ret;
821 struct smbcli_state *cli1;
823 if (!torture_open_connection(&cli1, 0))
824 return false;
826 fn = test->fn;
828 ret = fn(torture_ctx, cli1);
830 talloc_free(cli1);
832 return ret;
835 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
836 struct torture_suite *suite,
837 const char *name,
838 bool (*run) (struct torture_context *,
839 struct smbcli_state *))
841 struct torture_test *test;
842 struct torture_tcase *tcase;
844 tcase = torture_suite_add_tcase(suite, name);
846 test = talloc(tcase, struct torture_test);
848 test->name = talloc_strdup(test, name);
849 test->description = NULL;
850 test->run = wrap_simple_1smb_test;
851 test->fn = run;
852 test->dangerous = false;
854 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
856 return test;