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 char *sockops="";
32 static struct timeval tp1,tp2;
34 static void start_timer()
36 gettimeofday(&tp1,NULL);
39 static double end_timer()
41 gettimeofday(&tp2,NULL);
42 return((tp2.tv_sec - tp1.tv_sec) +
43 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
47 static BOOL open_connection(struct cli_state *c)
49 if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
50 printf("Failed to connect with %s\n", host);
54 if (!cli_session_request(c, host, 0x20, myname)) {
55 printf("%s rejected the session\n",host);
60 if (!cli_negprot(c)) {
61 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
66 if (!cli_session_setup(c, username, password, strlen(password),
68 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
73 if (!cli_send_tconX(c, share, "A:", password, strlen(password)+1)) {
74 printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
84 static void close_connection(struct cli_state *c)
87 printf("tdis failed (%s)\n", cli_errstr(c));
94 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
96 while (!cli_lock(c, fnum, offset, len, -1)) {
98 cli_error(c, &eclass, &num);
99 if (eclass != ERRDOS || num != ERRlock) {
100 printf("lock failed (%s)\n",
109 static BOOL rw_torture(struct cli_state *c, int numops)
111 char *lockfname = "\\torture.lck";
115 int pid2, pid = getpid();
118 fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
121 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
123 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
128 for (i=0;i<numops;i++) {
129 unsigned n = (unsigned)random()%10;
131 printf("%d\r", i); fflush(stdout);
133 sprintf(fname,"\\torture.%u", n);
135 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
139 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
141 printf("open failed (%s)\n", cli_errstr(c));
145 if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
146 printf("write failed (%s)\n", cli_errstr(c));
151 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
152 printf("read failed (%s)\n", cli_errstr(c));
156 printf("data corruption!\n");
159 if (!cli_close(c, fnum)) {
160 printf("close failed (%s)\n", cli_errstr(c));
163 if (!cli_unlink(c, fname)) {
164 printf("unlink failed (%s)\n", cli_errstr(c));
167 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
168 printf("unlock failed (%s)\n", cli_errstr(c));
177 static void usage(void)
179 printf("Usage: smbtorture \\\\server\\share <options>\n");
181 printf("\t-U user%%pass\n");
182 printf("\t-N numprocs\n");
183 printf("\t-n my_netbios_name\n");
184 printf("\t-W workgroup\n");
185 printf("\t-o num_operations\n");
186 printf("\t-O socket_options\n");
194 static void run_torture(int numops)
196 static struct cli_state cli;
198 if (open_connection(&cli)) {
199 cli_sockopt(&cli, sockops);
201 printf("pid %d OK\n", getpid());
203 rw_torture(&cli, numops);
205 close_connection(&cli);
210 This test checks for two things:
212 1) correct support for retaining locks over a close (ie. the server
213 must not use posix semantics)
214 2) support for lock timeouts
216 static void run_locktest1(void)
218 static struct cli_state cli1, cli2;
219 char *fname = "\\locktest.lck";
220 int fnum1, fnum2, fnum3;
223 if (!open_connection(&cli1) || !open_connection(&cli2)) {
226 cli_sockopt(&cli1, sockops);
227 cli_sockopt(&cli2, sockops);
229 printf("starting locktest1\n");
231 cli_unlink(&cli1, fname);
233 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
235 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
238 fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
240 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
243 fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
245 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
249 if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
250 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
255 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
256 printf("lock2 succeeded! This is a locking bug\n");
260 cli_error(&cli2, &eclass, &num);
261 if (eclass != ERRDOS || num != ERRlock) {
262 printf("error should have been ERRDOS/ERRlock (%s)\n",
269 printf("Testing lock timeouts\n");
271 if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
272 printf("lock3 succeeded! This is a locking bug\n");
276 cli_error(&cli2, &eclass, &num);
277 if (eclass != ERRDOS || num != ERRlock) {
278 printf("error should have been ERRDOS/ERRlock (%s)\n",
286 printf("error: This server appears not to support timed lock requests\n");
289 if (!cli_close(&cli1, fnum2)) {
290 printf("close1 failed (%s)\n", cli_errstr(&cli1));
294 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
295 printf("lock4 succeeded! This is a locking bug\n");
299 cli_error(&cli2, &eclass, &num);
300 if (eclass != ERRDOS || num != ERRlock) {
301 printf("error should have been ERRDOS/ERRlock (%s)\n",
307 if (!cli_close(&cli1, fnum1)) {
308 printf("close2 failed (%s)\n", cli_errstr(&cli1));
312 if (!cli_close(&cli2, fnum3)) {
313 printf("close3 failed (%s)\n", cli_errstr(&cli2));
317 if (!cli_unlink(&cli1, fname)) {
318 printf("unlink failed (%s)\n", cli_errstr(&cli1));
323 close_connection(&cli1);
324 close_connection(&cli2);
326 printf("Passed locktest1\n");
331 This test checks that
333 1) the server supports multiple locking contexts on the one SMB
334 connection, distinguished by PID.
336 2) the server correctly fails overlapping locks made by the same PID (this
337 goes against POSIX behaviour, which is why it is tricky to implement)
339 3) the server denies unlock requests by an incorrect client PID
341 static void run_locktest2(void)
343 static struct cli_state cli;
344 char *fname = "\\locktest.lck";
345 int fnum1, fnum2, fnum3;
347 if (!open_connection(&cli)) {
351 cli_sockopt(&cli, sockops);
353 printf("starting locktest2\n");
355 cli_unlink(&cli, fname);
359 fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
361 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
365 fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
367 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
373 fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
375 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
381 if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
382 printf("lock1 failed (%s)\n", cli_errstr(&cli));
386 if (cli_lock(&cli, fnum2, 0, 4, 0)) {
387 printf("lock2 succeeded! This is a locking bug\n");
390 cli_error(&cli, &eclass, &num);
391 if (eclass != ERRDOS || num != ERRlock) {
392 printf("error should have been ERRDOS/ERRlock (%s)\n",
400 if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
401 printf("unlock1 succeeded! This is a locking bug\n");
404 if (cli_lock(&cli, fnum3, 0, 4, 0)) {
405 printf("lock3 succeeded! This is a locking bug\n");
408 cli_error(&cli, &eclass, &num);
409 if (eclass != ERRDOS || num != ERRlock) {
410 printf("error should have been ERRDOS/ERRlock (%s)\n",
418 if (!cli_close(&cli, fnum1)) {
419 printf("close1 failed (%s)\n", cli_errstr(&cli));
423 if (!cli_close(&cli, fnum2)) {
424 printf("close2 failed (%s)\n", cli_errstr(&cli));
428 if (!cli_close(&cli, fnum3)) {
429 printf("close3 failed (%s)\n", cli_errstr(&cli));
433 close_connection(&cli);
435 printf("locktest2 finished\n");
440 This test checks that
442 1) the server supports the full offset range in lock requests
444 static void run_locktest3(int numops)
446 static struct cli_state cli1, cli2;
447 char *fname = "\\locktest.lck";
451 #define NEXT_OFFSET offset += (~(uint32)0) / numops
453 if (!open_connection(&cli1) || !open_connection(&cli2)) {
456 cli_sockopt(&cli1, sockops);
457 cli_sockopt(&cli2, sockops);
459 printf("starting locktest3\n");
461 cli_unlink(&cli1, fname);
463 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
465 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
468 fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
470 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
474 for (offset=i=0;i<numops;i++) {
476 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
477 printf("lock1 %d failed (%s)\n",
483 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
484 printf("lock2 %d failed (%s)\n",
491 for (offset=i=0;i<numops;i++) {
494 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
495 printf("error: lock1 %d succeeded!\n", i);
499 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
500 printf("error: lock2 %d succeeded!\n", i);
504 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
505 printf("error: lock3 %d succeeded!\n", i);
509 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
510 printf("error: lock4 %d succeeded!\n", i);
515 for (offset=i=0;i<numops;i++) {
518 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
519 printf("unlock1 %d failed (%s)\n",
525 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
526 printf("unlock2 %d failed (%s)\n",
533 if (!cli_close(&cli1, fnum1)) {
534 printf("close1 failed (%s)\n", cli_errstr(&cli1));
537 if (!cli_close(&cli2, fnum2)) {
538 printf("close2 failed (%s)\n", cli_errstr(&cli2));
541 if (!cli_unlink(&cli1, fname)) {
542 printf("unlink failed (%s)\n", cli_errstr(&cli1));
546 close_connection(&cli1);
547 close_connection(&cli2);
549 printf("finished locktest3\n");
554 This test checks that
556 1) the server does not allow an unlink on a file that is open
558 static void run_unlinktest(void)
560 static struct cli_state cli;
561 char *fname = "\\unlink.tst";
564 if (!open_connection(&cli)) {
568 cli_sockopt(&cli, sockops);
570 printf("starting unlink test\n");
572 cli_unlink(&cli, fname);
576 fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
578 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
582 if (cli_unlink(&cli, fname)) {
583 printf("error: server allowed unlink on an open file\n");
586 close_connection(&cli);
588 printf("unlink test finished\n");
593 static void browse_callback(char *sname, uint32 stype, char *comment)
595 printf("\t%20.20s %08x %s\n", sname, stype, comment);
600 This test checks the browse list code
603 static void run_browsetest(void)
605 static struct cli_state cli;
607 printf("staring browse test\n");
609 if (!open_connection(&cli)) {
613 printf("domain list:\n");
614 cli_NetServerEnum(&cli, workgroup,
618 printf("machine list:\n");
619 cli_NetServerEnum(&cli, workgroup,
623 close_connection(&cli);
625 printf("browse test finished\n");
630 static void create_procs(int nprocs, int numops)
634 for (i=0;i<nprocs;i++) {
636 int mypid = getpid();
637 srandom(mypid ^ time(NULL));
643 for (i=0;i<nprocs;i++)
644 waitpid(0, &status, 0);
649 /****************************************************************************
651 ****************************************************************************/
652 int main(int argc,char *argv[])
654 int nprocs=1, numops=100;
664 charset_initialise();
670 if (strncmp(argv[1], "\\\\", 2)) {
674 fstrcpy(host, &argv[1][2]);
675 p = strchr(&host[2],'\\');
682 get_myname(myname,NULL);
684 if (*username == 0 && getenv("LOGNAME")) {
685 strcpy(username,getenv("LOGNAME"));
692 while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:")) != EOF) {
695 fstrcpy(workgroup,optarg);
698 nprocs = atoi(optarg);
701 numops = atoi(optarg);
707 fstrcpy(myname, optarg);
710 strcpy(username,optarg);
711 p = strchr(username,'%');
714 strcpy(password, p+1);
719 printf("Unknown option %c (%d)\n", (char)opt, opt);
726 p = getpass("Password:");
733 printf("host=%s share=%s user=%s myname=%s\n",
734 host, share, username, myname);
737 create_procs(nprocs, numops);
738 printf("rw_torture: %g secs\n", end_timer());
742 run_locktest3(numops);