1/* *************************************************
2 * *********** README ******************************
3 * *************************************************
4 *
5 * COMPILE : make
6 * RUN : ./locktests -n <number of concurent process> -f <test file> [-P]
7 *
8 * GOAL : This test tries to stress the fcntl locking functions.  A
9 * master process sets a lock on a file region (this is called "byte
10 * range locking").  Some slave processes try to perform operations on
11 * this region, such as read, write, set a new lock ... The expected
12 * results of these operations are known.  If the operation result is
13 * the same as the expected one, the test suceeds, else it fails.
14 *
15 *
16 *
17 * Slaves are concurent processes or thread.
18 * -n <num>  : Number of threads to use (mandatory).
19 * -f <file> : Run the test on given test file defined by the -f option (mandatory).
20 * -c <num>  : Number of clients to connect before starting the tests.
21 *
22 * HISTORY : This program was written to stress NFSv4 locks.
23 * EXAMPLE : ./locktests -n 50 -f /file/system/to/test
24 *
25 *
26 * Vincent ROQUETA 2005 - vincent.roqueta@ext.bull.net
27 * BULL S.A.
28 */
29
30#include "locktests.h"
31
32int MAXLEN = 64;
33int MAXTEST = 10;
34extern int maxClients;
35extern int fdServer;
36
37char message[M_SIZE];
38int slaveReader;
39int masterReader;
40int slaveWriter;
41
42/* Which lock will be applied by the master process on test startup */
43int LIST_LOCKS[] = { READLOCK, WRITELOCK,
44	READLOCK, WRITELOCK,
45	READLOCK, WRITELOCK,
46	READLOCK, WRITELOCK,
47	BYTELOCK_READ, BYTELOCK_WRITE
48};
49
50/* The operations the slave processes will try to perform */
51int LIST_TESTS[] = { WRONLY, WRONLY,
52	RDONLY, RDONLY,
53	READLOCK, WRITELOCK,
54	WRITELOCK, READLOCK,
55	BYTELOCK_READ, BYTELOCK_WRITE
56};
57
58/* List of test names */
59char *LIST_NAMES_TESTS[] = { "WRITE ON A READ  LOCK",
60	"WRITE ON A WRITE LOCK",
61	"READ  ON A READ  LOCK",
62	"READ  ON A WRITE LOCK",
63	"SET A READ  LOCK ON A READ  LOCK",
64	"SET A WRITE LOCK ON A WRITE LOCK",
65	"SET A WRITE LOCK ON A READ  LOCK",
66	"SET A READ  LOCK ON A WRITE LOCK",
67	"READ LOCK THE WHOLE FILE BYTE BY BYTE",
68	"WRITE LOCK THE WHOLE FILE BYTE BY BYTE"
69};
70
71/* List of expected test results, when slaves are processes */
72int LIST_RESULTS_PROCESS[] = { SUCCES, SUCCES,
73	SUCCES, SUCCES,
74	SUCCES, ECHEC,
75	ECHEC, ECHEC,
76	SUCCES, SUCCES
77};
78
79/* List of expected test results, when slaves are threads */
80int LIST_RESULTS_THREADS[] = { SUCCES, SUCCES,
81	SUCCES, SUCCES,
82	SUCCES, SUCCES,
83	SUCCES, SUCCES,
84	ECHEC, ECHEC
85};
86
87int *LIST_RESULTS = NULL;
88char *eType = NULL;
89
90int TOTAL_RESULT_OK[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
91
92void *slave(void *data);
93int (*finish) (int a);
94
95int finishProcess(int a)
96{
97	exit(a);
98}
99
100int (*load) (void);
101
102struct dataPub dp;
103
104/* Functions to access tests/tests names/tests results*/
105int testSuiv(int n)
106{
107	return LIST_TESTS[n];
108}
109
110int resAttSuiv(int n)
111{
112	return LIST_RESULTS[n];
113}
114
115char *nomTestSuiv(int n)
116{
117	return LIST_NAMES_TESTS[n];
118}
119
120int lockSuiv(int n)
121{
122	return LIST_LOCKS[n];
123}
124
125/* Verify the test result is the expected one */
126int matchResult(int r, int n)
127{
128
129	P("r=%d\n", r);
130	if (r == LIST_RESULTS[n])
131		return 1;
132	else
133		return 0;
134}
135
136/* Increments the number of process which have successfully passed the test */
137void counter(int r, int n)
138{
139	TOTAL_RESULT_OK[n] += matchResult(r, n);
140}
141
142/* Special case for test 'lock file byte byte by byte'.
143 * We ensure each byte is correctly locked.
144 */
145void validationResults(int n)
146{
147	int i, u, l, fsize;
148	struct flock request;
149
150	fsize = dp.nclnt * (maxClients + 1);
151	TOTAL_RESULT_OK[n] = 0;
152	l = FALSE;
153	u = TRUE;
154
155	/* If the expected operation result is a success, we will have to increase the number of correct results */
156	if (LIST_RESULTS[n]) {
157		l = TRUE;
158		u = FALSE;
159	}
160
161	for (i = 0; i < fsize; i++) {
162		request.l_type = F_WRLCK;
163		request.l_whence = SEEK_SET;
164		request.l_start = i;
165		request.l_len = 1;
166		fcntl(dp.fd, F_GETLK, &request);
167		/* Ensure the lock is correctly set */
168		if (request.l_type != F_UNLCK)
169			TOTAL_RESULT_OK[n] += l;
170		else
171			TOTAL_RESULT_OK[n] += u;
172	}
173}
174
175int initTest(void)
176{
177
178	P("Master opens %s\n", dp.fname);
179	dp.fd = open(dp.fname, OPENFLAGS, MANDMODES);
180	if (dp.fd < 0) {
181		perror("lock test : can't open test file :");
182		finish(1);
183	}
184	P("fd=%d\n", dp.fd);
185	return 0;
186}
187
188struct dataChild *initClientFork(int i)
189{
190	struct dataPriv *dpr;
191	struct dataChild *df;
192
193	/* Initialize private data fields */
194	dpr = malloc(sizeof(struct dataPriv));
195	df = malloc(sizeof(struct dataChild));
196	dpr->whoami = i;
197	df->dp = &dp;
198	df->dpr = dpr;
199	/* Initialize master to client pipe */
200	dp.lclnt[i] = malloc(sizeof(int) * 2);
201	if (pipe(dp.lclnt[i]) < 0) {
202		perror("Impossible to create pipe\n");
203		exit(1);
204	}
205	P("Initialization %d\n", i);
206	write(0, ".", 1);
207	return df;
208}
209
210int initialize(int clnt)
211{
212
213	/* Initialize private data fields */
214	printf("Init\n");
215	dp.nclnt = clnt;
216	dp.lclnt = malloc(sizeof(int *) * clnt);
217	dp.lthreads = malloc(sizeof(pthread_t) * clnt);
218
219	/* Initialize client to master pipe */
220	if (pipe(dp.master) < 0) {
221		perror("Master pipe creation error\n");
222		exit(1);
223	}
224	printf("%s initialization\n", eType);
225	load();
226	initTest();
227
228	return 0;
229}
230
231void cleanClient(struct dataChild *df)
232{
233	int i;
234	i = df->dpr->whoami;
235	free(dp.lclnt[i]);
236	free(df->dpr);
237	free(df);
238}
239
240void clean(void)
241{
242	free(dp.lthreads);
243	free(dp.lclnt);
244}
245
246int loadProcess(void)
247{
248	int i;
249	struct dataChild *df;
250	for (i = 0; i < dp.nclnt; i++) {
251		df = initClientFork(i);
252		if (!fork()) {
253			P("Running slave num: %d\n", df->dpr->whoami);
254			write(0, ".", 1);
255			slave((void *)df);
256			cleanClient(df);
257			exit(0);
258		}
259	}
260	return 0;
261}
262
263void lockWholeFile(struct flock *request)
264{
265	request->l_whence = SEEK_SET;
266	request->l_start = 0;
267	/* Lock the whole file */
268	request->l_len = 0;
269}
270
271void selectTest(int n, struct s_test *test)
272{
273
274	test->test = testSuiv(n);
275	test->resAtt = resAttSuiv(n);
276	test->nom = nomTestSuiv(n);
277	test->type = lockSuiv(n);
278}
279
280/* Final test report */
281int report(int clnt)
282{
283	int rc = 0;
284	int i;
285	int totalClients;
286	totalClients = clnt * (maxClients + 1);
287	printf
288	    ("\n%s number : %d - Remote clients: %d local client 1 - Total client %d - Total concurent tests: %d\n",
289	     eType, clnt, maxClients, maxClients + 1, totalClients);
290	printf("%s number running test successfully :\n", eType);
291	for (i = 0; i < MAXTEST; i++) {
292		if (TOTAL_RESULT_OK[i] != totalClients)
293			rc = 1;
294
295		printf("%d %s of %d successfully ran test : %s\n",
296		       TOTAL_RESULT_OK[i], eType, totalClients,
297		       LIST_NAMES_TESTS[i]);
298    }
299    return rc;
300}
301
302int serverSendLocal(void)
303{
304	int i;
305	/* Synchronize slave processes */
306	/* Configure slaves for test */
307
308	for (i = 0; i < dp.nclnt; i++)
309		write(dp.lclnt[i][1], message, M_SIZE);
310	return 0;
311
312}
313
314void serverSendNet(void)
315{
316	writeToAllClients(message);
317}
318
319int serverReceiveNet(void)
320{
321	int i, c;
322	for (c = 0; c < maxClients; c++) {
323		for (i = 0; i < dp.nclnt; i++) {
324			serverReceiveClient(c);
325		}
326	}
327	return 0;
328}
329
330int serverReceiveLocal(void)
331{
332	int i;
333	for (i = 0; i < dp.nclnt; i++)
334		read(masterReader, message, M_SIZE);
335	return 0;
336}
337
338int clientReceiveLocal(void)
339{
340	read(slaveReader, message, M_SIZE);
341	return 0;
342}
343
344int clientSend(void)
345{
346	write(slaveWriter, message, M_SIZE);
347	return 0;
348}
349
350int serverSend(void)
351{
352	serverSendNet();
353	serverSendLocal();
354	return 0;
355}
356
357int serverReceive(void)
358{
359	serverReceiveNet();
360	serverReceiveLocal();
361	return 0;
362}
363
364/* binary structure <-> ASCII functions used to ensure data will be correctly used over
365 * the network, especially when multiples clients do not use the same hardware architecture.
366 */
367int serializeTLock(struct s_test *tLock)
368{
369	memset(message, 0, M_SIZE);
370	sprintf(message, "T:%d:%d:%d::", tLock->test, tLock->type,
371		tLock->resAtt);
372	return 0;
373}
374
375void unSerializeTLock(struct s_test *tLock)
376{
377	sscanf(message, "T:%d:%d:%d::", &(tLock->test), &(tLock->type),
378	       &(tLock->resAtt));
379	memset(message, 0, M_SIZE);
380
381}
382
383void serializeFLock(struct flock *request)
384{
385	int len, pid, start;
386	memset(message, 0, M_SIZE);
387	len = (int)request->l_len;
388	pid = (int)request->l_pid;
389	start = (int)request->l_start;
390	/* Beware to length of integer conversions ... */
391	sprintf(message, "L:%hd:%hd:%d:%d:%d::",
392		request->l_type, request->l_whence, start, len, pid);
393}
394
395void serializeResult(int result)
396{
397	memset(message, 0, M_SIZE);
398	sprintf(message, "R:%d::", result);
399
400}
401
402void unSerializeResult(int *result)
403{
404	sscanf(message, "R:%d::", result);
405}
406
407void unSerializeFLock(struct flock *request)
408{
409	int len, pid, start;
410	sscanf(message, "L:%hd:%hd:%d:%d:%d::",
411	       &(request->l_type), &(request->l_whence), &start, &len, &pid);
412	request->l_start = (off_t) start;
413	request->l_len = (off_t) len;
414	request->l_pid = (pid_t) pid;
415}
416
417int serverSendLockClient(struct flock *request, int client)
418{
419	serializeFLock(request);
420	return serverSendClient(client);
421}
422
423int serverSendLockLocal(struct flock *request, int slave)
424{
425	serializeFLock(request);
426	return write(dp.lclnt[slave][1], message, M_SIZE);
427}
428
429int getLockSection(struct flock *request)
430{
431	memset(message, 0, M_SIZE);
432	clientReceiveLocal();
433	unSerializeFLock(request);
434	return 0;
435}
436
437int sendLockTest(struct s_test *tLock)
438{
439	serializeTLock(tLock);
440	serverSend();
441	return 0;
442}
443
444int getLockTest(struct s_test *tLock)
445{
446	clientReceiveLocal();
447	unSerializeTLock(tLock);
448	return 0;
449}
450
451int sendResult(int result)
452{
453	serializeResult(result);
454	clientSend();
455	return 0;
456}
457
458int getResults(int ntest)
459{
460	int i, c;
461	int result = 0;
462	/* Add remote test results */
463	for (c = 0; c < maxClients; c++) {
464		for (i = 0; i < dp.nclnt; i++) {
465			serverReceiveClient(c);
466			unSerializeResult(&result);
467			counter(result, ntest);
468
469		}
470	}
471	/* Add local test results */
472	for (i = 0; i < dp.nclnt; i++) {
473		read(masterReader, message, M_SIZE);
474		unSerializeResult(&result);
475		counter(result, ntest);
476	}
477
478	return 0;
479}
480
481#ifdef DEBUG
482#define P(a,b)  memset(dbg,0,16);sprintf(dbg,a,b);write(0,dbg,16);
483#endif
484
485/* In the case of a network use, the master of the client application si only
486 * a 'repeater' of information. It resends server-master instructions to its own slaves.
487 */
488void masterClient(void)
489{
490	fd_set fdread;
491	struct timeval tv;
492	int n, i, r, m, start;
493#ifdef DEBUG
494	char dbg[16];
495#endif
496	struct flock lock;
497	int t;
498
499	masterReader = dp.master[0];
500	FD_ZERO(&fdread);
501	tv.tv_sec = 50;
502	tv.tv_usec = 0;
503	n = fdServer > masterReader ? fdServer : masterReader;
504	printf("Master Client - fdServer=%d\n", fdServer);
505	while (1) {
506		/* Add slave and server pipe file descriptors */
507		FD_ZERO(&fdread);
508		FD_SET(fdServer, &fdread);
509		FD_SET(masterReader, &fdread);
510		r = select(n + 1, &fdread, NULL, NULL, &tv);
511		if (r < 0) {
512			perror("select:\n");
513			continue;
514		}
515		if (r == 0) {
516			exit(0);
517		}
518
519		if (FD_ISSET(fdServer, &fdread)) {
520			/* We just have received information from the server.
521			 * We repeat it to slaves.
522			 */
523			i = readFromServer(message);
524			t = message[0];
525			switch (t) {
526			case 'L':
527				/* Lock instruction. We need to send a different section to lock to each process */
528				unSerializeFLock(&lock);
529				start = lock.l_start;
530				for (i = 0; i < dp.nclnt; i++) {
531					lock.l_start = start + i;
532					serializeFLock(&lock);
533					write(dp.lclnt[i][1], message, M_SIZE);
534				}
535				printf("\n");
536				continue;
537			case 'T':
538				/* Test instruction. Ensure server is not sending the END(ish) instruction to end tests */
539				/* To be rewritten asap */
540				m = atoi(&(message[2]));
541				if (m == END)
542					break;
543				if (m == CLEAN)
544					printf("\n");
545
546				serverSendLocal();
547				continue;
548			}
549			break;
550		} else {
551			/* Else, we read information from slaves and repeat them to the server */
552			for (i = 0; i < dp.nclnt; i++) {
553				r = read(masterReader, message, M_SIZE);
554				r = write(fdServer, message, M_SIZE);
555				if (r < 0)
556					perror("write : ");
557
558			}
559			continue;
560		}
561	}
562
563	/* Receive the END(ish) instruction */
564
565	/* Repeat it to the slaves */
566	printf("Exitting...\n");
567	serverSendLocal();
568
569	/* Ok, we can quit */
570	printf("Bye :)\n");
571
572}
573
574int master(void)
575{
576	int i, n, bl;
577	int clnt;
578	char tmp[MAXLEN], *buf;
579#ifdef DEBUG
580	char dbg[16];
581#endif
582	struct flock request;
583	struct s_test tLock;
584	enum state_t state;
585	int offset;
586	/* A test sentence written in the file */
587	char phraseTest[] =
588	    "Ceci est une phrase test ecrite par le maitre dans le fichier";
589	bl = -1;
590	clnt = dp.nclnt;
591	masterReader = dp.master[0];
592	state = SELECT;
593	/* Start with the first test ;) */
594	n = 0;
595	printf("\n--------------------------------------\n");
596	while (1) {
597		switch (state) {
598		case SELECT:
599			/* Select the test to perform   */
600			printf("\n");
601			E("Master: SELECT");
602			selectTest(n, &tLock);
603			state = tLock.type;
604			bl = 0;
605			if (n < MAXTEST) {
606				memset(tmp, 0, MAXLEN);
607				sprintf(tmp, "TEST : TRY TO %s:",
608					LIST_NAMES_TESTS[n]);
609				write(0, tmp, strlen(tmp));
610			} else
611				state = END;
612			P("state=%d\n", state);
613			n += 1;
614			continue;
615
616		case RDONLY:
617		case WRONLY:
618
619		case READLOCK:
620			P("Read lock :%d\n", state);
621			request.l_type = F_RDLCK;
622			state = LOCK;
623			continue;
624
625		case WRITELOCK:
626			P("Write lock :%d\n", state);
627			request.l_type = F_WRLCK;
628			state = LOCK;
629			continue;
630
631		case LOCK:
632			/* Apply the wanted lock */
633			E("Master: LOCK");
634			write(dp.fd, phraseTest, strlen(phraseTest));
635			lockWholeFile(&request);
636			if (fcntl(dp.fd, F_SETLK, &request) < 0) {
637				perror("Master: can't set lock\n");
638				perror("Echec\n");
639				exit(0);
640			}
641			E("Master");
642			state = SYNC;
643			continue;
644
645		case BYTELOCK_READ:
646			bl = 1;
647			request.l_type = F_RDLCK;
648			state = SYNC;
649			continue;
650
651		case BYTELOCK_WRITE:
652			bl = 1;
653			request.l_type = F_WRLCK;
654			state = SYNC;
655			continue;
656
657		case BYTELOCK:
658			/* The main idea is to lock all the bytes in a file. Each slave process locks one byte.
659			 *
660			 * We need :
661			 * - To create a file of a length equal to the total number of slave processes
662			 * - send the exact section to lock to each slave
663			 * - ensure locks have been correctly set
664			 */
665
666			/* Create a string to record in the test file. Length is exactly the number of sub process */
667			P("Master: BYTELOCK: %d\n", state);
668			buf = malloc(clnt * (maxClients + 1));
669			memset(buf, '*', clnt);
670			write(dp.fd, buf, clnt);
671			free(buf);
672
673			/* Each slave process re-writes its own field to lock */
674			request.l_whence = SEEK_SET;
675			request.l_start = 0;
676			request.l_len = 1;
677
678			/* Start to send sections to lock to remote process (network clients) */
679			for (i = 0; i < maxClients; i++) {
680				/* Set the correct byte to lock */
681				offset = (i + 1) * clnt;
682				request.l_start = (off_t) offset;
683				serverSendLockClient(&request, i);
684			}
685
686			/* Now send sections to local processes */
687			for (i = 0; i < clnt; i++) {
688				request.l_start = i;
689				serverSendLockLocal(&request, i);
690			}
691			state = RESULT;
692			continue;
693
694		case SYNC:
695			sendLockTest(&tLock);
696			if (bl) {
697				state = BYTELOCK;
698				continue;
699			}
700
701			if (n < MAXTEST + 1)
702				state = RESULT;
703			else
704				state = END;
705			continue;
706
707		case RESULT:
708			/* Read results by one */
709			getResults(n - 1);
710			if (bl)
711				validationResults(n - 1);
712			state = CLEAN;
713			continue;
714
715		case CLEAN:
716			/* Ask the clients to stop testing ... */
717			tLock.test = CLEAN;
718			serializeTLock(&tLock);
719			serverSend();
720			/* ... and wait for an ack before closing */
721			serverReceive();
722			/* Ignore message content : that is only an ack */
723
724			/* close and open file */
725			close(dp.fd);
726			initTest();
727			state = SELECT;
728			continue;
729		case END:
730			tLock.test = END;
731			serializeTLock(&tLock);
732			serverSend();
733			sleep(2);
734			break;
735
736			printf("(end)\n");
737			exit(0);
738
739		}
740		break;
741	}
742
743	return report(clnt);
744}
745
746/* Slave process/thread */
747
748void *slave(void *data)
749{
750	struct dataChild *df;
751	int i, a, result, ftest;
752	struct s_test tLock;
753	struct flock request;
754	char tmp[16];
755#ifdef DEBUG
756	char dbg[16];
757#endif
758	char *phraseTest = "L'ecriture a reussi";
759	int len;
760	enum state_t state;
761
762	result = -1;
763	ftest = -1;
764	len = strlen(phraseTest);
765	df = (struct dataChild *)data;
766	i = df->dpr->whoami;
767	P("Slave n=%d\n", i);
768	slaveReader = dp.lclnt[i][0];
769	slaveWriter = dp.master[1];
770	state = SYNC;
771	errno = 0;
772	memset(tmp, 0, 16);
773	while (1) {
774		switch (state) {
775		case SELECT:
776		case SYNC:
777			getLockTest(&tLock);
778			state = tLock.test;
779			P("Slave State=%d\n", state);
780
781			continue;
782		case RDONLY:
783			/* Try to read a file */
784			P("TEST READ ONLY %d\n", RDONLY);
785			if ((ftest = open(dp.fname, O_RDONLY | O_NONBLOCK)) < 0) {
786				result = ECHEC;
787				state = RESULT;
788				if (dp.verbose)
789					perror("Open:");
790				continue;
791			}
792			P("fd=%d\n", ftest);
793			a = read(ftest, tmp, 16);
794			if (a < 16)
795				result = ECHEC;
796			else
797				result = SUCCES;
798			state = RESULT;
799			continue;
800
801		case WRONLY:
802			/* Try to write a file */
803			P("TEST WRITE ONLY %d\n", WRONLY);
804			if ((ftest = open(dp.fname, O_WRONLY | O_NONBLOCK)) < 0) {
805				result = ECHEC;
806				state = RESULT;
807				if (dp.verbose)
808					perror("Open read only:");
809				continue;
810			}
811			P("fd=%d\n", ftest);
812			if (write(ftest, phraseTest, len) < len)
813				result = ECHEC;
814			else
815				result = SUCCES;
816			state = RESULT;
817			continue;
818
819		case LOCK:
820
821		case READLOCK:
822			/* Try to read a read-locked section */
823			P("READ LOCK %d\n", F_RDLCK);
824			if ((ftest = open(dp.fname, O_RDONLY | O_NONBLOCK)) < 0) {
825				result = ECHEC;
826				state = RESULT;
827				if (dp.verbose)
828					perror("Open read-write:");
829				continue;
830			}
831
832			P("fd=%d\n", ftest);
833			/* Lock the whole file */
834			request.l_type = F_RDLCK;
835			request.l_whence = SEEK_SET;
836			request.l_start = 0;
837			request.l_len = 0;
838
839			if (fcntl(ftest, F_SETLK, &request) < 0) {
840				if (dp.verbose || errno != EAGAIN)
841					perror("RDONLY: fcntl");
842				result = ECHEC;
843			} else
844				result = SUCCES;
845			state = RESULT;
846			continue;
847
848		case WRITELOCK:
849			/* Try to write a file */
850			P("WRITE LOCK %d\n", F_WRLCK);
851			if ((ftest = open(dp.fname, O_WRONLY | O_NONBLOCK)) < 0) {
852				result = ECHEC;
853				state = RESULT;
854				if (dp.verbose)
855					perror("\nOpen:");
856				continue;
857			}
858			/* Lock the whole file */
859			P("fd=%d\n", ftest);
860			request.l_type = F_WRLCK;
861			request.l_whence = SEEK_SET;
862			request.l_start = 0;
863			request.l_len = 0;
864
865			if (fcntl(ftest, F_SETLK, &request) < 0) {
866				if (dp.verbose || errno != EAGAIN)
867					perror("\nWRONLY: fcntl");
868				result = ECHEC;
869			} else
870				result = SUCCES;
871			state = RESULT;
872			continue;
873
874		case BYTELOCK_READ:
875			P("BYTE LOCK READ: %d\n", state);
876			state = BYTELOCK;
877			continue;
878
879		case BYTELOCK_WRITE:
880			P("BYTE LOCK WRITE: %d\n", state);
881			state = BYTELOCK;
882			continue;
883
884		case BYTELOCK:
885			/* Wait for the exact section to lock. The whole file is sent by the master */
886			P("BYTE LOCK %d\n", state);
887			getLockSection(&request);
888			if ((ftest = open(dp.fname, O_RDWR | O_NONBLOCK)) < 0) {
889				result = ECHEC;
890				state = RESULT;
891				if (dp.verbose)
892					perror("\nOpen:");
893				continue;
894			}
895
896			if (fcntl(ftest, F_SETLK, &request) < 0) {
897				if (dp.verbose || errno != EAGAIN)
898					perror("\nBTLOCK: fcntl");
899				result = ECHEC;
900				state = RESULT;
901				continue;
902			}
903			/* Change the character at the given position for an easier verification */
904			a = lseek(ftest, request.l_start, SEEK_SET);
905			write(ftest, "=", 1);
906			result = SUCCES;
907			state = RESULT;
908			continue;
909
910		case RESULT:
911			if (result == SUCCES)
912				write(0, "=", 1);
913			else
914				write(0, "x", 1);
915			P("RESULT: %d\n", result);
916			sendResult(result);
917			state = SYNC;
918			continue;
919
920		case CLEAN:
921			close(ftest);
922			/* Send CLEAN Ack */
923			sendResult(result);
924			state = SYNC;
925			continue;
926
927		case END:
928			E("(End)\n");
929			finish(0);
930			printf("Unknown command\n");
931			finish(1);
932
933		}
934	}
935
936}
937
938char *nextArg(int argc, char **argv, int *i)
939{
940	if (((*i) + 1) < argc) {
941		(*i) += 1;
942		return argv[(*i)];
943	}
944	return NULL;
945}
946
947int usage(void)
948{
949	printf("locktest -n <number of process> -f <test file> [-T]\n");
950	printf("Number of child process must be higher than 1\n");
951	exit(0);
952	return 0;
953}
954
955int main(int argc, char **argv)
956{
957	int rc = 0;
958	int i, nThread = 0;
959	char *tmp;
960	int type = 0;
961	int clients;
962	type = PROCESS;
963	dp.fname = NULL;
964	dp.verbose = 0;
965	int server = 1;
966	char *host;
967
968	host = NULL;
969	clients = 0;
970
971	for (i = 1; i < argc; i++) {
972
973		if (!strcmp("-n", argv[i])) {
974			if (!(tmp = nextArg(argc, argv, &i)))
975				usage();
976			nThread = atoi(tmp);
977			continue;
978		}
979
980		if (!strcmp("-f", argv[i])) {
981			if (!(dp.fname = nextArg(argc, argv, &i)))
982				usage();
983			continue;
984		}
985		if (!strcmp("-v", argv[i])) {
986			dp.verbose = TRUE;
987			continue;
988		}
989		if (!strcmp("-c", argv[i])) {
990			if (!(clients = atoi(nextArg(argc, argv, &i))))
991				usage();
992			continue;
993		}
994
995		if (!strcmp("--server", argv[i])) {
996			if (!(host = nextArg(argc, argv, &i)))
997				usage();
998			server = 0;
999			continue;
1000		}
1001		printf("Ignoring unknown option: %s\n", argv[i]);
1002	}
1003
1004	if (server) {
1005		if (!(dp.fname && nThread))
1006			usage();
1007		if (clients > 0) {
1008			configureServer(clients);
1009			setupClients(type, dp.fname, nThread);
1010		}
1011	} else {
1012		configureClient(host);
1013		dp.fname = malloc(512);
1014		memset(dp.fname, 0, 512);
1015		getConfiguration(&type, dp.fname, &nThread);
1016	}
1017
1018	if (dp.verbose)
1019		printf("By process.\n");
1020	load = loadProcess;
1021	eType = "process";
1022	finish = finishProcess;
1023	LIST_RESULTS = LIST_RESULTS_PROCESS;
1024	initialize(nThread);
1025	if (server) {
1026		rc = master();
1027	} else {
1028		masterClient();
1029		free(dp.fname);
1030	}
1031	clean();
1032
1033	return rc;
1034}
1035