The IRIX compiler does not like embedded unnamed unions
[Samba/gebeck_regimport.git] / source4 / torture / util_smb.c
blob32e4453acad9ce81f3c9688587df8dad92299efd
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 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/>.
21 #include "includes.h"
22 #include "lib/cmdline/popt_common.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.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/torture.h"
32 #include "util/dlinklist.h"
33 #include "auth/credentials/credentials.h"
34 #include "libcli/resolve/resolve.h"
35 #include "param/param.h"
38 /**
39 setup a directory ready for a test
41 _PUBLIC_ bool torture_setup_dir(struct smbcli_state *cli, const char *dname)
43 smb_raw_exit(cli->session);
44 if (smbcli_deltree(cli->tree, dname) == -1 ||
45 NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
46 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
47 return false;
49 return true;
53 create a directory, returning a handle to it
55 NTSTATUS create_directory_handle(struct smbcli_tree *tree, const char *dname, int *fnum)
57 NTSTATUS status;
58 union smb_open io;
59 TALLOC_CTX *mem_ctx;
61 mem_ctx = talloc_named_const(tree, 0, "create_directory_handle");
63 io.generic.level = RAW_OPEN_NTCREATEX;
64 io.ntcreatex.in.root_fid = 0;
65 io.ntcreatex.in.flags = 0;
66 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
67 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
68 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
69 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
70 io.ntcreatex.in.alloc_size = 0;
71 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
72 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
73 io.ntcreatex.in.security_flags = 0;
74 io.ntcreatex.in.fname = dname;
76 status = smb_raw_open(tree, mem_ctx, &io);
77 talloc_free(mem_ctx);
79 if (NT_STATUS_IS_OK(status)) {
80 *fnum = io.ntcreatex.out.file.fnum;
83 return status;
87 /**
88 sometimes we need a fairly complex file to work with, so we can test
89 all possible attributes.
91 _PUBLIC_ int create_complex_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *fname)
93 int fnum;
94 char buf[7] = "abc";
95 union smb_setfileinfo setfile;
96 union smb_fileinfo fileinfo;
97 time_t t = (time(NULL) & ~1);
98 NTSTATUS status;
100 smbcli_unlink(cli->tree, fname);
101 fnum = smbcli_nt_create_full(cli->tree, fname, 0,
102 SEC_RIGHTS_FILE_ALL,
103 FILE_ATTRIBUTE_NORMAL,
104 NTCREATEX_SHARE_ACCESS_DELETE|
105 NTCREATEX_SHARE_ACCESS_READ|
106 NTCREATEX_SHARE_ACCESS_WRITE,
107 NTCREATEX_DISP_OVERWRITE_IF,
108 0, 0);
109 if (fnum == -1) return -1;
111 smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
113 if (strchr(fname, ':') == NULL) {
114 /* setup some EAs */
115 setfile.generic.level = RAW_SFILEINFO_EA_SET;
116 setfile.generic.in.file.fnum = fnum;
117 setfile.ea_set.in.num_eas = 2;
118 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
119 setfile.ea_set.in.eas[0].flags = 0;
120 setfile.ea_set.in.eas[0].name.s = "EAONE";
121 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
122 setfile.ea_set.in.eas[1].flags = 0;
123 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
124 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
125 status = smb_raw_setfileinfo(cli->tree, &setfile);
126 if (!NT_STATUS_IS_OK(status)) {
127 printf("Failed to setup EAs\n");
131 /* make sure all the timestamps aren't the same, and are also
132 in different DST zones*/
133 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
134 setfile.generic.in.file.fnum = fnum;
136 setfile.setattre.in.create_time = t + 9*30*24*60*60;
137 setfile.setattre.in.access_time = t + 6*30*24*60*60;
138 setfile.setattre.in.write_time = t + 3*30*24*60*60;
140 status = smb_raw_setfileinfo(cli->tree, &setfile);
141 if (!NT_STATUS_IS_OK(status)) {
142 printf("Failed to setup file times - %s\n", nt_errstr(status));
145 /* make sure all the timestamps aren't the same */
146 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
147 fileinfo.generic.in.file.fnum = fnum;
149 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
150 if (!NT_STATUS_IS_OK(status)) {
151 printf("Failed to query file times - %s\n", nt_errstr(status));
154 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
155 printf("create_time not setup correctly\n");
157 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
158 printf("access_time not setup correctly\n");
160 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
161 printf("write_time not setup correctly\n");
164 return fnum;
169 sometimes we need a fairly complex directory to work with, so we can test
170 all possible attributes.
172 int create_complex_dir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx, const char *dname)
174 int fnum;
175 union smb_setfileinfo setfile;
176 union smb_fileinfo fileinfo;
177 time_t t = (time(NULL) & ~1);
178 NTSTATUS status;
180 smbcli_deltree(cli->tree, dname);
181 fnum = smbcli_nt_create_full(cli->tree, dname, 0,
182 SEC_RIGHTS_DIR_ALL,
183 FILE_ATTRIBUTE_DIRECTORY,
184 NTCREATEX_SHARE_ACCESS_READ|
185 NTCREATEX_SHARE_ACCESS_WRITE,
186 NTCREATEX_DISP_OPEN_IF,
187 NTCREATEX_OPTIONS_DIRECTORY, 0);
188 if (fnum == -1) return -1;
190 if (strchr(dname, ':') == NULL) {
191 /* setup some EAs */
192 setfile.generic.level = RAW_SFILEINFO_EA_SET;
193 setfile.generic.in.file.fnum = fnum;
194 setfile.ea_set.in.num_eas = 2;
195 setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2);
196 setfile.ea_set.in.eas[0].flags = 0;
197 setfile.ea_set.in.eas[0].name.s = "EAONE";
198 setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6);
199 setfile.ea_set.in.eas[1].flags = 0;
200 setfile.ea_set.in.eas[1].name.s = "SECONDEA";
201 setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8);
202 status = smb_raw_setfileinfo(cli->tree, &setfile);
203 if (!NT_STATUS_IS_OK(status)) {
204 printf("Failed to setup EAs\n");
208 /* make sure all the timestamps aren't the same, and are also
209 in different DST zones*/
210 setfile.generic.level = RAW_SFILEINFO_SETATTRE;
211 setfile.generic.in.file.fnum = fnum;
213 setfile.setattre.in.create_time = t + 9*30*24*60*60;
214 setfile.setattre.in.access_time = t + 6*30*24*60*60;
215 setfile.setattre.in.write_time = t + 3*30*24*60*60;
217 status = smb_raw_setfileinfo(cli->tree, &setfile);
218 if (!NT_STATUS_IS_OK(status)) {
219 printf("Failed to setup file times - %s\n", nt_errstr(status));
222 /* make sure all the timestamps aren't the same */
223 fileinfo.generic.level = RAW_FILEINFO_GETATTRE;
224 fileinfo.generic.in.file.fnum = fnum;
226 status = smb_raw_fileinfo(cli->tree, mem_ctx, &fileinfo);
227 if (!NT_STATUS_IS_OK(status)) {
228 printf("Failed to query file times - %s\n", nt_errstr(status));
231 if (setfile.setattre.in.create_time != fileinfo.getattre.out.create_time) {
232 printf("create_time not setup correctly\n");
234 if (setfile.setattre.in.access_time != fileinfo.getattre.out.access_time) {
235 printf("access_time not setup correctly\n");
237 if (setfile.setattre.in.write_time != fileinfo.getattre.out.write_time) {
238 printf("write_time not setup correctly\n");
241 return fnum;
246 /* return a pointer to a anonymous shared memory segment of size "size"
247 which will persist across fork() but will disappear when all processes
248 exit
250 The memory is not zeroed
252 This function uses system5 shared memory. It takes advantage of a property
253 that the memory is not destroyed if it is attached when the id is removed
255 void *shm_setup(int size)
257 int shmid;
258 void *ret;
260 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
261 if (shmid == -1) {
262 printf("can't get shared memory\n");
263 exit(1);
265 ret = (void *)shmat(shmid, 0, 0);
266 if (!ret || ret == (void *)-1) {
267 printf("can't attach to shared memory\n");
268 return NULL;
270 /* the following releases the ipc, but note that this process
271 and all its children will still have access to the memory, its
272 just that the shmid is no longer valid for other shm calls. This
273 means we don't leave behind lots of shm segments after we exit
275 See Stevens "advanced programming in unix env" for details
277 shmctl(shmid, IPC_RMID, 0);
279 return ret;
284 check that a wire string matches the flags specified
285 not 100% accurate, but close enough for testing
287 bool wire_bad_flags(struct smb_wire_string *str, int flags,
288 struct smbcli_transport *transport)
290 bool server_unicode;
291 int len;
292 if (!str || !str->s) return true;
293 len = strlen(str->s);
294 if (flags & STR_TERMINATE) len++;
296 server_unicode = (transport->negotiate.capabilities&CAP_UNICODE)?true:false;
297 if (getenv("CLI_FORCE_ASCII") || !transport->options.unicode) {
298 server_unicode = false;
301 if ((flags & STR_UNICODE) || server_unicode) {
302 len *= 2;
303 } else if (flags & STR_TERMINATE_ASCII) {
304 len++;
306 if (str->private_length != len) {
307 printf("Expected wire_length %d but got %d for '%s'\n",
308 len, str->private_length, str->s);
309 return true;
311 return false;
315 dump a all_info QFILEINFO structure
317 void dump_all_info(TALLOC_CTX *mem_ctx, union smb_fileinfo *finfo)
319 d_printf("\tcreate_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.create_time));
320 d_printf("\taccess_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.access_time));
321 d_printf("\twrite_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.write_time));
322 d_printf("\tchange_time: %s\n", nt_time_string(mem_ctx, finfo->all_info.out.change_time));
323 d_printf("\tattrib: 0x%x\n", finfo->all_info.out.attrib);
324 d_printf("\talloc_size: %llu\n", (long long)finfo->all_info.out.alloc_size);
325 d_printf("\tsize: %llu\n", (long long)finfo->all_info.out.size);
326 d_printf("\tnlink: %u\n", finfo->all_info.out.nlink);
327 d_printf("\tdelete_pending: %u\n", finfo->all_info.out.delete_pending);
328 d_printf("\tdirectory: %u\n", finfo->all_info.out.directory);
329 d_printf("\tea_size: %u\n", finfo->all_info.out.ea_size);
330 d_printf("\tfname: '%s'\n", finfo->all_info.out.fname.s);
334 dump file infor by name
336 void torture_all_info(struct smbcli_tree *tree, const char *fname)
338 TALLOC_CTX *mem_ctx = talloc_named(tree, 0, "%s", fname);
339 union smb_fileinfo finfo;
340 NTSTATUS status;
342 finfo.generic.level = RAW_FILEINFO_ALL_INFO;
343 finfo.generic.in.file.path = fname;
344 status = smb_raw_pathinfo(tree, mem_ctx, &finfo);
345 if (!NT_STATUS_IS_OK(status)) {
346 d_printf("%s - %s\n", fname, nt_errstr(status));
347 return;
350 d_printf("%s:\n", fname);
351 dump_all_info(mem_ctx, &finfo);
352 talloc_free(mem_ctx);
357 set a attribute on a file
359 bool torture_set_file_attribute(struct smbcli_tree *tree, const char *fname, uint16_t attrib)
361 union smb_setfileinfo sfinfo;
362 NTSTATUS status;
364 ZERO_STRUCT(sfinfo.basic_info.in);
365 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION;
366 sfinfo.basic_info.in.file.path = fname;
367 sfinfo.basic_info.in.attrib = attrib;
368 status = smb_raw_setpathinfo(tree, &sfinfo);
369 return NT_STATUS_IS_OK(status);
374 set a file descriptor as sparse
376 NTSTATUS torture_set_sparse(struct smbcli_tree *tree, int fnum)
378 union smb_ioctl nt;
379 NTSTATUS status;
380 TALLOC_CTX *mem_ctx;
382 mem_ctx = talloc_named_const(tree, 0, "torture_set_sparse");
383 if (!mem_ctx) {
384 return NT_STATUS_NO_MEMORY;
387 nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
388 nt.ntioctl.in.function = FSCTL_SET_SPARSE;
389 nt.ntioctl.in.file.fnum = fnum;
390 nt.ntioctl.in.fsctl = true;
391 nt.ntioctl.in.filter = 0;
392 nt.ntioctl.in.max_data = 0;
393 nt.ntioctl.in.blob = data_blob(NULL, 0);
395 status = smb_raw_ioctl(tree, mem_ctx, &nt);
397 talloc_free(mem_ctx);
399 return status;
403 check that an EA has the right value
405 NTSTATUS torture_check_ea(struct smbcli_state *cli,
406 const char *fname, const char *eaname, const char *value)
408 union smb_fileinfo info;
409 NTSTATUS status;
410 struct ea_name ea;
411 TALLOC_CTX *mem_ctx = talloc_new(cli);
413 info.ea_list.level = RAW_FILEINFO_EA_LIST;
414 info.ea_list.in.file.path = fname;
415 info.ea_list.in.num_names = 1;
416 info.ea_list.in.ea_names = &ea;
418 ea.name.s = eaname;
420 status = smb_raw_pathinfo(cli->tree, mem_ctx, &info);
421 if (!NT_STATUS_IS_OK(status)) {
422 talloc_free(mem_ctx);
423 return status;
426 if (info.ea_list.out.num_eas != 1) {
427 printf("Expected 1 ea in ea_list\n");
428 talloc_free(mem_ctx);
429 return NT_STATUS_EA_CORRUPT_ERROR;
432 if (strcasecmp_m(eaname, info.ea_list.out.eas[0].name.s) != 0) {
433 printf("Expected ea '%s' not '%s' in ea_list\n",
434 eaname, info.ea_list.out.eas[0].name.s);
435 talloc_free(mem_ctx);
436 return NT_STATUS_EA_CORRUPT_ERROR;
439 if (value == NULL) {
440 if (info.ea_list.out.eas[0].value.length != 0) {
441 printf("Expected zero length ea for %s\n", eaname);
442 talloc_free(mem_ctx);
443 return NT_STATUS_EA_CORRUPT_ERROR;
445 talloc_free(mem_ctx);
446 return NT_STATUS_OK;
449 if (strlen(value) == info.ea_list.out.eas[0].value.length &&
450 memcmp(value, info.ea_list.out.eas[0].value.data,
451 info.ea_list.out.eas[0].value.length) == 0) {
452 talloc_free(mem_ctx);
453 return NT_STATUS_OK;
456 printf("Expected value '%s' not '%*.*s' for ea %s\n",
457 value,
458 (int)info.ea_list.out.eas[0].value.length,
459 (int)info.ea_list.out.eas[0].value.length,
460 info.ea_list.out.eas[0].value.data,
461 eaname);
463 talloc_free(mem_ctx);
465 return NT_STATUS_EA_CORRUPT_ERROR;
468 _PUBLIC_ bool torture_open_connection_share(TALLOC_CTX *mem_ctx,
469 struct smbcli_state **c,
470 struct torture_context *tctx,
471 const char *hostname,
472 const char *sharename,
473 struct event_context *ev)
475 NTSTATUS status;
477 struct smbcli_options options;
478 struct smbcli_session_options session_options;
480 lp_smbcli_options(tctx->lp_ctx, &options);
481 lp_smbcli_session_options(tctx->lp_ctx, &session_options);
483 options.use_oplocks = torture_setting_bool(tctx, "use_oplocks", true);
484 options.use_level2_oplocks = torture_setting_bool(tctx, "use_level2_oplocks", true);
486 status = smbcli_full_connection(mem_ctx, c, hostname,
487 lp_smb_ports(tctx->lp_ctx),
488 sharename, NULL,
489 cmdline_credentials,
490 lp_resolve_context(tctx->lp_ctx),
491 ev, &options, &session_options);
492 if (!NT_STATUS_IS_OK(status)) {
493 printf("Failed to open connection - %s\n", nt_errstr(status));
494 return false;
497 return true;
500 _PUBLIC_ bool torture_get_conn_index(int conn_index,
501 TALLOC_CTX *mem_ctx,
502 struct torture_context *tctx,
503 char **host, char **share)
505 char **unc_list = NULL;
506 int num_unc_names = 0;
507 const char *p;
509 (*host) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "host", NULL));
510 (*share) = talloc_strdup(mem_ctx, torture_setting_string(tctx, "share", NULL));
512 p = torture_setting_string(tctx, "unclist", NULL);
513 if (!p) {
514 return true;
517 unc_list = file_lines_load(p, &num_unc_names, NULL);
518 if (!unc_list || num_unc_names <= 0) {
519 DEBUG(0,("Failed to load unc names list from '%s'\n", p));
520 return false;
523 if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
524 mem_ctx, host, share)) {
525 DEBUG(0, ("Failed to parse UNC name %s\n",
526 unc_list[conn_index % num_unc_names]));
527 return false;
530 talloc_free(unc_list);
531 return true;
536 _PUBLIC_ bool torture_open_connection_ev(struct smbcli_state **c,
537 int conn_index,
538 struct torture_context *tctx,
539 struct event_context *ev)
541 char *host, *share;
542 bool ret;
544 if (!torture_get_conn_index(conn_index, ev, tctx, &host, &share)) {
545 return false;
548 ret = torture_open_connection_share(NULL, c, tctx, host, share, ev);
549 talloc_free(host);
550 talloc_free(share);
552 return ret;
555 _PUBLIC_ bool torture_open_connection(struct smbcli_state **c, struct torture_context *tctx, int conn_index)
557 return torture_open_connection_ev(c, conn_index, tctx, tctx->ev);
562 _PUBLIC_ bool torture_close_connection(struct smbcli_state *c)
564 bool ret = true;
565 if (!c) return true;
566 if (NT_STATUS_IS_ERR(smbcli_tdis(c))) {
567 printf("tdis failed (%s)\n", smbcli_errstr(c->tree));
568 ret = false;
570 talloc_free(c);
571 return ret;
575 /* check if the server produced the expected error code */
576 _PUBLIC_ bool check_error(const char *location, struct smbcli_state *c,
577 uint8_t eclass, uint32_t ecode, NTSTATUS nterr)
579 NTSTATUS status;
581 status = smbcli_nt_error(c->tree);
582 if (NT_STATUS_IS_DOS(status)) {
583 int class, num;
584 class = NT_STATUS_DOS_CLASS(status);
585 num = NT_STATUS_DOS_CODE(status);
586 if (eclass != class || ecode != num) {
587 printf("unexpected error code %s\n", nt_errstr(status));
588 printf(" expected %s or %s (at %s)\n",
589 nt_errstr(NT_STATUS_DOS(eclass, ecode)),
590 nt_errstr(nterr), location);
591 return false;
593 } else {
594 if (!NT_STATUS_EQUAL(nterr, status)) {
595 printf("unexpected error code %s\n", nt_errstr(status));
596 printf(" expected %s (at %s)\n", nt_errstr(nterr), location);
597 return false;
601 return true;
604 static struct smbcli_state *current_cli;
605 static int procnum; /* records process count number when forking */
607 static void sigcont(int sig)
611 double torture_create_procs(struct torture_context *tctx,
612 bool (*fn)(struct torture_context *, struct smbcli_state *, int), bool *result)
614 int i, status;
615 volatile pid_t *child_status;
616 volatile bool *child_status_out;
617 int synccount;
618 int tries = 8;
619 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
620 double start_time_limit = 10 + (torture_nprocs * 1.5);
621 struct timeval tv;
623 *result = true;
625 synccount = 0;
627 signal(SIGCONT, sigcont);
629 child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
630 if (!child_status) {
631 printf("Failed to setup shared memory\n");
632 return -1;
635 child_status_out = (volatile bool *)shm_setup(sizeof(bool)*torture_nprocs);
636 if (!child_status_out) {
637 printf("Failed to setup result status shared memory\n");
638 return -1;
641 for (i = 0; i < torture_nprocs; i++) {
642 child_status[i] = 0;
643 child_status_out[i] = true;
646 tv = timeval_current();
648 for (i=0;i<torture_nprocs;i++) {
649 procnum = i;
650 if (fork() == 0) {
651 char *myname;
653 pid_t mypid = getpid();
654 srandom(((int)mypid) ^ ((int)time(NULL)));
656 asprintf(&myname, "CLIENT%d", i);
657 lp_set_cmdline(tctx->lp_ctx, "netbios name", myname);
658 free(myname);
661 while (1) {
662 if (torture_open_connection(&current_cli, tctx, i)) {
663 break;
665 if (tries-- == 0) {
666 printf("pid %d failed to start\n", (int)getpid());
667 _exit(1);
669 msleep(100);
672 child_status[i] = getpid();
674 pause();
676 if (child_status[i]) {
677 printf("Child %d failed to start!\n", i);
678 child_status_out[i] = 1;
679 _exit(1);
682 child_status_out[i] = fn(tctx, current_cli, i);
683 _exit(0);
687 do {
688 synccount = 0;
689 for (i=0;i<torture_nprocs;i++) {
690 if (child_status[i]) synccount++;
692 if (synccount == torture_nprocs) break;
693 msleep(100);
694 } while (timeval_elapsed(&tv) < start_time_limit);
696 if (synccount != torture_nprocs) {
697 printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
698 *result = false;
699 return timeval_elapsed(&tv);
702 printf("Starting %d clients\n", torture_nprocs);
704 /* start the client load */
705 tv = timeval_current();
706 for (i=0;i<torture_nprocs;i++) {
707 child_status[i] = 0;
710 printf("%d clients started\n", torture_nprocs);
712 kill(0, SIGCONT);
714 for (i=0;i<torture_nprocs;i++) {
715 int ret;
716 while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
717 if (ret == -1 || WEXITSTATUS(status) != 0) {
718 *result = false;
722 printf("\n");
724 for (i=0;i<torture_nprocs;i++) {
725 if (!child_status_out[i]) {
726 *result = false;
729 return timeval_elapsed(&tv);
732 static bool wrap_smb_multi_test(struct torture_context *torture,
733 struct torture_tcase *tcase,
734 struct torture_test *test)
736 bool (*fn)(struct torture_context *, struct smbcli_state *, int ) = test->fn;
737 bool result;
739 torture_create_procs(torture, fn, &result);
741 return result;
744 _PUBLIC_ struct torture_test *torture_suite_add_smb_multi_test(
745 struct torture_suite *suite,
746 const char *name,
747 bool (*run) (struct torture_context *,
748 struct smbcli_state *,
749 int i))
751 struct torture_test *test;
752 struct torture_tcase *tcase;
754 tcase = torture_suite_add_tcase(suite, name);
756 test = talloc(tcase, struct torture_test);
758 test->name = talloc_strdup(test, name);
759 test->description = NULL;
760 test->run = wrap_smb_multi_test;
761 test->fn = run;
762 test->dangerous = false;
764 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
766 return test;
770 static bool wrap_simple_2smb_test(struct torture_context *torture_ctx,
771 struct torture_tcase *tcase,
772 struct torture_test *test)
774 bool (*fn) (struct torture_context *, struct smbcli_state *,
775 struct smbcli_state *);
776 bool ret;
778 struct smbcli_state *cli1, *cli2;
780 if (!torture_open_connection(&cli1, torture_ctx, 0) ||
781 !torture_open_connection(&cli2, torture_ctx, 1))
782 return false;
784 fn = test->fn;
786 ret = fn(torture_ctx, cli1, cli2);
788 talloc_free(cli1);
789 talloc_free(cli2);
791 return ret;
796 _PUBLIC_ struct torture_test *torture_suite_add_2smb_test(
797 struct torture_suite *suite,
798 const char *name,
799 bool (*run) (struct torture_context *,
800 struct smbcli_state *,
801 struct smbcli_state *))
803 struct torture_test *test;
804 struct torture_tcase *tcase;
806 tcase = torture_suite_add_tcase(suite, name);
808 test = talloc(tcase, struct torture_test);
810 test->name = talloc_strdup(test, name);
811 test->description = NULL;
812 test->run = wrap_simple_2smb_test;
813 test->fn = run;
814 test->dangerous = false;
816 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
818 return test;
822 static bool wrap_simple_1smb_test(struct torture_context *torture_ctx,
823 struct torture_tcase *tcase,
824 struct torture_test *test)
826 bool (*fn) (struct torture_context *, struct smbcli_state *);
827 bool ret;
829 struct smbcli_state *cli1;
831 if (!torture_open_connection(&cli1, torture_ctx, 0))
832 return false;
834 fn = test->fn;
836 ret = fn(torture_ctx, cli1);
838 talloc_free(cli1);
840 return ret;
843 _PUBLIC_ struct torture_test *torture_suite_add_1smb_test(
844 struct torture_suite *suite,
845 const char *name,
846 bool (*run) (struct torture_context *, struct smbcli_state *))
848 struct torture_test *test;
849 struct torture_tcase *tcase;
851 tcase = torture_suite_add_tcase(suite, name);
853 test = talloc(tcase, struct torture_test);
855 test->name = talloc_strdup(test, name);
856 test->description = NULL;
857 test->run = wrap_simple_1smb_test;
858 test->fn = run;
859 test->dangerous = false;
861 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
863 return test;
867 NTSTATUS torture_second_tcon(TALLOC_CTX *mem_ctx,
868 struct smbcli_session *session,
869 const char *sharename,
870 struct smbcli_tree **res)
872 union smb_tcon tcon;
873 struct smbcli_tree *result;
874 TALLOC_CTX *tmp_ctx;
875 NTSTATUS status;
877 if ((tmp_ctx = talloc_new(mem_ctx)) == NULL) {
878 return NT_STATUS_NO_MEMORY;
881 result = smbcli_tree_init(session, tmp_ctx, false);
882 if (result == NULL) {
883 talloc_free(tmp_ctx);
884 return NT_STATUS_NO_MEMORY;
887 tcon.generic.level = RAW_TCON_TCONX;
888 tcon.tconx.in.flags = 0;
890 /* Ignore share mode security here */
891 tcon.tconx.in.password = data_blob(NULL, 0);
892 tcon.tconx.in.path = sharename;
893 tcon.tconx.in.device = "?????";
895 status = smb_raw_tcon(result, tmp_ctx, &tcon);
896 if (!NT_STATUS_IS_OK(status)) {
897 talloc_free(tmp_ctx);
898 return status;
901 result->tid = tcon.tconx.out.tid;
902 *res = talloc_steal(mem_ctx, result);
903 talloc_free(tmp_ctx);
904 return NT_STATUS_OK;