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