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