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