src/locktest.c: Fix return code if last test fails
[xfstests-dev.git] / src / locktest.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000-2003 Silicon Graphics, Inc.
4  * All Rights Reserved.
5  */
6
7 /*
8  * Synchronized byte range lock exerciser
9  */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <malloc.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <sys/stat.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <netinet/tcp.h>
21
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <netdb.h>
25 #include <endian.h>
26 #include <byteswap.h>
27 #include <errno.h>
28 #include <string.h>
29 #define     HEX_2_ASC(x)    ((x) > 9) ? (x)-10+'a' : (x)+'0'
30 #define         FILE_SIZE       1024
31 #define PLATFORM_INIT()     /*no-op*/
32 #define PLATFORM_CLEANUP()  /*no-op*/
33 #define LL                  "ll"
34
35 extern int h_errno;
36
37 #define inet_aton(STRING, INADDRP) \
38     (((INADDRP)->s_addr = inet_addr(STRING)) == -1 ? 0 : 1)
39
40 /* this assumes 32 bit pointers */
41 #define PTR_TO_U64(P) ((unsigned __int64)(unsigned int)(P))
42 #define U64_TO_PTR(T,U) ((T)(void *)(unsigned int)(U))
43
44 #if __BYTE_ORDER == __LITTLE_ENDIAN
45 #define bswap_uint16(x)         (uint16_t)bswap_16(x)
46 #define bswap_uint32(x)         (uint32_t)bswap_32(x)
47 #define bswap_uint64(x)         (uint64_t)bswap_64(x)
48 #else
49 #define bswap_uint16(x)         x
50 #define bswap_uint32(x)         x
51 #define bswap_uint64(x)         x
52 #endif
53
54 #define SOCKET              int
55 #define SOCKET_READ         read
56 #define SOCKET_WRITE        write
57 #define SOCKET_CLOSE(S)     (close(S))
58 #define INVALID_SOCKET      -1
59
60 #define O_BINARY            0
61        
62 #define HANDLE              int
63 #define INVALID_HANDLE      -1
64 #define SEEK(H, O)          (lseek(H, O, SEEK_SET))
65 #define READ(H, B, L)       (read(H, B, L))
66 #define WRITE(H, B, L)      (write(H, B, L))
67 #define CLOSE(H)            (close(H))
68
69 #define RAND()              (rand())
70 #define SRAND(s)            (srand(s))
71
72 #define MIN(A,B)            (((A)<(B))?(A):(B))
73 #define MAX(A,B)            (((A)>(B))?(A):(B))
74
75 #define ALLOC_ALIGNED(S)    (memalign(65536, S)) 
76 #define FREE_ALIGNED(P)     (free(P)) 
77
78 static char     *prog;
79 static char     *filename = 0;
80 static int      debug = 0;
81 static int      server = 1;
82 static int      port = 0;
83 static int      testnumber = -1;
84 static int      saved_errno = 0;
85
86 static SOCKET   s_fd = -1;              /* listen socket    */
87 static SOCKET   c_fd = -1;              /* IPC socket       */
88 static HANDLE   f_fd = INVALID_HANDLE;  /* shared file      */
89
90 #define         CMD_WRLOCK      0
91 #define         CMD_RDLOCK      1
92 #define         CMD_UNLOCK      2
93 #define         CMD_CLOSE       3
94 #define         CMD_OPEN        4
95 #define         CMD_WRTEST      5
96 #define         CMD_RDTEST      6
97
98 #define         PASS    1
99 #define         FAIL    0
100
101 #define         SERVER  0
102 #define         CLIENT  1
103
104 #define         TEST_NUM        0
105 #define         COMMAND         1
106 #define         OFFSET          2
107 #define         LENGTH          3
108 #define         RESULT          4
109 #define         WHO             5
110 #define         FLAGS           2 /* index 2 is also used for do_open() flag, see below */
111
112 static char *get_cmd_str(int cmd)
113 {
114         switch (cmd) {
115                 case CMD_WRLOCK: return "write lock"; break;
116                 case CMD_RDLOCK: return "read lock"; break;
117                 case CMD_UNLOCK: return "unlock"; break;
118                 case CMD_CLOSE:  return "close"; break;
119                 case CMD_OPEN:   return "open"; break;
120                 case CMD_WRTEST: return "Wait for SIGIO"; break;
121                 case CMD_RDTEST: return "Truncate"; break;
122         }
123         return "unknown";
124 }
125 /* 
126  * flags for Mac OS X do_open() 
127  * O_RDONLY     0x0000
128  * O_WRONLY     0x0001  
129  * O_RDWR       0x0002
130  * O_NONBLOCK   0x0004  
131  * O_APPEND     0x0008
132  * O_SHLOCK     0x0010  
133  * O_EXLOCK     0x0020
134  * O_ASYNC      0x0040  
135  * O_FSYNC      0x0080
136  * O_NOFOLLOW   0x0100  
137  * O_CREAT      0x0200
138  * O_TRUNC      0x0400
139  * O_EXCL       0x0800
140  */
141
142 /*
143  * When adding tests be sure to add to both the descriptions AND tests array. 
144  * Also, be sure to undo whatever is set for each test (eg unlock any locks)
145  * There is no need to have a matching client command for each server command
146  * (or vice versa)
147  */
148
149 char *descriptions[] = {
150     /* 1 */"Add a lock to an empty lock list",
151     /* 2 */"Add a lock to the start and end of a list - no overlaps",
152     /* 3 */"Add a lock to the middle of a list - no overlap",
153     /* 4 */"Add different lock types to middle of the list - overlap exact match", 
154     /* 5 */"Add new lock which completely overlaps any old lock in the list", 
155     /* 6 */"Add new lock which itself is completely overlaped by any old lock in the list",
156     /* 7 */"Add new lock which starts before any old lock in the list",
157     /* 8 */"Add new lock which starts in the middle of any old lock in the list and ends after",
158     /* 9 */"Add different new lock types which completely overlaps any old lock in the list",
159     /* 10 */"Add different new locks which are completely overlaped by an old lock in the list",
160     /* 11 */"Add different new lock types which start before the old lock in the list",
161     /* 12 */"Add different new lock types which start in the middle of an old lock in the list and end after",
162     /* 13 */"Add new lock, differing types and processes, to middle of the list - exact overlap match",
163     /* 14 */"Add new lock, differing types and processes, which completely overlap any of the locks in the list",
164     /* 15 */"Add new lock, differing types and processes, which are completely overlaped by locks in the list",
165     /* 16 */"Add new lock, differing types and processes, which start before a lock in the list",
166     /* 17 */"Add new lock, differing types and processes, which starts in the middle of a lock, and ends after",
167     /* 18 */"Acquire write locks with overlapping ranges",
168     /* 19 */"Acquire write locks with non-overlapping ranges extending beyond EOF",
169     /* 20 */"Acquire write locks with overlapping ranges extending beyond EOF",
170     /* 21 */"Acquire write locks on whole files",
171     /* 22 */"Acquire write lock on whole file and range write lock",
172     /* 23 */"Acquire read locks with non-overlapping ranges",
173     /* 24 */"Acquire read locks with overlapping ranges",
174     /* 25 */"Acquire read and write locks with no overlapping ranges",
175     /* 26 */"Acquire read and write locks with overlapping ranges",
176     /* 27 */"Acquire whole file write lock and then close without unlocking (and attempt a lock)",
177     /* 28 */"Acquire two read locks, close and reopen the file, and test if the inital lock is still there",
178     /* 29 */"Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write",
179     #if defined(macosx)
180     /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too",
181     /* 31 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK",
182     /* 32 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too"
183     #endif
184 };
185
186 static int64_t tests[][6] =
187         /*      test #  Action  [offset|flags]  length          expected        server/client */
188         {       
189         /* Various simple tests exercising the list */
190
191 /* SECTION 1: WRITE and CMD_UNLOCK with the same process (SERVER) */
192         /* Add a lock to an empty list */
193                 {1,     CMD_WRLOCK,     1,              10,             PASS,           SERVER  },
194                 {1,     CMD_UNLOCK,     1,              10,             PASS,           SERVER  },
195                 
196         /* Add a lock to the start and end of a list - 1, 13 - no overlap */
197                 {2,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
198                 {2,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
199                 {2,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
200                 {2,     CMD_WRLOCK,     1,              5,              PASS,           SERVER  },
201                 {2,     CMD_WRLOCK,     70,             5,              PASS,           SERVER  },
202                 
203                 {2,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
204                 {2,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
205                 {2,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
206                 {2,     CMD_UNLOCK,     1,              5,              PASS,           SERVER  },
207                 {2,     CMD_UNLOCK,     70,             5,              PASS,           SERVER  },
208                 
209         /* Add a lock to the middle of a list - no overlap */
210                 {3,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
211                 {3,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
212                 {3,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
213                 {3,     CMD_WRLOCK,     42,             5,              PASS,           SERVER  },
214                 
215                 {3,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
216                 {3,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
217                 {3,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
218                 {3,     CMD_UNLOCK,     42,             5,              PASS,           SERVER  },
219                 
220         /* Add different lock types to middle of the list - overlap exact match - 3 */
221                 {4,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
222                 {4,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
223                 {4,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
224                 /* Exact match - same lock type */
225                 {4,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
226                 /* Exact match - different lock type */
227                 {4,     CMD_RDLOCK,     30,             10,             PASS,           SERVER  },
228                 /* Exact match - unlock */
229                 {4,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
230                 /* New lock - as above, inserting in the list again */
231                 {4,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
232                 
233                 {4,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
234                 {4,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
235                 {4,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
236                 
237         /* Add new lock which completely overlaps any old lock in the list - 4,5,6 */
238                 {5,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
239                 {5,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
240                 {5,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
241                 /* The start is the same, end overlaps */
242                 {5,     CMD_WRLOCK,     30,             15,             PASS,           SERVER  },
243                 /* The start is before, end is the same */
244                 {5,     CMD_WRLOCK,     25,             20,             PASS,           SERVER  },
245                 /* Both start and end overlap */
246                 {5,     CMD_WRLOCK,     22,             26,             PASS,           SERVER  },
247                 
248                 {5,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
249                 {5,     CMD_UNLOCK,     22,             26,             PASS,           SERVER  },
250                 {5,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
251                 
252         /* Add new lock which itself is completely overlaped by any old lock in the list - 7,8,10 */
253                 {6,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
254                 {6,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
255                 {6,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
256                 /* The start is the same, end is in the middle of old lock - NOP */
257                 {6,     CMD_WRLOCK,     30,             5,              PASS,           SERVER  },
258                 /* The start and end are in the middle of old lock - NOP */
259                 {6,     CMD_WRLOCK,     32,             6,              PASS,           SERVER  },
260                 /* Start in the middle and end is the same - NOP */
261                 {6,     CMD_WRLOCK,     32,             8,              PASS,           SERVER  },
262                 
263                 {6,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
264                 {6,     CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
265                 {6,     CMD_UNLOCK,     32,             8,              PASS,           SERVER  },
266                 {6,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
267                 
268         /* Add new lock which starts before any old lock in the list - 2,9 */
269                 {7,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
270                 {7,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
271                 {7,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
272                 /* Here is the new lock */
273                 {7,     CMD_WRLOCK,     27,             10,             PASS,           SERVER  },
274                 /* Go again with the end of the new lock matching the start of old lock */
275                 {7,     CMD_WRLOCK,     25,             2,              PASS,           SERVER  },
276                 
277                 {7,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
278                 {7,     CMD_UNLOCK,     25,             15,             PASS,           SERVER  },
279                 {7,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
280         
281         /* Add new lock which starts in the middle of any old lock in the list and ends after - 11,12 */
282                 {8,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
283                 {8,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
284                 {8,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
285                 /* Here is the new lock */
286                 {8,     CMD_WRLOCK,     35,             10,             PASS,           SERVER  },
287                 /* Go again with the end of the new lock matching the start of old lock */
288                 {8,     CMD_WRLOCK,     45,             2,              PASS,           SERVER  },
289                 
290                 {8,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
291                 {8,     CMD_UNLOCK,     30,             17,             PASS,           SERVER  },
292                 {8,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
293 /* SECTION 2: Overlapping READ and WRITE and CMD_UNLOCK with the same process (SERVER) */
294         /* Add different new lock types which completely overlaps any old lock in the list - 4,5,6 */
295                 {9,     CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
296                 {9,     CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
297                 {9,     CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
298                 /* The start is the same, end overlaps */
299                 {9,     CMD_RDLOCK,     30,             15,             PASS,           SERVER  },
300                 /* The start is before, end is the same */
301                 {9,     CMD_WRLOCK,     25,             20,             PASS,           SERVER  },
302                 /* Both start and end overlap */
303                 {9,     CMD_RDLOCK,     22,             26,             PASS,           SERVER  },
304                 
305                 {9,     CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
306                 {9,     CMD_UNLOCK,     22,             26,             PASS,           SERVER  },
307                 {9,     CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
308                 
309         /* Add different new locks which are completely overlaped by an old lock in the list - 7,8,10 */
310                 {10,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
311                 {10,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
312                 {10,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
313                 /* The start is the same, end is in the middle of old lock */
314                 {10,    CMD_RDLOCK,     30,             5,              PASS,           SERVER  },
315                 /* The start and end are in the middle of a lock */
316                 {10,    CMD_WRLOCK,     32,             2,              PASS,           SERVER  },
317                 /* Start in the middle and end is the same */
318                 {10,    CMD_RDLOCK,     36,             5,              PASS,           SERVER  },
319                 
320                 {10,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
321                 {10,    CMD_UNLOCK,     30,             11,             PASS,           SERVER  },
322                 {10,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
323                 
324         /* Add different new lock types which start before the old lock in the list - 2,9 */
325                 {11,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
326                 {11,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
327                 {11,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
328                 /* Here is the new lock */
329                 {11,    CMD_RDLOCK,     27,             10,             PASS,           SERVER  },
330                 /* Go again with the end of the new lock matching the start of lock */
331                 {11,    CMD_WRLOCK,     25,             3,              PASS,           SERVER  },
332                 
333                 {11,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
334                 {11,    CMD_UNLOCK,     25,             15,             PASS,           SERVER  },
335                 {11,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
336         
337         /* Add different new lock types which start in the middle of an old lock in the list and end after - 11,12 */
338                 {12,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
339                 {12,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
340                 {12,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
341                 /* Here is the new lock */
342                 {12,    CMD_RDLOCK,     35,             10,             PASS,           SERVER  },
343                 /* Go again with the end of the new lock matching the start of old lock */
344                 {12,    CMD_WRLOCK,     44,             3,              PASS,           SERVER  },
345                 
346                 {12,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
347                 {12,    CMD_UNLOCK,     30,             18,             PASS,           SERVER  },
348                 {12,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
349
350 /* SECTION 3: Overlapping READ and WRITE and CMD_UNLOCK with the different processes (CLIENT/SERVER) */
351         /* Add new lock, differing types and processes, to middle of the list - exact overlap match - 3 */
352                 {13,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
353                 {13,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
354                 {13,    CMD_RDLOCK,     50,             10,             PASS,           SERVER  },
355                 /* Same lock type, different process */
356                 {13,    CMD_WRLOCK,     30,             10,             FAIL,           CLIENT  },
357                 {13,    CMD_RDLOCK,     50,             10,             PASS,           CLIENT  },
358                 /* Exact match - different lock type, different process */
359                 {13,    CMD_RDLOCK,     30,             10,             FAIL,           CLIENT  },
360                 /* Exact match - unlock */
361                 {13,    CMD_UNLOCK,     30,             10,             PASS,           CLIENT  },
362                 /* New lock - as above, inserting in the list again */
363                 {13,    CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
364                 /* Exact match - same lock type, different process */
365                 {13,    CMD_WRLOCK,     30,             10,             PASS,           CLIENT  },
366                 
367                 {13,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
368                 {13,    CMD_UNLOCK,     30,             10,             PASS,           CLIENT  },
369                 {13,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
370                 
371         /* Add new lock, differing types and processes, which completely overlap any of the locks in the list - 4,5,6 */
372                 {14,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
373                 {14,    CMD_WRLOCK,     30,             10,             PASS,           SERVER  },
374                 {14,    CMD_RDLOCK,     50,             10,             PASS,           SERVER  },
375                 /* The start is the same, end overlaps */
376                 {14,    CMD_RDLOCK,     30,             15,             FAIL,           CLIENT  },
377                 {14,    CMD_WRLOCK,     30,             15,             FAIL,           CLIENT  },
378                 /* The start is before, end is the same */
379                 {14,    CMD_RDLOCK,     25,             20,             FAIL,           CLIENT  },
380                 {14,    CMD_WRLOCK,     25,             20,             FAIL,           CLIENT  },
381                 /* Both start and end overlap */
382                 {14,    CMD_RDLOCK,     22,             26,             FAIL,           CLIENT  },
383                 {14,    CMD_WRLOCK,     22,             26,             FAIL,           CLIENT  },
384                 
385                 /* The start is the same, end overlaps */
386                 {14,    CMD_RDLOCK,     50,             15,             PASS,           CLIENT  },
387                 {14,    CMD_WRLOCK,     50,             17,             FAIL,           CLIENT  },
388                 /* The start is before, end is the same */
389                 {14,    CMD_RDLOCK,     45,             20,             PASS,           CLIENT  },
390                 {14,    CMD_WRLOCK,     43,             22,             FAIL,           CLIENT  },
391                 /* Both start and end overlap */
392                 {14,    CMD_RDLOCK,     42,             26,             PASS,           CLIENT  },
393                 {14,    CMD_WRLOCK,     41,             28,             FAIL,           CLIENT  },
394                 
395                 {14,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
396                 {14,    CMD_UNLOCK,     22,             26,             PASS,           SERVER  },
397                 {14,    CMD_UNLOCK,     42,             26,             PASS,           CLIENT  },
398
399         /* Add new lock, differing types and processes, which are completely overlaped by an old lock in the list - 7,8,10 */
400                 {15,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
401                 {15,    CMD_RDLOCK,     30,             10,             PASS,           SERVER  },
402                 {15,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
403                 /* The start is the same, end is in the middle of old lock */
404                 {15,    CMD_RDLOCK,     50,             5,              FAIL,           CLIENT  },
405                 {15,    CMD_WRLOCK,     50,             5,              FAIL,           CLIENT  },
406                 /* The start and end are in the middle of old lock */
407                 {15,    CMD_RDLOCK,     52,             6,              FAIL,           CLIENT  },
408                 {15,    CMD_WRLOCK,     52,             6,              FAIL,           CLIENT  },
409                 /* Start in the middle and end is the same */
410                 {15,    CMD_RDLOCK,     52,             8,              FAIL,           CLIENT  },
411                 {15,    CMD_WRLOCK,     52,             8,              FAIL,           CLIENT  },
412                 /* The start is the same, end is in the middle of old lock */
413                 {15,    CMD_RDLOCK,     30,             5,              PASS,           CLIENT  },
414                 {15,    CMD_WRLOCK,     30,             5,              FAIL,           CLIENT  },
415                 /* The start and end are in the middle of old lock */
416                 {15,    CMD_RDLOCK,     32,             6,              PASS,           CLIENT  },
417                 {15,    CMD_WRLOCK,     32,             6,              FAIL,           CLIENT  },
418                 /* Start in the middle and end is the same */
419                 {15,    CMD_RDLOCK,     32,             8,              PASS,           CLIENT  },
420                 {15,    CMD_WRLOCK,     32,             8,              FAIL,           CLIENT  },
421                 
422                 {15,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
423                 {15,    CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
424                 {15,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
425         /* Add new lock, differing types and processes, which start before a lock in the list - 2,9 */
426                 {16,    CMD_RDLOCK,     10,             10,             PASS,           SERVER  },
427                 {16,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
428                 /* Start is before, end is the start of the old lock in list */
429                 {16,    CMD_RDLOCK,     5,              6,              PASS,           CLIENT  },
430                 {16,    CMD_WRLOCK,     5,              6,              FAIL,           CLIENT  },
431                 /* Start is before, end is in the middle of the old lock */
432                 {16,    CMD_RDLOCK,     5,              10,             PASS,           CLIENT  },
433                 {16,    CMD_WRLOCK,     5,              10,             FAIL,           CLIENT  },
434                 /* Start is before, end is the start of the old lock in list */
435                 {16,    CMD_RDLOCK,     45,             6,              FAIL,           CLIENT  },
436                 {16,    CMD_WRLOCK,     45,             6,              FAIL,           CLIENT  },
437                 /* Start is before, end is in the middle of the old lock */
438                 {16,    CMD_RDLOCK,     45,             10,             FAIL,           CLIENT  },
439                 {16,    CMD_WRLOCK,     45,             10,             FAIL,           CLIENT  },
440                 
441                 {16,    CMD_UNLOCK,     5,              15,             PASS,           CLIENT  },
442                 {16,    CMD_UNLOCK,     30,             10,             PASS,           SERVER  },
443                 {16,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
444
445         /* Add new lock, differing types and processes, which starts in the middle of a lock, and ends after - 11,12 */
446                 {17,    CMD_WRLOCK,     10,             10,             PASS,           SERVER  },
447                 {17,    CMD_RDLOCK,     30,             10,             PASS,           SERVER  },
448                 {17,    CMD_WRLOCK,     50,             10,             PASS,           SERVER  },
449                 /* Start in the middle, end after lock in list */
450                 {17,    CMD_WRLOCK,     35,             10,             FAIL,           CLIENT  },
451                 /* Start matches end of lock in list  */
452                 {17,    CMD_RDLOCK,     35,             10,             PASS,           CLIENT  },
453                 {17,    CMD_RDLOCK,     44,             2,              PASS,           CLIENT  },
454                 /* Start in the middle, end after lock in list */
455                 {17,    CMD_RDLOCK,     55,             10,             FAIL,           CLIENT  },
456                 {17,    CMD_WRLOCK,     55,             10,             FAIL,           CLIENT  },
457                 /* Start matches end of lock in list  */
458                 {17,    CMD_RDLOCK,     59,             5,              FAIL,           CLIENT  },
459                 {17,    CMD_WRLOCK,     59,             5,              FAIL,           CLIENT  },
460                 
461                 {17,    CMD_UNLOCK,     10,             10,             PASS,           SERVER  },
462                 {17,    CMD_UNLOCK,     30,             16,             PASS,           CLIENT  },
463                 {17,    CMD_UNLOCK,     50,             10,             PASS,           SERVER  },
464
465 /* SECTION 4: overlapping and EOF tests */
466         /* Acquire overlapping ranges */
467                 {18,    CMD_WRLOCK,     11,             7,              PASS,           SERVER  },
468                 {18,    CMD_WRLOCK,     13,             8,              FAIL,           CLIENT  },
469                 {18,    CMD_UNLOCK,     11,             7,              PASS,           SERVER  },
470         /* Acquire different ranges beyond EOF */
471                 {19,    CMD_WRLOCK,     10,             FILE_SIZE,      PASS,           SERVER  },
472                 {19,    CMD_WRLOCK,     FILE_SIZE + 10, 10,             PASS,           CLIENT  },
473                 {19,    CMD_UNLOCK,     10,             FILE_SIZE,      PASS,           SERVER  },
474                 {19,    CMD_UNLOCK,     FILE_SIZE + 10, 10,             PASS,           CLIENT  },
475         /* Acquire same range beyong EOF */
476                 {20,    CMD_WRLOCK,     10,             FILE_SIZE,      PASS,           SERVER, },
477                 {20,    CMD_WRLOCK,     10,             FILE_SIZE,      FAIL,           CLIENT, },
478                 {20,    CMD_UNLOCK,     10,             FILE_SIZE,      PASS,           SERVER, },
479         /* Acquire whole file lock */
480                 {21,    CMD_WRLOCK,     0,              0,              PASS,           SERVER, },
481                 {21,    CMD_WRLOCK,     0,              0,              FAIL,           CLIENT, },
482                 {21,    CMD_UNLOCK,     0,              0,              PASS,           SERVER, },
483         /* Acquire whole file lock, then range */
484                 {22,    CMD_WRLOCK,     0,              0,              PASS,           SERVER, },
485                 {22,    CMD_WRLOCK,     1,              5,              FAIL,           CLIENT, },
486                 {22,    CMD_UNLOCK,     0,              0,              PASS,           SERVER, },
487         /* Acquire non-overlapping read locks */
488                 {23,    CMD_RDLOCK, 1,          5,              PASS,           SERVER, },
489                 {23,    CMD_RDLOCK, 7,          6,              PASS,           CLIENT, },
490                 {23,    CMD_UNLOCK, 1,          5,              PASS,           SERVER, },
491                 {23,    CMD_UNLOCK, 7,          6,              PASS,           CLIENT, },
492         /* Acquire overlapping read locks */
493                 {24,    CMD_RDLOCK, 1,          5,              PASS,           SERVER, },
494                 {24,    CMD_RDLOCK, 2,          6,              PASS,           CLIENT, },
495                 {24,    CMD_UNLOCK, 1,          5,              PASS,           SERVER, },
496                 {24,    CMD_UNLOCK, 1,          7,              PASS,           CLIENT, },
497         /* Acquire non-overlapping read and write locks */
498                 {25,    CMD_RDLOCK, 1,          5,              PASS,           SERVER, },
499                 {25,    CMD_WRLOCK, 7,          6,              PASS,           CLIENT, },
500                 {25,    CMD_UNLOCK, 1,          5,              PASS,           SERVER, },
501                 {25,    CMD_UNLOCK, 7,          6,              PASS,           CLIENT, },
502         /* Acquire overlapping read and write locks */
503                 {26,    CMD_RDLOCK, 1,          5,              PASS,           SERVER, },
504                 {26,    CMD_WRLOCK, 2,          6,              FAIL,           CLIENT, },
505                 {26,    CMD_UNLOCK, 1,          5,              PASS,           SERVER, },
506         /* Acquire whole file lock, then close (without unlocking) */
507                 {27,    CMD_WRLOCK,     0,              0,              PASS,           SERVER, },
508                 {27,    CMD_WRLOCK,     1,              5,              FAIL,           CLIENT, },
509                 {27,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
510                 {27,    CMD_WRLOCK,     1,              5,              PASS,           CLIENT, },
511                 {27,    CMD_OPEN,       O_RDWR,         0,              PASS,           SERVER, },
512                 {27,    CMD_UNLOCK,     1,              5,              PASS,           CLIENT, },
513         /* Acquire two read locks, close one file and then reopen to check that first lock still exists */
514                 {28,    CMD_RDLOCK,     1,              5,              PASS,           SERVER, },
515                 {28,    CMD_RDLOCK,     1,              5,              PASS,           CLIENT, },
516                 {28,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
517                 {28,    CMD_OPEN,       O_RDWR,         0,              PASS,           SERVER, },
518                 {28,    CMD_WRLOCK,     0,              0,              FAIL,           SERVER, },
519                 {28,    CMD_UNLOCK,     1,              5,              PASS,           SERVER, },
520         /* Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write */
521                 {29,    CMD_CLOSE, 0,           0,              PASS,           SERVER, },
522                 {29,    CMD_OPEN, O_RDONLY,     0,              PASS,           SERVER, },
523                 {29,    CMD_WRTEST, 0,          0,              PASS,           SERVER, },
524                 {29,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
525                 {29,    CMD_OPEN,       O_RDWR,         0,              PASS,           SERVER, },
526 #ifdef macosx
527         /* Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too */
528                 {30,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
529                 {30,    CMD_OPEN,       O_RDWR|O_SHLOCK|O_NONBLOCK,     0,      PASS,           SERVER, },
530                 {30,    CMD_CLOSE,0,            0,              PASS,           CLIENT, },
531                 {30,    CMD_OPEN,       O_RDWR|O_SHLOCK|O_NONBLOCK,     0,      PASS,           CLIENT, },
532         /* Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK */
533                 {31,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
534                 {31,    CMD_CLOSE,0,            0,              PASS,           CLIENT, },
535                 {31,    CMD_OPEN,       O_RDWR|O_SHLOCK|O_NONBLOCK,     0,      PASS,           SERVER, },
536                 {31,    CMD_OPEN,       O_RDWR|O_EXLOCK|O_NONBLOCK,     0,      FAIL,           CLIENT, },
537         /* Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too */
538                 {32,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
539                 {32,    CMD_CLOSE,0,            0,              FAIL,           CLIENT, },
540                 {32,    CMD_OPEN,       O_RDWR|O_EXLOCK|O_NONBLOCK,     0,      PASS,           SERVER, },
541                 {32,    CMD_OPEN,       O_RDWR|O_EXLOCK|O_NONBLOCK,     0,      FAIL,           CLIENT, },
542                 {32,    CMD_CLOSE,0,            0,              PASS,           SERVER, },
543                 {32,    CMD_CLOSE,0,            0,              FAIL,           CLIENT, },
544                 {32,    CMD_OPEN,       O_RDWR,         0,              PASS,           SERVER, },
545                 {32,    CMD_OPEN,       O_RDWR,         0,              PASS,           CLIENT, },
546 #endif /* macosx */
547         /* indicate end of array */
548                 {0,0,0,0,0,SERVER},
549                 {0,0,0,0,0,CLIENT}
550         };
551
552 static struct {
553     int32_t             test;
554     int32_t             command;
555     int64_t             offset;
556     int64_t             length;
557     int32_t             result;
558     int32_t             index;
559     int32_t             error;
560     int32_t             padding; /* So mac and irix have the same size struct (bloody alignment) */
561 } ctl;
562
563
564 void
565 usage(void)
566 {
567     fprintf(stderr, "Usage: %s [options] sharedfile\n\
568 \n\
569 options:\n\
570   -p port       TCP/IP port number for client-server communication\n\
571   -d            enable debug tracing\n\
572   -n #          test number to run\n\
573   -h host       run as client and connect to server on remote host\n\
574                 [default run as server]\n", prog);
575     exit(1);
576 }
577
578 #define INIT_BUFSZ 512 
579
580 void
581 initialize(HANDLE fd)
582 {
583     char*       ibuf;
584     int         j=0;
585     int         nwrite;
586     int         offset = 0;
587     int         togo = FILE_SIZE;
588
589     ibuf = (char*)malloc(INIT_BUFSZ);
590     memset(ibuf, ':', INIT_BUFSZ);
591
592     SEEK(fd, 0L);
593     while (togo) {
594         offset+=j;
595         j = togo > INIT_BUFSZ ? INIT_BUFSZ : togo;
596
597         if ((nwrite = WRITE(fd, ibuf, j)) != j) {
598             if (nwrite < 0)
599                 perror("initialize write:");
600             else
601                 fprintf(stderr, "initialize: write() returns %d, not %d as expected\n", 
602                         nwrite, j);
603             exit(1);
604             /*NOTREACHED*/
605         }
606         togo -= j;
607     }
608 }
609
610
611 int do_open(int flag)
612 {
613     int flags = flag|O_CREAT|O_BINARY;
614
615     if(debug > 1)
616         fprintf(stderr, "do_open %s 0x%x\n", filename, flags);
617
618     if ((f_fd = open(filename, flags, 0666)) == INVALID_HANDLE) {
619         perror("shared file create");
620         return FAIL;
621         /*NOTREACHED*/
622     }
623     return PASS;
624 }
625
626 static int do_lock(int cmd, int type, int start, int length)
627 {
628     int ret;
629     int filedes = f_fd;
630     struct flock fl;
631
632     if(debug > 1) {
633         fprintf(stderr, "do_lock: cmd=%d type=%d start=%d, length=%d\n", cmd, type, start, length);
634     }
635
636     if (f_fd < 0)
637         return f_fd;
638     
639     fl.l_start = start;
640     fl.l_len = length;
641     fl.l_whence = SEEK_SET;
642     fl.l_pid = getpid();
643     fl.l_type = type;
644
645     errno = 0;
646
647     ret = fcntl(filedes, cmd, &fl);
648     saved_errno = errno;            
649
650     if(debug > 1 && ret)
651         fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno));
652
653     return(ret==0?PASS:FAIL);
654 }
655
656 int do_close(void)
657 {       
658     if(debug > 1) {
659         fprintf(stderr, "do_close\n");
660     }
661
662     errno =0;
663     CLOSE(f_fd);
664     f_fd = INVALID_HANDLE;
665
666     saved_errno = errno;            
667         
668     if (errno)
669         return FAIL;
670     return PASS;
671 }
672
673 static void init_ctl(int32_t index)
674 {
675     ctl.test= (int32_t)tests[index][TEST_NUM];
676     ctl.command = (int32_t)tests[index][COMMAND];
677     ctl.offset = tests[index][OFFSET];
678     ctl.length = tests[index][LENGTH];
679     ctl.index = index;
680     ctl.result = (int32_t)tests[index][RESULT];
681     ctl.error = 0;
682 }
683
684 void
685 send_ctl(void)
686 {
687     int         nwrite;
688
689     if (debug > 1) {
690         fprintf(stderr, "send_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n", 
691                 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length,ctl.result, ctl.error);
692     }
693
694     ctl.test= bswap_uint32(ctl.test);
695     ctl.command = bswap_uint32(ctl.command);
696     ctl.offset = bswap_uint64(ctl.offset);
697     ctl.length = bswap_uint64(ctl.length);
698     ctl.result = bswap_uint32(ctl.result);
699     ctl.index= bswap_uint32(ctl.index);
700     ctl.error = bswap_uint32(ctl.error);
701     nwrite = SOCKET_WRITE(c_fd, (char*)&ctl, sizeof(ctl));
702
703     ctl.test= bswap_uint32(ctl.test);
704     ctl.command = bswap_uint32(ctl.command);
705     ctl.offset = bswap_uint64(ctl.offset);
706     ctl.length = bswap_uint64(ctl.length);
707     ctl.result = bswap_uint32(ctl.result);
708     ctl.index= bswap_uint32(ctl.index);
709     ctl.error= bswap_uint32(ctl.error);
710     if (nwrite != sizeof(ctl)) {
711         if (nwrite < 0)
712             perror("send_ctl: write");
713         else
714             fprintf(stderr, "send_ctl[%d]: write() returns %d, not %zu as expected\n", 
715                     ctl.test, nwrite, sizeof(ctl));
716         exit(1);
717         /*NOTREACHED*/
718     }
719 }
720
721 void recv_ctl(void)
722 {
723     int         nread;
724
725     if ((nread = SOCKET_READ(c_fd, (char*)&ctl, sizeof(ctl))) != sizeof(ctl)) {
726         if (nread < 0)
727             perror("recv_ctl: read");
728         else {
729             fprintf(stderr, "recv_ctl[%d]: read() returns %d, not %zu as expected\n", 
730                     ctl.test, nread, sizeof(ctl));
731             fprintf(stderr, "socket might has been closed by other locktest\n");
732         } 
733         exit(1);
734         /*NOTREACHED*/
735     }
736     ctl.test= bswap_uint32(ctl.test);
737     ctl.command = bswap_uint32(ctl.command);
738     ctl.offset = bswap_uint64(ctl.offset);
739     ctl.length = bswap_uint64(ctl.length);
740     ctl.result = bswap_uint32(ctl.result);
741     ctl.index= bswap_uint32(ctl.index);
742     ctl.error= bswap_uint32(ctl.error);
743
744     if (debug > 1) {
745         fprintf(stderr, "recv_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n", 
746                 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length, ctl.result, ctl.error);
747     }
748 }
749
750 void
751 cleanup(void)
752 {
753     if (f_fd>=0)
754         CLOSE(f_fd);
755     
756     if (c_fd>=0)
757         SOCKET_CLOSE(c_fd);
758     
759     if (s_fd>=0)
760         SOCKET_CLOSE(s_fd);
761     
762     PLATFORM_CLEANUP();
763 }
764
765 int
766 main(int argc, char *argv[])
767 {
768     int         i, sts;
769     int         c;
770     struct sockaddr_in  myAddr;
771     struct linger       noLinger = {1, 0};
772     char        *host = NULL;
773     char        *endnum;
774     int         errflag = 0;
775     char        *p;
776     extern char *optarg;
777     extern int  optind;
778     int fail_count = 0;; 
779     
780     atexit(cleanup);
781     
782     PLATFORM_INIT();
783
784     /* trim command name of leading directory components */
785     prog = argv[0];
786     for (p = prog; *p; p++) {
787         if (*p == '/')
788             prog = p+1;
789     }
790
791     while ((c = getopt(argc, argv, "dn:h:p:?")) != EOF) {
792         switch (c) {
793
794         case 'd':       /* debug flag */
795             debug++;
796             break;
797
798         case 'h':       /* (server) hostname */
799             server = 0;
800             host = optarg;
801             break;
802
803         case 'n':
804             testnumber = atoi(optarg);
805             break;
806
807         case 'p':       /* TCP/IP port */
808             port = (int)strtol(optarg, &endnum, 10);
809             if (*endnum != '\0') {
810                 fprintf(stderr, "%s: -p argument must be a numeric\n", 
811                         prog);
812                 exit(1);
813                 /*NOTREACHED*/
814             }
815             break;
816
817         case '?':
818         default:
819             errflag++;
820             break;
821         }
822     }
823
824     if (errflag || optind != argc-1) {
825         usage();
826         /*NOTREACHED*/
827     }
828
829     filename=argv[optind];
830     if (do_open(O_RDWR) == FAIL)
831         exit(1);
832
833     setbuf(stderr, NULL);
834
835     if (server) {
836         int one = 1;
837         
838         s_fd = socket(AF_INET, SOCK_STREAM, 0);
839         if (s_fd == INVALID_SOCKET) {
840             perror("socket");
841             exit(1);
842             /*NOTREACHED*/
843         }
844         if (setsockopt(s_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) < 0) {
845             perror("setsockopt(nodelay)");
846             exit(1);
847             /*NOTREACHED*/
848         }
849         if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one))<0) {
850             perror("setsockopt(reuseaddr)");
851             exit(1);
852             /*NOTREACHED*/
853         }
854 #ifdef SO_REUSEPORT
855         if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&one, sizeof(one))<0) {
856             perror("setsockopt(reuseport)");
857             exit(1);
858             /*NOTREACHED*/
859         }
860 #endif
861
862         memset(&myAddr, 0, sizeof(myAddr));
863         myAddr.sin_family = AF_INET;
864         myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
865         myAddr.sin_port = htons((short)port);
866         sts = bind(s_fd, (struct sockaddr*)&myAddr, sizeof(myAddr));
867         if (sts < 0) {
868             perror("bind");
869             exit(1);
870             /*NOTREACHED*/
871         }
872
873         sts = listen(s_fd, 5);  /* Max. of 5 pending connection requests */
874         if (sts == -1) {
875             perror("listen");
876             exit(1);
877             /*NOTREACHED*/
878         }
879
880         if (port == 0) {
881                 socklen_t addr_len = sizeof(myAddr);
882
883                 if (getsockname(s_fd, &myAddr, &addr_len)) {
884                     perror("getsockname");
885                     exit(1);
886                 }
887
888                 port = ntohs(myAddr.sin_port);
889         }
890
891         printf("server port: %d\n", port);
892         fflush(stdout);
893
894         c_fd = accept(s_fd, NULL, NULL);
895         if (c_fd == INVALID_SOCKET) {
896             perror("accept");
897             exit(1);
898             /*NOTREACHED*/
899         }
900
901         if (debug) fprintf(stderr, "Client accepted\n");
902         SRAND(12345L);
903     }
904     else {
905         struct hostent  *servInfo;
906
907         if ((servInfo = gethostbyname(host)) == NULL) {
908             printf("Couldn't get hostbyname for %s", host);
909             if (h_errno == HOST_NOT_FOUND)
910                 printf(": host not found");
911             printf("\n");
912             exit(1);
913             /*NOTREACHED*/
914         }
915
916         c_fd = socket(AF_INET, SOCK_STREAM, 0);
917         if (c_fd == INVALID_SOCKET) {
918             perror("socket");
919             exit(1);
920             /*NOTREACHED*/
921         }
922         /* avoid 200 ms delay */
923         if (setsockopt(c_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) {
924             perror("setsockopt(nodelay)");
925             exit(1);
926             /*NOTREACHED*/
927         }
928         /* Don't linger on close */
929         if (setsockopt(c_fd, SOL_SOCKET, SO_LINGER, (char *)&noLinger, sizeof(noLinger)) < 0) {
930             perror("setsockopt(nolinger)");
931             exit(1);
932             /*NOTREACHED*/
933         }
934
935         memset(&myAddr, 0, sizeof(myAddr));     /* Arrgh! &myAddr, not myAddr */
936         myAddr.sin_family = AF_INET;
937         memcpy(&myAddr.sin_addr, servInfo->h_addr, servInfo->h_length);
938         myAddr.sin_port = htons((short)port);
939
940         if (connect(c_fd, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0) {
941             perror("unable to connect");
942             fprintf(stderr, "Server might still initializing the shared file\n ");
943             exit(1);
944             /*NOTREACHED*/
945         }
946
947         if (debug) fprintf(stderr, "Connected to server\n");
948         SRAND(6789L);
949     }
950
951     if (server)
952         /* only server need do shared file */
953         initialize(f_fd);
954
955     /*
956      * TCP/IP connection to be established, safe to proceed.
957      *
958      * real work is in here ...
959      */
960     i = 0;
961 {
962     int index = 0;
963     int end = 0;
964     int result = 0;
965     int last_test = 0;
966     int test_count = -1;
967     int fail_flag = 0;
968     while(!end) {
969         if (server) {
970             if(testnumber > 0) {
971                 last_test = testnumber - 1;
972                 while(tests[index][TEST_NUM] != testnumber && tests[index][TEST_NUM] != 0) {
973                     index++;
974                 }
975             }
976             /* If we have a server command, deal with it */
977             if(tests[index][WHO] == SERVER) {
978                 if(debug>1)
979                     fprintf(stderr, "Got a server command (%d)\n", index);
980                 if(tests[index][TEST_NUM] == 0) {
981                     index++;
982                     continue;
983                 } 
984                 memset(&ctl, 0, sizeof(ctl));
985                 ctl.test = tests[index][TEST_NUM];
986
987                 if(tests[index][TEST_NUM] != 0) {
988                     switch(tests[index][COMMAND]) {
989                         case CMD_WRLOCK:
990                             result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
991                             break;
992                         case CMD_RDLOCK:
993                             result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
994                             break;
995                         case CMD_UNLOCK:
996                             result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]);
997                             break;
998                         case CMD_CLOSE:
999                             result = do_close();
1000                             break;
1001                         case CMD_OPEN:
1002                             result = do_open(tests[index][FLAGS]);
1003                             break;
1004                         case CMD_WRTEST:
1005                             result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1006                             break;
1007                         case CMD_RDTEST:
1008                             result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1009                             break;
1010                     }
1011                     if( result != tests[index][RESULT]) {
1012                         fail_flag++;
1013                         /* We have a failure */
1014                         if(debug)
1015                             fprintf(stderr, "Server failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n", 
1016                                         ctl.test,
1017                                         get_cmd_str(tests[index][COMMAND]),
1018                                                 (long long)tests[index][OFFSET],
1019                                                 (long long)tests[index][LENGTH],
1020                                                 saved_errno, strerror(saved_errno));
1021                         fprintf(stderr, "Server failure in %lld:%s\n",
1022                                         (long long)tests[index][TEST_NUM],
1023                                         descriptions[tests[index][TEST_NUM] - 1]);
1024                     }
1025                 }
1026             /* else send it off to the client */
1027             } else if (tests[index][WHO] == CLIENT) {
1028                 if(tests[index][TEST_NUM] == 0) {
1029                     ctl.test = 0;
1030                     end=1;
1031                 } 
1032                 /* get the client to do something */
1033                 init_ctl(index);
1034                 if(debug > 1)
1035                     fprintf(stderr, "Sending command to client (%d) - %s - %lld:%lld\n", 
1036                                         index,
1037                                         get_cmd_str(ctl.command),
1038                                         (long long)tests[index][OFFSET],
1039                                         (long long)tests[index][LENGTH]);
1040                 /* get the client to do something */
1041                 ctl.index = index;
1042                 send_ctl();
1043                 if(ctl.test != 0) {
1044                     /* Get the clients response */
1045                     recv_ctl();
1046                     /* this is the whether the test passed or failed,
1047                      * not what the command returned */
1048                     if( ctl.result == FAIL ) {
1049                         fail_flag++;
1050                         if(debug)
1051                             fprintf(stderr, "Client failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1052                                         ctl.test, get_cmd_str(ctl.command),
1053                                         (long long)ctl.offset, (long long)ctl.length,
1054                                         ctl.error, strerror(ctl.error));
1055                         fprintf(stderr, "Client failure in %lld:%s\n",
1056                                         (long long)tests[index][TEST_NUM],
1057                                         descriptions[tests[index][TEST_NUM] - 1]);
1058                     }
1059                 }
1060             }
1061
1062             if(last_test != tests[index][TEST_NUM]) {
1063                 test_count++;
1064                 if(fail_flag)
1065                     fail_count++;
1066                 fail_flag = 0;
1067                 last_test = tests[index][TEST_NUM];
1068             }
1069                 
1070             index++;
1071         } else { /* CLIENT */
1072             if(debug > 2)
1073                 fprintf(stderr,"client: waiting...\n");
1074             /* wait for the server to do something */
1075             recv_ctl();
1076
1077             /* check for a client command */
1078             index = ctl.index;
1079             if (tests[index][WHO] != CLIENT) { 
1080                 fprintf(stderr, "not a client command index (%d)\n", index);
1081                 exit(1);
1082             }
1083                 
1084             if(ctl.test == 0) {
1085                 end = 1;
1086                 break;
1087             }
1088
1089             switch(ctl.command) {
1090                 case CMD_WRLOCK:
1091                     result = do_lock(F_SETLK, F_WRLCK, ctl.offset, ctl.length);
1092                     break;
1093                 case CMD_RDLOCK:
1094                     result = do_lock(F_SETLK, F_RDLCK, ctl.offset, ctl.length);
1095                     break;
1096                 case CMD_UNLOCK:
1097                     result = do_lock(F_SETLK, F_UNLCK, ctl.offset, ctl.length);
1098                     break;
1099                 case CMD_CLOSE:
1100                     result = do_close();
1101                     break;
1102                 case CMD_OPEN:
1103                     result = do_open(tests[index][FLAGS]);
1104                     break;
1105                 case CMD_WRTEST:
1106                     result = do_lock(F_GETLK, F_WRLCK, ctl.offset, ctl.length);
1107                     break;
1108                 case CMD_RDTEST:
1109                     result = do_lock(F_GETLK, F_RDLCK, ctl.offset, ctl.length);
1110                     break;
1111             }
1112             if( result != ctl.result ) {
1113                 if(debug)
1114                     fprintf(stderr,"Got %d, wanted %d\n",
1115                                 result, ctl.result);
1116                 ctl.result = FAIL;
1117                 ctl.error = saved_errno;
1118                 fail_count++;
1119             } else {
1120                 ctl.result = PASS;
1121                 ctl.error = 0;
1122             }
1123             if(debug > 2)
1124                 fprintf(stderr,"client: sending result to server (%d)\n", ctl.index);
1125             /* Send result to the server */
1126             send_ctl();
1127             if(last_test != tests[index][TEST_NUM]) {
1128                 test_count++;
1129                 last_test = tests[index][TEST_NUM];
1130             }
1131         }
1132     }
1133     if(server)
1134         printf("%d tests run, %d failed\n", test_count, fail_count);
1135 }   
1136     
1137     exit(fail_count);
1138     /*NOTREACHED*/
1139 }
1140
1141