r3586: Fix some of the issues with the module init functions.
[tprouty/samba.git] / source4 / torture / gentest.c
1 /* 
2    Unix SMB/CIFS implementation.
3    generic testing tool
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "dynconfig.h"
23 #include "system/time.h"
24 #include "request.h"
25 #include "libcli/raw/libcliraw.h"
26
27 #define NSERVERS 2
28 #define NINSTANCES 2
29
30 /* global options */
31 static struct gentest_options {
32         BOOL showall;
33         BOOL analyze;
34         BOOL analyze_always;
35         BOOL analyze_continuous;
36         uint_t max_open_handles;
37         uint_t seed;
38         uint_t numops;
39         BOOL use_oplocks;
40         char **ignore_patterns;
41         const char *seeds_file;
42         BOOL use_preset_seeds;
43         BOOL fast_reconnect;
44 } options;
45
46 /* mapping between open handles on the server and local handles */
47 static struct {
48         BOOL active;
49         uint_t instance;
50         uint_t server_fnum[NSERVERS];
51         const char *name;
52 } *open_handles;
53 static uint_t num_open_handles;
54
55 /* state information for the servers. We open NINSTANCES connections to
56    each server */
57 static struct {
58         struct smbcli_state *cli[NINSTANCES];
59         char *server_name;
60         char *share_name;
61         char *username;
62         char *password;
63 } servers[NSERVERS];
64
65 /* the seeds and flags for each operation */
66 static struct {
67         uint_t seed;
68         BOOL disabled;
69 } *op_parms;
70
71
72 /* oplock break info */
73 static struct {
74         BOOL got_break;
75         uint16_t fnum;
76         uint16_t handle;
77         uint8_t level;
78         BOOL do_close;
79 } oplocks[NSERVERS][NINSTANCES];
80
81 /* change notify reply info */
82 static struct {
83         int notify_count;
84         NTSTATUS status;
85         struct smb_notify notify;
86 } notifies[NSERVERS][NINSTANCES];
87
88 /* info relevant to the current operation */
89 static struct {
90         const char *name;
91         uint_t seed;
92         NTSTATUS status;
93         uint_t opnum;
94         TALLOC_CTX *mem_ctx;
95 } current_op;
96
97
98
99 #define BAD_HANDLE 0xFFFE
100
101 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private);
102 static void idle_func(struct smbcli_transport *transport, void *private);
103
104 /*
105   check if a string should be ignored. This is used as the basis
106   for all error ignore settings
107 */
108 static BOOL ignore_pattern(const char *str)
109 {
110         int i;
111         if (!options.ignore_patterns) return False;
112
113         for (i=0;options.ignore_patterns[i];i++) {
114                 if (strcmp(options.ignore_patterns[i], str) == 0 ||
115                     gen_fnmatch(options.ignore_patterns[i], str) == 0) {
116                         DEBUG(2,("Ignoring '%s'\n", str));
117                         return True;
118                 }
119         }
120         return False;
121 }
122
123 /***************************************************** 
124 connect to the servers
125 *******************************************************/
126 static BOOL connect_servers_fast(void)
127 {
128         int h, i;
129
130         /* close all open files */
131         for (h=0;h<options.max_open_handles;h++) {
132                 if (!open_handles[h].active) continue;
133                 for (i=0;i<NSERVERS;i++) {
134                         if (NT_STATUS_IS_ERR((smbcli_close(servers[i].cli[open_handles[h].instance]->tree,
135                                        open_handles[h].server_fnum[i])))) {
136                                 return False;
137                         }
138                         open_handles[h].active = False;
139                 }
140         }
141
142         return True;
143 }
144
145
146
147
148 /***************************************************** 
149 connect to the servers
150 *******************************************************/
151 static BOOL connect_servers(void)
152 {
153         int i, j;
154
155         if (options.fast_reconnect && servers[0].cli[0]) {
156                 if (connect_servers_fast()) {
157                         return True;
158                 }
159         }
160
161         /* close any existing connections */
162         for (i=0;i<NSERVERS;i++) {
163                 for (j=0;j<NINSTANCES;j++) {
164                         if (servers[i].cli[j]) {
165                                 smbcli_tdis(servers[i].cli[j]);
166                                 smbcli_shutdown(servers[i].cli[j]);
167                                 servers[i].cli[j] = NULL;
168                         }
169                 }
170         }
171
172         for (i=0;i<NSERVERS;i++) {
173                 for (j=0;j<NINSTANCES;j++) {
174                         NTSTATUS status;
175                         printf("Connecting to \\\\%s\\%s as %s - instance %d\n",
176                                servers[i].server_name, servers[i].share_name, 
177                                servers[i].username, j);
178                         status = smbcli_full_connection(NULL, &servers[i].cli[j],
179                                                      "gentest",
180                                                      servers[i].server_name, NULL, 
181                                                      servers[i].share_name, "?????", 
182                                                      servers[i].username, lp_workgroup(),
183                                                      servers[i].password, 0, NULL);
184                         if (!NT_STATUS_IS_OK(status)) {
185                                 printf("Failed to connect to \\\\%s\\%s - %s\n",
186                                        servers[i].server_name, servers[i].share_name,
187                                        nt_errstr(status));
188                                 return False;
189                         }
190
191                         smbcli_oplock_handler(servers[i].cli[j]->transport, oplock_handler, NULL);
192                         smbcli_transport_idle_handler(servers[i].cli[j]->transport, idle_func, 50000, NULL);
193                 }
194         }
195
196         return True;
197 }
198
199 /*
200   work out the time skew between the servers - be conservative
201 */
202 static uint_t time_skew(void)
203 {
204         uint_t ret;
205         ret = ABS(servers[0].cli[0]->transport->negotiate.server_time -
206                   servers[1].cli[0]->transport->negotiate.server_time);
207         return ret + 300;
208 }
209
210 /*
211   turn an fnum for an instance into a handle
212 */
213 static uint_t fnum_to_handle(int server, int instance, uint16_t fnum)
214 {
215         uint_t i;
216         for (i=0;i<options.max_open_handles;i++) {
217                 if (!open_handles[i].active ||
218                     instance != open_handles[i].instance) continue;
219                 if (open_handles[i].server_fnum[server] == fnum) {
220                         return i;
221                 }
222         }
223         printf("Invalid fnum %d in fnum_to_handle on server %d instance %d\n", 
224                fnum, server, instance);
225         return BAD_HANDLE;
226 }
227
228 /*
229   add some newly opened handles
230 */
231 static void gen_add_handle(int instance, const char *name, uint16_t fnums[NSERVERS])
232 {
233         int i, h;
234         for (h=0;h<options.max_open_handles;h++) {
235                 if (!open_handles[h].active) break;
236         }
237         if (h == options.max_open_handles) {
238                 /* we have to force close a random handle */
239                 h = random() % options.max_open_handles;
240                 for (i=0;i<NSERVERS;i++) {
241                         if (NT_STATUS_IS_ERR((smbcli_close(servers[i].cli[open_handles[h].instance]->tree, 
242                                        open_handles[h].server_fnum[i])))) {
243                                 printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n",
244                                        smbcli_errstr(servers[i].cli[open_handles[h].instance]->tree));
245                         }
246                 }
247                 printf("Recovered handle %d\n", h);
248                 num_open_handles--;
249         }
250         for (i=0;i<NSERVERS;i++) {
251                 open_handles[h].server_fnum[i] = fnums[i];
252                 open_handles[h].instance = instance;
253                 open_handles[h].active = True;
254                 open_handles[h].name = name;
255         }
256         num_open_handles++;
257
258         printf("OPEN num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n", 
259                num_open_handles, h, 
260                open_handles[h].server_fnum[0], open_handles[h].server_fnum[1],
261                name);
262 }
263
264 /*
265   remove a closed handle
266 */
267 static void gen_remove_handle(int instance, uint16_t fnums[NSERVERS])
268 {
269         int h;
270         for (h=0;h<options.max_open_handles;h++) {
271                 if (instance == open_handles[h].instance &&
272                     open_handles[h].server_fnum[0] == fnums[0]) {
273                         open_handles[h].active = False;                 
274                         num_open_handles--;
275                         printf("CLOSE num_open_handles=%d h=%d s1=0x%x s2=0x%x (%s)\n", 
276                                num_open_handles, h, 
277                                open_handles[h].server_fnum[0], open_handles[h].server_fnum[1],
278                                open_handles[h].name);
279                         return;
280                 }
281         }
282         printf("Removing invalid handle!?\n");
283         exit(1);
284 }
285
286 /*
287   return True with 'chance' probability as a percentage
288 */
289 static BOOL gen_chance(uint_t chance)
290 {
291         return ((random() % 100) <= chance);
292 }
293
294 /*
295   map an internal handle number to a server fnum
296 */
297 static uint16_t gen_lookup_fnum(int server, uint16_t handle)
298 {
299         if (handle == BAD_HANDLE) return handle;
300         return open_handles[handle].server_fnum[server];
301 }
302
303 /*
304   return a file handle
305 */
306 static uint16_t gen_fnum(int instance)
307 {
308         uint16_t h;
309         int count = 0;
310
311         if (gen_chance(20)) return BAD_HANDLE;
312
313         while (num_open_handles > 0 && count++ < 10*options.max_open_handles) {
314                 h = random() % options.max_open_handles;
315                 if (open_handles[h].active && 
316                     open_handles[h].instance == instance) {
317                         return h;
318                 }
319         }
320         return BAD_HANDLE;
321 }
322
323 /*
324   return a file handle, but skewed so we don't close the last
325   couple of handles too readily
326 */
327 static uint16_t gen_fnum_close(int instance)
328 {
329         if (num_open_handles < 3) {
330                 if (gen_chance(80)) return BAD_HANDLE;
331         }
332
333         return gen_fnum(instance);
334 }
335
336 /*
337   generate an integer in a specified range
338 */
339 static int gen_int_range(uint_t min, uint_t max)
340 {
341         uint_t r = random();
342         return min + (r % (1+max-min));
343 }
344
345 /*
346   return a fnum for use as a root fid
347   be careful to call GEN_SET_FNUM() when you use this!
348 */
349 static uint16_t gen_root_fid(int instance)
350 {
351         if (gen_chance(5)) return gen_fnum(instance);
352         return 0;
353 }
354
355 /*
356   generate a file offset
357 */
358 static int gen_offset(void)
359 {
360         if (gen_chance(20)) return 0;
361         return gen_int_range(0, 1024*1024);
362 }
363
364 /*
365   generate a io count
366 */
367 static int gen_io_count(void)
368 {
369         if (gen_chance(20)) return 0;
370         return gen_int_range(0, 4096);
371 }
372
373 /*
374   generate a filename
375 */
376 static const char *gen_fname(void)
377 {
378         const char *names[] = {"\\gentest\\gentest.dat", 
379                                "\\gentest\\foo", 
380                                "\\gentest\\foo2.sym", 
381                                "\\gentest\\foo3.dll", 
382                                "\\gentest\\foo4", 
383                                "\\gentest\\foo4:teststream1", 
384                                "\\gentest\\foo4:teststream2", 
385                                "\\gentest\\foo5.exe", 
386                                "\\gentest\\foo5.exe:teststream3", 
387                                "\\gentest\\foo5.exe:teststream4", 
388                                "\\gentest\\foo6.com", 
389                                "\\gentest\\blah", 
390                                "\\gentest\\blah\\blergh.txt", 
391                                "\\gentest\\blah\\blergh2", 
392                                "\\gentest\\blah\\blergh3.txt", 
393                                "\\gentest\\blah\\blergh4", 
394                                "\\gentest\\blah\\blergh5.txt", 
395                                "\\gentest\\blah\\blergh5", 
396                                "\\gentest\\blah\\.", 
397 #if 0
398                                /* this causes problem with w2k3 */
399                                "\\gentest\\blah\\..", 
400 #endif
401                                "\\gentest\\a_very_long_name.bin", 
402                                "\\gentest\\x.y", 
403                                "\\gentest\\blah"};
404         int i;
405
406         do {
407                 i = gen_int_range(0, ARRAY_SIZE(names)-1);
408         } while (ignore_pattern(names[i]));
409
410         return names[i];
411 }
412
413 /*
414   generate a filename with a higher chance of choosing an already 
415   open file
416 */
417 static const char *gen_fname_open(int instance)
418 {
419         uint16_t h;
420         h = gen_fnum(instance);
421         if (h == BAD_HANDLE) {
422                 return gen_fname();
423         }
424         return open_handles[h].name;
425 }
426
427 /*
428   generate a wildcard pattern
429 */
430 static const char *gen_pattern(void)
431 {
432         int i;
433         const char *names[] = {"\\gentest\\*.dat", 
434                                "\\gentest\\*", 
435                                "\\gentest\\*.*", 
436                                "\\gentest\\blah\\*.*", 
437                                "\\gentest\\blah\\*", 
438                                "\\gentest\\?"};
439
440         if (gen_chance(50)) return gen_fname();
441
442         do {
443                 i = gen_int_range(0, ARRAY_SIZE(names)-1);
444         } while (ignore_pattern(names[i]));
445
446         return names[i];
447 }
448
449 /*
450   generate a bitmask
451 */
452 static uint32_t gen_bits_mask(uint_t mask)
453 {
454         uint_t ret = random();
455         return ret & mask;
456 }
457
458 /*
459   generate a bitmask with high probability of the first mask
460   and low of the second
461 */
462 static uint32_t gen_bits_mask2(uint32_t mask1, uint32_t mask2)
463 {
464         if (gen_chance(10)) return gen_bits_mask(mask2);
465         return gen_bits_mask(mask1);
466 }
467
468 /*
469   generate a boolean
470 */
471 static BOOL gen_bool(void)
472 {
473         return gen_bits_mask2(0x1, 0xFF);
474 }
475
476 /*
477   generate ntrename flags
478 */
479 static uint16_t gen_rename_flags(void)
480 {
481         if (gen_chance(30)) return RENAME_FLAG_RENAME;
482         if (gen_chance(30)) return RENAME_FLAG_HARD_LINK;
483         if (gen_chance(30)) return RENAME_FLAG_COPY;
484         return gen_bits_mask(0xFFFF);
485 }
486
487
488 /*
489   return a lockingx lock mode
490 */
491 static uint16_t gen_lock_mode(void)
492 {
493         if (gen_chance(5))  return gen_bits_mask(0xFFFF);
494         if (gen_chance(20)) return gen_bits_mask(0x1F);
495         return gen_bits_mask(LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES);
496 }
497
498 /*
499   generate a pid 
500 */
501 static uint16_t gen_pid(void)
502 {
503         if (gen_chance(10)) return gen_bits_mask(0xFFFF);
504         return getpid();
505 }
506
507 /*
508   generate a lock count
509 */
510 static off_t gen_lock_count(void)
511 {
512         return gen_int_range(0, 3);
513 }
514
515 /*
516   generate a ntcreatex flags field
517 */
518 static uint32_t gen_ntcreatex_flags(void)
519 {
520         if (gen_chance(70)) return NTCREATEX_FLAGS_EXTENDED;
521         return gen_bits_mask2(0x1F, 0xFFFFFFFF);
522 }
523
524 /*
525   generate a NT access mask
526 */
527 static uint32_t gen_access_mask(void)
528 {
529         if (gen_chance(50)) return SEC_RIGHT_MAXIMUM_ALLOWED;
530         if (gen_chance(20)) return GENERIC_RIGHTS_FILE_ALL_ACCESS;
531         return gen_bits_mask(0xFFFFFFFF);
532 }
533
534 /*
535   generate a ntcreatex create options bitfield
536 */
537 static uint32_t gen_create_options(void)
538 {
539         if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
540         if (gen_chance(50)) return 0;
541         return gen_bits_mask(NTCREATEX_OPTIONS_DELETE_ON_CLOSE | NTCREATEX_OPTIONS_DIRECTORY);
542 }
543
544 /*
545   generate a ntcreatex open disposition
546 */
547 static uint32_t gen_open_disp(void)
548 {
549         if (gen_chance(10)) return gen_bits_mask(0xFFFFFFFF);
550         return gen_int_range(0, 5);
551 }
552
553 /*
554   generate an openx open mode
555 */
556 static uint16_t gen_openx_mode(void)
557 {
558         if (gen_chance(20)) return gen_bits_mask(0xFFFF);
559         if (gen_chance(20)) return gen_bits_mask(0xFF);
560         return OPENX_MODE_DENY_NONE | gen_bits_mask(0x3);
561 }
562
563 /*
564   generate an openx flags field
565 */
566 static uint16_t gen_openx_flags(void)
567 {
568         if (gen_chance(20)) return gen_bits_mask(0xFFFF);
569         return gen_bits_mask(0x7);
570 }
571
572 /*
573   generate an openx open function
574 */
575 static uint16_t gen_openx_func(void)
576 {
577         if (gen_chance(20)) return gen_bits_mask(0xFFFF);
578         return gen_bits_mask(0x13);
579 }
580
581 /*
582   generate a file attrib combination
583 */
584 static uint32_t gen_attrib(void)
585 {
586         if (gen_chance(20)) return gen_bits_mask(0xFFFFFFFF);
587         return gen_bits_mask(FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
588 }
589
590 /*
591   generate a unix timestamp
592 */
593 static time_t gen_timet(void)
594 {
595         if (gen_chance(30)) return 0;
596         return (time_t)random();
597 }
598
599 /*
600   generate a unix timestamp
601 */
602 static NTTIME gen_nttime(void)
603 {
604         NTTIME ret;
605         unix_to_nt_time(&ret, gen_timet());
606         return ret;
607 }
608
609 /*
610   generate a milliseconds protocol timeout
611 */
612 static uint32_t gen_timeout(void)
613 {
614         if (gen_chance(98)) return 0;
615         return random() % 50;
616 }
617
618 /*
619   generate a file allocation size
620 */
621 static uint_t gen_alloc_size(void)
622 {
623         uint_t ret;
624
625         if (gen_chance(30)) return 0;
626
627         ret = random() % 4*1024*1024;
628         /* give a high chance of a round number */
629         if (gen_chance(60)) {
630                 ret &= ~(1024*1024 - 1);
631         }
632         return ret;
633 }
634
635 /*
636   generate an ea_struct
637 */
638 static struct ea_struct gen_ea_struct(void)
639 {
640         struct ea_struct ea;
641         const char *names[] = {"EAONE", 
642                                "", 
643                                "FOO!", 
644                                " WITH SPACES ", 
645                                ".", 
646                                "AVERYLONGATTRIBUTENAME"};
647         const char *values[] = {"VALUE1", 
648                                "", 
649                                "NOT MUCH FOO", 
650                                " LEADING SPACES ", 
651                                ":", 
652                                "ASOMEWHATLONGERATTRIBUTEVALUE"};
653         int i;
654
655         do {
656                 i = gen_int_range(0, ARRAY_SIZE(names)-1);
657         } while (ignore_pattern(names[i]));
658
659         ea.name.s = names[i];
660
661         do {
662                 i = gen_int_range(0, ARRAY_SIZE(values)-1);
663         } while (ignore_pattern(values[i]));
664
665         ea.value = data_blob(values[i], strlen(values[i]));
666
667         if (gen_chance(10)) ea.flags = gen_bits_mask(0xFF);
668         ea.flags = 0;
669
670         return ea;
671 }
672
673
674 /*
675   this is called when a change notify reply comes in
676 */
677 static void async_notify(struct smbcli_request *req)
678 {
679         struct smb_notify notify;
680         NTSTATUS status;
681         int i, j;
682         uint16_t tid;
683         struct smbcli_transport *transport = req->transport;
684
685         tid = SVAL(req->in.hdr, HDR_TID);
686
687         status = smb_raw_changenotify_recv(req, current_op.mem_ctx, &notify);
688         if (NT_STATUS_IS_OK(status)) {
689                 printf("notify tid=%d num_changes=%d action=%d name=%s\n", 
690                        tid, 
691                        notify.out.num_changes,
692                        notify.out.changes[0].action,
693                        notify.out.changes[0].name.s);
694         }
695
696         for (i=0;i<NSERVERS;i++) {
697                 for (j=0;j<NINSTANCES;j++) {
698                         if (transport == servers[i].cli[j]->transport &&
699                             tid == servers[i].cli[j]->tree->tid) {
700                                 notifies[i][j].notify_count++;
701                                 notifies[i][j].status = status;
702                                 notifies[i][j].notify = notify;
703                         }
704                 }
705         }
706 }
707
708 /*
709   the oplock handler will either ack the break or close the file
710 */
711 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private)
712 {
713         union smb_close io;
714         NTSTATUS status;
715         int i, j;
716         BOOL do_close;
717         struct smbcli_tree *tree = NULL;
718
719         srandom(current_op.seed);
720         do_close = gen_chance(50);
721
722         for (i=0;i<NSERVERS;i++) {
723                 for (j=0;j<NINSTANCES;j++) {
724                         if (transport == servers[i].cli[j]->transport &&
725                             tid == servers[i].cli[j]->tree->tid) {
726                                 oplocks[i][j].got_break = True;
727                                 oplocks[i][j].fnum = fnum;
728                                 oplocks[i][j].handle = fnum_to_handle(i, j, fnum);
729                                 oplocks[i][j].level = level;
730                                 oplocks[i][j].do_close = do_close;
731                                 tree = servers[i].cli[j]->tree;
732                         }
733                 }
734         }
735
736         if (!tree) {
737                 printf("Oplock break not for one of our trees!?\n");
738                 return False;
739         }
740
741         if (!do_close) {
742                 printf("oplock ack fnum=%d\n", fnum);
743                 return smbcli_oplock_ack(tree, fnum, level);
744         }
745
746         printf("oplock close fnum=%d\n", fnum);
747
748         io.close.level = RAW_CLOSE_CLOSE;
749         io.close.in.fnum = fnum;
750         io.close.in.write_time = 0;
751         status = smb_raw_close(tree, &io);
752
753         if (!NT_STATUS_IS_OK(status)) {
754                 printf("WARNING: close failed in oplock_handler_close - %s\n", nt_errstr(status));
755         }
756         return True;
757 }
758
759
760 /*
761   the idle function tries to cope with getting an oplock break on a connection, and
762   an operation on another connection blocking until that break is acked
763   we check for operations on all transports in the idle function
764 */
765 static void idle_func(struct smbcli_transport *transport, void *private)
766 {
767         int i, j;
768         for (i=0;i<NSERVERS;i++) {
769                 for (j=0;j<NINSTANCES;j++) {
770                         if (servers[i].cli[j] &&
771                             transport != servers[i].cli[j]->transport) {
772                                 smbcli_transport_process(servers[i].cli[j]->transport);
773                         }
774                 }
775         }
776
777 }
778
779
780 /*
781   compare NTSTATUS, using checking ignored patterns
782 */
783 static BOOL compare_status(NTSTATUS status1, NTSTATUS status2)
784 {
785         if (NT_STATUS_EQUAL(status1, status2)) return True;
786
787         /* one code being an error and the other OK is always an error */
788         if (NT_STATUS_IS_OK(status1) || NT_STATUS_IS_OK(status2)) return False;
789
790         /* if we are ignoring one of the status codes then consider this a match */
791         if (ignore_pattern(nt_errstr(status1)) ||
792             ignore_pattern(nt_errstr(status2))) {
793                 return True;
794         }
795         return False;
796 }
797
798
799 /*
800   check for pending packets on all connections
801 */
802 static void check_pending(void)
803 {
804         int i, j;
805
806         msleep(20);
807
808         for (j=0;j<NINSTANCES;j++) {
809                 for (i=0;i<NSERVERS;i++) {
810                         smbcli_transport_process(servers[i].cli[j]->transport);
811                 }
812         }       
813 }
814
815 /*
816   check that the same oplock breaks have been received by all instances
817 */
818 static BOOL check_oplocks(const char *call)
819 {
820         int i, j;
821         int tries = 0;
822
823 again:
824         check_pending();
825
826         for (j=0;j<NINSTANCES;j++) {
827                 for (i=1;i<NSERVERS;i++) {
828                         if (oplocks[0][j].got_break != oplocks[i][j].got_break ||
829                             oplocks[0][j].handle != oplocks[i][j].handle ||
830                             oplocks[0][j].level != oplocks[i][j].level) {
831                                 if (tries++ < 10) goto again;
832                                 printf("oplock break inconsistent - %d/%d/%d vs %d/%d/%d\n",
833                                        oplocks[0][j].got_break, 
834                                        oplocks[0][j].handle, 
835                                        oplocks[0][j].level, 
836                                        oplocks[i][j].got_break, 
837                                        oplocks[i][j].handle, 
838                                        oplocks[i][j].level);
839                                 return False;
840                         }
841                 }
842         }
843
844         /* if we got a break and closed then remove the handle */
845         for (j=0;j<NINSTANCES;j++) {
846                 if (oplocks[0][j].got_break &&
847                     oplocks[0][j].do_close) {
848                         uint16_t fnums[NSERVERS];
849                         for (i=0;i<NSERVERS;i++) {
850                                 fnums[i] = oplocks[i][j].fnum;
851                         }
852                         gen_remove_handle(j, fnums);
853                         break;
854                 }
855         }       
856         return True;
857 }
858
859
860 /*
861   check that the same change notify info has been received by all instances
862 */
863 static BOOL check_notifies(const char *call)
864 {
865         int i, j;
866         int tries = 0;
867
868 again:
869         check_pending();
870
871         for (j=0;j<NINSTANCES;j++) {
872                 for (i=1;i<NSERVERS;i++) {
873                         int n;
874                         struct smb_notify not1, not2;
875
876                         if (notifies[0][j].notify_count != notifies[i][j].notify_count) {
877                                 if (tries++ < 10) goto again;
878                                 printf("Notify count inconsistent %d %d\n",
879                                        notifies[0][j].notify_count,
880                                        notifies[i][j].notify_count);
881                                 return False;
882                         }
883
884                         if (notifies[0][j].notify_count == 0) continue;
885
886                         if (!NT_STATUS_EQUAL(notifies[0][j].status,
887                                              notifies[i][j].status)) {
888                                 printf("Notify status mismatch - %s - %s\n",
889                                        nt_errstr(notifies[0][j].status),
890                                        nt_errstr(notifies[i][j].status));
891                                 return False;
892                         }
893
894                         if (!NT_STATUS_IS_OK(notifies[0][j].status)) {
895                                 continue;
896                         }
897
898                         not1 = notifies[0][j].notify;
899                         not2 = notifies[i][j].notify;
900
901                         for (n=0;n<not1.out.num_changes;n++) {
902                                 if (not1.out.changes[n].action != 
903                                     not2.out.changes[n].action) {
904                                         printf("Notify action %d inconsistent %d %d\n", n,
905                                                not1.out.changes[n].action,
906                                                not2.out.changes[n].action);
907                                         return False;
908                                 }
909                                 if (strcmp(not1.out.changes[n].name.s,
910                                            not2.out.changes[n].name.s)) {
911                                         printf("Notify name %d inconsistent %s %s\n", n,
912                                                not1.out.changes[n].name.s,
913                                                not2.out.changes[n].name.s);
914                                         return False;
915                                 }
916                                 if (not1.out.changes[n].name.private_length !=
917                                     not2.out.changes[n].name.private_length) {
918                                         printf("Notify name length %d inconsistent %d %d\n", n,
919                                                not1.out.changes[n].name.private_length,
920                                                not2.out.changes[n].name.private_length);
921                                         return False;
922                                 }
923                         }
924                 }
925         }
926
927         ZERO_STRUCT(notifies);
928
929         return True;
930 }
931
932
933 #define GEN_COPY_PARM do { \
934         int i; \
935         for (i=1;i<NSERVERS;i++) { \
936                 parm[i] = parm[0]; \
937         } \
938 } while (0)
939
940 #define GEN_CALL(call) do { \
941         int i; \
942         ZERO_STRUCT(oplocks); \
943         ZERO_STRUCT(notifies); \
944         for (i=0;i<NSERVERS;i++) { \
945                 struct smbcli_tree *tree = servers[i].cli[instance]->tree; \
946                 status[i] = call; \
947         } \
948         current_op.status = status[0]; \
949         for (i=1;i<NSERVERS;i++) { \
950                 if (!compare_status(status[i], status[0])) { \
951                         printf("status different in %s - %s %s\n", #call, \
952                                nt_errstr(status[0]), nt_errstr(status[i])); \
953                         return False; \
954                 } \
955         } \
956         if (!check_oplocks(#call)) return False; \
957         if (!check_notifies(#call)) return False; \
958         if (!NT_STATUS_IS_OK(status[0])) { \
959                 return True; \
960         } \
961 } while(0)
962
963 #define ADD_HANDLE(name, field) do { \
964         uint16_t fnums[NSERVERS]; \
965         int i; \
966         for (i=0;i<NSERVERS;i++) { \
967                 fnums[i] = parm[i].field; \
968         } \
969         gen_add_handle(instance, name, fnums); \
970 } while(0)
971
972 #define REMOVE_HANDLE(field) do { \
973         uint16_t fnums[NSERVERS]; \
974         int i; \
975         for (i=0;i<NSERVERS;i++) { \
976                 fnums[i] = parm[i].field; \
977         } \
978         gen_remove_handle(instance, fnums); \
979 } while(0)
980
981 #define GEN_SET_FNUM(field) do { \
982         int i; \
983         for (i=0;i<NSERVERS;i++) { \
984                 parm[i].field = gen_lookup_fnum(i, parm[i].field); \
985         } \
986 } while(0)
987
988 #define CHECK_EQUAL(field) do { \
989         if (parm[0].field != parm[1].field && !ignore_pattern(#field)) { \
990                 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
991                        (int)parm[0].field, (int)parm[1].field); \
992                 return False; \
993         } \
994 } while(0)
995
996 #define CHECK_WSTR_EQUAL(field) do { \
997         if ((!parm[0].field.s && parm[1].field.s) || (parm[0].field.s && !parm[1].field.s)) { \
998                 printf("%s is NULL!\n", #field); \
999                 return False; \
1000         } \
1001         if (parm[0].field.s && strcmp(parm[0].field.s, parm[1].field.s) != 0 && !ignore_pattern(#field)) { \
1002                 printf("Mismatch in %s - %s %s\n", #field, \
1003                        parm[0].field.s, parm[1].field.s); \
1004                 return False; \
1005         } \
1006         CHECK_EQUAL(field.private_length); \
1007 } while(0)
1008
1009 #define CHECK_BLOB_EQUAL(field) do { \
1010         if (memcmp(parm[0].field.data, parm[1].field.data, parm[0].field.length) != 0 && !ignore_pattern(#field)) { \
1011                 printf("Mismatch in %s\n", #field); \
1012                 return False; \
1013         } \
1014         CHECK_EQUAL(field.length); \
1015 } while(0)
1016
1017 #define CHECK_TIMES_EQUAL(field) do { \
1018         if (ABS(parm[0].field - parm[1].field) > time_skew() && \
1019             !ignore_pattern(#field)) { \
1020                 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1021                        (int)parm[0].field, (int)parm[1].field); \
1022                 return False; \
1023         } \
1024 } while(0)
1025
1026 #define CHECK_NTTIMES_EQUAL(field) do { \
1027         if (ABS(nt_time_to_unix(parm[0].field) - \
1028                 nt_time_to_unix(parm[1].field)) > time_skew() && \
1029             !ignore_pattern(#field)) { \
1030                 printf("Mismatch in %s - 0x%x 0x%x\n", #field, \
1031                        (int)nt_time_to_unix(parm[0].field), \
1032                        (int)nt_time_to_unix(parm[1].field)); \
1033                 return False; \
1034         } \
1035 } while(0)
1036
1037 /*
1038   generate openx operations
1039 */
1040 static BOOL handler_openx(int instance)
1041 {
1042         union smb_open parm[NSERVERS];
1043         NTSTATUS status[NSERVERS];
1044
1045         parm[0].openx.level = RAW_OPEN_OPENX;
1046         parm[0].openx.in.flags = gen_openx_flags();
1047         parm[0].openx.in.open_mode = gen_openx_mode();
1048         parm[0].openx.in.search_attrs = gen_attrib();
1049         parm[0].openx.in.file_attrs = gen_attrib();
1050         parm[0].openx.in.write_time = gen_timet();
1051         parm[0].openx.in.open_func = gen_openx_func();
1052         parm[0].openx.in.size = gen_io_count();
1053         parm[0].openx.in.timeout = gen_timeout();
1054         parm[0].openx.in.fname = gen_fname_open(instance);
1055
1056         if (!options.use_oplocks) {
1057                 /* mask out oplocks */
1058                 parm[0].openx.in.flags &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
1059                                             OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
1060         }
1061         
1062         GEN_COPY_PARM;
1063         GEN_CALL(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1064
1065         CHECK_EQUAL(openx.out.attrib);
1066         CHECK_EQUAL(openx.out.size);
1067         CHECK_EQUAL(openx.out.access);
1068         CHECK_EQUAL(openx.out.ftype);
1069         CHECK_EQUAL(openx.out.devstate);
1070         CHECK_EQUAL(openx.out.action);
1071         CHECK_EQUAL(openx.out.access_mask);
1072         CHECK_EQUAL(openx.out.unknown);
1073         CHECK_TIMES_EQUAL(openx.out.write_time);
1074
1075         /* open creates a new file handle */
1076         ADD_HANDLE(parm[0].openx.in.fname, openx.out.fnum);
1077
1078         return True;
1079 }
1080
1081
1082 /*
1083   generate open operations
1084 */
1085 static BOOL handler_open(int instance)
1086 {
1087         union smb_open parm[NSERVERS];
1088         NTSTATUS status[NSERVERS];
1089
1090         parm[0].openold.level = RAW_OPEN_OPEN;
1091         parm[0].openold.in.flags = gen_bits_mask2(0xF, 0xFFFF);
1092         parm[0].openold.in.search_attrs = gen_attrib();
1093         parm[0].openold.in.fname = gen_fname_open(instance);
1094
1095         if (!options.use_oplocks) {
1096                 /* mask out oplocks */
1097                 parm[0].openold.in.flags &= ~(OPENX_FLAGS_REQUEST_OPLOCK|
1098                                            OPENX_FLAGS_REQUEST_BATCH_OPLOCK);
1099         }
1100         
1101         GEN_COPY_PARM;
1102         GEN_CALL(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1103
1104         CHECK_EQUAL(openold.out.attrib);
1105         CHECK_TIMES_EQUAL(openold.out.write_time);
1106         CHECK_EQUAL(openold.out.size);
1107         CHECK_EQUAL(openold.out.rmode);
1108
1109         /* open creates a new file handle */
1110         ADD_HANDLE(parm[0].openold.in.fname, openold.out.fnum);
1111
1112         return True;
1113 }
1114
1115
1116 /*
1117   generate ntcreatex operations
1118 */
1119 static BOOL handler_ntcreatex(int instance)
1120 {
1121         union smb_open parm[NSERVERS];
1122         NTSTATUS status[NSERVERS];
1123
1124         parm[0].ntcreatex.level = RAW_OPEN_NTCREATEX;
1125         parm[0].ntcreatex.in.flags = gen_ntcreatex_flags();
1126         parm[0].ntcreatex.in.root_fid = gen_root_fid(instance);
1127         parm[0].ntcreatex.in.access_mask = gen_access_mask();
1128         parm[0].ntcreatex.in.alloc_size = gen_alloc_size();
1129         parm[0].ntcreatex.in.file_attr = gen_attrib();
1130         parm[0].ntcreatex.in.share_access = gen_bits_mask2(0x7, 0xFFFFFFFF);
1131         parm[0].ntcreatex.in.open_disposition = gen_open_disp();
1132         parm[0].ntcreatex.in.create_options = gen_create_options();
1133         parm[0].ntcreatex.in.impersonation = gen_bits_mask2(0, 0xFFFFFFFF);
1134         parm[0].ntcreatex.in.security_flags = gen_bits_mask2(0, 0xFF);
1135         parm[0].ntcreatex.in.fname = gen_fname_open(instance);
1136
1137         if (!options.use_oplocks) {
1138                 /* mask out oplocks */
1139                 parm[0].ntcreatex.in.flags &= ~(NTCREATEX_FLAGS_REQUEST_OPLOCK|
1140                                                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK);
1141         }
1142         
1143         GEN_COPY_PARM;
1144         if (parm[0].ntcreatex.in.root_fid != 0) {
1145                 GEN_SET_FNUM(ntcreatex.in.root_fid);
1146         }
1147         GEN_CALL(smb_raw_open(tree, current_op.mem_ctx, &parm[i]));
1148
1149         CHECK_EQUAL(ntcreatex.out.oplock_level);
1150         CHECK_EQUAL(ntcreatex.out.create_action);
1151         CHECK_NTTIMES_EQUAL(ntcreatex.out.create_time);
1152         CHECK_NTTIMES_EQUAL(ntcreatex.out.access_time);
1153         CHECK_NTTIMES_EQUAL(ntcreatex.out.write_time);
1154         CHECK_NTTIMES_EQUAL(ntcreatex.out.change_time);
1155         CHECK_EQUAL(ntcreatex.out.attrib);
1156         CHECK_EQUAL(ntcreatex.out.alloc_size);
1157         CHECK_EQUAL(ntcreatex.out.size);
1158         CHECK_EQUAL(ntcreatex.out.file_type);
1159         CHECK_EQUAL(ntcreatex.out.ipc_state);
1160         CHECK_EQUAL(ntcreatex.out.is_directory);
1161
1162         /* ntcreatex creates a new file handle */
1163         ADD_HANDLE(parm[0].ntcreatex.in.fname, ntcreatex.out.fnum);
1164
1165         return True;
1166 }
1167
1168 /*
1169   generate close operations
1170 */
1171 static BOOL handler_close(int instance)
1172 {
1173         union smb_close parm[NSERVERS];
1174         NTSTATUS status[NSERVERS];
1175
1176         parm[0].close.level = RAW_CLOSE_CLOSE;
1177         parm[0].close.in.fnum = gen_fnum_close(instance);
1178         parm[0].close.in.write_time = gen_timet();
1179
1180         GEN_COPY_PARM;
1181         GEN_SET_FNUM(close.in.fnum);
1182         GEN_CALL(smb_raw_close(tree, &parm[i]));
1183
1184         REMOVE_HANDLE(close.in.fnum);
1185
1186         return True;
1187 }
1188
1189 /*
1190   generate unlink operations
1191 */
1192 static BOOL handler_unlink(int instance)
1193 {
1194         struct smb_unlink parm[NSERVERS];
1195         NTSTATUS status[NSERVERS];
1196
1197         parm[0].in.pattern = gen_pattern();
1198         parm[0].in.attrib = gen_attrib();
1199
1200         GEN_COPY_PARM;
1201         GEN_CALL(smb_raw_unlink(tree, &parm[i]));
1202
1203         return True;
1204 }
1205
1206 /*
1207   generate chkpath operations
1208 */
1209 static BOOL handler_chkpath(int instance)
1210 {
1211         struct smb_chkpath parm[NSERVERS];
1212         NTSTATUS status[NSERVERS];
1213
1214         parm[0].in.path = gen_fname_open(instance);
1215
1216         GEN_COPY_PARM;
1217         GEN_CALL(smb_raw_chkpath(tree, &parm[i]));
1218
1219         return True;
1220 }
1221
1222 /*
1223   generate mkdir operations
1224 */
1225 static BOOL handler_mkdir(int instance)
1226 {
1227         union smb_mkdir parm[NSERVERS];
1228         NTSTATUS status[NSERVERS];
1229
1230         parm[0].mkdir.level = RAW_MKDIR_MKDIR;
1231         parm[0].mkdir.in.path = gen_fname_open(instance);
1232
1233         GEN_COPY_PARM;
1234         GEN_CALL(smb_raw_mkdir(tree, &parm[i]));
1235
1236         return True;
1237 }
1238
1239 /*
1240   generate rmdir operations
1241 */
1242 static BOOL handler_rmdir(int instance)
1243 {
1244         struct smb_rmdir parm[NSERVERS];
1245         NTSTATUS status[NSERVERS];
1246
1247         parm[0].in.path = gen_fname_open(instance);
1248
1249         GEN_COPY_PARM;
1250         GEN_CALL(smb_raw_rmdir(tree, &parm[i]));
1251
1252         return True;
1253 }
1254
1255 /*
1256   generate rename operations
1257 */
1258 static BOOL handler_rename(int instance)
1259 {
1260         union smb_rename parm[NSERVERS];
1261         NTSTATUS status[NSERVERS];
1262
1263         parm[0].generic.level = RAW_RENAME_RENAME;
1264         parm[0].rename.in.pattern1 = gen_pattern();
1265         parm[0].rename.in.pattern2 = gen_pattern();
1266         parm[0].rename.in.attrib = gen_attrib();
1267
1268         GEN_COPY_PARM;
1269         GEN_CALL(smb_raw_rename(tree, &parm[i]));
1270
1271         return True;
1272 }
1273
1274 /*
1275   generate ntrename operations
1276 */
1277 static BOOL handler_ntrename(int instance)
1278 {
1279         union smb_rename parm[NSERVERS];
1280         NTSTATUS status[NSERVERS];
1281
1282         parm[0].generic.level = RAW_RENAME_NTRENAME;
1283         parm[0].ntrename.in.old_name = gen_fname();
1284         parm[0].ntrename.in.new_name = gen_fname();
1285         parm[0].ntrename.in.attrib = gen_attrib();
1286         parm[0].ntrename.in.cluster_size = gen_bits_mask2(0, 0xFFFFFFF);
1287         parm[0].ntrename.in.flags = gen_rename_flags();
1288
1289         GEN_COPY_PARM;
1290         GEN_CALL(smb_raw_rename(tree, &parm[i]));
1291
1292         return True;
1293 }
1294
1295
1296 /*
1297   generate seek operations
1298 */
1299 static BOOL handler_seek(int instance)
1300 {
1301         struct smb_seek parm[NSERVERS];
1302         NTSTATUS status[NSERVERS];
1303
1304         parm[0].in.fnum = gen_fnum(instance);
1305         parm[0].in.mode = gen_bits_mask2(0x3, 0xFFFF);
1306         parm[0].in.offset = gen_offset();
1307
1308         GEN_COPY_PARM;
1309         GEN_SET_FNUM(in.fnum);
1310         GEN_CALL(smb_raw_seek(tree, &parm[i]));
1311
1312         CHECK_EQUAL(out.offset);
1313
1314         return True;
1315 }
1316
1317
1318 /*
1319   generate readx operations
1320 */
1321 static BOOL handler_readx(int instance)
1322 {
1323         union smb_read parm[NSERVERS];
1324         NTSTATUS status[NSERVERS];
1325
1326         parm[0].readx.level = RAW_READ_READX;
1327         parm[0].readx.in.fnum = gen_fnum(instance);
1328         parm[0].readx.in.offset = gen_offset();
1329         parm[0].readx.in.mincnt = gen_io_count();
1330         parm[0].readx.in.maxcnt = gen_io_count();
1331         parm[0].readx.in.remaining = gen_io_count();
1332         parm[0].readx.out.data = talloc(current_op.mem_ctx,
1333                                         MAX(parm[0].readx.in.mincnt, parm[0].readx.in.maxcnt));
1334
1335         GEN_COPY_PARM;
1336         GEN_SET_FNUM(readx.in.fnum);
1337         GEN_CALL(smb_raw_read(tree, &parm[i]));
1338
1339         CHECK_EQUAL(readx.out.remaining);
1340         CHECK_EQUAL(readx.out.compaction_mode);
1341         CHECK_EQUAL(readx.out.nread);
1342
1343         return True;
1344 }
1345
1346 /*
1347   generate writex operations
1348 */
1349 static BOOL handler_writex(int instance)
1350 {
1351         union smb_write parm[NSERVERS];
1352         NTSTATUS status[NSERVERS];
1353
1354         parm[0].writex.level = RAW_WRITE_WRITEX;
1355         parm[0].writex.in.fnum = gen_fnum(instance);
1356         parm[0].writex.in.offset = gen_offset();
1357         parm[0].writex.in.wmode = gen_bits_mask(0xFFFF);
1358         parm[0].writex.in.remaining = gen_io_count();
1359         parm[0].writex.in.count = gen_io_count();
1360         parm[0].writex.in.data = talloc_zero(current_op.mem_ctx, parm[0].writex.in.count);
1361
1362         GEN_COPY_PARM;
1363         GEN_SET_FNUM(writex.in.fnum);
1364         GEN_CALL(smb_raw_write(tree, &parm[i]));
1365
1366         CHECK_EQUAL(writex.out.nwritten);
1367         CHECK_EQUAL(writex.out.remaining);
1368
1369         return True;
1370 }
1371
1372 /*
1373   generate lockingx operations
1374 */
1375 static BOOL handler_lockingx(int instance)
1376 {
1377         union smb_lock parm[NSERVERS];
1378         NTSTATUS status[NSERVERS];
1379         int n, nlocks;
1380
1381         parm[0].lockx.level = RAW_LOCK_LOCKX;
1382         parm[0].lockx.in.fnum = gen_fnum(instance);
1383         parm[0].lockx.in.mode = gen_lock_mode();
1384         parm[0].lockx.in.timeout = gen_timeout();
1385         do {
1386                 /* make sure we don't accidentially generate an oplock
1387                    break ack - otherwise the server can just block forever */
1388                 parm[0].lockx.in.ulock_cnt = gen_lock_count();
1389                 parm[0].lockx.in.lock_cnt = gen_lock_count();
1390                 nlocks = parm[0].lockx.in.ulock_cnt + parm[0].lockx.in.lock_cnt;
1391         } while (nlocks == 0);
1392
1393         if (nlocks > 0) {
1394                 parm[0].lockx.in.locks = talloc(current_op.mem_ctx,
1395                                                 sizeof(parm[0].lockx.in.locks[0]) * nlocks);
1396                 for (n=0;n<nlocks;n++) {
1397                         parm[0].lockx.in.locks[n].pid = gen_pid();
1398                         parm[0].lockx.in.locks[n].offset = gen_offset();
1399                         parm[0].lockx.in.locks[n].count = gen_io_count();
1400                 }
1401         }
1402
1403         GEN_COPY_PARM;
1404         GEN_SET_FNUM(lockx.in.fnum);
1405         GEN_CALL(smb_raw_lock(tree, &parm[i]));
1406
1407         return True;
1408 }
1409
1410 /*
1411   generate a fileinfo query structure
1412 */
1413 static void gen_fileinfo(int instance, union smb_fileinfo *info)
1414 {
1415         int i;
1416         #define LVL(v) {RAW_FILEINFO_ ## v, "RAW_FILEINFO_" #v}
1417         struct {
1418                 enum smb_fileinfo_level level;
1419                 const char *name;
1420         }  levels[] = {
1421                 LVL(GETATTR), LVL(GETATTRE), LVL(STANDARD),
1422                 LVL(EA_SIZE), LVL(ALL_EAS), LVL(IS_NAME_VALID),
1423                 LVL(BASIC_INFO), LVL(STANDARD_INFO), LVL(EA_INFO),
1424                 LVL(NAME_INFO), LVL(ALL_INFO), LVL(ALT_NAME_INFO),
1425                 LVL(STREAM_INFO), LVL(COMPRESSION_INFO), LVL(BASIC_INFORMATION),
1426                 LVL(STANDARD_INFORMATION), LVL(INTERNAL_INFORMATION), LVL(EA_INFORMATION),
1427                 LVL(ACCESS_INFORMATION), LVL(NAME_INFORMATION), LVL(POSITION_INFORMATION),
1428                 LVL(MODE_INFORMATION), LVL(ALIGNMENT_INFORMATION), LVL(ALL_INFORMATION),
1429                 LVL(ALT_NAME_INFORMATION), LVL(STREAM_INFORMATION), LVL(COMPRESSION_INFORMATION),
1430                 LVL(NETWORK_OPEN_INFORMATION), LVL(ATTRIBUTE_TAG_INFORMATION)
1431         };
1432         do {
1433                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
1434         } while (ignore_pattern(levels[i].name));
1435
1436         info->generic.level = levels[i].level;
1437 }
1438
1439 /*
1440   compare returned fileinfo structures
1441 */
1442 static BOOL cmp_fileinfo(int instance, 
1443                          union smb_fileinfo parm[NSERVERS],
1444                          NTSTATUS status[NSERVERS])
1445 {
1446         int i;
1447
1448         switch (parm[0].generic.level) {
1449         case RAW_FILEINFO_GENERIC:
1450                 return False;
1451
1452         case RAW_FILEINFO_GETATTR:
1453                 CHECK_EQUAL(getattr.out.attrib);
1454                 CHECK_EQUAL(getattr.out.size);
1455                 CHECK_TIMES_EQUAL(getattr.out.write_time);
1456                 break;
1457
1458         case RAW_FILEINFO_GETATTRE:
1459                 CHECK_TIMES_EQUAL(getattre.out.create_time);
1460                 CHECK_TIMES_EQUAL(getattre.out.access_time);
1461                 CHECK_TIMES_EQUAL(getattre.out.write_time);
1462                 CHECK_EQUAL(getattre.out.size);
1463                 CHECK_EQUAL(getattre.out.alloc_size);
1464                 CHECK_EQUAL(getattre.out.attrib);
1465                 break;
1466
1467         case RAW_FILEINFO_STANDARD:
1468                 CHECK_TIMES_EQUAL(standard.out.create_time);
1469                 CHECK_TIMES_EQUAL(standard.out.access_time);
1470                 CHECK_TIMES_EQUAL(standard.out.write_time);
1471                 CHECK_EQUAL(standard.out.size);
1472                 CHECK_EQUAL(standard.out.alloc_size);
1473                 CHECK_EQUAL(standard.out.attrib);
1474                 break;
1475
1476         case RAW_FILEINFO_EA_SIZE:
1477                 CHECK_TIMES_EQUAL(ea_size.out.create_time);
1478                 CHECK_TIMES_EQUAL(ea_size.out.access_time);
1479                 CHECK_TIMES_EQUAL(ea_size.out.write_time);
1480                 CHECK_EQUAL(ea_size.out.size);
1481                 CHECK_EQUAL(ea_size.out.alloc_size);
1482                 CHECK_EQUAL(ea_size.out.attrib);
1483                 CHECK_EQUAL(ea_size.out.ea_size);
1484                 break;
1485
1486         case RAW_FILEINFO_ALL_EAS:
1487                 CHECK_EQUAL(all_eas.out.num_eas);
1488                 for (i=0;i<parm[0].all_eas.out.num_eas;i++) {
1489                         CHECK_EQUAL(all_eas.out.eas[i].flags);
1490                         CHECK_WSTR_EQUAL(all_eas.out.eas[i].name);
1491                         CHECK_BLOB_EQUAL(all_eas.out.eas[i].value);
1492                 }
1493                 break;
1494
1495         case RAW_FILEINFO_IS_NAME_VALID:
1496                 break;
1497                 
1498         case RAW_FILEINFO_BASIC_INFO:
1499         case RAW_FILEINFO_BASIC_INFORMATION:
1500                 CHECK_NTTIMES_EQUAL(basic_info.out.create_time);
1501                 CHECK_NTTIMES_EQUAL(basic_info.out.access_time);
1502                 CHECK_NTTIMES_EQUAL(basic_info.out.write_time);
1503                 CHECK_NTTIMES_EQUAL(basic_info.out.change_time);
1504                 CHECK_EQUAL(basic_info.out.attrib);
1505                 break;
1506
1507         case RAW_FILEINFO_STANDARD_INFO:
1508         case RAW_FILEINFO_STANDARD_INFORMATION:
1509                 CHECK_EQUAL(standard_info.out.alloc_size);
1510                 CHECK_EQUAL(standard_info.out.size);
1511                 CHECK_EQUAL(standard_info.out.nlink);
1512                 CHECK_EQUAL(standard_info.out.delete_pending);
1513                 CHECK_EQUAL(standard_info.out.directory);
1514                 break;
1515
1516         case RAW_FILEINFO_EA_INFO:
1517         case RAW_FILEINFO_EA_INFORMATION:
1518                 CHECK_EQUAL(ea_info.out.ea_size);
1519                 break;
1520
1521         case RAW_FILEINFO_NAME_INFO:
1522         case RAW_FILEINFO_NAME_INFORMATION:
1523                 CHECK_WSTR_EQUAL(name_info.out.fname);
1524                 break;
1525
1526         case RAW_FILEINFO_ALL_INFO:
1527         case RAW_FILEINFO_ALL_INFORMATION:
1528                 CHECK_NTTIMES_EQUAL(all_info.out.create_time);
1529                 CHECK_NTTIMES_EQUAL(all_info.out.access_time);
1530                 CHECK_NTTIMES_EQUAL(all_info.out.write_time);
1531                 CHECK_NTTIMES_EQUAL(all_info.out.change_time);
1532                 CHECK_EQUAL(all_info.out.attrib);
1533                 CHECK_EQUAL(all_info.out.alloc_size);
1534                 CHECK_EQUAL(all_info.out.size);
1535                 CHECK_EQUAL(all_info.out.nlink);
1536                 CHECK_EQUAL(all_info.out.delete_pending);
1537                 CHECK_EQUAL(all_info.out.directory);
1538                 CHECK_EQUAL(all_info.out.ea_size);
1539                 CHECK_WSTR_EQUAL(all_info.out.fname);
1540                 break;
1541
1542         case RAW_FILEINFO_ALT_NAME_INFO:
1543         case RAW_FILEINFO_ALT_NAME_INFORMATION:
1544                 CHECK_WSTR_EQUAL(alt_name_info.out.fname);
1545                 break;
1546
1547         case RAW_FILEINFO_STREAM_INFO:
1548         case RAW_FILEINFO_STREAM_INFORMATION:
1549                 CHECK_EQUAL(stream_info.out.num_streams);
1550                 for (i=0;i<parm[0].stream_info.out.num_streams;i++) {
1551                         CHECK_EQUAL(stream_info.out.streams[i].size);
1552                         CHECK_EQUAL(stream_info.out.streams[i].alloc_size);
1553                         CHECK_WSTR_EQUAL(stream_info.out.streams[i].stream_name);
1554                 }
1555                 break;
1556
1557         case RAW_FILEINFO_COMPRESSION_INFO:
1558         case RAW_FILEINFO_COMPRESSION_INFORMATION:
1559                 CHECK_EQUAL(compression_info.out.compressed_size);
1560                 CHECK_EQUAL(compression_info.out.format);
1561                 CHECK_EQUAL(compression_info.out.unit_shift);
1562                 CHECK_EQUAL(compression_info.out.chunk_shift);
1563                 CHECK_EQUAL(compression_info.out.cluster_shift);
1564                 break;
1565
1566         case RAW_FILEINFO_INTERNAL_INFORMATION:
1567                 CHECK_EQUAL(internal_information.out.file_id);
1568                 break;
1569
1570         case RAW_FILEINFO_ACCESS_INFORMATION:
1571                 CHECK_EQUAL(access_information.out.access_flags);
1572                 break;
1573
1574         case RAW_FILEINFO_POSITION_INFORMATION:
1575                 CHECK_EQUAL(position_information.out.position);
1576                 break;
1577
1578         case RAW_FILEINFO_MODE_INFORMATION:
1579                 CHECK_EQUAL(mode_information.out.mode);
1580                 break;
1581
1582         case RAW_FILEINFO_ALIGNMENT_INFORMATION:
1583                 CHECK_EQUAL(alignment_information.out.alignment_requirement);
1584                 break;
1585
1586         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
1587                 CHECK_NTTIMES_EQUAL(network_open_information.out.create_time);
1588                 CHECK_NTTIMES_EQUAL(network_open_information.out.access_time);
1589                 CHECK_NTTIMES_EQUAL(network_open_information.out.write_time);
1590                 CHECK_NTTIMES_EQUAL(network_open_information.out.change_time);
1591                 CHECK_EQUAL(network_open_information.out.alloc_size);
1592                 CHECK_EQUAL(network_open_information.out.size);
1593                 CHECK_EQUAL(network_open_information.out.attrib);
1594                 break;
1595
1596         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
1597                 CHECK_EQUAL(attribute_tag_information.out.attrib);
1598                 CHECK_EQUAL(attribute_tag_information.out.reparse_tag);
1599                 break;
1600         }
1601
1602         return True;
1603 }
1604
1605 /*
1606   generate qpathinfo operations
1607 */
1608 static BOOL handler_qpathinfo(int instance)
1609 {
1610         union smb_fileinfo parm[NSERVERS];
1611         NTSTATUS status[NSERVERS];
1612
1613         parm[0].generic.in.fname = gen_fname_open(instance);
1614
1615         gen_fileinfo(instance, &parm[0]);
1616
1617         GEN_COPY_PARM;
1618         GEN_CALL(smb_raw_pathinfo(tree, current_op.mem_ctx, &parm[i]));
1619
1620         return cmp_fileinfo(instance, parm, status);
1621 }
1622
1623 /*
1624   generate qfileinfo operations
1625 */
1626 static BOOL handler_qfileinfo(int instance)
1627 {
1628         union smb_fileinfo parm[NSERVERS];
1629         NTSTATUS status[NSERVERS];
1630
1631         parm[0].generic.in.fnum = gen_fnum(instance);
1632
1633         gen_fileinfo(instance, &parm[0]);
1634
1635         GEN_COPY_PARM;
1636         GEN_SET_FNUM(generic.in.fnum);
1637         GEN_CALL(smb_raw_fileinfo(tree, current_op.mem_ctx, &parm[i]));
1638
1639         return cmp_fileinfo(instance, parm, status);
1640 }
1641
1642
1643 /*
1644   generate a fileinfo query structure
1645 */
1646 static void gen_setfileinfo(int instance, union smb_setfileinfo *info)
1647 {
1648         int i;
1649         #undef LVL
1650         #define LVL(v) {RAW_SFILEINFO_ ## v, "RAW_SFILEINFO_" #v}
1651         struct {
1652                 enum smb_setfileinfo_level level;
1653                 const char *name;
1654         }  levels[] = {
1655 #if 0
1656                 /* disabled until win2003 can handle them ... */
1657                 LVL(EA_SET), LVL(BASIC_INFO), LVL(DISPOSITION_INFO), 
1658                 LVL(STANDARD), LVL(ALLOCATION_INFO), LVL(END_OF_FILE_INFO), 
1659 #endif
1660                 LVL(SETATTR), LVL(SETATTRE), LVL(BASIC_INFORMATION),
1661                 LVL(RENAME_INFORMATION), LVL(DISPOSITION_INFORMATION), 
1662                 LVL(POSITION_INFORMATION), LVL(MODE_INFORMATION),
1663                 LVL(ALLOCATION_INFORMATION), LVL(END_OF_FILE_INFORMATION), 
1664                 LVL(1023), LVL(1025), LVL(1029), LVL(1032), LVL(1039), LVL(1040)
1665         };
1666         do {
1667                 i = gen_int_range(0, ARRAY_SIZE(levels)-1);
1668         } while (ignore_pattern(levels[i].name));
1669
1670         info->generic.level = levels[i].level;
1671
1672         switch (info->generic.level) {
1673         case RAW_SFILEINFO_SETATTR:
1674                 info->setattr.in.attrib = gen_attrib();
1675                 info->setattr.in.write_time = gen_timet();
1676                 break;
1677         case RAW_SFILEINFO_SETATTRE:
1678                 info->setattre.in.create_time = gen_timet();
1679                 info->setattre.in.access_time = gen_timet();
1680                 info->setattre.in.write_time = gen_timet();
1681                 break;
1682         case RAW_SFILEINFO_STANDARD:
1683                 info->standard.in.create_time = gen_timet();
1684                 info->standard.in.access_time = gen_timet();
1685                 info->standard.in.write_time = gen_timet();
1686                 break;
1687         case RAW_SFILEINFO_EA_SET:
1688                 info->ea_set.in.ea = gen_ea_struct();
1689                 break;
1690         case RAW_SFILEINFO_BASIC_INFO:
1691         case RAW_SFILEINFO_BASIC_INFORMATION:
1692                 info->basic_info.in.create_time = gen_nttime();
1693                 info->basic_info.in.access_time = gen_nttime();
1694                 info->basic_info.in.write_time = gen_nttime();
1695                 info->basic_info.in.change_time = gen_nttime();
1696                 info->basic_info.in.attrib = gen_attrib();
1697                 break;
1698         case RAW_SFILEINFO_DISPOSITION_INFO:
1699         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
1700                 info->disposition_info.in.delete_on_close = gen_bool();
1701                 break;
1702         case RAW_SFILEINFO_ALLOCATION_INFO:
1703         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
1704                 info->allocation_info.in.alloc_size = gen_alloc_size();
1705                 break;
1706         case RAW_SFILEINFO_END_OF_FILE_INFO:
1707         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
1708                 info->end_of_file_info.in.size = gen_offset();
1709                 break;
1710         case RAW_SFILEINFO_RENAME_INFORMATION:
1711                 info->rename_information.in.overwrite = gen_bool();
1712                 info->rename_information.in.root_fid = gen_root_fid(instance);
1713                 info->rename_information.in.new_name = gen_fname_open(instance);
1714                 break;
1715         case RAW_SFILEINFO_POSITION_INFORMATION:
1716                 info->position_information.in.position = gen_offset();
1717                 break;
1718         case RAW_SFILEINFO_MODE_INFORMATION:
1719                 info->mode_information.in.mode = gen_bits_mask(0xFFFFFFFF);
1720                 break;
1721         }
1722 }
1723
1724 /*
1725   generate setpathinfo operations
1726 */
1727 static BOOL handler_spathinfo(int instance)
1728 {
1729         union smb_setfileinfo parm[NSERVERS];
1730         NTSTATUS status[NSERVERS];
1731
1732         parm[0].generic.file.fname = gen_fname_open(instance);
1733
1734         gen_setfileinfo(instance, &parm[0]);
1735
1736         GEN_COPY_PARM;
1737
1738         /* a special case for the fid in a RENAME */
1739         if (parm[0].generic.level == RAW_SFILEINFO_RENAME_INFORMATION &&
1740             parm[0].rename_information.in.root_fid != 0) {
1741                 GEN_SET_FNUM(rename_information.in.root_fid);
1742         }
1743
1744         GEN_CALL(smb_raw_setpathinfo(tree, &parm[i]));
1745
1746         return True;
1747 }
1748
1749
1750 /*
1751   generate setfileinfo operations
1752 */
1753 static BOOL handler_sfileinfo(int instance)
1754 {
1755         union smb_setfileinfo parm[NSERVERS];
1756         NTSTATUS status[NSERVERS];
1757
1758         parm[0].generic.file.fnum = gen_fnum(instance);
1759
1760         gen_setfileinfo(instance, &parm[0]);
1761
1762         GEN_COPY_PARM;
1763         GEN_SET_FNUM(generic.file.fnum);
1764         GEN_CALL(smb_raw_setfileinfo(tree, &parm[i]));
1765
1766         return True;
1767 }
1768
1769
1770 /*
1771   generate change notify operations
1772 */
1773 static BOOL handler_notify(int instance)
1774 {
1775         struct smb_notify parm[NSERVERS];
1776         int n;
1777
1778         parm[0].in.buffer_size = gen_io_count();
1779         parm[0].in.completion_filter = gen_bits_mask(0xFF);
1780         parm[0].in.fnum = gen_fnum(instance);
1781         parm[0].in.recursive = gen_bool();
1782
1783         GEN_COPY_PARM;
1784         GEN_SET_FNUM(in.fnum);
1785
1786         for (n=0;n<NSERVERS;n++) {
1787                 struct smbcli_request *req;
1788                 req = smb_raw_changenotify_send(servers[n].cli[instance]->tree, &parm[n]);
1789                 req->async.fn = async_notify;
1790         }
1791
1792         return True;
1793 }
1794
1795 /*
1796   wipe any relevant files
1797 */
1798 static void wipe_files(void)
1799 {
1800         int i;
1801         for (i=0;i<NSERVERS;i++) {
1802                 int n = smbcli_deltree(servers[i].cli[0]->tree, "\\gentest");
1803                 if (n == -1) {
1804                         printf("Failed to wipe tree on server %d\n", i);
1805                         exit(1);
1806                 }
1807                 if (NT_STATUS_IS_ERR(smbcli_mkdir(servers[i].cli[0]->tree, "\\gentest"))) {
1808                         printf("Failed to create \\gentest - %s\n",
1809                                smbcli_errstr(servers[i].cli[0]->tree));
1810                         exit(1);
1811                 }
1812                 if (n > 0) {
1813                         printf("Deleted %d files on server %d\n", n, i);
1814                 }
1815         }
1816 }
1817
1818 /*
1819   dump the current seeds - useful for continuing a backtrack
1820 */
1821 static void dump_seeds(void)
1822 {
1823         int i;
1824         FILE *f;
1825
1826         if (!options.seeds_file) {
1827                 return;
1828         }
1829         f = fopen("seeds.tmp", "w");
1830         if (!f) return;
1831
1832         for (i=0;i<options.numops;i++) {
1833                 fprintf(f, "%u\n", op_parms[i].seed);
1834         }
1835         fclose(f);
1836         rename("seeds.tmp", options.seeds_file);
1837 }
1838
1839
1840
1841 /*
1842   the list of top-level operations that we will generate
1843 */
1844 static struct {
1845         const char *name;
1846         BOOL (*handler)(int instance);
1847         int count, success_count;
1848 } gen_ops[] = {
1849         {"OPEN",       handler_open},
1850         {"OPENX",      handler_openx},
1851         {"NTCREATEX",  handler_ntcreatex},
1852         {"CLOSE",      handler_close},
1853         {"UNLINK",     handler_unlink},
1854         {"MKDIR",      handler_mkdir},
1855         {"RMDIR",      handler_rmdir},
1856         {"RENAME",     handler_rename},
1857         {"NTRENAME",   handler_ntrename},
1858         {"READX",      handler_readx},
1859         {"WRITEX",     handler_writex},
1860         {"CHKPATH",    handler_chkpath},
1861         {"LOCKINGX",   handler_lockingx},
1862         {"QPATHINFO",  handler_qpathinfo},
1863         {"QFILEINFO",  handler_qfileinfo},
1864         {"SPATHINFO",  handler_spathinfo},
1865         {"SFILEINFO",  handler_sfileinfo},
1866         {"NOTIFY",     handler_notify},
1867         {"SEEK",       handler_seek},
1868 };
1869
1870
1871 /*
1872   run the test with the current set of op_parms parameters
1873   return the number of operations that completed successfully
1874 */
1875 static int run_test(void)
1876 {
1877         int op, i;
1878
1879         if (!connect_servers()) {
1880                 printf("Failed to connect to servers\n");
1881                 exit(1);
1882         }
1883
1884         dump_seeds();
1885
1886         /* wipe any leftover files from old runs */
1887         wipe_files();
1888
1889         /* reset the open handles array */
1890         memset(open_handles, 0, options.max_open_handles * sizeof(open_handles[0]));
1891         num_open_handles = 0;
1892
1893         for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
1894                 gen_ops[i].count = 0;
1895                 gen_ops[i].success_count = 0;
1896         }
1897
1898         for (op=0; op<options.numops; op++) {
1899                 int instance, which_op;
1900                 BOOL ret;
1901
1902                 if (op_parms[op].disabled) continue;
1903
1904                 srandom(op_parms[op].seed);
1905
1906                 instance = gen_int_range(0, NINSTANCES-1);
1907
1908                 /* generate a non-ignored operation */
1909                 do {
1910                         which_op = gen_int_range(0, ARRAY_SIZE(gen_ops)-1);
1911                 } while (ignore_pattern(gen_ops[which_op].name));
1912
1913                 DEBUG(3,("Generating op %s on instance %d\n",
1914                          gen_ops[which_op].name, instance));
1915
1916                 current_op.seed = op_parms[op].seed;
1917                 current_op.opnum = op;
1918                 current_op.name = gen_ops[which_op].name;
1919                 current_op.status = NT_STATUS_OK;
1920                 current_op.mem_ctx = talloc_init("%s", current_op.name);
1921
1922                 ret = gen_ops[which_op].handler(instance);
1923
1924                 talloc_destroy(current_op.mem_ctx);
1925
1926                 gen_ops[which_op].count++;
1927                 if (NT_STATUS_IS_OK(current_op.status)) {
1928                         gen_ops[which_op].success_count++;                      
1929                 }
1930
1931                 if (!ret) {
1932                         printf("Failed at operation %d - %s\n",
1933                                op, gen_ops[which_op].name);
1934                         return op;
1935                 }
1936
1937                 if (op % 100 == 0) {
1938                         printf("%d\n", op);
1939                 }
1940         }
1941
1942         for (i=0;i<ARRAY_SIZE(gen_ops);i++) {
1943                 printf("Op %-10s got %d/%d success\n", 
1944                        gen_ops[i].name,
1945                        gen_ops[i].success_count,
1946                        gen_ops[i].count);
1947         }
1948
1949         return op;
1950 }
1951
1952 /* 
1953    perform a backtracking analysis of the minimal set of operations
1954    to generate an error
1955 */
1956 static void backtrack_analyze(void)
1957 {
1958         int chunk, ret;
1959
1960         chunk = options.numops / 2;
1961
1962         do {
1963                 int base;
1964                 for (base=0; 
1965                      chunk > 0 && base+chunk < options.numops && options.numops > 1; ) {
1966                         int i, max;
1967
1968                         chunk = MIN(chunk, options.numops / 2);
1969
1970                         /* mark this range as disabled */
1971                         max = MIN(options.numops, base+chunk);
1972                         for (i=base;i<max; i++) {
1973                                 op_parms[i].disabled = True;
1974                         }
1975                         printf("Testing %d ops with %d-%d disabled\n", 
1976                                options.numops, base, max-1);
1977                         ret = run_test();
1978                         printf("Completed %d of %d ops\n", ret, options.numops);
1979                         for (i=base;i<max; i++) {
1980                                 op_parms[i].disabled = False;
1981                         }
1982                         if (ret == options.numops) {
1983                                 /* this chunk is needed */
1984                                 base += chunk;
1985                         } else if (ret < base) {
1986                                 printf("damn - inconsistent errors! found early error\n");
1987                                 options.numops = ret+1;
1988                                 base = 0;
1989                         } else {
1990                                 /* it failed - this chunk isn't needed for a failure */
1991                                 memmove(&op_parms[base], &op_parms[max], 
1992                                         sizeof(op_parms[0]) * (options.numops - max));
1993                                 options.numops = (ret+1) - (max - base);
1994                         }
1995                 }
1996
1997                 if (chunk == 2) {
1998                         chunk = 1;
1999                 } else {
2000                         chunk *= 0.4;
2001                 }
2002
2003                 if (options.analyze_continuous && chunk == 0 && options.numops != 1) {
2004                         chunk = 1;
2005                 }
2006         } while (chunk > 0);
2007
2008         printf("Reduced to %d ops\n", options.numops);
2009         ret = run_test();
2010         if (ret != options.numops - 1) {
2011                 printf("Inconsistent result? ret=%d numops=%d\n", ret, options.numops);
2012         }
2013 }
2014
2015 /* 
2016    start the main gentest process
2017 */
2018 static BOOL start_gentest(void)
2019 {
2020         int op;
2021         int ret;
2022
2023         /* allocate the open_handles array */
2024         open_handles = calloc(options.max_open_handles, sizeof(open_handles[0]));
2025
2026         srandom(options.seed);
2027         op_parms = calloc(options.numops, sizeof(op_parms[0]));
2028
2029         /* generate the seeds - after this everything is deterministic */
2030         if (options.use_preset_seeds) {
2031                 int numops;
2032                 char **preset = file_lines_load(options.seeds_file, &numops);
2033                 if (!preset) {
2034                         printf("Failed to load %s - %s\n", options.seeds_file, strerror(errno));
2035                         exit(1);
2036                 }
2037                 if (numops < options.numops) {
2038                         options.numops = numops;
2039                 }
2040                 for (op=0;op<options.numops;op++) {
2041                         if (!preset[op]) {
2042                                 printf("Not enough seeds in %s\n", options.seeds_file);
2043                                 exit(1);
2044                         }
2045                         op_parms[op].seed = atoi(preset[op]);
2046                 }
2047                 printf("Loaded %d seeds from %s\n", options.numops, options.seeds_file);
2048         } else {
2049                 for (op=0; op<options.numops; op++) {
2050                         op_parms[op].seed = random();
2051                 }
2052         }
2053
2054         ret = run_test();
2055
2056         if (ret != options.numops && options.analyze) {
2057                 options.numops = ret+1;
2058                 backtrack_analyze();
2059         } else if (options.analyze_always) {
2060                 backtrack_analyze();
2061         } else if (options.analyze_continuous) {
2062                 while (run_test() == options.numops) ;
2063         }
2064
2065         return ret == options.numops;
2066 }
2067
2068
2069 static void usage(void)
2070 {
2071         printf(
2072 "Usage:\n\
2073   gentest2 //server1/share1 //server2/share2 [options..]\n\
2074   options:\n\
2075         -U user%%pass        (can be specified twice)\n\
2076         -s seed\n\
2077         -o numops\n\
2078         -a            (show all ops)\n\
2079         -A            backtrack to find minimal ops\n\
2080         -i FILE       add a list of wildcard exclusions\n\
2081         -O            enable oplocks\n\
2082         -S FILE       set preset seeds file\n\
2083         -L            use preset seeds\n\
2084         -F            fast reconnect (just close files)\n\
2085         -C            continuous analysis mode\n\
2086         -X            analyse even when test OK\n\
2087 ");
2088 }
2089
2090 /****************************************************************************
2091   main program
2092 ****************************************************************************/
2093  int main(int argc, char *argv[])
2094 {
2095         int opt;
2096         int i;
2097         BOOL ret;
2098
2099         setlinebuf(stdout);
2100
2101         setup_logging("gentest", DEBUG_STDOUT);
2102
2103         if (argc < 3 || argv[1][0] == '-') {
2104                 usage();
2105                 exit(1);
2106         }
2107
2108         setup_logging(argv[0], DEBUG_STDOUT);
2109
2110         gentest_init_subsystems;
2111
2112         for (i=0;i<NSERVERS;i++) {
2113                 const char *share = argv[1+i];
2114                 if (!split_unc_name(share, &servers[i].server_name, &servers[i].share_name)) {
2115                         printf("Invalid share name '%s'\n", share);
2116                         return -1;
2117                 }
2118         }
2119
2120         argc -= NSERVERS;
2121         argv += NSERVERS;
2122
2123         lp_load(dyn_CONFIGFILE,True,False,False);
2124         load_interfaces();
2125
2126         options.seed = time(NULL);
2127         options.numops = 1000;
2128         options.max_open_handles = 20;
2129         options.seeds_file = "gentest_seeds.dat";
2130
2131         while ((opt = getopt(argc, argv, "U:s:o:ad:i:AOhS:LFXC")) != EOF) {
2132                 switch (opt) {
2133                 case 'U':
2134                         i = servers[0].username?1:0;
2135                         if (!split_username(optarg, 
2136                                             &servers[i].username, 
2137                                             &servers[i].password)) {
2138                                 printf("Must supply USER%%PASS\n");
2139                                 return -1;
2140                         }
2141                         break;
2142                 case 'd':
2143                         DEBUGLEVEL = atoi(optarg);
2144                         setup_logging(NULL, DEBUG_STDOUT);
2145                         break;
2146                 case 's':
2147                         options.seed = atoi(optarg);
2148                         break;
2149                 case 'S':
2150                         options.seeds_file = optarg;
2151                         break;
2152                 case 'L':
2153                         options.use_preset_seeds = True;
2154                         break;
2155                 case 'F':
2156                         options.fast_reconnect = True;
2157                         break;
2158                 case 'o':
2159                         options.numops = atoi(optarg);
2160                         break;
2161                 case 'O':
2162                         options.use_oplocks = True;
2163                         break;
2164                 case 'a':
2165                         options.showall = True;
2166                         break;
2167                 case 'A':
2168                         options.analyze = True;
2169                         break;
2170                 case 'X':
2171                         options.analyze_always = True;
2172                         break;
2173                 case 'C':
2174                         options.analyze_continuous = True;
2175                         break;
2176                 case 'i':
2177                         options.ignore_patterns = file_lines_load(optarg, NULL);
2178                         break;
2179                 case 'h':
2180                         usage();
2181                         exit(1);
2182                 default:
2183                         printf("Unknown option %c (%d)\n", (char)opt, opt);
2184                         exit(1);
2185                 }
2186         }
2187
2188         if (!servers[0].username) {
2189                 usage();
2190                 return -1;
2191         }
2192         if (!servers[1].username) {
2193                 servers[1].username = servers[0].username;
2194                 servers[1].password = servers[0].password;
2195         }
2196
2197         printf("seed=%u\n", options.seed);
2198
2199         ret = start_gentest();
2200
2201         if (ret) {
2202                 printf("gentest completed - no errors\n");
2203         } else {
2204                 printf("gentest failed\n");
2205         }
2206
2207         return ret?0:-1;
2208 }