2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1997-1998
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.
26 static fstring host, workgroup, share, password, username, myname;
27 static int max_protocol = PROTOCOL_NT1;
28 static char *sockops="";
31 static struct timeval tp1,tp2;
33 static void start_timer(void)
35 gettimeofday(&tp1,NULL);
38 static double end_timer(void)
40 gettimeofday(&tp2,NULL);
41 return((tp2.tv_sec - tp1.tv_sec) +
42 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
46 static BOOL open_connection(struct cli_state *c)
48 struct nmb_name called, calling;
50 if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
51 printf("Failed to connect with %s\n", host);
55 make_nmb_name(&calling, myname, 0x0, "");
56 make_nmb_name(&called , host, 0x20, "");
58 if (!cli_session_request(c, &calling, &called)) {
59 printf("%s rejected the session\n",host);
64 c->protocol = max_protocol;
66 if (!cli_negprot(c)) {
67 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
72 if (!cli_session_setup(c, username, password, strlen(password),
74 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
79 if (!cli_send_tconX(c, share,
80 strstr(share,"IPC$")?"IPC":"A:",
81 password, strlen(password)+1)) {
82 printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
92 static void close_connection(struct cli_state *c)
95 printf("tdis failed (%s)\n", cli_errstr(c));
102 /* check if the server produced the expected error code */
103 static BOOL check_error(struct cli_state *c,
104 uint8 eclass, uint32 ecode, uint32 nterr)
109 eno = cli_error(c, &eclass, &num);
110 if ((eclass != class || ecode != num) &&
111 num != (nterr&0xFFFFFF)) {
112 printf("unexpected error code class=%d code=%d\n",
113 (int)class, (int)num);
114 printf(" expected %d/%d %d\n",
115 (int)eclass, (int)ecode, (int)nterr);
122 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
124 while (!cli_lock(c, fnum, offset, len, -1)) {
125 if (!check_error(c, ERRDOS, ERRlock, 0)) return False;
131 static BOOL rw_torture(struct cli_state *c, int numops)
133 char *lockfname = "\\torture.lck";
137 int pid2, pid = getpid();
141 fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
144 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
146 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
151 for (i=0;i<numops;i++) {
152 unsigned n = (unsigned)sys_random()%10;
154 printf("%d\r", i); fflush(stdout);
156 slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
158 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
162 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
164 printf("open failed (%s)\n", cli_errstr(c));
168 if (cli_write(c, fnum, 0, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
169 printf("write failed (%s)\n", cli_errstr(c));
173 if (cli_write(c, fnum, 0, (char *)buf,
174 sizeof(pid)+(j*sizeof(buf)),
175 sizeof(buf)) != sizeof(buf)) {
176 printf("write failed (%s)\n", cli_errstr(c));
182 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
183 printf("read failed (%s)\n", cli_errstr(c));
187 printf("data corruption!\n");
190 if (!cli_close(c, fnum)) {
191 printf("close failed (%s)\n", cli_errstr(c));
194 if (!cli_unlink(c, fname)) {
195 printf("unlink failed (%s)\n", cli_errstr(c));
198 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
199 printf("unlock failed (%s)\n", cli_errstr(c));
204 cli_unlink(c, lockfname);
211 static void usage(void)
213 printf("Usage: smbtorture //server/share <options>\n");
215 printf("\t-U user%%pass\n");
216 printf("\t-N numprocs\n");
217 printf("\t-n my_netbios_name\n");
218 printf("\t-W workgroup\n");
219 printf("\t-o num_operations\n");
220 printf("\t-O socket_options\n");
221 printf("\t-m maximum protocol\n");
229 static void run_torture(int numops)
231 static struct cli_state cli;
233 if (open_connection(&cli)) {
234 cli_sockopt(&cli, sockops);
236 printf("pid %d OK\n", getpid());
238 rw_torture(&cli, numops);
240 close_connection(&cli);
245 This test checks for two things:
247 1) correct support for retaining locks over a close (ie. the server
248 must not use posix semantics)
249 2) support for lock timeouts
251 static void run_locktest1(void)
253 static struct cli_state cli1, cli2;
254 char *fname = "\\lockt1.lck";
255 int fnum1, fnum2, fnum3;
258 if (!open_connection(&cli1) || !open_connection(&cli2)) {
261 cli_sockopt(&cli1, sockops);
262 cli_sockopt(&cli2, sockops);
264 printf("starting locktest1\n");
266 cli_unlink(&cli1, fname);
268 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
270 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
273 fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
275 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
278 fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
280 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
284 if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
285 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
290 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
291 printf("lock2 succeeded! This is a locking bug\n");
294 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
298 printf("Testing lock timeouts\n");
300 if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
301 printf("lock3 succeeded! This is a locking bug\n");
304 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
309 printf("error: This server appears not to support timed lock requests\n");
312 if (!cli_close(&cli1, fnum2)) {
313 printf("close1 failed (%s)\n", cli_errstr(&cli1));
317 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
318 printf("lock4 succeeded! This is a locking bug\n");
321 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
324 if (!cli_close(&cli1, fnum1)) {
325 printf("close2 failed (%s)\n", cli_errstr(&cli1));
329 if (!cli_close(&cli2, fnum3)) {
330 printf("close3 failed (%s)\n", cli_errstr(&cli2));
334 if (!cli_unlink(&cli1, fname)) {
335 printf("unlink failed (%s)\n", cli_errstr(&cli1));
340 close_connection(&cli1);
341 close_connection(&cli2);
343 printf("Passed locktest1\n");
348 This test checks that
350 1) the server supports multiple locking contexts on the one SMB
351 connection, distinguished by PID.
353 2) the server correctly fails overlapping locks made by the same PID (this
354 goes against POSIX behaviour, which is why it is tricky to implement)
356 3) the server denies unlock requests by an incorrect client PID
358 static void run_locktest2(void)
360 static struct cli_state cli;
361 char *fname = "\\lockt2.lck";
362 int fnum1, fnum2, fnum3;
364 if (!open_connection(&cli)) {
368 cli_sockopt(&cli, sockops);
370 printf("starting locktest2\n");
372 cli_unlink(&cli, fname);
376 fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
378 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
382 fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
384 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
390 fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
392 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
398 if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
399 printf("lock1 failed (%s)\n", cli_errstr(&cli));
403 if (cli_lock(&cli, fnum2, 0, 4, 0)) {
404 printf("lock2 succeeded! This is a locking bug\n");
406 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
411 if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
412 printf("unlock1 succeeded! This is a locking bug\n");
415 if (cli_lock(&cli, fnum3, 0, 4, 0)) {
416 printf("lock3 succeeded! This is a locking bug\n");
418 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
423 if (!cli_close(&cli, fnum1)) {
424 printf("close1 failed (%s)\n", cli_errstr(&cli));
428 if (!cli_close(&cli, fnum2)) {
429 printf("close2 failed (%s)\n", cli_errstr(&cli));
433 if (!cli_close(&cli, fnum3)) {
434 printf("close3 failed (%s)\n", cli_errstr(&cli));
438 close_connection(&cli);
440 printf("locktest2 finished\n");
445 This test checks that
447 1) the server supports the full offset range in lock requests
449 static void run_locktest3(int numops)
451 static struct cli_state cli1, cli2;
452 char *fname = "\\lockt3.lck";
456 #define NEXT_OFFSET offset += (~(uint32)0) / numops
458 if (!open_connection(&cli1) || !open_connection(&cli2)) {
461 cli_sockopt(&cli1, sockops);
462 cli_sockopt(&cli2, sockops);
464 printf("starting locktest3\n");
466 cli_unlink(&cli1, fname);
468 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
470 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
473 fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
475 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
479 for (offset=i=0;i<numops;i++) {
481 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
482 printf("lock1 %d failed (%s)\n",
488 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
489 printf("lock2 %d failed (%s)\n",
496 for (offset=i=0;i<numops;i++) {
499 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
500 printf("error: lock1 %d succeeded!\n", i);
504 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
505 printf("error: lock2 %d succeeded!\n", i);
509 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
510 printf("error: lock3 %d succeeded!\n", i);
514 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
515 printf("error: lock4 %d succeeded!\n", i);
520 for (offset=i=0;i<numops;i++) {
523 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
524 printf("unlock1 %d failed (%s)\n",
530 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
531 printf("unlock2 %d failed (%s)\n",
538 if (!cli_close(&cli1, fnum1)) {
539 printf("close1 failed (%s)\n", cli_errstr(&cli1));
542 if (!cli_close(&cli2, fnum2)) {
543 printf("close2 failed (%s)\n", cli_errstr(&cli2));
546 if (!cli_unlink(&cli1, fname)) {
547 printf("unlink failed (%s)\n", cli_errstr(&cli1));
551 close_connection(&cli1);
552 close_connection(&cli2);
554 printf("finished locktest3\n");
559 This test checks that
561 1) the server does not allow an unlink on a file that is open
563 static void run_unlinktest(void)
565 static struct cli_state cli;
566 char *fname = "\\unlink.tst";
569 if (!open_connection(&cli)) {
573 cli_sockopt(&cli, sockops);
575 printf("starting unlink test\n");
577 cli_unlink(&cli, fname);
581 fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
583 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
587 if (cli_unlink(&cli, fname)) {
588 printf("error: server allowed unlink on an open file\n");
591 cli_close(&cli, fnum);
592 cli_unlink(&cli, fname);
594 close_connection(&cli);
596 printf("unlink test finished\n");
599 /* generate a random buffer */
600 static void rand_buf(char *buf, int len)
608 /* send random IPC commands */
609 static void run_randomipc(void)
615 int api, param_len, i;
616 static struct cli_state cli;
618 printf("starting random ipc test\n");
620 if (!open_connection(&cli)) {
624 for (i=0;i<1000;i++) {
625 api = sys_random() % 500;
626 param_len = (sys_random() % 64) + 4;
628 rand_buf(param, param_len);
634 NULL, 0, BUFFER_SIZE,
639 close_connection(&cli);
641 printf("finished random ipc test\n");
646 static void browse_callback(const char *sname, uint32 stype,
649 printf("\t%20.20s %08x %s\n", sname, stype, comment);
655 This test checks the browse list code
658 static void run_browsetest(void)
660 static struct cli_state cli;
662 printf("starting browse test\n");
664 if (!open_connection(&cli)) {
668 printf("domain list:\n");
669 cli_NetServerEnum(&cli, workgroup,
673 printf("machine list:\n");
674 cli_NetServerEnum(&cli, workgroup,
678 close_connection(&cli);
680 printf("browse test finished\n");
685 This checks how the getatr calls works
687 static void run_attrtest(void)
689 static struct cli_state cli;
692 char *fname = "\\attrib.tst";
694 printf("starting attrib test\n");
696 if (!open_connection(&cli)) {
700 cli_unlink(&cli, fname);
701 fnum = cli_open(&cli, fname,
702 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
703 cli_close(&cli, fnum);
704 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
705 printf("getatr failed (%s)\n", cli_errstr(&cli));
708 if (abs(t - time(NULL)) > 2) {
709 printf("ERROR: SMBgetatr bug. time is %s",
714 t2 = t-60*60*24; /* 1 day ago */
716 if (!cli_setatr(&cli, fname, 0, t2)) {
717 printf("setatr failed (%s)\n", cli_errstr(&cli));
720 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
721 printf("getatr failed (%s)\n", cli_errstr(&cli));
725 printf("ERROR: getatr/setatr bug. times are\n%s",
727 printf("%s", ctime(&t2));
730 cli_unlink(&cli, fname);
732 close_connection(&cli);
734 printf("attrib test finished\n");
739 This checks a couple of trans2 calls
741 static void run_trans2test(void)
743 static struct cli_state cli;
746 time_t c_time, a_time, m_time, w_time, m_time2;
747 char *fname = "\\trans2.tst";
748 char *dname = "\\trans2";
749 char *fname2 = "\\trans2\\trans2.tst";
751 printf("starting trans2 test\n");
753 if (!open_connection(&cli)) {
757 cli_unlink(&cli, fname);
758 fnum = cli_open(&cli, fname,
759 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
760 if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time)) {
761 printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
763 cli_close(&cli, fnum);
767 cli_unlink(&cli, fname);
768 fnum = cli_open(&cli, fname,
769 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
770 cli_close(&cli, fnum);
772 if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
773 printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
775 if (c_time != m_time) {
776 printf("create time=%s", ctime(&c_time));
777 printf("modify time=%s", ctime(&m_time));
778 printf("This system appears to have sticky create times\n");
780 if (a_time % (60*60) == 0) {
781 printf("access time=%s", ctime(&a_time));
782 printf("This system appears to set a midnight access time\n");
785 if (abs(m_time - time(NULL)) > 60*60*24*7) {
786 printf("ERROR: totally incorrect times - maybe word reversed?\n");
791 cli_unlink(&cli, fname);
792 fnum = cli_open(&cli, fname,
793 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
794 cli_close(&cli, fnum);
795 if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time,
796 &w_time, &size, NULL)) {
797 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
799 if (w_time < 60*60*24*2) {
800 printf("write time=%s", ctime(&w_time));
801 printf("This system appears to set a initial 0 write time\n");
805 cli_unlink(&cli, fname);
808 /* check if the server updates the directory modification time
809 when creating a new file */
810 if (!cli_mkdir(&cli, dname)) {
811 printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
814 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time,
815 &w_time, &size, NULL)) {
816 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
819 fnum = cli_open(&cli, fname2,
820 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
821 cli_write(&cli, fnum, 0, (char *)&fnum, 0, sizeof(fnum));
822 cli_close(&cli, fnum);
823 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2,
824 &w_time, &size, NULL)) {
825 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
827 if (m_time2 == m_time)
828 printf("This system does not update directory modification times\n");
830 cli_unlink(&cli, fname2);
831 cli_rmdir(&cli, dname);
834 close_connection(&cli);
836 printf("trans2 test finished\n");
840 static void create_procs(int nprocs, int numops)
844 for (i=0;i<nprocs;i++) {
846 int mypid = getpid();
847 sys_srandom(mypid ^ time(NULL));
853 for (i=0;i<nprocs;i++)
854 waitpid(0, &status, 0);
859 /****************************************************************************
861 ****************************************************************************/
862 int main(int argc,char *argv[])
864 int nprocs=1, numops=100;
874 charset_initialise();
880 for(p = argv[1]; *p; p++)
884 if (strncmp(argv[1], "//", 2)) {
888 fstrcpy(host, &argv[1][2]);
889 p = strchr(&host[2],'/');
896 get_myname(myname,NULL);
898 if (*username == 0 && getenv("LOGNAME")) {
899 pstrcpy(username,getenv("LOGNAME"));
906 while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
909 fstrcpy(workgroup,optarg);
912 max_protocol = interpret_protocol(optarg, max_protocol);
915 nprocs = atoi(optarg);
918 numops = atoi(optarg);
924 fstrcpy(myname, optarg);
927 pstrcpy(username,optarg);
928 p = strchr(username,'%');
931 pstrcpy(password, p+1);
936 printf("Unknown option %c (%d)\n", (char)opt, opt);
943 p = getpass("Password:");
945 pstrcpy(password, p);
950 printf("host=%s share=%s user=%s myname=%s\n",
951 host, share, username, myname);
956 create_procs(nprocs, numops);
957 printf("rw_torture: %g secs\n", end_timer());
961 run_locktest3(numops);