• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.0.25b/source/torture/
1/*
2   Unix SMB/CIFS implementation.
3   randomised byte range lock tester
4   Copyright (C) Andrew Tridgell 1999
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23static fstring password[2];
24static fstring username[2];
25static int got_user;
26static int got_pass;
27static BOOL use_kerberos;
28static int numops = 1000;
29static BOOL showall;
30static BOOL analyze;
31static BOOL hide_unlock_fails;
32static BOOL use_oplocks;
33static unsigned lock_range = 100;
34static unsigned lock_base = 0;
35static unsigned min_length = 0;
36static BOOL exact_error_codes;
37static BOOL zero_zero;
38
39extern char *optarg;
40extern int optind;
41
42#define FILENAME "\\locktest.dat"
43
44#define READ_PCT 50
45#define LOCK_PCT 45
46#define UNLOCK_PCT 70
47#define RANGE_MULTIPLE 1
48#define NSERVERS 2
49#define NCONNECTIONS 2
50#define NFILES 2
51#define LOCK_TIMEOUT 0
52
53#define NASTY_POSIX_LOCK_HACK 0
54
55enum lock_op {OP_LOCK, OP_UNLOCK, OP_REOPEN};
56
57static const char *lock_op_type(int op)
58{
59	if (op == WRITE_LOCK) return "write";
60	else if (op == READ_LOCK) return "read";
61	else return "other";
62}
63
64static const char *lock_op_name(enum lock_op op)
65{
66	if (op == OP_LOCK) return "lock";
67	else if (op == OP_UNLOCK) return "unlock";
68	else return "reopen";
69}
70
71struct record {
72	enum lock_op lock_op;
73	enum brl_type lock_type;
74	char conn, f;
75	SMB_BIG_UINT start, len;
76	char needed;
77};
78
79#define PRESETS 0
80
81#if PRESETS
82static struct record preset[] = {
83{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
84{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
85{OP_LOCK, WRITE_LOCK, 0, 0, 3, 0, 1},
86{OP_UNLOCK, 0       , 0, 0, 2, 0, 1},
87{OP_REOPEN, 0, 0, 0, 0, 0, 1},
88
89{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
90{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
91{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
92{OP_REOPEN, 0, 0, 0, 0, 0, 1},
93
94{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
95{OP_LOCK, WRITE_LOCK, 0, 0, 3, 1, 1},
96{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
97{OP_REOPEN, 0, 0, 0, 0, 0, 1},
98
99{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
100{OP_LOCK, WRITE_LOCK, 0, 0, 1, 1, 1},
101{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
102{OP_REOPEN, 0, 0, 0, 0, 0, 1},
103
104{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
105{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
106{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
107{OP_REOPEN, 0, 0, 0, 0, 0, 1},
108
109{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
110{OP_LOCK, READ_LOCK, 0, 0, 3, 1, 1},
111{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
112{OP_REOPEN, 0, 0, 0, 0, 0, 1},
113
114};
115#endif
116
117static struct record *recorded;
118
119static void print_brl(SMB_DEV_T dev,
120			SMB_INO_T ino,
121			struct process_id pid,
122			enum brl_type lock_type,
123			enum brl_flavour lock_flav,
124			br_off start,
125			br_off size)
126{
127#if NASTY_POSIX_LOCK_HACK
128	{
129		pstring cmd;
130		static SMB_INO_T lastino;
131
132		if (lastino != ino) {
133			slprintf(cmd, sizeof(cmd),
134				 "egrep POSIX.*%u /proc/locks", (int)ino);
135			system(cmd);
136		}
137		lastino = ino;
138	}
139#endif
140
141	printf("%s   %05x:%05x    %s  %.0f:%.0f(%.0f)\n",
142	       procid_str_static(&pid), (int)dev, (int)ino,
143	       lock_type==READ_LOCK?"R":"W",
144	       (double)start, (double)start+size-1,(double)size);
145
146}
147
148
149static void show_locks(void)
150{
151	brl_forall(print_brl);
152	/* system("cat /proc/locks"); */
153}
154
155
156/*****************************************************
157return a connection to a server
158*******************************************************/
159static struct cli_state *connect_one(char *share, int snum)
160{
161	struct cli_state *c;
162	struct nmb_name called, calling;
163	char *server_n;
164	fstring server;
165	struct in_addr ip;
166	fstring myname;
167	static int count;
168
169	fstrcpy(server,share+2);
170	share = strchr_m(server,'\\');
171	if (!share) return NULL;
172	*share = 0;
173	share++;
174
175	server_n = server;
176
177        zero_ip(&ip);
178
179	slprintf(myname,sizeof(myname), "lock-%lu-%u", (unsigned long)getpid(), count++);
180
181	make_nmb_name(&calling, myname, 0x0);
182	make_nmb_name(&called , server, 0x20);
183
184 again:
185        zero_ip(&ip);
186
187	/* have to open a new connection */
188	if (!(c=cli_initialise()) || !cli_connect(c, server_n, &ip)) {
189		DEBUG(0,("Connection to %s failed\n", server_n));
190		return NULL;
191	}
192
193	c->use_kerberos = use_kerberos;
194
195	if (!cli_session_request(c, &calling, &called)) {
196		DEBUG(0,("session request to %s failed\n", called.name));
197		cli_shutdown(c);
198		if (strcmp(called.name, "*SMBSERVER")) {
199			make_nmb_name(&called , "*SMBSERVER", 0x20);
200			goto again;
201		}
202		return NULL;
203	}
204
205	DEBUG(4,(" session request ok\n"));
206
207	if (!cli_negprot(c)) {
208		DEBUG(0,("protocol negotiation failed\n"));
209		cli_shutdown(c);
210		return NULL;
211	}
212
213	if (!got_pass) {
214		char *pass = getpass("Password: ");
215		if (pass) {
216			fstrcpy(password[0], pass);
217			fstrcpy(password[1], pass);
218		}
219	}
220
221	if (got_pass == 1) {
222		fstrcpy(password[1], password[0]);
223		fstrcpy(username[1], username[0]);
224	}
225
226	if (!NT_STATUS_IS_OK(cli_session_setup(c, username[snum],
227					       password[snum],
228					       strlen(password[snum]),
229					       password[snum],
230					       strlen(password[snum]),
231					       lp_workgroup()))) {
232		DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
233		return NULL;
234	}
235
236	/*
237	 * These next two lines are needed to emulate
238	 * old client behaviour for people who have
239	 * scripts based on client output.
240	 * QUESTION ? Do we want to have a 'client compatibility
241	 * mode to turn these on/off ? JRA.
242	 */
243
244	if (*c->server_domain || *c->server_os || *c->server_type)
245		DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
246			c->server_domain,c->server_os,c->server_type));
247
248	DEBUG(4,(" session setup ok\n"));
249
250	if (!cli_send_tconX(c, share, "?????",
251			    password[snum], strlen(password[snum])+1)) {
252		DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
253		cli_shutdown(c);
254		return NULL;
255	}
256
257	DEBUG(4,(" tconx ok\n"));
258
259	c->use_oplocks = use_oplocks;
260
261	return c;
262}
263
264
265static void reconnect(struct cli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES],
266		      char *share[NSERVERS])
267{
268	int server, conn, f;
269
270	for (server=0;server<NSERVERS;server++)
271	for (conn=0;conn<NCONNECTIONS;conn++) {
272		if (cli[server][conn]) {
273			for (f=0;f<NFILES;f++) {
274				if (fnum[server][conn][f] != -1) {
275					cli_close(cli[server][conn], fnum[server][conn][f]);
276					fnum[server][conn][f] = -1;
277				}
278			}
279			cli_ulogoff(cli[server][conn]);
280			cli_shutdown(cli[server][conn]);
281		}
282		cli[server][conn] = connect_one(share[server], server);
283		if (!cli[server][conn]) {
284			DEBUG(0,("Failed to connect to %s\n", share[server]));
285			exit(1);
286		}
287	}
288}
289
290
291
292static BOOL test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
293		     int fnum[NSERVERS][NCONNECTIONS][NFILES],
294		     struct record *rec)
295{
296	unsigned conn = rec->conn;
297	unsigned f = rec->f;
298	SMB_BIG_UINT start = rec->start;
299	SMB_BIG_UINT len = rec->len;
300	enum brl_type op = rec->lock_type;
301	int server;
302	BOOL ret[NSERVERS];
303	NTSTATUS status[NSERVERS];
304
305	switch (rec->lock_op) {
306	case OP_LOCK:
307		/* set a lock */
308		for (server=0;server<NSERVERS;server++) {
309			ret[server] = cli_lock64(cli[server][conn],
310						 fnum[server][conn][f],
311						 start, len, LOCK_TIMEOUT, op);
312			status[server] = cli_nt_error(cli[server][conn]);
313			if (!exact_error_codes &&
314			    NT_STATUS_EQUAL(status[server],
315					    NT_STATUS_FILE_LOCK_CONFLICT)) {
316				status[server] = NT_STATUS_LOCK_NOT_GRANTED;
317			}
318		}
319		if (showall || !NT_STATUS_EQUAL(status[0],status[1])) {
320			printf("lock   conn=%u f=%u range=%.0f(%.0f) op=%s -> %s:%s\n",
321			       conn, f,
322			       (double)start, (double)len,
323			       op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
324			       nt_errstr(status[0]), nt_errstr(status[1]));
325		}
326		if (showall || !NT_STATUS_EQUAL(status[0],status[1])) show_locks();
327		if (!NT_STATUS_EQUAL(status[0],status[1])) return False;
328		break;
329
330	case OP_UNLOCK:
331		/* unset a lock */
332		for (server=0;server<NSERVERS;server++) {
333			ret[server] = cli_unlock64(cli[server][conn],
334						   fnum[server][conn][f],
335						   start, len);
336			status[server] = cli_nt_error(cli[server][conn]);
337		}
338		if (showall ||
339		    (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1]))) {
340			printf("unlock conn=%u f=%u range=%.0f(%.0f)       -> %s:%s\n",
341			       conn, f,
342			       (double)start, (double)len,
343			       nt_errstr(status[0]), nt_errstr(status[1]));
344		}
345		if (showall || !NT_STATUS_EQUAL(status[0],status[1])) show_locks();
346		if (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1]))
347			return False;
348		break;
349
350	case OP_REOPEN:
351		/* reopen the file */
352		for (server=0;server<NSERVERS;server++) {
353			cli_close(cli[server][conn], fnum[server][conn][f]);
354			fnum[server][conn][f] = -1;
355		}
356		for (server=0;server<NSERVERS;server++) {
357			fnum[server][conn][f] = cli_open(cli[server][conn], FILENAME,
358							 O_RDWR|O_CREAT,
359							 DENY_NONE);
360			if (fnum[server][conn][f] == -1) {
361				printf("failed to reopen on share%d\n", server);
362				return False;
363			}
364		}
365		if (showall) {
366			printf("reopen conn=%u f=%u\n",
367			       conn, f);
368			show_locks();
369		}
370		break;
371	}
372
373	return True;
374}
375
376static void close_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
377			int fnum[NSERVERS][NCONNECTIONS][NFILES])
378{
379	int server, conn, f;
380
381	for (server=0;server<NSERVERS;server++)
382	for (conn=0;conn<NCONNECTIONS;conn++)
383	for (f=0;f<NFILES;f++) {
384		if (fnum[server][conn][f] != -1) {
385			cli_close(cli[server][conn], fnum[server][conn][f]);
386			fnum[server][conn][f] = -1;
387		}
388	}
389	for (server=0;server<NSERVERS;server++) {
390		cli_unlink(cli[server][0], FILENAME);
391	}
392}
393
394static void open_files(struct cli_state *cli[NSERVERS][NCONNECTIONS],
395		       int fnum[NSERVERS][NCONNECTIONS][NFILES])
396{
397	int server, conn, f;
398
399	for (server=0;server<NSERVERS;server++)
400	for (conn=0;conn<NCONNECTIONS;conn++)
401	for (f=0;f<NFILES;f++) {
402		fnum[server][conn][f] = cli_open(cli[server][conn], FILENAME,
403						 O_RDWR|O_CREAT,
404						 DENY_NONE);
405		if (fnum[server][conn][f] == -1) {
406			fprintf(stderr,"Failed to open fnum[%u][%u][%u]\n",
407				server, conn, f);
408			exit(1);
409		}
410	}
411}
412
413
414static int retest(struct cli_state *cli[NSERVERS][NCONNECTIONS],
415		   int fnum[NSERVERS][NCONNECTIONS][NFILES],
416		   int n)
417{
418	int i;
419	printf("testing %u ...\n", n);
420	for (i=0; i<n; i++) {
421		if (i && i % 100 == 0) {
422			printf("%u\n", i);
423		}
424
425		if (recorded[i].needed &&
426		    !test_one(cli, fnum, &recorded[i])) return i;
427	}
428	return n;
429}
430
431
432/* each server has two connections open to it. Each connection has two file
433   descriptors open on the file - 8 file descriptors in total
434
435   we then do random locking ops in tamdem on the 4 fnums from each
436   server and ensure that the results match
437 */
438static void test_locks(char *share[NSERVERS])
439{
440	struct cli_state *cli[NSERVERS][NCONNECTIONS];
441	int fnum[NSERVERS][NCONNECTIONS][NFILES];
442	int n, i, n1, skip, r1, r2;
443
444	ZERO_STRUCT(fnum);
445	ZERO_STRUCT(cli);
446
447	recorded = SMB_MALLOC_ARRAY(struct record, numops);
448
449	for (n=0; n<numops; n++) {
450#if PRESETS
451		if (n < sizeof(preset) / sizeof(preset[0])) {
452			recorded[n] = preset[n];
453		} else {
454#endif
455			recorded[n].conn = random() % NCONNECTIONS;
456			recorded[n].f = random() % NFILES;
457			recorded[n].start = lock_base + ((unsigned)random() % (lock_range-1));
458			recorded[n].len =  min_length +
459				random() % (lock_range-(recorded[n].start-lock_base));
460			recorded[n].start *= RANGE_MULTIPLE;
461			recorded[n].len *= RANGE_MULTIPLE;
462			r1 = random() % 100;
463			r2 = random() % 100;
464			if (r1 < READ_PCT) {
465				recorded[n].lock_type = READ_LOCK;
466			} else {
467				recorded[n].lock_type = WRITE_LOCK;
468			}
469			if (r2 < LOCK_PCT) {
470				recorded[n].lock_op = OP_LOCK;
471			} else if (r2 < UNLOCK_PCT) {
472				recorded[n].lock_op = OP_UNLOCK;
473			} else {
474				recorded[n].lock_op = OP_REOPEN;
475			}
476			recorded[n].needed = True;
477			if (!zero_zero && recorded[n].start==0 && recorded[n].len==0) {
478				recorded[n].len = 1;
479			}
480#if PRESETS
481		}
482#endif
483	}
484
485	reconnect(cli, fnum, share);
486	open_files(cli, fnum);
487	n = retest(cli, fnum, numops);
488
489	if (n == numops || !analyze) return;
490	n++;
491
492	skip = n/2;
493
494	while (1) {
495		n1 = n;
496
497		close_files(cli, fnum);
498		reconnect(cli, fnum, share);
499		open_files(cli, fnum);
500
501		for (i=0;i<n-skip;i+=skip) {
502			int m, j;
503			printf("excluding %d-%d\n", i, i+skip-1);
504			for (j=i;j<i+skip;j++) {
505				recorded[j].needed = False;
506			}
507
508			close_files(cli, fnum);
509			open_files(cli, fnum);
510
511			m = retest(cli, fnum, n);
512			if (m == n) {
513				for (j=i;j<i+skip;j++) {
514					recorded[j].needed = True;
515				}
516			} else {
517				if (i+(skip-1) < m) {
518					memmove(&recorded[i], &recorded[i+skip],
519						(m-(i+skip-1))*sizeof(recorded[0]));
520				}
521				n = m-(skip-1);
522				i--;
523			}
524		}
525
526		if (skip > 1) {
527			skip = skip/2;
528			printf("skip=%d\n", skip);
529			continue;
530		}
531
532		if (n1 == n) break;
533	}
534
535	close_files(cli, fnum);
536	reconnect(cli, fnum, share);
537	open_files(cli, fnum);
538	showall = True;
539	n1 = retest(cli, fnum, n);
540	if (n1 != n-1) {
541		printf("ERROR - inconsistent result (%u %u)\n", n1, n);
542	}
543	close_files(cli, fnum);
544
545	for (i=0;i<n;i++) {
546		printf("{%s, %s, conn = %u, file = %u, start = %.0f, len = %.0f, %u},\n",
547		       lock_op_name(recorded[i].lock_op),
548		       lock_op_type(recorded[i].lock_type),
549		       recorded[i].conn,
550		       recorded[i].f,
551		       (double)recorded[i].start,
552		       (double)recorded[i].len,
553		       recorded[i].needed);
554	}
555}
556
557
558
559static void usage(void)
560{
561	printf(
562"Usage:\n\
563  locktest //server1/share1 //server2/share2 [options..]\n\
564  options:\n\
565        -U user%%pass        (may be specified twice)\n\
566        -k               use kerberos\n\
567        -s seed\n\
568        -o numops\n\
569        -u          hide unlock fails\n\
570        -a          (show all ops)\n\
571        -A          analyse for minimal ops\n\
572        -O          use oplocks\n\
573        -E          enable exact error code checking\n\
574        -Z          enable the zero/zero lock\n\
575        -R range    set lock range\n\
576        -B base     set lock base\n\
577        -M min      set min lock length\n\
578");
579}
580
581/****************************************************************************
582  main program
583****************************************************************************/
584 int main(int argc,char *argv[])
585{
586	char *share[NSERVERS];
587	int opt;
588	char *p;
589	int seed, server;
590
591	setlinebuf(stdout);
592
593	load_case_tables();
594
595	dbf = x_stderr;
596
597	if (argc < 3 || argv[1][0] == '-') {
598		usage();
599		exit(1);
600	}
601
602	setup_logging(argv[0],True);
603
604	for (server=0;server<NSERVERS;server++) {
605		share[server] = argv[1+server];
606		all_string_sub(share[server],"/","\\",0);
607	}
608
609	argc -= NSERVERS;
610	argv += NSERVERS;
611
612	lp_load(dyn_CONFIGFILE,True,False,False,True);
613	load_interfaces();
614
615	if (getenv("USER")) {
616		fstrcpy(username[0],getenv("USER"));
617		fstrcpy(username[1],getenv("USER"));
618	}
619
620	seed = time(NULL);
621
622	while ((opt = getopt(argc, argv, "U:s:ho:aAW:OkR:B:M:EZ")) != EOF) {
623		switch (opt) {
624		case 'k':
625#ifdef HAVE_KRB5
626			use_kerberos = True;
627#else
628			d_printf("No kerberos support compiled in\n");
629			exit(1);
630#endif
631			break;
632		case 'U':
633			got_user = 1;
634			if (got_pass == 2) {
635				d_printf("Max of 2 usernames\n");
636				exit(1);
637			}
638			fstrcpy(username[got_pass],optarg);
639			p = strchr_m(username[got_pass],'%');
640			if (p) {
641				*p = 0;
642				fstrcpy(password[got_pass], p+1);
643				got_pass++;
644			}
645			break;
646		case 'R':
647			lock_range = strtol(optarg, NULL, 0);
648			break;
649		case 'B':
650			lock_base = strtol(optarg, NULL, 0);
651			break;
652		case 'M':
653			min_length = strtol(optarg, NULL, 0);
654			break;
655		case 's':
656			seed = atoi(optarg);
657			break;
658		case 'u':
659			hide_unlock_fails = True;
660			break;
661		case 'o':
662			numops = atoi(optarg);
663			break;
664		case 'O':
665			use_oplocks = True;
666			break;
667		case 'a':
668			showall = True;
669			break;
670		case 'A':
671			analyze = True;
672			break;
673		case 'Z':
674			zero_zero = True;
675			break;
676		case 'E':
677			exact_error_codes = True;
678			break;
679		case 'h':
680			usage();
681			exit(1);
682		default:
683			printf("Unknown option %c (%d)\n", (char)opt, opt);
684			exit(1);
685		}
686	}
687
688	if(use_kerberos && !got_user) got_pass = True;
689
690	argc -= optind;
691	argv += optind;
692
693	DEBUG(0,("seed=%u\n", seed));
694	srandom(seed);
695
696	test_locks(share);
697
698	return(0);
699}
700