2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1997
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.
28 static fstring host
, workgroup
, share
, password
, username
, myname
;
29 static int max_protocol
= PROTOCOL_NT1
;
30 static char *sockops
="";
33 static struct timeval tp1
,tp2
;
35 static void start_timer()
37 gettimeofday(&tp1
,NULL
);
40 static double end_timer()
42 gettimeofday(&tp2
,NULL
);
43 return((tp2
.tv_sec
- tp1
.tv_sec
) +
44 (tp2
.tv_usec
- tp1
.tv_usec
)*1.0e-6);
48 static BOOL
open_connection(struct cli_state
*c
)
50 if (!cli_initialise(c
) || !cli_connect(c
, host
, NULL
)) {
51 printf("Failed to connect with %s\n", host
);
55 if (!cli_session_request(c
, host
, 0x20, myname
)) {
56 printf("%s rejected the session\n",host
);
61 c
->protocol
= max_protocol
;
63 if (!cli_negprot(c
)) {
64 printf("%s rejected the negprot (%s)\n",host
, cli_errstr(c
));
69 if (!cli_session_setup(c
, username
, password
, strlen(password
),
71 printf("%s rejected the sessionsetup (%s)\n", host
, cli_errstr(c
));
76 if (!cli_send_tconX(c
, share
, "A:", password
, strlen(password
)+1)) {
77 printf("%s refused tree connect (%s)\n", host
, cli_errstr(c
));
87 static void close_connection(struct cli_state
*c
)
90 printf("tdis failed (%s)\n", cli_errstr(c
));
97 static BOOL
wait_lock(struct cli_state
*c
, int fnum
, uint32 offset
, uint32 len
)
99 while (!cli_lock(c
, fnum
, offset
, len
, -1)) {
101 cli_error(c
, &eclass
, &num
);
102 if (eclass
!= ERRDOS
|| num
!= ERRlock
) {
103 printf("lock failed (%s)\n",
112 static BOOL
rw_torture(struct cli_state
*c
, int numops
)
114 char *lockfname
= "\\torture.lck";
118 int pid2
, pid
= getpid();
121 fnum2
= cli_open(c
, lockfname
, O_RDWR
| O_CREAT
| O_EXCL
,
124 fnum2
= cli_open(c
, lockfname
, O_RDWR
, DENY_NONE
);
126 printf("open of %s failed (%s)\n", lockfname
, cli_errstr(c
));
131 for (i
=0;i
<numops
;i
++) {
132 unsigned n
= (unsigned)random()%10;
134 printf("%d\r", i
); fflush(stdout
);
136 sprintf(fname
,"\\torture.%u", n
);
138 if (!wait_lock(c
, fnum2
, n
*sizeof(int), sizeof(int))) {
142 fnum
= cli_open(c
, fname
, O_RDWR
| O_CREAT
| O_TRUNC
, DENY_ALL
);
144 printf("open failed (%s)\n", cli_errstr(c
));
148 if (cli_write(c
, fnum
, (char *)&pid
, 0, sizeof(pid
)) != sizeof(pid
)) {
149 printf("write failed (%s)\n", cli_errstr(c
));
154 if (cli_read(c
, fnum
, (char *)&pid2
, 0, sizeof(pid
)) != sizeof(pid
)) {
155 printf("read failed (%s)\n", cli_errstr(c
));
159 printf("data corruption!\n");
162 if (!cli_close(c
, fnum
)) {
163 printf("close failed (%s)\n", cli_errstr(c
));
166 if (!cli_unlink(c
, fname
)) {
167 printf("unlink failed (%s)\n", cli_errstr(c
));
170 if (!cli_unlock(c
, fnum2
, n
*sizeof(int), sizeof(int), -1)) {
171 printf("unlock failed (%s)\n", cli_errstr(c
));
180 static void usage(void)
182 printf("Usage: smbtorture \\\\server\\share <options>\n");
184 printf("\t-U user%%pass\n");
185 printf("\t-N numprocs\n");
186 printf("\t-n my_netbios_name\n");
187 printf("\t-W workgroup\n");
188 printf("\t-o num_operations\n");
189 printf("\t-O socket_options\n");
190 printf("\t-m maximum protocol\n");
198 static void run_torture(int numops
)
200 static struct cli_state cli
;
202 if (open_connection(&cli
)) {
203 cli_sockopt(&cli
, sockops
);
205 printf("pid %d OK\n", getpid());
207 rw_torture(&cli
, numops
);
209 close_connection(&cli
);
214 This test checks for two things:
216 1) correct support for retaining locks over a close (ie. the server
217 must not use posix semantics)
218 2) support for lock timeouts
220 static void run_locktest1(void)
222 static struct cli_state cli1
, cli2
;
223 char *fname
= "\\locktest.lck";
224 int fnum1
, fnum2
, fnum3
;
227 if (!open_connection(&cli1
) || !open_connection(&cli2
)) {
230 cli_sockopt(&cli1
, sockops
);
231 cli_sockopt(&cli2
, sockops
);
233 printf("starting locktest1\n");
235 cli_unlink(&cli1
, fname
);
237 fnum1
= cli_open(&cli1
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
239 printf("open of %s failed (%s)\n", fname
, cli_errstr(&cli1
));
242 fnum2
= cli_open(&cli1
, fname
, O_RDWR
, DENY_NONE
);
244 printf("open2 of %s failed (%s)\n", fname
, cli_errstr(&cli1
));
247 fnum3
= cli_open(&cli2
, fname
, O_RDWR
, DENY_NONE
);
249 printf("open3 of %s failed (%s)\n", fname
, cli_errstr(&cli2
));
253 if (!cli_lock(&cli1
, fnum1
, 0, 4, 0)) {
254 printf("lock1 failed (%s)\n", cli_errstr(&cli1
));
259 if (cli_lock(&cli2
, fnum3
, 0, 4, 0)) {
260 printf("lock2 succeeded! This is a locking bug\n");
264 cli_error(&cli2
, &eclass
, &num
);
265 if (eclass
!= ERRDOS
|| num
!= ERRlock
) {
266 printf("error should have been ERRDOS/ERRlock (%s)\n",
273 printf("Testing lock timeouts\n");
275 if (cli_lock(&cli2
, fnum3
, 0, 4, 10*1000)) {
276 printf("lock3 succeeded! This is a locking bug\n");
280 cli_error(&cli2
, &eclass
, &num
);
281 if (eclass
!= ERRDOS
|| num
!= ERRlock
) {
282 printf("error should have been ERRDOS/ERRlock (%s)\n",
290 printf("error: This server appears not to support timed lock requests\n");
293 if (!cli_close(&cli1
, fnum2
)) {
294 printf("close1 failed (%s)\n", cli_errstr(&cli1
));
298 if (cli_lock(&cli2
, fnum3
, 0, 4, 0)) {
299 printf("lock4 succeeded! This is a locking bug\n");
303 cli_error(&cli2
, &eclass
, &num
);
304 if (eclass
!= ERRDOS
|| num
!= ERRlock
) {
305 printf("error should have been ERRDOS/ERRlock (%s)\n",
311 if (!cli_close(&cli1
, fnum1
)) {
312 printf("close2 failed (%s)\n", cli_errstr(&cli1
));
316 if (!cli_close(&cli2
, fnum3
)) {
317 printf("close3 failed (%s)\n", cli_errstr(&cli2
));
321 if (!cli_unlink(&cli1
, fname
)) {
322 printf("unlink failed (%s)\n", cli_errstr(&cli1
));
327 close_connection(&cli1
);
328 close_connection(&cli2
);
330 printf("Passed locktest1\n");
335 This test checks that
337 1) the server supports multiple locking contexts on the one SMB
338 connection, distinguished by PID.
340 2) the server correctly fails overlapping locks made by the same PID (this
341 goes against POSIX behaviour, which is why it is tricky to implement)
343 3) the server denies unlock requests by an incorrect client PID
345 static void run_locktest2(void)
347 static struct cli_state cli
;
348 char *fname
= "\\locktest.lck";
349 int fnum1
, fnum2
, fnum3
;
351 if (!open_connection(&cli
)) {
355 cli_sockopt(&cli
, sockops
);
357 printf("starting locktest2\n");
359 cli_unlink(&cli
, fname
);
363 fnum1
= cli_open(&cli
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
365 printf("open of %s failed (%s)\n", fname
, cli_errstr(&cli
));
369 fnum2
= cli_open(&cli
, fname
, O_RDWR
, DENY_NONE
);
371 printf("open2 of %s failed (%s)\n", fname
, cli_errstr(&cli
));
377 fnum3
= cli_open(&cli
, fname
, O_RDWR
, DENY_NONE
);
379 printf("open3 of %s failed (%s)\n", fname
, cli_errstr(&cli
));
385 if (!cli_lock(&cli
, fnum1
, 0, 4, 0)) {
386 printf("lock1 failed (%s)\n", cli_errstr(&cli
));
390 if (cli_lock(&cli
, fnum2
, 0, 4, 0)) {
391 printf("lock2 succeeded! This is a locking bug\n");
394 cli_error(&cli
, &eclass
, &num
);
395 if (eclass
!= ERRDOS
|| num
!= ERRlock
) {
396 printf("error should have been ERRDOS/ERRlock (%s)\n",
404 if (cli_unlock(&cli
, fnum1
, 0, 4, 0)) {
405 printf("unlock1 succeeded! This is a locking bug\n");
408 if (cli_lock(&cli
, fnum3
, 0, 4, 0)) {
409 printf("lock3 succeeded! This is a locking bug\n");
412 cli_error(&cli
, &eclass
, &num
);
413 if (eclass
!= ERRDOS
|| num
!= ERRlock
) {
414 printf("error should have been ERRDOS/ERRlock (%s)\n",
422 if (!cli_close(&cli
, fnum1
)) {
423 printf("close1 failed (%s)\n", cli_errstr(&cli
));
427 if (!cli_close(&cli
, fnum2
)) {
428 printf("close2 failed (%s)\n", cli_errstr(&cli
));
432 if (!cli_close(&cli
, fnum3
)) {
433 printf("close3 failed (%s)\n", cli_errstr(&cli
));
437 close_connection(&cli
);
439 printf("locktest2 finished\n");
444 This test checks that
446 1) the server supports the full offset range in lock requests
448 static void run_locktest3(int numops
)
450 static struct cli_state cli1
, cli2
;
451 char *fname
= "\\locktest.lck";
455 #define NEXT_OFFSET offset += (~(uint32)0) / numops
457 if (!open_connection(&cli1
) || !open_connection(&cli2
)) {
460 cli_sockopt(&cli1
, sockops
);
461 cli_sockopt(&cli2
, sockops
);
463 printf("starting locktest3\n");
465 cli_unlink(&cli1
, fname
);
467 fnum1
= cli_open(&cli1
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
469 printf("open of %s failed (%s)\n", fname
, cli_errstr(&cli1
));
472 fnum2
= cli_open(&cli2
, fname
, O_RDWR
, DENY_NONE
);
474 printf("open2 of %s failed (%s)\n", fname
, cli_errstr(&cli2
));
478 for (offset
=i
=0;i
<numops
;i
++) {
480 if (!cli_lock(&cli1
, fnum1
, offset
-1, 1, 0)) {
481 printf("lock1 %d failed (%s)\n",
487 if (!cli_lock(&cli2
, fnum2
, offset
-2, 1, 0)) {
488 printf("lock2 %d failed (%s)\n",
495 for (offset
=i
=0;i
<numops
;i
++) {
498 if (cli_lock(&cli1
, fnum1
, offset
-2, 1, 0)) {
499 printf("error: lock1 %d succeeded!\n", i
);
503 if (cli_lock(&cli2
, fnum2
, offset
-1, 1, 0)) {
504 printf("error: lock2 %d succeeded!\n", i
);
508 if (cli_lock(&cli1
, fnum1
, offset
-1, 1, 0)) {
509 printf("error: lock3 %d succeeded!\n", i
);
513 if (cli_lock(&cli2
, fnum2
, offset
-2, 1, 0)) {
514 printf("error: lock4 %d succeeded!\n", i
);
519 for (offset
=i
=0;i
<numops
;i
++) {
522 if (!cli_unlock(&cli1
, fnum1
, offset
-1, 1, 0)) {
523 printf("unlock1 %d failed (%s)\n",
529 if (!cli_unlock(&cli2
, fnum2
, offset
-2, 1, 0)) {
530 printf("unlock2 %d failed (%s)\n",
537 if (!cli_close(&cli1
, fnum1
)) {
538 printf("close1 failed (%s)\n", cli_errstr(&cli1
));
541 if (!cli_close(&cli2
, fnum2
)) {
542 printf("close2 failed (%s)\n", cli_errstr(&cli2
));
545 if (!cli_unlink(&cli1
, fname
)) {
546 printf("unlink failed (%s)\n", cli_errstr(&cli1
));
550 close_connection(&cli1
);
551 close_connection(&cli2
);
553 printf("finished locktest3\n");
558 This test checks that
560 1) the server does not allow an unlink on a file that is open
562 static void run_unlinktest(void)
564 static struct cli_state cli
;
565 char *fname
= "\\unlink.tst";
568 if (!open_connection(&cli
)) {
572 cli_sockopt(&cli
, sockops
);
574 printf("starting unlink test\n");
576 cli_unlink(&cli
, fname
);
580 fnum
= cli_open(&cli
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
582 printf("open of %s failed (%s)\n", fname
, cli_errstr(&cli
));
586 if (cli_unlink(&cli
, fname
)) {
587 printf("error: server allowed unlink on an open file\n");
590 close_connection(&cli
);
592 printf("unlink test finished\n");
597 static void browse_callback(char *sname
, uint32 stype
, char *comment
)
599 printf("\t%20.20s %08x %s\n", sname
, stype
, comment
);
604 This test checks the browse list code
607 static void run_browsetest(void)
609 static struct cli_state cli
;
611 printf("staring browse test\n");
613 if (!open_connection(&cli
)) {
617 printf("domain list:\n");
618 cli_NetServerEnum(&cli
, workgroup
,
622 printf("machine list:\n");
623 cli_NetServerEnum(&cli
, workgroup
,
627 close_connection(&cli
);
629 printf("browse test finished\n");
634 This checks how the getatr calls works
636 static void run_attrtest(void)
638 static struct cli_state cli
;
641 char *fname
= "\\attrib.tst";
643 printf("staring attrib test\n");
645 if (!open_connection(&cli
)) {
649 cli_unlink(&cli
, fname
);
650 fnum
= cli_open(&cli
, fname
,
651 O_RDWR
| O_CREAT
| O_TRUNC
, DENY_NONE
);
652 cli_close(&cli
, fnum
);
653 if (!cli_stat(&cli
, fname
, &st
)) {
654 printf("getatr failed (%s)\n", cli_errstr(&cli
));
657 if (abs(st
.st_mtime
- time(NULL
)) > 2) {
658 printf("ERROR: SMBgetatr bug. time is %s",
659 ctime(&st
.st_mtime
));
662 close_connection(&cli
);
664 printf("attrib test finished\n");
668 static void create_procs(int nprocs
, int numops
)
672 for (i
=0;i
<nprocs
;i
++) {
674 int mypid
= getpid();
675 srandom(mypid
^ time(NULL
));
681 for (i
=0;i
<nprocs
;i
++)
682 waitpid(0, &status
, 0);
687 /****************************************************************************
689 ****************************************************************************/
690 int main(int argc
,char *argv
[])
692 int nprocs
=1, numops
=100;
702 charset_initialise();
708 if (strncmp(argv
[1], "\\\\", 2)) {
712 fstrcpy(host
, &argv
[1][2]);
713 p
= strchr(&host
[2],'\\');
720 get_myname(myname
,NULL
);
722 if (*username
== 0 && getenv("LOGNAME")) {
723 strcpy(username
,getenv("LOGNAME"));
730 while ((opt
= getopt(argc
, argv
, "hW:U:n:N:O:o:m:")) != EOF
) {
733 fstrcpy(workgroup
,optarg
);
736 max_protocol
= interpret_protocol(optarg
, max_protocol
);
739 nprocs
= atoi(optarg
);
742 numops
= atoi(optarg
);
748 fstrcpy(myname
, optarg
);
751 strcpy(username
,optarg
);
752 p
= strchr(username
,'%');
755 strcpy(password
, p
+1);
760 printf("Unknown option %c (%d)\n", (char)opt
, opt
);
767 p
= getpass("Password:");
774 printf("host=%s share=%s user=%s myname=%s\n",
775 host
, share
, username
, myname
);
778 create_procs(nprocs
, numops
);
779 printf("rw_torture: %g secs\n", end_timer());
783 run_locktest3(numops
);