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