print a + at the start of the unlink phase, so we can see it more
[Samba/gbeck.git] / source / utils / torture.c
blobf2945cb56b0b491aaaecfdf641cdc8e7c5821152
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 SMB torture tester
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.
22 #define NO_SYSLOG
24 #include "includes.h"
26 static fstring host, workgroup, share, password, username, myname;
27 static int max_protocol = PROTOCOL_NT1;
28 static char *sockops="TCP_NODELAY";
29 static int nprocs=1, numops=100;
30 static pid_t master_pid;
31 static struct cli_state current_cli;
33 static double create_procs(void (*fn)(void));
36 static struct timeval tp1,tp2;
38 static void start_timer(void)
40 gettimeofday(&tp1,NULL);
43 static double end_timer(void)
45 gettimeofday(&tp2,NULL);
46 return((tp2.tv_sec - tp1.tv_sec) +
47 (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
51 /* return a pointer to a anonymous shared memory segment of size "size"
52 which will persist across fork() but will disappear when all processes
53 exit
55 The memory is not zeroed
57 This function uses system5 shared memory. It takes advantage of a property
58 that the memory is not destroyed if it is attached when the id is removed
60 static void *shm_setup(int size)
62 int shmid;
63 void *ret;
65 shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
66 if (shmid == -1) {
67 printf("can't get shared memory\n");
68 exit(1);
70 ret = (void *)shmat(shmid, 0, 0);
71 if (!ret || ret == (void *)-1) {
72 printf("can't attach to shared memory\n");
73 return NULL;
75 /* the following releases the ipc, but note that this process
76 and all its children will still have access to the memory, its
77 just that the shmid is no longer valid for other shm calls. This
78 means we don't leave behind lots of shm segments after we exit
80 See Stevens "advanced programming in unix env" for details
82 shmctl(shmid, IPC_RMID, 0);
84 return ret;
88 static BOOL open_connection(struct cli_state *c)
90 struct nmb_name called, calling;
92 ZERO_STRUCTP(c);
94 make_nmb_name(&calling, myname, 0x0, "");
95 make_nmb_name(&called , host, 0x20, "");
97 if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
98 printf("Failed to connect with %s\n", host);
99 return False;
102 c->timeout = 120000; /* set a really long timeout (2 minutes) */
104 if (!cli_session_request(c, &calling, &called)) {
105 printf("%s rejected the session\n",host);
106 cli_shutdown(c);
107 return False;
110 if (!cli_negprot(c)) {
111 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
112 cli_shutdown(c);
113 return False;
116 if (!cli_session_setup(c, username,
117 password, strlen(password),
118 password, strlen(password),
119 workgroup)) {
120 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
121 cli_shutdown(c);
122 return False;
125 if (!cli_send_tconX(c, share, "?????",
126 password, strlen(password)+1)) {
127 printf("%s refused tree connect (%s)\n", host, cli_errstr(c));
128 cli_shutdown(c);
129 return False;
132 return True;
137 static void close_connection(struct cli_state *c)
139 if (!cli_tdis(c)) {
140 printf("tdis failed (%s)\n", cli_errstr(c));
143 cli_shutdown(c);
147 /* check if the server produced the expected error code */
148 static BOOL check_error(struct cli_state *c,
149 uint8 eclass, uint32 ecode, uint32 nterr)
151 uint8 class;
152 uint32 num;
153 int eno;
154 eno = cli_error(c, &class, &num, NULL);
155 if ((eclass != class || ecode != num) &&
156 num != (nterr&0xFFFFFF)) {
157 printf("unexpected error code class=%d code=%d\n",
158 (int)class, (int)num);
159 printf(" expected %d/%d %d\n",
160 (int)eclass, (int)ecode, (int)nterr);
161 return False;
163 return True;
167 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
169 while (!cli_lock(c, fnum, offset, len, -1)) {
170 if (!check_error(c, ERRDOS, ERRlock, 0)) return False;
172 return True;
176 static BOOL rw_torture(struct cli_state *c)
178 char *lockfname = "\\torture.lck";
179 fstring fname;
180 int fnum;
181 int fnum2;
182 int pid2, pid = getpid();
183 int i, j;
184 char buf[1024];
186 fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL,
187 DENY_NONE);
188 if (fnum2 == -1)
189 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
190 if (fnum2 == -1) {
191 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
192 return False;
196 for (i=0;i<numops;i++) {
197 unsigned n = (unsigned)sys_random()%10;
198 if (i % 10 == 0) {
199 printf("%d\r", i); fflush(stdout);
201 slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
203 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
204 return False;
207 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
208 if (fnum == -1) {
209 printf("open failed (%s)\n", cli_errstr(c));
210 break;
213 if (cli_write(c, fnum, 0, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
214 printf("write failed (%s)\n", cli_errstr(c));
217 for (j=0;j<50;j++) {
218 if (cli_write(c, fnum, 0, (char *)buf,
219 sizeof(pid)+(j*sizeof(buf)),
220 sizeof(buf)) != sizeof(buf)) {
221 printf("write failed (%s)\n", cli_errstr(c));
225 pid2 = 0;
227 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
228 printf("read failed (%s)\n", cli_errstr(c));
231 if (pid2 != pid) {
232 printf("data corruption!\n");
235 if (!cli_close(c, fnum)) {
236 printf("close failed (%s)\n", cli_errstr(c));
239 if (!cli_unlink(c, fname)) {
240 printf("unlink failed (%s)\n", cli_errstr(c));
243 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
244 printf("unlock failed (%s)\n", cli_errstr(c));
248 cli_close(c, fnum2);
249 cli_unlink(c, lockfname);
251 printf("%d\n", i);
253 return True;
256 static void run_torture(void)
258 struct cli_state cli;
260 cli = current_cli;
262 cli_sockopt(&cli, sockops);
264 rw_torture(&cli);
266 close_connection(&cli);
269 static int nbsize1, nbsize2, nbprob1;
271 /* run a test that simulates an approximate netbench client load */
272 static void run_netbench(void)
274 struct cli_state cli;
275 int fnum, i;
276 int pid = getpid();
277 size_t size;
278 char buf[8192];
279 fstring fname;
281 cli = current_cli;
283 cli_sockopt(&cli, sockops);
285 for (i=0;i<numops;i++) {
286 slprintf(fname, sizeof(fname) - 1, "\\%03d%05d.doc", i, pid);
288 fnum = cli_open(&cli, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
289 if (fnum == -1) {
290 printf("open failed (%s)\n", cli_errstr(&cli));
291 break;
294 size = 0;
295 while (size < 256*1024) {
296 int s;
297 if (((unsigned)random()) % 100 > nbprob1) {
298 s = nbsize2;
299 } else {
300 s = nbsize1;
303 if (cli_smbwrite(&cli, fnum, buf, size, s) != s) {
304 printf("write failed (%s)\n", cli_errstr(&cli));
305 break;
307 size += s;
309 cli_close(&cli, fnum);
310 printf("."); fflush(stdout);
313 printf("+"); fflush(stdout);
315 for (i=0;i<numops;i++) {
316 slprintf(fname, sizeof(fname) - 1, "\\%03d%05d.doc", i, pid);
317 cli_unlink(&cli, fname);
320 close_connection(&cli);
324 /* run a test that simulates an approximate netbench w9X client load */
325 static void run_nbw95(void)
327 double t;
328 nbsize1 = 4096;
329 nbsize2 = 0;
330 nbprob1 = 100;
331 t = create_procs(run_netbench);
332 printf("Throughput %g MB/sec\n", nprocs*numops*256.0/(t*1024));
335 /* run a test that simulates an approximate netbench wNT client load */
336 static void run_nbwnt(void)
338 double t;
339 nbsize1 = 4296;
340 nbsize2 = 0;
341 nbprob1 = 67;
342 t = create_procs(run_netbench);
343 printf("Throughput %g MB/sec\n", nprocs*numops*256.0/(t*1024));
349 This test checks for two things:
351 1) correct support for retaining locks over a close (ie. the server
352 must not use posix semantics)
353 2) support for lock timeouts
355 static void run_locktest1(void)
357 static struct cli_state cli1, cli2;
358 char *fname = "\\lockt1.lck";
359 int fnum1, fnum2, fnum3;
360 time_t t1, t2;
362 if (!open_connection(&cli1) || !open_connection(&cli2)) {
363 return;
365 cli_sockopt(&cli1, sockops);
366 cli_sockopt(&cli2, sockops);
368 printf("starting locktest1\n");
370 cli_unlink(&cli1, fname);
372 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
373 if (fnum1 == -1) {
374 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
375 return;
377 fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
378 if (fnum2 == -1) {
379 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
380 return;
382 fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
383 if (fnum3 == -1) {
384 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
385 return;
388 if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
389 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
390 return;
394 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
395 printf("lock2 succeeded! This is a locking bug\n");
396 return;
397 } else {
398 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
402 printf("Testing lock timeouts\n");
403 t1 = time(NULL);
404 if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
405 printf("lock3 succeeded! This is a locking bug\n");
406 return;
407 } else {
408 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
410 t2 = time(NULL);
412 if (t2 - t1 < 5) {
413 printf("error: This server appears not to support timed lock requests\n");
416 if (!cli_close(&cli1, fnum2)) {
417 printf("close1 failed (%s)\n", cli_errstr(&cli1));
418 return;
421 if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
422 printf("lock4 succeeded! This is a locking bug\n");
423 return;
424 } else {
425 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
428 if (!cli_close(&cli1, fnum1)) {
429 printf("close2 failed (%s)\n", cli_errstr(&cli1));
430 return;
433 if (!cli_close(&cli2, fnum3)) {
434 printf("close3 failed (%s)\n", cli_errstr(&cli2));
435 return;
438 if (!cli_unlink(&cli1, fname)) {
439 printf("unlink failed (%s)\n", cli_errstr(&cli1));
440 return;
444 close_connection(&cli1);
445 close_connection(&cli2);
447 printf("Passed locktest1\n");
452 This test checks that
454 1) the server supports multiple locking contexts on the one SMB
455 connection, distinguished by PID.
457 2) the server correctly fails overlapping locks made by the same PID (this
458 goes against POSIX behaviour, which is why it is tricky to implement)
460 3) the server denies unlock requests by an incorrect client PID
462 static void run_locktest2(void)
464 static struct cli_state cli;
465 char *fname = "\\lockt2.lck";
466 int fnum1, fnum2, fnum3;
468 if (!open_connection(&cli)) {
469 return;
472 cli_sockopt(&cli, sockops);
474 printf("starting locktest2\n");
476 cli_unlink(&cli, fname);
478 cli_setpid(&cli, 1);
480 fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
481 if (fnum1 == -1) {
482 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
483 return;
486 fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
487 if (fnum2 == -1) {
488 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
489 return;
492 cli_setpid(&cli, 2);
494 fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
495 if (fnum3 == -1) {
496 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
497 return;
500 cli_setpid(&cli, 1);
502 if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
503 printf("lock1 failed (%s)\n", cli_errstr(&cli));
504 return;
507 if (cli_lock(&cli, fnum2, 0, 4, 0)) {
508 printf("lock2 succeeded! This is a locking bug\n");
509 } else {
510 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
513 cli_setpid(&cli, 2);
515 if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
516 printf("unlock1 succeeded! This is a locking bug\n");
519 if (cli_lock(&cli, fnum3, 0, 4, 0)) {
520 printf("lock3 succeeded! This is a locking bug\n");
521 } else {
522 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
525 cli_setpid(&cli, 1);
527 if (!cli_close(&cli, fnum1)) {
528 printf("close1 failed (%s)\n", cli_errstr(&cli));
529 return;
532 if (!cli_close(&cli, fnum2)) {
533 printf("close2 failed (%s)\n", cli_errstr(&cli));
534 return;
537 if (!cli_close(&cli, fnum3)) {
538 printf("close3 failed (%s)\n", cli_errstr(&cli));
539 return;
542 close_connection(&cli);
544 printf("locktest2 finished\n");
549 This test checks that
551 1) the server supports the full offset range in lock requests
553 static void run_locktest3(void)
555 static struct cli_state cli1, cli2;
556 char *fname = "\\lockt3.lck";
557 int fnum1, fnum2, i;
558 uint32 offset;
560 #define NEXT_OFFSET offset += (~(uint32)0) / numops
562 if (!open_connection(&cli1) || !open_connection(&cli2)) {
563 return;
565 cli_sockopt(&cli1, sockops);
566 cli_sockopt(&cli2, sockops);
568 printf("starting locktest3\n");
570 cli_unlink(&cli1, fname);
572 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
573 if (fnum1 == -1) {
574 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
575 return;
577 fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
578 if (fnum2 == -1) {
579 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
580 return;
583 for (offset=i=0;i<numops;i++) {
584 NEXT_OFFSET;
585 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
586 printf("lock1 %d failed (%s)\n",
588 cli_errstr(&cli1));
589 return;
592 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
593 printf("lock2 %d failed (%s)\n",
595 cli_errstr(&cli1));
596 return;
600 for (offset=i=0;i<numops;i++) {
601 NEXT_OFFSET;
603 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
604 printf("error: lock1 %d succeeded!\n", i);
605 return;
608 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
609 printf("error: lock2 %d succeeded!\n", i);
610 return;
613 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
614 printf("error: lock3 %d succeeded!\n", i);
615 return;
618 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
619 printf("error: lock4 %d succeeded!\n", i);
620 return;
624 for (offset=i=0;i<numops;i++) {
625 NEXT_OFFSET;
627 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
628 printf("unlock1 %d failed (%s)\n",
630 cli_errstr(&cli1));
631 return;
634 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
635 printf("unlock2 %d failed (%s)\n",
637 cli_errstr(&cli1));
638 return;
642 if (!cli_close(&cli1, fnum1)) {
643 printf("close1 failed (%s)\n", cli_errstr(&cli1));
646 if (!cli_close(&cli2, fnum2)) {
647 printf("close2 failed (%s)\n", cli_errstr(&cli2));
650 if (!cli_unlink(&cli1, fname)) {
651 printf("unlink failed (%s)\n", cli_errstr(&cli1));
652 return;
655 close_connection(&cli1);
656 close_connection(&cli2);
658 printf("finished locktest3\n");
663 test whether fnums and tids open on one VC are available on another (a major
664 security hole)
666 static void run_fdpasstest(void)
668 static struct cli_state cli1, cli2;
669 char *fname = "\\fdpass.tst";
670 int fnum1;
671 pstring buf;
673 if (!open_connection(&cli1) || !open_connection(&cli2)) {
674 return;
676 cli_sockopt(&cli1, sockops);
677 cli_sockopt(&cli2, sockops);
679 printf("starting fdpasstest\n");
681 cli_unlink(&cli1, fname);
683 fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
684 if (fnum1 == -1) {
685 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
686 return;
689 if (cli_write(&cli1, fnum1, 0, "hello world\n", 0, 13) != 13) {
690 printf("write failed (%s)\n", cli_errstr(&cli1));
691 return;
694 cli2.vuid = cli1.vuid;
695 cli2.cnum = cli1.cnum;
696 cli2.pid = cli1.pid;
699 if (cli_read(&cli2, fnum1, buf, 0, 13) == 13) {
700 printf("read succeeded! nasty security hole [%s]\n",
701 buf);
702 return;
705 cli_close(&cli1, fnum1);
706 cli_unlink(&cli1, fname);
708 close_connection(&cli1);
709 close_connection(&cli2);
711 printf("finished fdpasstest\n");
716 This test checks that
718 1) the server does not allow an unlink on a file that is open
720 static void run_unlinktest(void)
722 static struct cli_state cli;
723 char *fname = "\\unlink.tst";
724 int fnum;
726 if (!open_connection(&cli)) {
727 return;
730 cli_sockopt(&cli, sockops);
732 printf("starting unlink test\n");
734 cli_unlink(&cli, fname);
736 cli_setpid(&cli, 1);
738 fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
739 if (fnum == -1) {
740 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
741 return;
744 if (cli_unlink(&cli, fname)) {
745 printf("error: server allowed unlink on an open file\n");
748 cli_close(&cli, fnum);
749 cli_unlink(&cli, fname);
751 close_connection(&cli);
753 printf("unlink test finished\n");
758 test how many open files this server supports on the one socket
760 static void run_maxfidtest(void)
762 static struct cli_state cli;
763 char *template = "\\maxfid.%d.%d";
764 fstring fname;
765 int fnum;
766 int retries=4;
767 int n = numops;
769 cli = current_cli;
771 if (retries <= 0) {
772 printf("failed to connect\n");
773 return;
776 cli_sockopt(&cli, sockops);
778 fnum = 0;
779 while (1) {
780 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
781 if (cli_open(&cli, fname,
782 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE) ==
783 -1) {
784 printf("open of %s failed (%s)\n",
785 fname, cli_errstr(&cli));
786 printf("maximum fnum is %d\n", fnum);
787 break;
789 fnum++;
792 printf("cleaning up\n");
793 while (fnum > n) {
794 fnum--;
795 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
796 if (cli_unlink(&cli, fname)) {
797 printf("unlink of %s failed (%s)\n",
798 fname, cli_errstr(&cli));
802 printf("maxfid test finished\n");
803 close_connection(&cli);
806 /* generate a random buffer */
807 static void rand_buf(char *buf, int len)
809 while (len--) {
810 *buf = sys_random();
811 buf++;
815 /* send random IPC commands */
816 static void run_randomipc(void)
818 char *rparam = NULL;
819 char *rdata = NULL;
820 int rdrcnt,rprcnt;
821 pstring param;
822 int api, param_len, i;
823 static struct cli_state cli;
825 printf("starting random ipc test\n");
827 if (!open_connection(&cli)) {
828 return;
831 for (i=0;i<50000;i++) {
832 api = sys_random() % 500;
833 param_len = (sys_random() % 64);
835 rand_buf(param, param_len);
837 SSVAL(param,0,api);
839 cli_api(&cli,
840 param, param_len, 8,
841 NULL, 0, BUFFER_SIZE,
842 &rparam, &rprcnt,
843 &rdata, &rdrcnt);
846 close_connection(&cli);
848 printf("finished random ipc test\n");
853 static void browse_callback(const char *sname, uint32 stype,
854 const char *comment)
856 printf("\t%20.20s %08x %s\n", sname, stype, comment);
862 This test checks the browse list code
865 static void run_browsetest(void)
867 static struct cli_state cli;
869 printf("starting browse test\n");
871 if (!open_connection(&cli)) {
872 return;
875 printf("domain list:\n");
876 cli_NetServerEnum(&cli, workgroup,
877 SV_TYPE_DOMAIN_ENUM,
878 browse_callback);
880 printf("machine list:\n");
881 cli_NetServerEnum(&cli, workgroup,
882 SV_TYPE_ALL,
883 browse_callback);
885 close_connection(&cli);
887 printf("browse test finished\n");
892 This checks how the getatr calls works
894 static void run_attrtest(void)
896 static struct cli_state cli;
897 int fnum;
898 time_t t, t2;
899 char *fname = "\\attrib.tst";
901 printf("starting attrib test\n");
903 if (!open_connection(&cli)) {
904 return;
907 cli_unlink(&cli, fname);
908 fnum = cli_open(&cli, fname,
909 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
910 cli_close(&cli, fnum);
911 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
912 printf("getatr failed (%s)\n", cli_errstr(&cli));
915 if (abs(t - time(NULL)) > 2) {
916 printf("ERROR: SMBgetatr bug. time is %s",
917 ctime(&t));
918 t = time(NULL);
921 t2 = t-60*60*24; /* 1 day ago */
923 if (!cli_setatr(&cli, fname, 0, t2)) {
924 printf("setatr failed (%s)\n", cli_errstr(&cli));
927 if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
928 printf("getatr failed (%s)\n", cli_errstr(&cli));
931 if (t != t2) {
932 printf("ERROR: getatr/setatr bug. times are\n%s",
933 ctime(&t));
934 printf("%s", ctime(&t2));
937 cli_unlink(&cli, fname);
939 close_connection(&cli);
941 printf("attrib test finished\n");
946 This checks a couple of trans2 calls
948 static void run_trans2test(void)
950 static struct cli_state cli;
951 int fnum;
952 size_t size;
953 time_t c_time, a_time, m_time, w_time, m_time2;
954 char *fname = "\\trans2.tst";
955 char *dname = "\\trans2";
956 char *fname2 = "\\trans2\\trans2.tst";
958 printf("starting trans2 test\n");
960 if (!open_connection(&cli)) {
961 return;
964 cli_unlink(&cli, fname);
965 fnum = cli_open(&cli, fname,
966 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
967 if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time,
968 NULL, NULL)) {
969 printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
971 cli_close(&cli, fnum);
973 sleep(2);
975 cli_unlink(&cli, fname);
976 fnum = cli_open(&cli, fname,
977 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
978 cli_close(&cli, fnum);
980 if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
981 printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
982 } else {
983 if (c_time != m_time) {
984 printf("create time=%s", ctime(&c_time));
985 printf("modify time=%s", ctime(&m_time));
986 printf("This system appears to have sticky create times\n");
988 if (a_time % (60*60) == 0) {
989 printf("access time=%s", ctime(&a_time));
990 printf("This system appears to set a midnight access time\n");
993 if (abs(m_time - time(NULL)) > 60*60*24*7) {
994 printf("ERROR: totally incorrect times - maybe word reversed?\n");
999 cli_unlink(&cli, fname);
1000 fnum = cli_open(&cli, fname,
1001 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1002 cli_close(&cli, fnum);
1003 if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time,
1004 &w_time, &size, NULL, NULL)) {
1005 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
1006 } else {
1007 if (w_time < 60*60*24*2) {
1008 printf("write time=%s", ctime(&w_time));
1009 printf("This system appears to set a initial 0 write time\n");
1013 cli_unlink(&cli, fname);
1016 /* check if the server updates the directory modification time
1017 when creating a new file */
1018 if (!cli_mkdir(&cli, dname)) {
1019 printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
1021 sleep(3);
1022 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time,
1023 &w_time, &size, NULL, NULL)) {
1024 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
1027 fnum = cli_open(&cli, fname2,
1028 O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
1029 cli_write(&cli, fnum, 0, (char *)&fnum, 0, sizeof(fnum));
1030 cli_close(&cli, fnum);
1031 if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2,
1032 &w_time, &size, NULL, NULL)) {
1033 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
1034 } else {
1035 if (m_time2 == m_time)
1036 printf("This system does not update directory modification times\n");
1038 cli_unlink(&cli, fname2);
1039 cli_rmdir(&cli, dname);
1042 close_connection(&cli);
1044 printf("trans2 test finished\n");
1047 static double create_procs(void (*fn)(void))
1049 int i, status;
1050 volatile int *child_status;
1051 int synccount;
1052 int tries = 8;
1054 start_timer();
1056 master_pid = getpid();
1057 synccount = 0;
1059 child_status = (volatile int *)shm_setup(sizeof(int)*nprocs);
1060 if (!child_status) {
1061 printf("Failed to setup shared memory\n");
1062 return end_timer();
1065 memset(child_status, 0, sizeof(int)*nprocs);
1067 for (i=0;i<nprocs;i++) {
1068 if (fork() == 0) {
1069 int mypid = getpid();
1070 sys_srandom(mypid ^ time(NULL));
1072 while (1) {
1073 memset(&current_cli, 0, sizeof(current_cli));
1074 if (open_connection(&current_cli)) break;
1075 if (tries-- == 0) {
1076 printf("pid %d failed to start\n", getpid());
1077 _exit(1);
1079 msleep(10);
1082 child_status[i] = getpid();
1084 while (child_status[i]) msleep(2);
1086 fn();
1087 _exit(0);
1091 do {
1092 synccount = 0;
1093 for (i=0;i<nprocs;i++) {
1094 if (child_status[i]) synccount++;
1096 if (synccount == nprocs) break;
1097 msleep(10);
1098 } while (end_timer() < 30);
1100 if (synccount != nprocs) {
1101 printf("FAILED TO START %d CLIENTS (started %d)\n", nprocs, synccount);
1102 return end_timer();
1105 /* start the client load */
1106 start_timer();
1108 for (i=0;i<nprocs;i++) {
1109 child_status[i] = 0;
1112 printf("%d clients started\n", nprocs);
1114 for (i=0;i<nprocs;i++) {
1115 waitpid(0, &status, 0);
1116 printf("*");
1118 printf("\n");
1119 return end_timer();
1123 #define FLAG_MULTIPROC 1
1125 static struct {
1126 char *name;
1127 void (*fn)(void);
1128 unsigned flags;
1129 } torture_ops[] = {
1130 {"FDPASS", run_fdpasstest, 0},
1131 {"LOCK1", run_locktest1, 0},
1132 {"LOCK2", run_locktest2, 0},
1133 {"LOCK3", run_locktest3, 0},
1134 {"UNLINK", run_unlinktest, 0},
1135 {"BROWSE", run_browsetest, 0},
1136 {"ATTR", run_attrtest, 0},
1137 {"TRANS2", run_trans2test, 0},
1138 {"MAXFID", run_maxfidtest, FLAG_MULTIPROC},
1139 {"TORTURE",run_torture, FLAG_MULTIPROC},
1140 {"RANDOMIPC", run_randomipc, 0},
1141 {"NBW95", run_nbw95, 0},
1142 {"NBWNT", run_nbwnt, 0},
1143 {NULL, NULL, 0}};
1146 /****************************************************************************
1147 run a specified test or "ALL"
1148 ****************************************************************************/
1149 static void run_test(char *name)
1151 int i;
1152 if (strequal(name,"ALL")) {
1153 for (i=0;torture_ops[i].name;i++) {
1154 run_test(torture_ops[i].name);
1158 for (i=0;torture_ops[i].name;i++) {
1159 if (strequal(name, torture_ops[i].name)) {
1160 start_timer();
1161 printf("Running %s\n", name);
1162 if (torture_ops[i].flags & FLAG_MULTIPROC) {
1163 create_procs(torture_ops[i].fn);
1164 } else {
1165 torture_ops[i].fn();
1167 printf("%s took %g secs\n\n", name, end_timer());
1173 static void usage(void)
1175 int i;
1177 printf("Usage: smbtorture //server/share <options> TEST1 TEST2 ...\n");
1179 printf("\t-U user%%pass\n");
1180 printf("\t-N numprocs\n");
1181 printf("\t-n my_netbios_name\n");
1182 printf("\t-W workgroup\n");
1183 printf("\t-o num_operations\n");
1184 printf("\t-O socket_options\n");
1185 printf("\t-m maximum protocol\n");
1186 printf("\n\n");
1188 printf("tests are:");
1189 for (i=0;torture_ops[i].name;i++) {
1190 printf(" %s", torture_ops[i].name);
1192 printf("\n");
1194 printf("default test is ALL\n");
1196 exit(1);
1203 /****************************************************************************
1204 main program
1205 ****************************************************************************/
1206 int main(int argc,char *argv[])
1208 int opt, i;
1209 char *p;
1210 int gotpass = 0;
1211 extern char *optarg;
1212 extern int optind;
1213 extern FILE *dbf;
1215 dbf = stdout;
1217 setbuffer(stdout, NULL, 0);
1219 charset_initialise();
1221 if (argc < 2) {
1222 usage();
1225 for(p = argv[1]; *p; p++)
1226 if(*p == '\\')
1227 *p = '/';
1229 if (strncmp(argv[1], "//", 2)) {
1230 usage();
1233 fstrcpy(host, &argv[1][2]);
1234 p = strchr(&host[2],'/');
1235 if (!p) {
1236 usage();
1238 *p = 0;
1239 fstrcpy(share, p+1);
1241 get_myname(myname,NULL);
1243 if (*username == 0 && getenv("LOGNAME")) {
1244 pstrcpy(username,getenv("LOGNAME"));
1247 argc--;
1248 argv++;
1251 while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
1252 switch (opt) {
1253 case 'W':
1254 fstrcpy(workgroup,optarg);
1255 break;
1256 case 'm':
1257 max_protocol = interpret_protocol(optarg, max_protocol);
1258 break;
1259 case 'N':
1260 nprocs = atoi(optarg);
1261 break;
1262 case 'o':
1263 numops = atoi(optarg);
1264 break;
1265 case 'O':
1266 sockops = optarg;
1267 break;
1268 case 'n':
1269 fstrcpy(myname, optarg);
1270 break;
1271 case 'U':
1272 pstrcpy(username,optarg);
1273 p = strchr(username,'%');
1274 if (p) {
1275 *p = 0;
1276 pstrcpy(password, p+1);
1277 gotpass = 1;
1279 break;
1280 default:
1281 printf("Unknown option %c (%d)\n", (char)opt, opt);
1282 usage();
1287 while (!gotpass) {
1288 p = getpass("Password:");
1289 if (p) {
1290 pstrcpy(password, p);
1291 gotpass = 1;
1295 printf("host=%s share=%s user=%s myname=%s\n",
1296 host, share, username, myname);
1298 if (argc == 1) {
1299 run_test("ALL");
1300 } else {
1301 for (i=1;i<argc;i++) {
1302 run_test(argv[i]);
1306 return(0);