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 
32 int MAXLEN = 64;
33 int MAXTEST = 10;
34 extern int maxClients;
35 extern int fdServer;
36 
37 char message[M_SIZE];
38 int slaveReader;
39 int masterReader;
40 int slaveWriter;
41 
42 /* Which lock will be applied by the master process on test startup */
43 int 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 */
51 int 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 */
59 char *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 */
72 int 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 */
80 int LIST_RESULTS_THREADS[] = { SUCCES, SUCCES,
81 	SUCCES, SUCCES,
82 	SUCCES, SUCCES,
83 	SUCCES, SUCCES,
84 	ECHEC, ECHEC
85 };
86 
87 int *LIST_RESULTS = NULL;
88 char *eType = NULL;
89 
90 int TOTAL_RESULT_OK[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
91 
92 void *slave(void *data);
93 int (*finish) (int a);
94 
finishProcess(int a)95 int finishProcess(int a)
96 {
97 	exit(a);
98 }
99 
100 int (*load) (void);
101 
102 struct dataPub dp;
103 
104 /* Functions to access tests/tests names/tests results*/
testSuiv(int n)105 int testSuiv(int n)
106 {
107 	return LIST_TESTS[n];
108 }
109 
resAttSuiv(int n)110 int resAttSuiv(int n)
111 {
112 	return LIST_RESULTS[n];
113 }
114 
nomTestSuiv(int n)115 char *nomTestSuiv(int n)
116 {
117 	return LIST_NAMES_TESTS[n];
118 }
119 
lockSuiv(int n)120 int lockSuiv(int n)
121 {
122 	return LIST_LOCKS[n];
123 }
124 
125 /* Verify the test result is the expected one */
matchResult(int r,int n)126 int 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 */
counter(int r,int n)137 void 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  */
validationResults(int n)145 void 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 
initTest(void)175 int 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 
initClientFork(int i)188 struct 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 
initialize(int clnt)210 int 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 
cleanClient(struct dataChild * df)231 void 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 
clean(void)240 void clean(void)
241 {
242 	free(dp.lthreads);
243 	free(dp.lclnt);
244 }
245 
loadProcess(void)246 int 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 
lockWholeFile(struct flock * request)263 void 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 
selectTest(int n,struct s_test * test)271 void 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 */
report(int clnt)281 int 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 
serverSendLocal(void)302 int 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 
serverSendNet(void)314 void serverSendNet(void)
315 {
316 	writeToAllClients(message);
317 }
318 
serverReceiveNet(void)319 int 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 
serverReceiveLocal(void)330 int 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 
clientReceiveLocal(void)338 int clientReceiveLocal(void)
339 {
340 	read(slaveReader, message, M_SIZE);
341 	return 0;
342 }
343 
clientSend(void)344 int clientSend(void)
345 {
346 	write(slaveWriter, message, M_SIZE);
347 	return 0;
348 }
349 
serverSend(void)350 int serverSend(void)
351 {
352 	serverSendNet();
353 	serverSendLocal();
354 	return 0;
355 }
356 
serverReceive(void)357 int 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  */
serializeTLock(struct s_test * tLock)367 int 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 
unSerializeTLock(struct s_test * tLock)375 void 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 
serializeFLock(struct flock * request)383 void 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 
serializeResult(int result)395 void serializeResult(int result)
396 {
397 	memset(message, 0, M_SIZE);
398 	sprintf(message, "R:%d::", result);
399 
400 }
401 
unSerializeResult(int * result)402 void unSerializeResult(int *result)
403 {
404 	sscanf(message, "R:%d::", result);
405 }
406 
unSerializeFLock(struct flock * request)407 void 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 
serverSendLockClient(struct flock * request,int client)417 int serverSendLockClient(struct flock *request, int client)
418 {
419 	serializeFLock(request);
420 	return serverSendClient(client);
421 }
422 
serverSendLockLocal(struct flock * request,int slave)423 int serverSendLockLocal(struct flock *request, int slave)
424 {
425 	serializeFLock(request);
426 	return write(dp.lclnt[slave][1], message, M_SIZE);
427 }
428 
getLockSection(struct flock * request)429 int getLockSection(struct flock *request)
430 {
431 	memset(message, 0, M_SIZE);
432 	clientReceiveLocal();
433 	unSerializeFLock(request);
434 	return 0;
435 }
436 
sendLockTest(struct s_test * tLock)437 int sendLockTest(struct s_test *tLock)
438 {
439 	serializeTLock(tLock);
440 	serverSend();
441 	return 0;
442 }
443 
getLockTest(struct s_test * tLock)444 int getLockTest(struct s_test *tLock)
445 {
446 	clientReceiveLocal();
447 	unSerializeTLock(tLock);
448 	return 0;
449 }
450 
sendResult(int result)451 int sendResult(int result)
452 {
453 	serializeResult(result);
454 	clientSend();
455 	return 0;
456 }
457 
getResults(int ntest)458 int 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  */
masterClient(void)488 void 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 
master(void)574 int 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 
slave(void * data)748 void *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 
nextArg(int argc,char ** argv,int * i)938 char *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 
usage(void)947 int 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 
main(int argc,char ** argv)955 int 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