025a473370bff74e2e4ff2e8534374cd90f947b5
[kai/samba.git] / source / utils / locktest.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.0
4    mask_match tester
5    Copyright (C) Andrew Tridgell 1999
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #define NO_SYSLOG
23
24 #include "includes.h"
25
26 static fstring password;
27 static fstring username;
28 static fstring workgroup;
29 static int got_pass;
30 static int numops = 1000;
31 static BOOL showall;
32
33 #define FILENAME "locktest.dat"
34 #define LOCKRANGE 100
35
36 #define READ_PCT 50
37 #define LOCK_PCT 45
38 #define UNLOCK_PCT 45
39
40 /* each server has two connections open to it. Each connection has two file
41    descriptors open on the file - 8 file descriptors in total 
42
43    we then do random locking ops in tamdem on the 4 fnums from each
44    server and ensure that the results match
45  */
46 static void test_locks(struct cli_state *cli[2][2])
47 {
48         int fnum[2][2][2];
49         int server, conn, f, n; 
50
51         cli_unlink(cli[0][0], FILENAME);
52         cli_unlink(cli[1][0], FILENAME);
53
54         for (server=0;server<2;server++)
55         for (conn=0;conn<2;conn++)
56         for (f=0;f<2;f++) {
57                 fnum[server][conn][f] = cli_open(cli[server][conn], FILENAME,
58                                                  O_RDWR|O_CREAT,
59                                                  DENY_NONE);
60                 if (fnum[server][conn][f] == -1) {
61                         fprintf(stderr,"Failed to open fnum[%d][%d][%d]\n",
62                                 server, conn, f);
63                         return;
64                 }
65         }
66
67         for (n=0; n<numops; n++) {
68                 int start, len, op, r;
69                 BOOL ret1, ret2;
70
71                 conn = random() % 2;
72                 f = random() % 2;
73                 start = random() % (LOCKRANGE-1);
74                 len = 1 + random() % (LOCKRANGE-start);
75
76                 r = random() % 100;
77
78                 if (r < READ_PCT) {
79                         op = READ_LOCK; 
80                 } else {
81                         op = WRITE_LOCK; 
82                 }
83
84                 r = random() % 100;
85
86                 if (r < LOCK_PCT) {
87                         /* set a lock */
88                         ret1 = cli_lock(cli[0][conn], 
89                                         fnum[0][conn][f],
90                                         start, len, 0, op);
91                         ret2 = cli_lock(cli[1][conn], 
92                                         fnum[1][conn][f],
93                                         start, len, 0, op);
94                         if (showall || ret1 != ret2) {
95                                 printf("%5d lock   conn=%d f=%d %d:%d op=%s -> %d:%d\n",
96                                        n, conn, f, start, len, op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
97                                        ret1, ret2);
98                         }
99                         if (ret1 != ret2) return;
100                 } else if (r < LOCK_PCT+UNLOCK_PCT) {
101                         /* unset a lock */
102                         /* set a lock */
103                         ret1 = cli_unlock(cli[0][conn], 
104                                           fnum[0][conn][f],
105                                           start, len);
106                         ret2 = cli_unlock(cli[1][conn], 
107                                           fnum[1][conn][f],
108                                           start, len);
109                         if (showall || ret1 != ret2) {
110                                 printf("%5d unlock conn=%d f=%d %d:%d       -> %d:%d\n",
111                                        n, conn, f, start, len,
112                                        ret1, ret2);
113                         }
114                 } else {
115                         /* reopen the file */
116                         cli_close(cli[0][conn], fnum[0][conn][f]);
117                         cli_close(cli[1][conn], fnum[1][conn][f]);
118                         fnum[0][conn][f] = cli_open(cli[0][conn], FILENAME,
119                                                     O_RDWR|O_CREAT,
120                                                     DENY_NONE);
121                         fnum[1][conn][f] = cli_open(cli[1][conn], FILENAME,
122                                                     O_RDWR|O_CREAT,
123                                                     DENY_NONE);
124                         if (fnum[0][conn][f] == -1) {
125                                 printf("failed to reopen on share1\n");
126                                 return;
127                         }
128                         if (fnum[1][conn][f] == -1) {
129                                 printf("failed to reopen on share2\n");
130                                 return;
131                         }
132                         if (showall) {
133                                 printf("%5d reopen conn=%d f=%d\n",
134                                        n, conn, f);
135                         }
136                         if (ret1 != ret2) return;
137                 }
138                 if (n % 100 == 0) {
139                         printf("%d\n", n);
140                 }
141         }
142 }
143
144
145 /***************************************************** 
146 return a connection to a server
147 *******************************************************/
148 struct cli_state *connect_one(char *share)
149 {
150         struct cli_state *c;
151         struct nmb_name called, calling;
152         char *server_n;
153         fstring server;
154         struct in_addr ip;
155         extern struct in_addr ipzero;
156
157         fstrcpy(server,share+2);
158         share = strchr(server,'\\');
159         if (!share) return NULL;
160         *share = 0;
161         share++;
162
163         server_n = server;
164         
165         ip = ipzero;
166
167         make_nmb_name(&calling, "locktest", 0x0);
168         make_nmb_name(&called , server, 0x20);
169
170  again:
171         ip = ipzero;
172
173         /* have to open a new connection */
174         if (!(c=cli_initialise(NULL)) || (cli_set_port(c, 139) == 0) ||
175             !cli_connect(c, server_n, &ip)) {
176                 DEBUG(0,("Connection to %s failed\n", server_n));
177                 return NULL;
178         }
179
180         if (!cli_session_request(c, &calling, &called)) {
181                 DEBUG(0,("session request to %s failed\n", called.name));
182                 cli_shutdown(c);
183                 if (strcmp(called.name, "*SMBSERVER")) {
184                         make_nmb_name(&called , "*SMBSERVER", 0x20);
185                         goto again;
186                 }
187                 return NULL;
188         }
189
190         DEBUG(4,(" session request ok\n"));
191
192         if (!cli_negprot(c)) {
193                 DEBUG(0,("protocol negotiation failed\n"));
194                 cli_shutdown(c);
195                 return NULL;
196         }
197
198         if (!got_pass) {
199                 char *pass = getpass("Password: ");
200                 if (pass) {
201                         pstrcpy(password, pass);
202                 }
203         }
204
205         if (!cli_session_setup(c, username, 
206                                password, strlen(password),
207                                password, strlen(password),
208                                workgroup)) {
209                 DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
210                 return NULL;
211         }
212
213         /*
214          * These next two lines are needed to emulate
215          * old client behaviour for people who have
216          * scripts based on client output.
217          * QUESTION ? Do we want to have a 'client compatibility
218          * mode to turn these on/off ? JRA.
219          */
220
221         if (*c->server_domain || *c->server_os || *c->server_type)
222                 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
223                         c->server_domain,c->server_os,c->server_type));
224         
225         DEBUG(4,(" session setup ok\n"));
226
227         if (!cli_send_tconX(c, share, "?????",
228                             password, strlen(password)+1)) {
229                 DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
230                 cli_shutdown(c);
231                 return NULL;
232         }
233
234         DEBUG(4,(" tconx ok\n"));
235
236         return c;
237 }
238
239
240 static void usage(void)
241 {
242         printf(
243 "Usage:\n\
244   locktest //server1/share1 //server2/share2 [options..]\n\
245   options:\n\
246         -U user%%pass\n\
247         -s seed\n\
248         -o numops\n\
249         -a          (show all ops)\n\
250 ");
251 }
252
253 /****************************************************************************
254   main program
255 ****************************************************************************/
256  int main(int argc,char *argv[])
257 {
258         char *share1, *share2;
259         struct cli_state *cli[2][2];
260         extern char *optarg;
261         extern int optind;
262         extern FILE *dbf;
263         int opt;
264         char *p;
265         int seed;
266         static pstring servicesf = CONFIGFILE;
267
268         setlinebuf(stdout);
269
270         dbf = stderr;
271
272         if (argv[1][0] == '-' || argc < 3) {
273                 usage();
274                 exit(1);
275         }
276
277         share1 = argv[1];
278         share2 = argv[2];
279
280         all_string_sub(share1,"/","\\",0);
281         all_string_sub(share2,"/","\\",0);
282
283         setup_logging(argv[0],True);
284
285         argc -= 2;
286         argv += 2;
287
288         TimeInit();
289         charset_initialise();
290
291         lp_load(servicesf,True,False,False);
292         load_interfaces();
293
294         if (getenv("USER")) {
295                 pstrcpy(username,getenv("USER"));
296         }
297
298         seed = time(NULL);
299
300         while ((opt = getopt(argc, argv, "U:s:ho:a")) != EOF) {
301                 switch (opt) {
302                 case 'U':
303                         pstrcpy(username,optarg);
304                         p = strchr(username,'%');
305                         if (p) {
306                                 *p = 0;
307                                 pstrcpy(password, p+1);
308                                 got_pass = 1;
309                         }
310                         break;
311                 case 's':
312                         seed = atoi(optarg);
313                         break;
314                 case 'o':
315                         numops = atoi(optarg);
316                         break;
317                 case 'a':
318                         showall = True;
319                         break;
320                 case 'h':
321                         usage();
322                         exit(1);
323                 default:
324                         printf("Unknown option %c (%d)\n", (char)opt, opt);
325                         exit(1);
326                 }
327         }
328
329         argc -= optind;
330         argv += optind;
331
332         DEBUG(0,("seed=%d\n", seed));
333         srandom(seed);
334
335         cli[0][0] = connect_one(share1);
336         cli[0][1] = connect_one(share1);
337         if (!cli[0][0] || !cli[0][1]) {
338                 DEBUG(0,("Failed to connect to %s\n", share1));
339                 exit(1);
340         }
341
342         cli[1][0] = connect_one(share2);
343         cli[1][1] = connect_one(share2);
344         if (!cli[1][0] || !cli[1][1]) {
345                 DEBUG(0,("Failed to connect to %s\n", share2));
346                 exit(1);
347         }
348
349         test_locks(cli);
350
351         return(0);
352 }