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