94c94966df49f0d84bc600a503e167c2e5f828ab
[samba.git] / source3 / utils / torture.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB torture tester
5    Copyright (C) Andrew Tridgell 1997-1998
6    
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.
11    
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.
16    
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.
20 */
21
22 #define NO_SYSLOG
23
24 #include "includes.h"
25
26 static fstring host, workgroup, share, password, username, myname;
27 static int max_protocol = PROTOCOL_NT1;
28 static char *sockops="";
29
30
31 static struct timeval tp1,tp2;
32
33 static void start_timer(void)
34 {
35         gettimeofday(&tp1,NULL);
36 }
37
38 static double end_timer(void)
39 {
40         gettimeofday(&tp2,NULL);
41         return((tp2.tv_sec - tp1.tv_sec) + 
42                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
43 }
44
45
46 static BOOL open_connection(struct cli_state *c)
47 {
48         struct nmb_name called, calling;
49
50         if (!cli_initialise(c) || !cli_connect(c, host, NULL)) {
51                 printf("Failed to connect with %s\n", host);
52                 return False;
53         }
54
55         make_nmb_name(&calling, myname, 0x0, "");
56         make_nmb_name(&called , host, 0x20, "");
57
58         if (!cli_session_request(c, &calling, &called)) {
59                 printf("%s rejected the session\n",host);
60                 cli_shutdown(c);
61                 return False;
62         }
63
64         c->protocol = max_protocol;
65
66         if (!cli_negprot(c)) {
67                 printf("%s rejected the negprot (%s)\n",host, cli_errstr(c));
68                 cli_shutdown(c);
69                 return False;
70         }
71
72         if (!cli_session_setup(c, username, password, strlen(password),
73                                "", 0, workgroup)) {
74                 printf("%s rejected the sessionsetup (%s)\n", host, cli_errstr(c));
75                 cli_shutdown(c);
76                 return False;
77         }
78
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));
83                 cli_shutdown(c);
84                 return False;
85         }
86
87         return True;
88 }
89
90
91
92 static void close_connection(struct cli_state *c)
93 {
94         if (!cli_tdis(c)) {
95                 printf("tdis failed (%s)\n", cli_errstr(c));
96         }
97
98         cli_shutdown(c);
99 }
100
101
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)
105 {
106         uint8 class;
107         uint32 num;
108         int eno;
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);
116                 return False;
117         }
118         return True;
119 }
120
121
122 static BOOL wait_lock(struct cli_state *c, int fnum, uint32 offset, uint32 len)
123 {
124         while (!cli_lock(c, fnum, offset, len, -1)) {
125                 if (!check_error(c, ERRDOS, ERRlock, 0)) return False;
126         }
127         return True;
128 }
129
130
131 static BOOL rw_torture(struct cli_state *c, int numops)
132 {
133         char *lockfname = "\\torture.lck";
134         fstring fname;
135         int fnum;
136         int fnum2;
137         int pid2, pid = getpid();
138         int i, j;
139         char buf[1024];
140
141         fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL, 
142                          DENY_NONE);
143         if (fnum2 == -1)
144                 fnum2 = cli_open(c, lockfname, O_RDWR, DENY_NONE);
145         if (fnum2 == -1) {
146                 printf("open of %s failed (%s)\n", lockfname, cli_errstr(c));
147                 return False;
148         }
149
150
151         for (i=0;i<numops;i++) {
152                 unsigned n = (unsigned)sys_random()%10;
153                 if (i % 10 == 0) {
154                         printf("%d\r", i); fflush(stdout);
155                 }
156                 slprintf(fname, sizeof(fstring) - 1, "\\torture.%u", n);
157
158                 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
159                         return False;
160                 }
161
162                 fnum = cli_open(c, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
163                 if (fnum == -1) {
164                         printf("open failed (%s)\n", cli_errstr(c));
165                         break;
166                 }
167
168                 if (cli_write(c, fnum, (char *)&pid, 0, sizeof(pid)) != sizeof(pid)) {
169                         printf("write failed (%s)\n", cli_errstr(c));
170                 }
171
172                 for (j=0;j<50;j++) {
173                         if (cli_write(c, fnum, (char *)buf, 
174                                       sizeof(pid)+(j*sizeof(buf)), 
175                                       sizeof(buf)) != sizeof(buf)) {
176                                 printf("write failed (%s)\n", cli_errstr(c));
177                         }
178                 }
179
180                 pid2 = 0;
181
182                 if (cli_read(c, fnum, (char *)&pid2, 0, sizeof(pid)) != sizeof(pid)) {
183                         printf("read failed (%s)\n", cli_errstr(c));
184                 }
185
186                 if (pid2 != pid) {
187                         printf("data corruption!\n");
188                 }
189
190                 if (!cli_close(c, fnum)) {
191                         printf("close failed (%s)\n", cli_errstr(c));
192                 }
193
194                 if (!cli_unlink(c, fname)) {
195                         printf("unlink failed (%s)\n", cli_errstr(c));
196                 }
197
198                 if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int), -1)) {
199                         printf("unlock failed (%s)\n", cli_errstr(c));
200                 }
201         }
202
203         cli_close(c, fnum2);
204         cli_unlink(c, lockfname);
205
206         printf("%d\n", i);
207
208         return True;
209 }
210
211 static void usage(void)
212 {
213         printf("Usage: smbtorture //server/share <options>\n");
214
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");
222         printf("\n");
223
224         exit(1);
225 }
226
227
228
229 static void run_torture(int numops)
230 {
231         static struct cli_state cli;
232
233         if (open_connection(&cli)) {
234                 cli_sockopt(&cli, sockops);
235
236                 printf("pid %d OK\n", getpid());
237
238                 rw_torture(&cli, numops);
239
240                 close_connection(&cli);
241         }
242 }
243
244 /*
245   This test checks for two things:
246
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
250  */
251 static void run_locktest1(void)
252 {
253         static struct cli_state cli1, cli2;
254         char *fname = "\\lockt1.lck";
255         int fnum1, fnum2, fnum3;
256         time_t t1, t2;
257
258         if (!open_connection(&cli1) || !open_connection(&cli2)) {
259                 return;
260         }
261         cli_sockopt(&cli1, sockops);
262         cli_sockopt(&cli2, sockops);
263
264         printf("starting locktest1\n");
265
266         cli_unlink(&cli1, fname);
267
268         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
269         if (fnum1 == -1) {
270                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
271                 return;
272         }
273         fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_NONE);
274         if (fnum2 == -1) {
275                 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli1));
276                 return;
277         }
278         fnum3 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
279         if (fnum3 == -1) {
280                 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli2));
281                 return;
282         }
283
284         if (!cli_lock(&cli1, fnum1, 0, 4, 0)) {
285                 printf("lock1 failed (%s)\n", cli_errstr(&cli1));
286                 return;
287         }
288
289
290         if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
291                 printf("lock2 succeeded! This is a locking bug\n");
292                 return;
293         } else {
294                 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
295         }
296
297
298         printf("Testing lock timeouts\n");
299         t1 = time(NULL);
300         if (cli_lock(&cli2, fnum3, 0, 4, 10*1000)) {
301                 printf("lock3 succeeded! This is a locking bug\n");
302                 return;
303         } else {
304                 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
305         }
306         t2 = time(NULL);
307
308         if (t2 - t1 < 5) {
309                 printf("error: This server appears not to support timed lock requests\n");
310         }
311
312         if (!cli_close(&cli1, fnum2)) {
313                 printf("close1 failed (%s)\n", cli_errstr(&cli1));
314                 return;
315         }
316
317         if (cli_lock(&cli2, fnum3, 0, 4, 0)) {
318                 printf("lock4 succeeded! This is a locking bug\n");
319                 return;
320         } else {
321                 if (!check_error(&cli2, ERRDOS, ERRlock, 0)) return;
322         }
323
324         if (!cli_close(&cli1, fnum1)) {
325                 printf("close2 failed (%s)\n", cli_errstr(&cli1));
326                 return;
327         }
328
329         if (!cli_close(&cli2, fnum3)) {
330                 printf("close3 failed (%s)\n", cli_errstr(&cli2));
331                 return;
332         }
333
334         if (!cli_unlink(&cli1, fname)) {
335                 printf("unlink failed (%s)\n", cli_errstr(&cli1));
336                 return;
337         }
338
339
340         close_connection(&cli1);
341         close_connection(&cli2);
342
343         printf("Passed locktest1\n");
344 }
345
346
347 /*
348   This test checks that 
349
350   1) the server supports multiple locking contexts on the one SMB
351   connection, distinguished by PID.  
352
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)
355
356   3) the server denies unlock requests by an incorrect client PID
357 */
358 static void run_locktest2(void)
359 {
360         static struct cli_state cli;
361         char *fname = "\\lockt2.lck";
362         int fnum1, fnum2, fnum3;
363
364         if (!open_connection(&cli)) {
365                 return;
366         }
367
368         cli_sockopt(&cli, sockops);
369
370         printf("starting locktest2\n");
371
372         cli_unlink(&cli, fname);
373
374         cli_setpid(&cli, 1);
375
376         fnum1 = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
377         if (fnum1 == -1) {
378                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
379                 return;
380         }
381
382         fnum2 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
383         if (fnum2 == -1) {
384                 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli));
385                 return;
386         }
387
388         cli_setpid(&cli, 2);
389
390         fnum3 = cli_open(&cli, fname, O_RDWR, DENY_NONE);
391         if (fnum3 == -1) {
392                 printf("open3 of %s failed (%s)\n", fname, cli_errstr(&cli));
393                 return;
394         }
395
396         cli_setpid(&cli, 1);
397
398         if (!cli_lock(&cli, fnum1, 0, 4, 0)) {
399                 printf("lock1 failed (%s)\n", cli_errstr(&cli));
400                 return;
401         }
402
403         if (cli_lock(&cli, fnum2, 0, 4, 0)) {
404                 printf("lock2 succeeded! This is a locking bug\n");
405         } else {
406                 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
407         }
408
409         cli_setpid(&cli, 2);
410
411         if (cli_unlock(&cli, fnum1, 0, 4, 0)) {
412                 printf("unlock1 succeeded! This is a locking bug\n");
413         }
414
415         if (cli_lock(&cli, fnum3, 0, 4, 0)) {
416                 printf("lock3 succeeded! This is a locking bug\n");
417         } else {
418                 if (!check_error(&cli, ERRDOS, ERRlock, 0)) return;
419         }
420
421         cli_setpid(&cli, 1);
422
423         if (!cli_close(&cli, fnum1)) {
424                 printf("close1 failed (%s)\n", cli_errstr(&cli));
425                 return;
426         }
427
428         if (!cli_close(&cli, fnum2)) {
429                 printf("close2 failed (%s)\n", cli_errstr(&cli));
430                 return;
431         }
432
433         if (!cli_close(&cli, fnum3)) {
434                 printf("close3 failed (%s)\n", cli_errstr(&cli));
435                 return;
436         }
437
438         close_connection(&cli);
439
440         printf("locktest2 finished\n");
441 }
442
443
444 /*
445   This test checks that 
446
447   1) the server supports the full offset range in lock requests
448 */
449 static void run_locktest3(int numops)
450 {
451         static struct cli_state cli1, cli2;
452         char *fname = "\\lockt3.lck";
453         int fnum1, fnum2, i;
454         uint32 offset;
455
456 #define NEXT_OFFSET offset += (~(uint32)0) / numops
457
458         if (!open_connection(&cli1) || !open_connection(&cli2)) {
459                 return;
460         }
461         cli_sockopt(&cli1, sockops);
462         cli_sockopt(&cli2, sockops);
463
464         printf("starting locktest3\n");
465
466         cli_unlink(&cli1, fname);
467
468         fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
469         if (fnum1 == -1) {
470                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
471                 return;
472         }
473         fnum2 = cli_open(&cli2, fname, O_RDWR, DENY_NONE);
474         if (fnum2 == -1) {
475                 printf("open2 of %s failed (%s)\n", fname, cli_errstr(&cli2));
476                 return;
477         }
478
479         for (offset=i=0;i<numops;i++) {
480                 NEXT_OFFSET;
481                 if (!cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
482                         printf("lock1 %d failed (%s)\n", 
483                                i,
484                                cli_errstr(&cli1));
485                         return;
486                 }
487
488                 if (!cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
489                         printf("lock2 %d failed (%s)\n", 
490                                i,
491                                cli_errstr(&cli1));
492                         return;
493                 }
494         }
495
496         for (offset=i=0;i<numops;i++) {
497                 NEXT_OFFSET;
498
499                 if (cli_lock(&cli1, fnum1, offset-2, 1, 0)) {
500                         printf("error: lock1 %d succeeded!\n", i);
501                         return;
502                 }
503
504                 if (cli_lock(&cli2, fnum2, offset-1, 1, 0)) {
505                         printf("error: lock2 %d succeeded!\n", i);
506                         return;
507                 }
508
509                 if (cli_lock(&cli1, fnum1, offset-1, 1, 0)) {
510                         printf("error: lock3 %d succeeded!\n", i);
511                         return;
512                 }
513
514                 if (cli_lock(&cli2, fnum2, offset-2, 1, 0)) {
515                         printf("error: lock4 %d succeeded!\n", i);
516                         return;
517                 }
518         }
519
520         for (offset=i=0;i<numops;i++) {
521                 NEXT_OFFSET;
522
523                 if (!cli_unlock(&cli1, fnum1, offset-1, 1, 0)) {
524                         printf("unlock1 %d failed (%s)\n", 
525                                i,
526                                cli_errstr(&cli1));
527                         return;
528                 }
529
530                 if (!cli_unlock(&cli2, fnum2, offset-2, 1, 0)) {
531                         printf("unlock2 %d failed (%s)\n", 
532                                i,
533                                cli_errstr(&cli1));
534                         return;
535                 }
536         }
537
538         if (!cli_close(&cli1, fnum1)) {
539                 printf("close1 failed (%s)\n", cli_errstr(&cli1));
540         }
541
542         if (!cli_close(&cli2, fnum2)) {
543                 printf("close2 failed (%s)\n", cli_errstr(&cli2));
544         }
545
546         if (!cli_unlink(&cli1, fname)) {
547                 printf("unlink failed (%s)\n", cli_errstr(&cli1));
548                 return;
549         }
550
551         close_connection(&cli1);
552         close_connection(&cli2);
553
554         printf("finished locktest3\n");
555 }
556
557
558 /*
559   This test checks that 
560
561   1) the server does not allow an unlink on a file that is open
562 */
563 static void run_unlinktest(void)
564 {
565         static struct cli_state cli;
566         char *fname = "\\unlink.tst";
567         int fnum;
568
569         if (!open_connection(&cli)) {
570                 return;
571         }
572
573         cli_sockopt(&cli, sockops);
574
575         printf("starting unlink test\n");
576
577         cli_unlink(&cli, fname);
578
579         cli_setpid(&cli, 1);
580
581         fnum = cli_open(&cli, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
582         if (fnum == -1) {
583                 printf("open of %s failed (%s)\n", fname, cli_errstr(&cli));
584                 return;
585         }
586
587         if (cli_unlink(&cli, fname)) {
588                 printf("error: server allowed unlink on an open file\n");
589         }
590
591         cli_close(&cli, fnum);
592         cli_unlink(&cli, fname);
593
594         close_connection(&cli);
595
596         printf("unlink test finished\n");
597 }
598
599 /* generate a random buffer */
600 static void rand_buf(char *buf, int len)
601 {
602         while (len--) {
603                 *buf = sys_random();
604                 buf++;
605         }
606 }
607
608 /* send random IPC commands */
609 static void run_randomipc(void)
610 {
611         char *rparam = NULL;
612         char *rdata = NULL;
613         int rdrcnt,rprcnt;
614         pstring param;
615         int api, param_len, i;
616         static struct cli_state cli;
617
618         printf("starting random ipc test\n");
619
620         if (!open_connection(&cli)) {
621                 return;
622         }
623
624         for (i=0;i<1000;i++) {
625                 api = sys_random() % 500;
626                 param_len = sys_random() % 64;
627
628                 rand_buf(param, param_len);
629   
630                 SSVAL(param,0,api); 
631
632                 cli_api(&cli, 
633                         param, param_len, 8,  
634                         NULL, 0, BUFFER_SIZE, 
635                         &rparam, &rprcnt,     
636                         &rdata, &rdrcnt);
637         }
638
639         close_connection(&cli);
640
641         printf("finished random ipc test\n");
642 }
643
644
645
646 static void browse_callback(const char *sname, uint32 stype, 
647                             const char *comment)
648 {
649         printf("\t%20.20s %08x %s\n", sname, stype, comment);
650 }
651
652
653
654 /*
655   This test checks the browse list code
656
657 */
658 static void run_browsetest(void)
659 {
660         static struct cli_state cli;
661
662         printf("starting browse test\n");
663
664         if (!open_connection(&cli)) {
665                 return;
666         }
667
668         printf("domain list:\n");
669         cli_NetServerEnum(&cli, workgroup, 
670                           SV_TYPE_DOMAIN_ENUM,
671                           browse_callback);
672
673         printf("machine list:\n");
674         cli_NetServerEnum(&cli, workgroup, 
675                           SV_TYPE_ALL,
676                           browse_callback);
677
678         close_connection(&cli);
679
680         printf("browse test finished\n");
681 }
682
683
684 /*
685   This checks how the getatr calls works
686 */
687 static void run_attrtest(void)
688 {
689         static struct cli_state cli;
690         int fnum;
691         time_t t, t2;
692         char *fname = "\\attrib.tst";
693
694         printf("starting attrib test\n");
695
696         if (!open_connection(&cli)) {
697                 return;
698         }
699
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));
706         }
707
708         if (abs(t - time(NULL)) > 2) {
709                 printf("ERROR: SMBgetatr bug. time is %s",
710                        ctime(&t));
711                 t = time(NULL);
712         }
713
714         t2 = t-60*60*24; /* 1 day ago */
715
716         if (!cli_setatr(&cli, fname, 0, t2)) {
717                 printf("setatr failed (%s)\n", cli_errstr(&cli));
718         }
719
720         if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
721                 printf("getatr failed (%s)\n", cli_errstr(&cli));
722         }
723
724         if (t != t2) {
725                 printf("ERROR: getatr/setatr bug. times are\n%s",
726                        ctime(&t));
727                 printf("%s", ctime(&t2));
728         }
729
730         cli_unlink(&cli, fname);
731
732         close_connection(&cli);
733
734         printf("attrib test finished\n");
735 }
736
737
738 /*
739   This checks a couple of trans2 calls
740 */
741 static void run_trans2test(void)
742 {
743         static struct cli_state cli;
744         int fnum;
745         size_t size;
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";
750
751         printf("starting trans2 test\n");
752
753         if (!open_connection(&cli)) {
754                 return;
755         }
756
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));
762         }
763         cli_close(&cli, fnum);
764
765         sleep(2);
766
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);
771
772         if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
773                 printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
774         } else {
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");
779                 }
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");
783                 }
784
785                 if (abs(m_time - time(NULL)) > 60*60*24*7) {
786                         printf("ERROR: totally incorrect times - maybe word reversed?\n");
787                 }
788         }
789
790
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));
798         } else {
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");
802                 }
803         }
804
805         cli_unlink(&cli, fname);
806
807
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));
812         }
813         sleep(3);
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));
817         }
818
819         fnum = cli_open(&cli, fname2, 
820                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
821         cli_write(&cli, fnum,  (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));
826         } else {
827                 if (m_time2 == m_time)
828                         printf("This system does not update directory modification times\n");
829         }
830         cli_unlink(&cli, fname2);
831         cli_rmdir(&cli, dname);
832
833
834         close_connection(&cli);
835
836         printf("trans2 test finished\n");
837 }
838
839
840 static void create_procs(int nprocs, int numops)
841 {
842         int i, status;
843
844         for (i=0;i<nprocs;i++) {
845                 if (fork() == 0) {
846                         int mypid = getpid();
847                         sys_srandom(mypid ^ time(NULL));
848                         run_torture(numops);
849                         _exit(0);
850                 }
851         }
852
853         for (i=0;i<nprocs;i++)
854                 waitpid(0, &status, 0);
855 }
856
857
858
859 /****************************************************************************
860   main program
861 ****************************************************************************/
862  int main(int argc,char *argv[])
863 {
864         int nprocs=1, numops=100;
865         int opt;
866         char *p;
867         int gotpass = 0;
868         extern char *optarg;
869         extern int optind;
870         extern FILE *dbf;
871
872         dbf = stdout;
873
874         charset_initialise();
875
876         if (argc < 2) {
877                 usage();
878         }
879
880         for(p = argv[1]; *p; p++)
881           if(*p == '\\')
882             *p = '/';
883  
884         if (strncmp(argv[1], "//", 2)) {
885                 usage();
886         }
887
888         fstrcpy(host, &argv[1][2]);
889         p = strchr(&host[2],'/');
890         if (!p) {
891                 usage();
892         }
893         *p = 0;
894         fstrcpy(share, p+1);
895
896         get_myname(myname,NULL);
897
898         if (*username == 0 && getenv("LOGNAME")) {
899           pstrcpy(username,getenv("LOGNAME"));
900         }
901
902         argc--;
903         argv++;
904
905
906         while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
907                 switch (opt) {
908                 case 'W':
909                         fstrcpy(workgroup,optarg);
910                         break;
911                 case 'm':
912                         max_protocol = interpret_protocol(optarg, max_protocol);
913                         break;
914                 case 'N':
915                         nprocs = atoi(optarg);
916                         break;
917                 case 'o':
918                         numops = atoi(optarg);
919                         break;
920                 case 'O':
921                         sockops = optarg;
922                         break;
923                 case 'n':
924                         fstrcpy(myname, optarg);
925                         break;
926                 case 'U':
927                         pstrcpy(username,optarg);
928                         p = strchr(username,'%');
929                         if (p) {
930                                 *p = 0;
931                                 pstrcpy(password, p+1);
932                                 gotpass = 1;
933                         }
934                         break;
935                 default:
936                         printf("Unknown option %c (%d)\n", (char)opt, opt);
937                         usage();
938                 }
939         }
940
941
942         while (!gotpass) {
943                 p = getpass("Password:");
944                 if (p) {
945                         pstrcpy(password, p);
946                         gotpass = 1;
947                 }
948         }
949
950         printf("host=%s share=%s user=%s myname=%s\n", 
951                host, share, username, myname);
952
953         run_randomipc();
954
955         start_timer();
956         create_procs(nprocs, numops);
957         printf("rw_torture: %g secs\n", end_timer());
958
959         run_locktest1();
960         run_locktest2();
961         run_locktest3(numops);
962         run_unlinktest();
963         run_browsetest();
964         run_attrtest();
965         run_trans2test();
966
967         return(0);
968 }
969
970