dd5cf04cc58c20ca5ec04b63ddad847da3456c79
[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, &class, &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, 0, (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, 0, (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
600 /*
601 test how many open files this server supports on the one socket
602 */
603 static void run_maxfidtest(int n)
604 {
605         static struct cli_state cli;
606         char *template = "\\maxfid.%d.%d";
607         fstring fname;
608         int fnum;
609         int retries=4;
610
611         srandom(getpid());
612
613         while (!open_connection(&cli) && retries--) msleep(random() % 2000);
614
615         if (retries <= 0) {
616                 printf("failed to connect\n");
617                 return;
618         }
619
620         cli_sockopt(&cli, sockops);
621
622         printf("starting maxfid test\n");
623
624         fnum = 0;
625         while (1) {
626                 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
627                 if (cli_open(&cli, fname, 
628                              O_RDWR|O_CREAT|O_TRUNC, DENY_NONE) ==
629                     -1) {
630                         printf("open of %s failed (%s)\n", 
631                                fname, cli_errstr(&cli));
632                         printf("maximum fnum is %d\n", fnum);
633                         break;
634                 }
635                 fnum++;
636         }
637
638         printf("cleaning up\n");
639         while (fnum > n) {
640                 fnum--;
641                 slprintf(fname,sizeof(fname)-1,template, fnum,getpid());
642                 if (cli_unlink(&cli, fname)) {
643                         printf("unlink of %s failed (%s)\n", 
644                                fname, cli_errstr(&cli));
645                 }
646         }
647
648         printf("maxfid test finished\n");
649         close_connection(&cli);
650 }
651
652 /* generate a random buffer */
653 static void rand_buf(char *buf, int len)
654 {
655         while (len--) {
656                 *buf = sys_random();
657                 buf++;
658         }
659 }
660
661 /* send random IPC commands */
662 static void run_randomipc(void)
663 {
664         char *rparam = NULL;
665         char *rdata = NULL;
666         int rdrcnt,rprcnt;
667         pstring param;
668         int api, param_len, i;
669         static struct cli_state cli;
670
671         printf("starting random ipc test\n");
672
673         if (!open_connection(&cli)) {
674                 return;
675         }
676
677         for (i=0;i<50000;i++) {
678                 api = sys_random() % 500;
679                 param_len = (sys_random() % 64);
680
681                 rand_buf(param, param_len);
682   
683                 SSVAL(param,0,api); 
684
685                 cli_api(&cli, 
686                         param, param_len, 8,  
687                         NULL, 0, BUFFER_SIZE, 
688                         &rparam, &rprcnt,     
689                         &rdata, &rdrcnt);
690         }
691
692         close_connection(&cli);
693
694         printf("finished random ipc test\n");
695 }
696
697
698
699 static void browse_callback(const char *sname, uint32 stype, 
700                             const char *comment)
701 {
702         printf("\t%20.20s %08x %s\n", sname, stype, comment);
703 }
704
705
706
707 /*
708   This test checks the browse list code
709
710 */
711 static void run_browsetest(void)
712 {
713         static struct cli_state cli;
714
715         printf("starting browse test\n");
716
717         if (!open_connection(&cli)) {
718                 return;
719         }
720
721         printf("domain list:\n");
722         cli_NetServerEnum(&cli, workgroup, 
723                           SV_TYPE_DOMAIN_ENUM,
724                           browse_callback);
725
726         printf("machine list:\n");
727         cli_NetServerEnum(&cli, workgroup, 
728                           SV_TYPE_ALL,
729                           browse_callback);
730
731         close_connection(&cli);
732
733         printf("browse test finished\n");
734 }
735
736
737 /*
738   This checks how the getatr calls works
739 */
740 static void run_attrtest(void)
741 {
742         static struct cli_state cli;
743         int fnum;
744         time_t t, t2;
745         char *fname = "\\attrib.tst";
746
747         printf("starting attrib test\n");
748
749         if (!open_connection(&cli)) {
750                 return;
751         }
752
753         cli_unlink(&cli, fname);
754         fnum = cli_open(&cli, fname, 
755                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
756         cli_close(&cli, fnum);
757         if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
758                 printf("getatr failed (%s)\n", cli_errstr(&cli));
759         }
760
761         if (abs(t - time(NULL)) > 2) {
762                 printf("ERROR: SMBgetatr bug. time is %s",
763                        ctime(&t));
764                 t = time(NULL);
765         }
766
767         t2 = t-60*60*24; /* 1 day ago */
768
769         if (!cli_setatr(&cli, fname, 0, t2)) {
770                 printf("setatr failed (%s)\n", cli_errstr(&cli));
771         }
772
773         if (!cli_getatr(&cli, fname, NULL, NULL, &t)) {
774                 printf("getatr failed (%s)\n", cli_errstr(&cli));
775         }
776
777         if (t != t2) {
778                 printf("ERROR: getatr/setatr bug. times are\n%s",
779                        ctime(&t));
780                 printf("%s", ctime(&t2));
781         }
782
783         cli_unlink(&cli, fname);
784
785         close_connection(&cli);
786
787         printf("attrib test finished\n");
788 }
789
790
791 /*
792   This checks a couple of trans2 calls
793 */
794 static void run_trans2test(void)
795 {
796         static struct cli_state cli;
797         int fnum;
798         size_t size;
799         time_t c_time, a_time, m_time, w_time, m_time2;
800         char *fname = "\\trans2.tst";
801         char *dname = "\\trans2";
802         char *fname2 = "\\trans2\\trans2.tst";
803
804         printf("starting trans2 test\n");
805
806         if (!open_connection(&cli)) {
807                 return;
808         }
809
810         cli_unlink(&cli, fname);
811         fnum = cli_open(&cli, fname, 
812                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
813         if (!cli_qfileinfo(&cli, fnum, NULL, &size, &c_time, &a_time, &m_time)) {
814                 printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(&cli));
815         }
816         cli_close(&cli, fnum);
817
818         sleep(2);
819
820         cli_unlink(&cli, fname);
821         fnum = cli_open(&cli, fname, 
822                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
823         cli_close(&cli, fnum);
824
825         if (!cli_qpathinfo(&cli, fname, &c_time, &a_time, &m_time, &size, NULL)) {
826                 printf("ERROR: qpathinfo failed (%s)\n", cli_errstr(&cli));
827         } else {
828                 if (c_time != m_time) {
829                         printf("create time=%s", ctime(&c_time));
830                         printf("modify time=%s", ctime(&m_time));
831                         printf("This system appears to have sticky create times\n");
832                 }
833                 if (a_time % (60*60) == 0) {
834                         printf("access time=%s", ctime(&a_time));
835                         printf("This system appears to set a midnight access time\n");
836                 }
837
838                 if (abs(m_time - time(NULL)) > 60*60*24*7) {
839                         printf("ERROR: totally incorrect times - maybe word reversed?\n");
840                 }
841         }
842
843
844         cli_unlink(&cli, fname);
845         fnum = cli_open(&cli, fname, 
846                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
847         cli_close(&cli, fnum);
848         if (!cli_qpathinfo2(&cli, fname, &c_time, &a_time, &m_time, 
849                             &w_time, &size, NULL)) {
850                 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
851         } else {
852                 if (w_time < 60*60*24*2) {
853                         printf("write time=%s", ctime(&w_time));
854                         printf("This system appears to set a initial 0 write time\n");
855                 }
856         }
857
858         cli_unlink(&cli, fname);
859
860
861         /* check if the server updates the directory modification time
862            when creating a new file */
863         if (!cli_mkdir(&cli, dname)) {
864                 printf("ERROR: mkdir failed (%s)\n", cli_errstr(&cli));
865         }
866         sleep(3);
867         if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time, 
868                             &w_time, &size, NULL)) {
869                 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
870         }
871
872         fnum = cli_open(&cli, fname2, 
873                         O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
874         cli_write(&cli, fnum,  0, (char *)&fnum, 0, sizeof(fnum));
875         cli_close(&cli, fnum);
876         if (!cli_qpathinfo2(&cli, "\\trans2\\", &c_time, &a_time, &m_time2, 
877                             &w_time, &size, NULL)) {
878                 printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(&cli));
879         } else {
880                 if (m_time2 == m_time)
881                         printf("This system does not update directory modification times\n");
882         }
883         cli_unlink(&cli, fname2);
884         cli_rmdir(&cli, dname);
885
886
887         close_connection(&cli);
888
889         printf("trans2 test finished\n");
890 }
891
892
893 static void create_procs(int nprocs, int numops, void (*fn)(int ))
894 {
895         int i, status;
896
897         for (i=0;i<nprocs;i++) {
898                 if (fork() == 0) {
899                         int mypid = getpid();
900                         sys_srandom(mypid ^ time(NULL));
901                         fn(numops);
902                         _exit(0);
903                 }
904         }
905
906         for (i=0;i<nprocs;i++)
907                 waitpid(0, &status, 0);
908 }
909
910
911
912 /****************************************************************************
913   main program
914 ****************************************************************************/
915  int main(int argc,char *argv[])
916 {
917         int nprocs=1, numops=100;
918         int opt;
919         char *p;
920         int gotpass = 0;
921         extern char *optarg;
922         extern int optind;
923         extern FILE *dbf;
924
925         dbf = stdout;
926
927         charset_initialise();
928
929         if (argc < 2) {
930                 usage();
931         }
932
933         for(p = argv[1]; *p; p++)
934           if(*p == '\\')
935             *p = '/';
936  
937         if (strncmp(argv[1], "//", 2)) {
938                 usage();
939         }
940
941         fstrcpy(host, &argv[1][2]);
942         p = strchr(&host[2],'/');
943         if (!p) {
944                 usage();
945         }
946         *p = 0;
947         fstrcpy(share, p+1);
948
949         get_myname(myname,NULL);
950
951         if (*username == 0 && getenv("LOGNAME")) {
952           pstrcpy(username,getenv("LOGNAME"));
953         }
954
955         argc--;
956         argv++;
957
958
959         while ((opt = getopt(argc, argv, "hW:U:n:N:O:o:m:")) != EOF) {
960                 switch (opt) {
961                 case 'W':
962                         fstrcpy(workgroup,optarg);
963                         break;
964                 case 'm':
965                         max_protocol = interpret_protocol(optarg, max_protocol);
966                         break;
967                 case 'N':
968                         nprocs = atoi(optarg);
969                         break;
970                 case 'o':
971                         numops = atoi(optarg);
972                         break;
973                 case 'O':
974                         sockops = optarg;
975                         break;
976                 case 'n':
977                         fstrcpy(myname, optarg);
978                         break;
979                 case 'U':
980                         pstrcpy(username,optarg);
981                         p = strchr(username,'%');
982                         if (p) {
983                                 *p = 0;
984                                 pstrcpy(password, p+1);
985                                 gotpass = 1;
986                         }
987                         break;
988                 default:
989                         printf("Unknown option %c (%d)\n", (char)opt, opt);
990                         usage();
991                 }
992         }
993
994
995         while (!gotpass) {
996                 p = getpass("Password:");
997                 if (p) {
998                         pstrcpy(password, p);
999                         gotpass = 1;
1000                 }
1001         }
1002
1003         printf("host=%s share=%s user=%s myname=%s\n", 
1004                host, share, username, myname);
1005
1006         run_locktest1();
1007         run_locktest2();
1008         run_locktest3(numops);
1009         run_unlinktest();
1010         run_browsetest();
1011         run_attrtest();
1012         run_trans2test();
1013
1014         create_procs(nprocs, numops, run_maxfidtest);
1015
1016         start_timer();
1017         create_procs(nprocs, numops, run_torture);
1018         printf("rw_torture: %g secs\n", end_timer());
1019
1020         run_randomipc();        
1021
1022         return(0);
1023 }
1024
1025