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.
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"
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
));
51 create a directory, returning a handle to it
53 NTSTATUS
create_directory_handle(struct smbcli_tree
*tree
, const char *dname
, int *fnum
)
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
);
77 if (NT_STATUS_IS_OK(status
)) {
78 *fnum
= io
.ntcreatex
.out
.file
.fnum
;
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
)
93 union smb_setfileinfo setfile
;
94 union smb_fileinfo fileinfo
;
95 time_t t
= (time(NULL
) & ~1);
98 smbcli_unlink(cli
->tree
, fname
);
99 fnum
= smbcli_nt_create_full(cli
->tree
, fname
, 0,
101 FILE_ATTRIBUTE_NORMAL
,
102 NTCREATEX_SHARE_ACCESS_DELETE
|
103 NTCREATEX_SHARE_ACCESS_READ
|
104 NTCREATEX_SHARE_ACCESS_WRITE
,
105 NTCREATEX_DISP_OVERWRITE_IF
,
107 if (fnum
== -1) return -1;
109 smbcli_write(cli
->tree
, fnum
, 0, buf
, 0, sizeof(buf
));
111 if (strchr(fname
, ':') == NULL
) {
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");
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
)
173 union smb_setfileinfo setfile
;
174 union smb_fileinfo fileinfo
;
175 time_t t
= (time(NULL
) & ~1);
178 smbcli_deltree(cli
->tree
, dname
);
179 fnum
= smbcli_nt_create_full(cli
->tree
, dname
, 0,
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
) {
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");
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
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
)
258 shmid
= shmget(IPC_PRIVATE
, size
, SHM_R
| SHM_W
);
260 printf("can't get shared memory\n");
263 ret
= (void *)shmat(shmid
, 0, 0);
264 if (!ret
|| ret
== (void *)-1) {
265 printf("can't attach to shared memory\n");
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);
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
)
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
) {
300 } else if (flags
& STR_TERMINATE_ASCII
) {
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
);
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
;
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
));
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
;
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
)
379 mem_ctx
= talloc_named_const(tree
, 0, "torture_set_sparse");
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
);
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
;
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
;
417 status
= smb_raw_pathinfo(cli
->tree
, mem_ctx
, &info
);
418 if (!NT_STATUS_IS_OK(status
)) {
419 talloc_free(mem_ctx
);
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
;
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
);
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
);
453 printf("Expected value '%s' not '%*.*s' for ea %s\n",
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
,
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
)
473 status
= smbcli_full_connection(mem_ctx
, c
, hostname
,
475 cmdline_credentials
, ev
);
476 if (!NT_STATUS_IS_OK(status
)) {
477 printf("Failed to open connection - %s\n", nt_errstr(status
));
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
);
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;
497 p
= lp_parm_string(-1, "torture", "unclist");
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
);
506 if (!smbcli_parse_unc(unc_list
[conn_index
% num_unc_names
],
508 printf("Failed to parse UNC name %s\n",
509 unc_list
[conn_index
% num_unc_names
]);
516 return torture_open_connection_share(NULL
, c
, host
, share
, NULL
);
519 _PUBLIC_
bool torture_open_connection_ev(struct smbcli_state
**c
,
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;
529 p
= lp_parm_string(-1, "torture", "unclist");
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
);
538 if (!smbcli_parse_unc(unc_list
[conn_index
% num_unc_names
],
540 printf("Failed to parse UNC name %s\n",
541 unc_list
[conn_index
% num_unc_names
]);
549 return torture_open_connection_share(NULL
, c
, host
, share
, ev
);
554 _PUBLIC_
bool torture_close_connection(struct smbcli_state
*c
)
558 if (NT_STATUS_IS_ERR(smbcli_tdis(c
))) {
559 printf("tdis failed (%s)\n", smbcli_errstr(c
->tree
));
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
)
573 status
= smbcli_nt_error(c
->tree
);
574 if (NT_STATUS_IS_DOS(status
)) {
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
);
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
);
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
)
607 volatile pid_t
*child_status
;
608 volatile bool *child_status_out
;
611 int torture_nprocs
= lp_parm_int(-1, "torture", "nprocs", 4);
612 double start_time_limit
= 10 + (torture_nprocs
* 1.5);
619 signal(SIGCONT
, sigcont
);
621 child_status
= (volatile pid_t
*)shm_setup(sizeof(pid_t
)*torture_nprocs
);
623 printf("Failed to setup shared memory\n");
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");
633 for (i
= 0; i
< torture_nprocs
; i
++) {
635 child_status_out
[i
] = True
;
638 tv
= timeval_current();
640 for (i
=0;i
<torture_nprocs
;i
++) {
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
);
654 if (torture_open_connection(¤t_cli
, i
)) {
658 printf("pid %d failed to start\n", (int)getpid());
664 child_status
[i
] = getpid();
668 if (child_status
[i
]) {
669 printf("Child %d failed to start!\n", i
);
670 child_status_out
[i
] = 1;
674 child_status_out
[i
] = fn(tctx
, current_cli
, i
);
681 for (i
=0;i
<torture_nprocs
;i
++) {
682 if (child_status
[i
]) synccount
++;
684 if (synccount
== torture_nprocs
) break;
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
);
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
++) {
702 printf("%d clients started\n", torture_nprocs
);
706 for (i
=0;i
<torture_nprocs
;i
++) {
708 while ((ret
=waitpid(0, &status
, 0)) == -1 && errno
== EINTR
) /* noop */ ;
709 if (ret
== -1 || WEXITSTATUS(status
) != 0) {
716 for (i
=0;i
<torture_nprocs
;i
++) {
717 if (!child_status_out
[i
]) {
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
;
731 torture_create_procs(torture
, fn
, &result
);
736 _PUBLIC_
struct torture_test
*torture_suite_add_smb_multi_test(
737 struct torture_suite
*suite
,
739 bool (*run
) (struct torture_context
*,
740 struct smbcli_state
*,
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
;
754 test
->dangerous
= false;
756 DLIST_ADD_END(tcase
->tests
, test
, struct torture_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
*);
770 struct smbcli_state
*cli1
, *cli2
;
772 if (!torture_open_connection(&cli1
, 0) ||
773 !torture_open_connection(&cli2
, 1))
778 ret
= fn(torture_ctx
, cli1
, cli2
);
788 _PUBLIC_
struct torture_test
*torture_suite_add_2smb_test(
789 struct torture_suite
*suite
,
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
;
806 test
->dangerous
= false;
808 DLIST_ADD_END(tcase
->tests
, test
, struct torture_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
*);
821 struct smbcli_state
*cli1
;
823 if (!torture_open_connection(&cli1
, 0))
828 ret
= fn(torture_ctx
, cli1
);
835 _PUBLIC_
struct torture_test
*torture_suite_add_1smb_test(
836 struct torture_suite
*suite
,
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
;
852 test
->dangerous
= false;
854 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);