| // SPDX-License-Identifier: GPL-2.0 | 
 | /* | 
 |  * Copyright (c) 2000-2003 Silicon Graphics, Inc. | 
 |  * Copyright (c) 2019 Intel Corp. | 
 |  * All Rights Reserved. | 
 |  */ | 
 |  | 
 | /* | 
 |  * Synchronized byte range lock and lease exerciser | 
 |  */ | 
 |  | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <malloc.h> | 
 | #include <fcntl.h> | 
 | #include <errno.h> | 
 | #include <string.h> | 
 | #include <sys/stat.h> | 
 | #include <sys/socket.h> | 
 | #include <netinet/in.h> | 
 | #include <netinet/tcp.h> | 
 |  | 
 | #include <unistd.h> | 
 | #include <sys/types.h> | 
 | #include <netdb.h> | 
 | #include <endian.h> | 
 | #include <byteswap.h> | 
 | #include <errno.h> | 
 | #include <string.h> | 
 | #include <signal.h> | 
 |  | 
 | #define     HEX_2_ASC(x)    ((x) > 9) ? (x)-10+'a' : (x)+'0' | 
 | #define 	FILE_SIZE	1024 | 
 | #define PLATFORM_INIT()     /*no-op*/ | 
 | #define PLATFORM_CLEANUP()  /*no-op*/ | 
 | #define LL                  "ll" | 
 |  | 
 | extern int h_errno; | 
 |  | 
 | #define inet_aton(STRING, INADDRP) \ | 
 |     (((INADDRP)->s_addr = inet_addr(STRING)) == -1 ? 0 : 1) | 
 |  | 
 | /* this assumes 32 bit pointers */ | 
 | #define PTR_TO_U64(P) ((unsigned __int64)(unsigned int)(P)) | 
 | #define U64_TO_PTR(T,U) ((T)(void *)(unsigned int)(U)) | 
 |  | 
 | #if __BYTE_ORDER == __LITTLE_ENDIAN | 
 | #define bswap_uint16(x)         (uint16_t)bswap_16(x) | 
 | #define bswap_uint32(x)         (uint32_t)bswap_32(x) | 
 | #define bswap_uint64(x)         (uint64_t)bswap_64(x) | 
 | #else | 
 | #define bswap_uint16(x)         x | 
 | #define bswap_uint32(x)         x | 
 | #define bswap_uint64(x)         x | 
 | #endif | 
 |  | 
 | #define SOCKET              int | 
 | #define SOCKET_READ         read | 
 | #define SOCKET_WRITE        write | 
 | #define SOCKET_CLOSE(S)     (close(S)) | 
 | #define INVALID_SOCKET      -1 | 
 |  | 
 | #define O_BINARY            0 | 
 |         | 
 | #define HANDLE              int | 
 | #define INVALID_HANDLE      -1 | 
 | #define SEEK(H, O)          (lseek(H, O, SEEK_SET)) | 
 | #define READ(H, B, L)       (read(H, B, L)) | 
 | #define WRITE(H, B, L)      (write(H, B, L)) | 
 | #define CLOSE(H)            (close(H)) | 
 |  | 
 | #define RAND()              (rand()) | 
 | #define SRAND(s)            (srand(s)) | 
 |  | 
 | #define MIN(A,B)            (((A)<(B))?(A):(B)) | 
 | #define MAX(A,B)            (((A)>(B))?(A):(B)) | 
 |  | 
 | #define ALLOC_ALIGNED(S)    (memalign(65536, S))  | 
 | #define FREE_ALIGNED(P)     (free(P))  | 
 |  | 
 | static char	*prog; | 
 | static char	*filename = 0; | 
 | static int	debug = 0; | 
 | static int	server = 1; | 
 | static int	port = 0; | 
 | static int 	testnumber = -1; | 
 | static int	saved_errno = 0; | 
 | static int      got_sigio = 0; | 
 |  | 
 | static SOCKET	s_fd = -1;              /* listen socket    */ | 
 | static SOCKET	c_fd = -1;	        /* IPC socket       */ | 
 | static HANDLE	f_fd = INVALID_HANDLE;	/* shared file      */ | 
 |  | 
 | #define 	CMD_WRLOCK	0 | 
 | #define 	CMD_RDLOCK	1 | 
 | #define		CMD_UNLOCK	2 | 
 | #define		CMD_CLOSE	3 | 
 | #define		CMD_OPEN	4 | 
 | #define		CMD_WRTEST	5 | 
 | #define		CMD_RDTEST	6 | 
 | #define 	CMD_SETLEASE	7 | 
 | #define 	CMD_GETLEASE	8 | 
 | #define		CMD_SIGIO	9 | 
 | #define		CMD_WAIT_SIGIO	10 | 
 | #define		CMD_TRUNCATE	11 | 
 |  | 
 | #define		PASS 	1 | 
 | #define		FAIL	0 | 
 |  | 
 | #define		SERVER	0 | 
 | #define		CLIENT	1 | 
 |  | 
 | #define		TEST_NUM	0 | 
 | #define		COMMAND		1 | 
 | #define		OFFSET		2 | 
 | #define		LENGTH		3 | 
 | #define		RESULT		4 | 
 | #define		WHO		5 | 
 | #define		FLAGS		2 /* index 2 is also used for do_open() flag, see below */ | 
 | #define		ARG		FLAGS /* Arguments for Lease operations */ | 
 | #define		TIME		FLAGS /* Time for waiting on sigio */ | 
 |  | 
 | static char *get_cmd_str(int cmd) | 
 | { | 
 | 	switch (cmd) { | 
 | 		case CMD_WRLOCK: return "write lock"; break; | 
 | 		case CMD_RDLOCK: return "read lock"; break; | 
 | 		case CMD_UNLOCK: return "unlock"; break; | 
 | 		case CMD_CLOSE:  return "close"; break; | 
 | 		case CMD_OPEN:   return "open"; break; | 
 | 		case CMD_WRTEST: return "Wait for SIGIO"; break; | 
 | 		case CMD_RDTEST: return "Truncate"; break; | 
 | 		case CMD_SETLEASE: return "Set Lease"; break; | 
 | 		case CMD_GETLEASE: return "Get Lease"; break; | 
 | 		case CMD_SIGIO:    return "Setup SIGIO"; break; | 
 | 		case CMD_WAIT_SIGIO: return "Wait for SIGIO"; break; | 
 | 		case CMD_TRUNCATE: return "Truncate"; break; | 
 | 	} | 
 | 	return "unknown"; | 
 | } | 
 | /*  | 
 |  * flags for Mac OS X do_open()  | 
 |  * O_RDONLY	0x0000 | 
 |  * O_WRONLY	0x0001	 | 
 |  * O_RDWR	0x0002 | 
 |  * O_NONBLOCK	0x0004	 | 
 |  * O_APPEND	0x0008 | 
 |  * O_SHLOCK	0x0010	 | 
 |  * O_EXLOCK	0x0020 | 
 |  * O_ASYNC	0x0040	 | 
 |  * O_FSYNC	0x0080 | 
 |  * O_NOFOLLOW  	0x0100   | 
 |  * O_CREAT	0x0200 | 
 |  * O_TRUNC	0x0400 | 
 |  * O_EXCL	0x0800 | 
 |  */ | 
 |  | 
 | /* | 
 |  * When adding tests be sure to add to both the descriptions AND tests array.  | 
 |  * Also, be sure to undo whatever is set for each test (eg unlock any locks) | 
 |  * There is no need to have a matching client command for each server command | 
 |  * (or vice versa) | 
 |  */ | 
 |  | 
 | char *lock_descriptions[] = { | 
 |     /* 1 */"Add a lock to an empty lock list", | 
 |     /* 2 */"Add a lock to the start and end of a list - no overlaps", | 
 |     /* 3 */"Add a lock to the middle of a list - no overlap", | 
 |     /* 4 */"Add different lock types to middle of the list - overlap exact match",  | 
 |     /* 5 */"Add new lock which completely overlaps any old lock in the list",  | 
 |     /* 6 */"Add new lock which itself is completely overlaped by any old lock in the list", | 
 |     /* 7 */"Add new lock which starts before any old lock in the list", | 
 |     /* 8 */"Add new lock which starts in the middle of any old lock in the list and ends after", | 
 |     /* 9 */"Add different new lock types which completely overlaps any old lock in the list", | 
 |     /* 10 */"Add different new locks which are completely overlaped by an old lock in the list", | 
 |     /* 11 */"Add different new lock types which start before the old lock in the list", | 
 |     /* 12 */"Add different new lock types which start in the middle of an old lock in the list and end after", | 
 |     /* 13 */"Add new lock, differing types and processes, to middle of the list - exact overlap match", | 
 |     /* 14 */"Add new lock, differing types and processes, which completely overlap any of the locks in the list", | 
 |     /* 15 */"Add new lock, differing types and processes, which are completely overlaped by locks in the list", | 
 |     /* 16 */"Add new lock, differing types and processes, which start before a lock in the list", | 
 |     /* 17 */"Add new lock, differing types and processes, which starts in the middle of a lock, and ends after", | 
 |     /* 18 */"Acquire write locks with overlapping ranges", | 
 |     /* 19 */"Acquire write locks with non-overlapping ranges extending beyond EOF", | 
 |     /* 20 */"Acquire write locks with overlapping ranges extending beyond EOF", | 
 |     /* 21 */"Acquire write locks on whole files", | 
 |     /* 22 */"Acquire write lock on whole file and range write lock", | 
 |     /* 23 */"Acquire read locks with non-overlapping ranges", | 
 |     /* 24 */"Acquire read locks with overlapping ranges", | 
 |     /* 25 */"Acquire read and write locks with no overlapping ranges", | 
 |     /* 26 */"Acquire read and write locks with overlapping ranges", | 
 |     /* 27 */"Acquire whole file write lock and then close without unlocking (and attempt a lock)", | 
 |     /* 28 */"Acquire two read locks, close and reopen the file, and test if the inital lock is still there", | 
 |     /* 29 */"Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write", | 
 |     #if defined(macosx) | 
 |     /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too", | 
 |     /* 31 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK", | 
 |     /* 32 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too" | 
 |     #endif | 
 | }; | 
 |  | 
 | static int64_t lock_tests[][6] = | 
 | 	/*	test #	Action	[offset|flags]	length		expected	server/client */ | 
 | 	{ 	 | 
 | 	/* Various simple tests exercising the list */ | 
 |  | 
 | /* SECTION 1: WRITE and CMD_UNLOCK with the same process (SERVER) */ | 
 | 	/* Add a lock to an empty list */ | 
 | 		{1,	CMD_WRLOCK,	1,		10,		PASS,		SERVER	}, | 
 | 		{1,	CMD_UNLOCK,	1,		10,		PASS,		SERVER	}, | 
 | 		 | 
 | 	/* Add a lock to the start and end of a list - 1, 13 - no overlap */ | 
 | 		{2,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{2,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{2,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		{2,	CMD_WRLOCK,	1,		5,		PASS,		SERVER	}, | 
 | 		{2,	CMD_WRLOCK,	70,		5,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{2,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{2,	CMD_UNLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{2,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		{2,	CMD_UNLOCK,	1,		5,		PASS,		SERVER	}, | 
 | 		{2,	CMD_UNLOCK,	70,		5,		PASS,		SERVER	}, | 
 | 		 | 
 | 	/* Add a lock to the middle of a list - no overlap */ | 
 | 		{3,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{3,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{3,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		{3,	CMD_WRLOCK,	42,		5,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{3,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{3,	CMD_UNLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{3,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		{3,	CMD_UNLOCK,	42,		5,		PASS,		SERVER	}, | 
 | 		 | 
 | 	/* Add different lock types to middle of the list - overlap exact match - 3 */ | 
 | 		{4,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{4,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{4,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* Exact match - same lock type */ | 
 | 		{4,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		/* Exact match - different lock type */ | 
 | 		{4,	CMD_RDLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		/* Exact match - unlock */ | 
 | 		{4,	CMD_UNLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		/* New lock - as above, inserting in the list again */ | 
 | 		{4,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{4,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{4,	CMD_UNLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{4,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		 | 
 | 	/* Add new lock which completely overlaps any old lock in the list - 4,5,6 */ | 
 | 		{5,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{5,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{5,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* The start is the same, end overlaps */ | 
 | 		{5,	CMD_WRLOCK,	30,		15,		PASS,		SERVER	}, | 
 | 		/* The start is before, end is the same */ | 
 | 		{5,	CMD_WRLOCK,	25,		20,		PASS,		SERVER	}, | 
 | 		/* Both start and end overlap */ | 
 | 		{5,	CMD_WRLOCK,	22,		26,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{5,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{5,	CMD_UNLOCK,	22,		26,		PASS,		SERVER	}, | 
 | 		{5,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		 | 
 | 	/* Add new lock which itself is completely overlaped by any old lock in the list - 7,8,10 */ | 
 | 		{6,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{6,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{6,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* The start is the same, end is in the middle of old lock - NOP */ | 
 | 		{6,	CMD_WRLOCK,	30,		5,		PASS,		SERVER	}, | 
 | 		/* The start and end are in the middle of old lock - NOP */ | 
 | 		{6,	CMD_WRLOCK,	32,		6,		PASS,		SERVER	}, | 
 | 		/* Start in the middle and end is the same - NOP */ | 
 | 		{6,	CMD_WRLOCK,	32,		8,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{6,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{6,	CMD_UNLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{6,	CMD_UNLOCK,	32,		8,		PASS,		SERVER	}, | 
 | 		{6,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		 | 
 | 	/* Add new lock which starts before any old lock in the list - 2,9 */ | 
 | 		{7,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{7,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{7,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* Here is the new lock */ | 
 | 		{7,	CMD_WRLOCK,	27,		10,		PASS,		SERVER	}, | 
 | 		/* Go again with the end of the new lock matching the start of old lock */ | 
 | 		{7,	CMD_WRLOCK,	25,		2,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{7,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{7,	CMD_UNLOCK,	25,		15,		PASS,		SERVER	}, | 
 | 		{7,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 	 | 
 | 	/* Add new lock which starts in the middle of any old lock in the list and ends after - 11,12 */ | 
 | 		{8,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{8,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{8,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* Here is the new lock */ | 
 | 		{8,	CMD_WRLOCK,	35,		10,		PASS,		SERVER	}, | 
 | 		/* Go again with the end of the new lock matching the start of old lock */ | 
 | 		{8,	CMD_WRLOCK,	45,		2,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{8,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{8,	CMD_UNLOCK,	30,		17,		PASS,		SERVER	}, | 
 | 		{8,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | /* SECTION 2: Overlapping READ and WRITE and CMD_UNLOCK with the same process (SERVER) */ | 
 | 	/* Add different new lock types which completely overlaps any old lock in the list - 4,5,6 */ | 
 | 		{9,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{9,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{9,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* The start is the same, end overlaps */ | 
 | 		{9,	CMD_RDLOCK,	30,		15,		PASS,		SERVER	}, | 
 | 		/* The start is before, end is the same */ | 
 | 		{9,	CMD_WRLOCK,	25,		20,		PASS,		SERVER	}, | 
 | 		/* Both start and end overlap */ | 
 | 		{9,	CMD_RDLOCK,	22,		26,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{9,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{9,	CMD_UNLOCK,	22,		26,		PASS,		SERVER	}, | 
 | 		{9,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		 | 
 | 	/* Add different new locks which are completely overlaped by an old lock in the list - 7,8,10 */ | 
 | 		{10,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{10,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{10,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* The start is the same, end is in the middle of old lock */ | 
 | 		{10,	CMD_RDLOCK,	30,		5,		PASS,		SERVER	}, | 
 | 		/* The start and end are in the middle of a lock */ | 
 | 		{10,	CMD_WRLOCK,	32,		2,		PASS,		SERVER	}, | 
 | 		/* Start in the middle and end is the same */ | 
 | 		{10,	CMD_RDLOCK,	36,		5,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{10,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{10,	CMD_UNLOCK,	30,		11,		PASS,		SERVER	}, | 
 | 		{10,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		 | 
 | 	/* Add different new lock types which start before the old lock in the list - 2,9 */ | 
 | 		{11,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{11,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{11,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* Here is the new lock */ | 
 | 		{11,	CMD_RDLOCK,	27,		10,		PASS,		SERVER	}, | 
 | 		/* Go again with the end of the new lock matching the start of lock */ | 
 | 		{11,	CMD_WRLOCK,	25,		3,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{11,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{11,	CMD_UNLOCK,	25,		15,		PASS,		SERVER	}, | 
 | 		{11,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 	 | 
 | 	/* Add different new lock types which start in the middle of an old lock in the list and end after - 11,12 */ | 
 | 		{12,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{12,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{12,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* Here is the new lock */ | 
 | 		{12,	CMD_RDLOCK,	35,		10,		PASS,		SERVER	}, | 
 | 		/* Go again with the end of the new lock matching the start of old lock */ | 
 | 		{12,	CMD_WRLOCK,	44,		3,		PASS,		SERVER	}, | 
 | 		 | 
 | 		{12,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{12,	CMD_UNLOCK,	30,		18,		PASS,		SERVER	}, | 
 | 		{12,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 |  | 
 | /* SECTION 3: Overlapping READ and WRITE and CMD_UNLOCK with the different processes (CLIENT/SERVER) */ | 
 | 	/* Add new lock, differing types and processes, to middle of the list - exact overlap match - 3 */ | 
 | 		{13,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{13,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{13,	CMD_RDLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* Same lock type, different process */ | 
 | 		{13,	CMD_WRLOCK,	30,		10,		FAIL,		CLIENT	}, | 
 | 		{13,	CMD_RDLOCK,	50,		10,		PASS,		CLIENT	}, | 
 | 		/* Exact match - different lock type, different process */ | 
 | 		{13,	CMD_RDLOCK,	30,		10,		FAIL,		CLIENT	}, | 
 | 		/* Exact match - unlock */ | 
 | 		{13,	CMD_UNLOCK,	30,		10,		PASS,		CLIENT	}, | 
 | 		/* New lock - as above, inserting in the list again */ | 
 | 		{13,	CMD_UNLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		/* Exact match - same lock type, different process */ | 
 | 		{13,	CMD_WRLOCK,	30,		10,		PASS,		CLIENT	}, | 
 | 		 | 
 | 		{13,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{13,	CMD_UNLOCK,	30,		10,		PASS,		CLIENT	}, | 
 | 		{13,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		 | 
 | 	/* Add new lock, differing types and processes, which completely overlap any of the locks in the list - 4,5,6 */ | 
 | 		{14,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{14,	CMD_WRLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{14,	CMD_RDLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* The start is the same, end overlaps */ | 
 | 		{14,	CMD_RDLOCK,	30,		15,		FAIL,		CLIENT	}, | 
 | 		{14,	CMD_WRLOCK,	30,		15,		FAIL,		CLIENT	}, | 
 | 		/* The start is before, end is the same */ | 
 | 		{14,	CMD_RDLOCK,	25,		20,		FAIL,		CLIENT	}, | 
 | 		{14,	CMD_WRLOCK,	25,		20,		FAIL,		CLIENT	}, | 
 | 		/* Both start and end overlap */ | 
 | 		{14,	CMD_RDLOCK,	22,		26,		FAIL,		CLIENT	}, | 
 | 		{14,	CMD_WRLOCK,	22,		26,		FAIL,		CLIENT	}, | 
 | 		 | 
 | 		/* The start is the same, end overlaps */ | 
 | 		{14,	CMD_RDLOCK,	50,		15,		PASS,		CLIENT	}, | 
 | 		{14,	CMD_WRLOCK,	50,		17,		FAIL,		CLIENT	}, | 
 | 		/* The start is before, end is the same */ | 
 | 		{14,	CMD_RDLOCK,	45,		20,		PASS,		CLIENT	}, | 
 | 		{14,	CMD_WRLOCK,	43,		22,		FAIL,		CLIENT	}, | 
 | 		/* Both start and end overlap */ | 
 | 		{14,	CMD_RDLOCK,	42,		26,		PASS,		CLIENT	}, | 
 | 		{14,	CMD_WRLOCK,	41,		28,		FAIL,		CLIENT	}, | 
 | 		 | 
 | 		{14,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{14,	CMD_UNLOCK,	22,		26,		PASS,		SERVER	}, | 
 | 		{14,	CMD_UNLOCK,	42,		26,		PASS,		CLIENT	}, | 
 |  | 
 | 	/* Add new lock, differing types and processes, which are completely overlaped by an old lock in the list - 7,8,10 */ | 
 | 		{15,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{15,	CMD_RDLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{15,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* The start is the same, end is in the middle of old lock */ | 
 | 		{15,	CMD_RDLOCK,	50,		5,		FAIL,		CLIENT	}, | 
 | 		{15,	CMD_WRLOCK,	50,		5,		FAIL,		CLIENT	}, | 
 | 		/* The start and end are in the middle of old lock */ | 
 | 		{15,	CMD_RDLOCK,	52,		6,		FAIL,		CLIENT	}, | 
 | 		{15,	CMD_WRLOCK,	52,		6,		FAIL,		CLIENT	}, | 
 | 		/* Start in the middle and end is the same */ | 
 | 		{15,	CMD_RDLOCK,	52,		8,		FAIL,		CLIENT	}, | 
 | 		{15,	CMD_WRLOCK,	52,		8,		FAIL,		CLIENT	}, | 
 | 		/* The start is the same, end is in the middle of old lock */ | 
 | 		{15,	CMD_RDLOCK,	30,		5,		PASS,		CLIENT	}, | 
 | 		{15,	CMD_WRLOCK,	30,		5,		FAIL,		CLIENT	}, | 
 | 		/* The start and end are in the middle of old lock */ | 
 | 		{15,	CMD_RDLOCK,	32,		6,		PASS,		CLIENT	}, | 
 | 		{15,	CMD_WRLOCK,	32,		6,		FAIL,		CLIENT	}, | 
 | 		/* Start in the middle and end is the same */ | 
 | 		{15,	CMD_RDLOCK,	32,		8,		PASS,		CLIENT	}, | 
 | 		{15,	CMD_WRLOCK,	32,		8,		FAIL,		CLIENT	}, | 
 | 		 | 
 | 		{15,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{15,	CMD_UNLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{15,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 	/* Add new lock, differing types and processes, which start before a lock in the list - 2,9 */ | 
 | 		{16,	CMD_RDLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{16,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* Start is before, end is the start of the old lock in list */ | 
 | 		{16,	CMD_RDLOCK,	5,		6,		PASS,		CLIENT	}, | 
 | 		{16,	CMD_WRLOCK,	5,		6,		FAIL,		CLIENT	}, | 
 | 		/* Start is before, end is in the middle of the old lock */ | 
 | 		{16,	CMD_RDLOCK,	5,		10,		PASS,		CLIENT	}, | 
 | 		{16,	CMD_WRLOCK,	5,		10,		FAIL,		CLIENT	}, | 
 | 		/* Start is before, end is the start of the old lock in list */ | 
 | 		{16,	CMD_RDLOCK,	45,		6,		FAIL,		CLIENT	}, | 
 | 		{16,	CMD_WRLOCK,	45,		6,		FAIL,		CLIENT	}, | 
 | 		/* Start is before, end is in the middle of the old lock */ | 
 | 		{16,	CMD_RDLOCK,	45,		10,		FAIL,		CLIENT	}, | 
 | 		{16,	CMD_WRLOCK,	45,		10,		FAIL,		CLIENT	}, | 
 | 		 | 
 | 		{16,	CMD_UNLOCK,	5,		15,		PASS,		CLIENT	}, | 
 | 		{16,	CMD_UNLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{16,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 |  | 
 | 	/* Add new lock, differing types and processes, which starts in the middle of a lock, and ends after - 11,12 */ | 
 | 		{17,	CMD_WRLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{17,	CMD_RDLOCK,	30,		10,		PASS,		SERVER	}, | 
 | 		{17,	CMD_WRLOCK,	50,		10,		PASS,		SERVER	}, | 
 | 		/* Start in the middle, end after lock in list */ | 
 | 		{17,	CMD_WRLOCK,	35,		10,		FAIL,		CLIENT	}, | 
 | 		/* Start matches end of lock in list  */ | 
 | 		{17,	CMD_RDLOCK,	35,		10,		PASS,		CLIENT	}, | 
 | 		{17,	CMD_RDLOCK,	44,		2,		PASS,		CLIENT	}, | 
 | 		/* Start in the middle, end after lock in list */ | 
 | 		{17,	CMD_RDLOCK,	55,		10,		FAIL,		CLIENT	}, | 
 | 		{17,	CMD_WRLOCK,	55,		10,		FAIL,		CLIENT	}, | 
 | 		/* Start matches end of lock in list  */ | 
 | 		{17,	CMD_RDLOCK,	59,		5,		FAIL,		CLIENT	}, | 
 | 		{17,	CMD_WRLOCK,	59,		5,		FAIL,		CLIENT	}, | 
 | 		 | 
 | 		{17,	CMD_UNLOCK,	10,		10,		PASS,		SERVER	}, | 
 | 		{17,	CMD_UNLOCK,	30,		16,		PASS,		CLIENT	}, | 
 | 		{17,	CMD_UNLOCK,	50,		10,		PASS,		SERVER	}, | 
 |  | 
 | /* SECTION 4: overlapping and EOF tests */ | 
 | 	/* Acquire overlapping ranges */ | 
 | 		{18,	CMD_WRLOCK,	11,		7,		PASS,		SERVER	}, | 
 | 		{18,	CMD_WRLOCK,	13,		8,		FAIL,		CLIENT	}, | 
 | 		{18,	CMD_UNLOCK,	11,		7,		PASS,		SERVER	}, | 
 | 	/* Acquire different ranges beyond EOF */ | 
 | 		{19,	CMD_WRLOCK,	10,		FILE_SIZE,	PASS,		SERVER	}, | 
 | 		{19,	CMD_WRLOCK,	FILE_SIZE + 10,	10,		PASS,		CLIENT	}, | 
 | 		{19,	CMD_UNLOCK,	10,		FILE_SIZE,	PASS,		SERVER	}, | 
 | 		{19,	CMD_UNLOCK,	FILE_SIZE + 10,	10,		PASS,		CLIENT	}, | 
 | 	/* Acquire same range beyong EOF */ | 
 | 		{20,	CMD_WRLOCK,	10,		FILE_SIZE,	PASS,		SERVER,	}, | 
 | 		{20,	CMD_WRLOCK,	10,		FILE_SIZE,	FAIL,		CLIENT,	}, | 
 | 		{20,	CMD_UNLOCK,	10,		FILE_SIZE,	PASS,		SERVER,	}, | 
 | 	/* Acquire whole file lock */ | 
 | 		{21,	CMD_WRLOCK,	0,		0,		PASS,		SERVER,	}, | 
 | 		{21,	CMD_WRLOCK,	0,		0,		FAIL,		CLIENT,	}, | 
 | 		{21,	CMD_UNLOCK,	0,		0,		PASS,		SERVER,	}, | 
 | 	/* Acquire whole file lock, then range */ | 
 | 		{22,	CMD_WRLOCK,	0,		0,		PASS,		SERVER,	}, | 
 | 		{22,	CMD_WRLOCK,	1,		5,		FAIL,		CLIENT,	}, | 
 | 		{22,	CMD_UNLOCK,	0,		0,		PASS,		SERVER,	}, | 
 | 	/* Acquire non-overlapping read locks */ | 
 | 		{23,	CMD_RDLOCK, 1,		5,		PASS,		SERVER, }, | 
 | 		{23,	CMD_RDLOCK, 7,		6,		PASS,		CLIENT, }, | 
 | 		{23,	CMD_UNLOCK, 1, 		5,		PASS,		SERVER, }, | 
 | 		{23,	CMD_UNLOCK, 7,		6,		PASS,		CLIENT, }, | 
 | 	/* Acquire overlapping read locks */ | 
 | 		{24,	CMD_RDLOCK, 1,		5,		PASS,		SERVER, }, | 
 | 		{24,	CMD_RDLOCK, 2,		6,		PASS,		CLIENT, }, | 
 | 		{24,	CMD_UNLOCK, 1, 		5,		PASS,		SERVER, }, | 
 | 		{24,	CMD_UNLOCK, 1,		7,		PASS,		CLIENT, }, | 
 | 	/* Acquire non-overlapping read and write locks */ | 
 | 		{25,	CMD_RDLOCK, 1,		5,		PASS,		SERVER, }, | 
 | 		{25,	CMD_WRLOCK, 7,		6,		PASS,		CLIENT, }, | 
 | 		{25,	CMD_UNLOCK, 1, 		5,		PASS,		SERVER, }, | 
 | 		{25,	CMD_UNLOCK, 7,		6,		PASS,		CLIENT, }, | 
 | 	/* Acquire overlapping read and write locks */ | 
 | 		{26,	CMD_RDLOCK, 1,		5,		PASS,		SERVER, }, | 
 | 		{26,	CMD_WRLOCK, 2,		6,		FAIL,		CLIENT, }, | 
 | 		{26,	CMD_UNLOCK, 1, 		5,		PASS,		SERVER, }, | 
 | 	/* Acquire whole file lock, then close (without unlocking) */ | 
 | 		{27,	CMD_WRLOCK,	0,		0,		PASS,		SERVER,	}, | 
 | 		{27,	CMD_WRLOCK,	1,		5,		FAIL,		CLIENT,	}, | 
 | 		{27,	CMD_CLOSE,0,		0,		PASS,		SERVER,	}, | 
 | 		{27,	CMD_WRLOCK,	1,		5,		PASS,		CLIENT,	}, | 
 | 		{27,	CMD_OPEN,	O_RDWR,		0,		PASS,		SERVER,	}, | 
 | 		{27,	CMD_UNLOCK,	1,		5,		PASS,		CLIENT,	}, | 
 | 	/* Acquire two read locks, close one file and then reopen to check that first lock still exists */ | 
 | 		{28,	CMD_RDLOCK,	1,		5,		PASS,		SERVER,	}, | 
 | 		{28,	CMD_RDLOCK,	1,		5,		PASS,		CLIENT,	}, | 
 | 		{28,	CMD_CLOSE,0,		0,		PASS,		SERVER,	}, | 
 | 		{28,	CMD_OPEN,	O_RDWR,		0,		PASS,		SERVER,	}, | 
 | 		{28,	CMD_WRLOCK,	0,		0,		FAIL,		SERVER,	}, | 
 | 		{28,	CMD_UNLOCK,	1,		5,		PASS,		SERVER,	}, | 
 | 	/* Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write */ | 
 | 		{29,	CMD_CLOSE, 0,		0,		PASS,		SERVER, }, | 
 | 		{29,	CMD_OPEN, O_RDONLY,	0,		PASS,		SERVER, }, | 
 | 		{29,	CMD_WRTEST, 0,		0,		PASS,		SERVER, }, | 
 | 		{29,	CMD_CLOSE,0,		0,		PASS,		SERVER,	}, | 
 | 		{29,	CMD_OPEN,	O_RDWR,		0,		PASS,		SERVER,	}, | 
 | #ifdef macosx | 
 | 	/* Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too */ | 
 | 		{30,	CMD_CLOSE,0,		0,		PASS,		SERVER,	}, | 
 | 		{30,	CMD_OPEN,	O_RDWR|O_SHLOCK|O_NONBLOCK,	0,	PASS,		SERVER,	}, | 
 | 		{30,	CMD_CLOSE,0,		0,		PASS,		CLIENT,	}, | 
 | 		{30,	CMD_OPEN,	O_RDWR|O_SHLOCK|O_NONBLOCK,	0,	PASS,		CLIENT,	}, | 
 | 	/* Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK */ | 
 | 		{31,	CMD_CLOSE,0,		0,		PASS,		SERVER,	}, | 
 | 		{31,	CMD_CLOSE,0,		0,		PASS,		CLIENT,	}, | 
 | 		{31,	CMD_OPEN,	O_RDWR|O_SHLOCK|O_NONBLOCK,	0,	PASS,		SERVER,	}, | 
 | 		{31,	CMD_OPEN,	O_RDWR|O_EXLOCK|O_NONBLOCK,	0,	FAIL,		CLIENT,	}, | 
 | 	/* Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too */ | 
 | 		{32,	CMD_CLOSE,0,		0,		PASS,		SERVER,	}, | 
 | 		{32,	CMD_CLOSE,0,		0,		FAIL,		CLIENT,	}, | 
 | 		{32,	CMD_OPEN,	O_RDWR|O_EXLOCK|O_NONBLOCK,	0,	PASS,		SERVER,	}, | 
 | 		{32,	CMD_OPEN,	O_RDWR|O_EXLOCK|O_NONBLOCK,	0,	FAIL,		CLIENT,	}, | 
 | 		{32,	CMD_CLOSE,0,		0,		PASS,		SERVER,	}, | 
 | 		{32,	CMD_CLOSE,0,		0,		FAIL,		CLIENT,	}, | 
 | 		{32,	CMD_OPEN,	O_RDWR,		0,		PASS,		SERVER,	}, | 
 | 		{32,	CMD_OPEN,	O_RDWR,		0,		PASS,		CLIENT,	}, | 
 | #endif /* macosx */ | 
 |  | 
 | 	/* indicate end of array */ | 
 | 		{0,0,0,0,0,SERVER}, | 
 | 		{0,0,0,0,0,CLIENT} | 
 | 	}; | 
 |  | 
 |  | 
 | char *lease_descriptions[] = { | 
 |     /*  1 */"Take Read Lease", | 
 |     /*  2 */"Take Write Lease", | 
 |     /*  3 */"Fail Write Lease if file is open somewhere else", | 
 |     /*  4 */"Fail Read Lease if opened with write permissions", | 
 |     /*  5 */"Read lease gets SIGIO on write open", | 
 |     /*  6 */"Write lease gets SIGIO on read open", | 
 |     /*  7 */"Read lease does _not_ get SIGIO on read open", | 
 |     /*  8 */"Read lease gets SIGIO on write open", | 
 |     /*  9 */"Write lease gets SIGIO on truncate", | 
 |     /* 10 */"Read lease gets SIGIO on truncate", | 
 | }; | 
 |  | 
 | static int64_t lease_tests[][6] = | 
 | 	/*	test #	Action	[offset|flags|arg]	length		expected	server/client */ | 
 | 	/*			[sigio_wait_time]						*/ | 
 | 	{ | 
 | 	/* Various tests to exercise leases */ | 
 |  | 
 | /* SECTION 1: Simple verification of being able to take leases */ | 
 | 	/* Take Read Lease */ | 
 | 		{1,	CMD_CLOSE,	0,		0,	PASS,		CLIENT	}, | 
 | 		{1,	CMD_OPEN,	O_RDONLY,	0,	PASS,		CLIENT	}, | 
 | 		{1,	CMD_CLOSE,	0,		0,	PASS,		SERVER	}, | 
 | 		{1,	CMD_OPEN,	O_RDONLY,	0,	PASS,		SERVER	}, | 
 | 		{1,	CMD_SETLEASE,	F_RDLCK,	0,	PASS,		SERVER	}, | 
 | 		{1,	CMD_GETLEASE,	F_RDLCK,	0,	PASS,		SERVER	}, | 
 | 		{1,	CMD_SETLEASE,	F_UNLCK,	0,	PASS,		SERVER	}, | 
 | 		{1,	CMD_CLOSE,	0,		0,	PASS,		SERVER	}, | 
 | 		{1,	CMD_CLOSE,	0,		0,	PASS,		CLIENT	}, | 
 |  | 
 | 	/* Take Write Lease */ | 
 | 		{2,	CMD_OPEN,	O_RDWR,		0,	PASS,		SERVER	}, | 
 | 		{2,	CMD_SETLEASE,	F_WRLCK,	0,	PASS,		SERVER	}, | 
 | 		{2,	CMD_GETLEASE,	F_WRLCK,	0,	PASS,		SERVER	}, | 
 | 		{2,	CMD_SETLEASE,	F_UNLCK,	0,	PASS,		SERVER	}, | 
 | 		{2,	CMD_CLOSE,	0,		0,	PASS,		SERVER	}, | 
 | 	/* Fail Write Lease with other users */ | 
 | 		{3,	CMD_OPEN,	O_RDONLY,	0,	PASS,		CLIENT  }, | 
 | 		{3,	CMD_OPEN,	O_RDWR,		0,	PASS,		SERVER	}, | 
 | 		{3,	CMD_SETLEASE,	F_WRLCK,	0,	FAIL,		SERVER	}, | 
 | 		{3,	CMD_GETLEASE,	F_WRLCK,	0,	FAIL,		SERVER	}, | 
 | 		{3,	CMD_CLOSE,	0,		0,	PASS,		SERVER	}, | 
 | 		{3,	CMD_CLOSE,	0,		0,	PASS,		CLIENT	}, | 
 | 	/* Fail Read Lease if opened for write */ | 
 | 		{4,	CMD_OPEN,	O_RDWR,		0,	PASS,		SERVER	}, | 
 | 		{4,	CMD_SETLEASE,	F_RDLCK,	0,	FAIL,		SERVER	}, | 
 | 		{4,	CMD_GETLEASE,	F_RDLCK,	0,	FAIL,		SERVER	}, | 
 | 		{4,	CMD_CLOSE,	0,		0,	PASS,		SERVER	}, | 
 |  | 
 | /* SECTION 2: Proper SIGIO notifications */ | 
 | 	/* Get SIGIO when read lease is broken by write */ | 
 | 		{5,	CMD_OPEN,	O_RDONLY,	0,	PASS,		CLIENT	}, | 
 | 		{5,	CMD_SETLEASE,	F_RDLCK,	0,	PASS,		CLIENT	}, | 
 | 		{5,	CMD_GETLEASE,	F_RDLCK,	0,	PASS,		CLIENT	}, | 
 | 		{5,	CMD_SIGIO,	0,		0,	PASS,		CLIENT	}, | 
 | 		{5,	CMD_OPEN,	O_RDWR,		0,	PASS,		SERVER	}, | 
 | 		{5,	CMD_WAIT_SIGIO,	5,		0,	PASS,		CLIENT	}, | 
 | 		{5,	CMD_CLOSE,	0,		0,	PASS,		SERVER	}, | 
 | 		{5,	CMD_CLOSE,	0,		0,	PASS,		CLIENT	}, | 
 |  | 
 | 	/* Get SIGIO when write lease is broken by read */ | 
 | 		{6,	CMD_OPEN,	O_RDWR,		0,	PASS,		CLIENT	}, | 
 | 		{6,	CMD_SETLEASE,	F_WRLCK,	0,	PASS,		CLIENT	}, | 
 | 		{6,	CMD_GETLEASE,	F_WRLCK,	0,	PASS,		CLIENT	}, | 
 | 		{6,	CMD_SIGIO,	0,		0,	PASS,		CLIENT	}, | 
 | 		{6,	CMD_OPEN,	O_RDONLY,	0,	PASS,		SERVER	}, | 
 | 		{6,	CMD_WAIT_SIGIO,	5,		0,	PASS,		CLIENT	}, | 
 | 		{6,	CMD_CLOSE,	0,		0,	PASS,		SERVER	}, | 
 | 		{6,	CMD_CLOSE,	0,		0,	PASS,		CLIENT	}, | 
 |  | 
 | 	/* Don't get SIGIO when read lease is taken by read */ | 
 | 		{7,	CMD_OPEN,	O_RDONLY,	0,	PASS,		CLIENT	}, | 
 | 		{7,	CMD_SETLEASE,	F_RDLCK,	0,	PASS,		CLIENT	}, | 
 | 		{7,	CMD_GETLEASE,	F_RDLCK,	0,	PASS,		CLIENT	}, | 
 | 		{7,	CMD_SIGIO,	0,		0,	PASS,		CLIENT	}, | 
 | 		{7,	CMD_OPEN,	O_RDONLY,	0,	PASS,		SERVER	}, | 
 | 		{7,	CMD_WAIT_SIGIO,	5,		0,	FAIL,		CLIENT	}, | 
 | 		{7,	CMD_CLOSE,	0,		0,	PASS,		SERVER	}, | 
 | 		{7,	CMD_CLOSE,	0,		0,	PASS,		CLIENT	}, | 
 |  | 
 | 	/* Get SIGIO when Read lease is broken by Write */ | 
 | 		{8,	CMD_OPEN,	O_RDONLY,	0,	PASS,		CLIENT	}, | 
 | 		{8,	CMD_SETLEASE,	F_RDLCK,	0,	PASS,		CLIENT	}, | 
 | 		{8,	CMD_GETLEASE,	F_RDLCK,	0,	PASS,		CLIENT	}, | 
 | 		{8,	CMD_SIGIO,	0,		0,	PASS,		CLIENT	}, | 
 | 		{8,	CMD_OPEN,	O_RDWR,		0,	PASS,		SERVER	}, | 
 | 		{8,	CMD_WAIT_SIGIO,	5,		0,	PASS,		CLIENT	}, | 
 | 		{8,	CMD_CLOSE,	0,		0,	PASS,		SERVER	}, | 
 | 		{8,	CMD_CLOSE,	0,		0,	PASS,		CLIENT	}, | 
 |  | 
 | 	/* Get SIGIO when Write lease is broken by Truncate */ | 
 | 		{9,	CMD_OPEN,	O_RDWR,		0,	PASS,		CLIENT	}, | 
 | 		{9,	CMD_SETLEASE,	F_WRLCK,	0,	PASS,		CLIENT	}, | 
 | 		{9,	CMD_GETLEASE,	F_WRLCK,	0,	PASS,		CLIENT	}, | 
 | 		{9,	CMD_SIGIO,	0,		0,	PASS,		CLIENT	}, | 
 | 		{9,	CMD_TRUNCATE,	FILE_SIZE/2,	0,	PASS,		CLIENT	}, | 
 | 		{9,	CMD_WAIT_SIGIO,	5,		0,	PASS,		CLIENT	}, | 
 | 		{9,	CMD_CLOSE,	0,		0,	PASS,		CLIENT	}, | 
 |  | 
 | 	/* Get SIGIO when Read lease is broken by Truncate */ | 
 | 		{10,	CMD_OPEN,	O_RDONLY,	0,	PASS,		CLIENT	}, | 
 | 		{10,	CMD_SETLEASE,	F_RDLCK,	0,	PASS,		CLIENT	}, | 
 | 		{10,	CMD_GETLEASE,	F_RDLCK,	0,	PASS,		CLIENT	}, | 
 | 		{10,	CMD_SIGIO,	0,		0,	PASS,		CLIENT	}, | 
 | 		{10,	CMD_TRUNCATE,	FILE_SIZE/2,	0,	PASS,		SERVER	}, | 
 | 		{10,	CMD_WAIT_SIGIO,	5,		0,	PASS,		CLIENT	}, | 
 | 		{10,	CMD_CLOSE,	0,		0,	PASS,		CLIENT	}, | 
 |  | 
 |  | 
 | 	/* indicate end of array */ | 
 | 		{0,0,0,0,0,SERVER}, | 
 | 		{0,0,0,0,0,CLIENT} | 
 | 	}; | 
 |  | 
 | static struct { | 
 |     int32_t		test; | 
 |     int32_t		command; | 
 |     int64_t	        offset; | 
 |     int64_t		length; | 
 |     int32_t		result; | 
 |     int32_t		index; | 
 |     int32_t		error; | 
 |     int32_t		padding; /* So mac and irix have the same size struct (bloody alignment) */ | 
 | } ctl; | 
 |  | 
 |  | 
 | void | 
 | usage(void) | 
 | { | 
 |     fprintf(stderr, "Usage: %s [options] sharedfile\n\ | 
 | \n\ | 
 | options:\n\ | 
 |   -p port	TCP/IP port number for client-server communication\n\ | 
 |   -d		enable debug tracing\n\ | 
 |   -n #		test number to run\n\ | 
 |   -h host	run as client and connect to server on remote host\n\ | 
 |   		[default run as server]\n", prog); | 
 |     exit(1); | 
 | } | 
 |  | 
 | #define INIT_BUFSZ 512  | 
 |  | 
 | void | 
 | initialize(HANDLE fd) | 
 | { | 
 |     char*	ibuf; | 
 |     int		j=0; | 
 |     int		nwrite; | 
 |     int 	offset = 0; | 
 |     int 	togo = FILE_SIZE; | 
 |  | 
 |     ibuf = (char*)malloc(INIT_BUFSZ); | 
 |     memset(ibuf, ':', INIT_BUFSZ); | 
 |  | 
 |     SEEK(fd, 0L); | 
 |     while (togo) { | 
 | 	offset+=j; | 
 | 	j = togo > INIT_BUFSZ ? INIT_BUFSZ : togo; | 
 |  | 
 | 	if ((nwrite = WRITE(fd, ibuf, j)) != j) { | 
 | 	    if (nwrite < 0) | 
 | 		perror("initialize write:"); | 
 | 	    else | 
 | 		fprintf(stderr, "initialize: write() returns %d, not %d as expected\n",  | 
 |                         nwrite, j); | 
 | 	    exit(1); | 
 | 	    /*NOTREACHED*/ | 
 | 	} | 
 | 	togo -= j; | 
 |     } | 
 | } | 
 |  | 
 | static int do_truncate(size_t length) | 
 | { | 
 |     int rc; | 
 |  | 
 |     if (debug) | 
 | 	fprintf(stderr, "truncating to %ld\n", length); | 
 |  | 
 | again: | 
 |     rc = truncate(filename, length); | 
 |     if (rc && errno == EINTR) | 
 | 	goto again; | 
 |  | 
 |     saved_errno = errno; | 
 |  | 
 |     if (rc) | 
 | 	fprintf(stderr, "%s %d : %s\n", | 
 | 		__FILE__, errno, strerror(errno)); | 
 |  | 
 |     return (rc == 0 ? PASS:FAIL); | 
 | } | 
 |  | 
 | void release_lease(int fd) | 
 | { | 
 | 	int rc; | 
 |  | 
 | 	rc = fcntl(fd, F_SETLEASE, F_UNLCK); | 
 | 	if (rc != 0) | 
 | 		fprintf(stderr, "%s Failed to remove lease %d : %d %s\n", | 
 | 			__FILE__, rc, errno, strerror(errno)); | 
 | } | 
 |  | 
 | void lease_break(int sig, siginfo_t *info, void *p) | 
 | { | 
 |     if (debug) | 
 | 	fprintf(stderr, "lease break %d %p fd %d\n", | 
 | 		sig, info, info->si_fd); | 
 |     got_sigio = 1; | 
 |     release_lease(f_fd); | 
 | } | 
 |  | 
 | struct sigaction lease_break_action = { | 
 | 	.sa_sigaction = lease_break, | 
 | 	.sa_flags = SA_SIGINFO, | 
 | }; | 
 |  | 
 | int do_setup_sigio(int fd) | 
 | { | 
 | 	int rc; | 
 |  | 
 | 	got_sigio = 0; | 
 |  | 
 | 	rc = sigaction(SIGIO, &lease_break_action, NULL); | 
 | 	if (rc != 0) { | 
 | 		fprintf(stderr, "%s Set '%s' sigaction failed %d\n", | 
 | 			__FILE__, strsignal(SIGIO), rc); | 
 | 		return FAIL; | 
 | 	} | 
 |  | 
 | 	if (debug) | 
 | 		fprintf(stderr, "Set '%s' sigaction on %d\n", | 
 | 			strsignal(SIGIO), fd); | 
 |  | 
 | 	rc = fcntl(fd, F_SETSIG, SIGIO); | 
 | 	if (rc) | 
 | 		fprintf(stderr, "%s Set '%s' sigaction failed %d\n", | 
 | 			__FILE__, strsignal(SIGIO), rc); | 
 |  | 
 | 	return (rc == 0 ? PASS : FAIL); | 
 | } | 
 |  | 
 | int do_wait_sigio(int32_t time) | 
 | { | 
 |     if (time <= 0) | 
 | 	return FAIL; | 
 |  | 
 |     while (!got_sigio && time--) { | 
 | 	sleep(1); | 
 |     } | 
 |  | 
 |     if (debug > 1 && !got_sigio) | 
 | 	fprintf(stderr, "%s failed to get sigio\n", | 
 | 		__FILE__); | 
 |  | 
 |     return (got_sigio ? PASS: FAIL); | 
 | } | 
 |  | 
 | int do_open(int flag) | 
 | { | 
 |     int flags = flag|O_CREAT|O_BINARY; | 
 |  | 
 |     if(debug > 1) | 
 | 	fprintf(stderr, "do_open %s 0x%x\n", filename, flags); | 
 |  | 
 |     if ((f_fd = open(filename, flags, 0666)) == INVALID_HANDLE) { | 
 | 	perror("shared file create"); | 
 | 	return FAIL; | 
 | 	/*NOTREACHED*/ | 
 |     } | 
 |     return PASS; | 
 | } | 
 |  | 
 | static int do_lock(int cmd, int type, int start, int length) | 
 | { | 
 |     int ret; | 
 |     int filedes = f_fd; | 
 |     struct flock fl; | 
 |  | 
 |     if(debug > 1) { | 
 | 	fprintf(stderr, "do_lock: cmd=%d type=%d start=%d, length=%d\n", cmd, type, start, length); | 
 |     } | 
 |  | 
 |     if (f_fd < 0) | 
 | 	return f_fd; | 
 |      | 
 |     fl.l_start = start; | 
 |     fl.l_len = length; | 
 |     fl.l_whence = SEEK_SET; | 
 |     fl.l_pid = getpid(); | 
 |     fl.l_type = type; | 
 |  | 
 |     errno = 0; | 
 |  | 
 |     ret = fcntl(filedes, cmd, &fl); | 
 |     saved_errno = errno;	     | 
 |  | 
 |     if(ret) | 
 | 	fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno)); | 
 |  | 
 |     return(ret==0?PASS:FAIL); | 
 | } | 
 |  | 
 | static int do_lease(int cmd, int arg, int expected) | 
 | { | 
 |     int ret; | 
 |  | 
 |     if(debug > 1) | 
 | 	fprintf(stderr, "do_lease: cmd=%d arg=%d exp=%X\n", | 
 | 		cmd, arg, expected); | 
 |  | 
 |     if (f_fd < 0) | 
 | 	return f_fd; | 
 |  | 
 |     errno = 0; | 
 |  | 
 |     ret = fcntl(f_fd, cmd, arg); | 
 |     saved_errno = errno; | 
 |  | 
 |     if (expected && (expected == ret)) | 
 | 	ret = 0; | 
 |  | 
 |     if(ret) | 
 | 	fprintf(stderr, "%s do_lease: ret = %d, errno = %d (%s)\n", | 
 | 		__FILE__, ret, errno, strerror(errno)); | 
 |  | 
 |     return(ret==0?PASS:FAIL); | 
 | } | 
 |  | 
 | int do_close(void) | 
 | {	 | 
 |     if(debug > 1) { | 
 | 	fprintf(stderr, "do_close\n"); | 
 |     } | 
 |  | 
 |     errno =0; | 
 |     CLOSE(f_fd); | 
 |     f_fd = INVALID_HANDLE; | 
 |  | 
 |     saved_errno = errno;	     | 
 | 	 | 
 |     if (errno) { | 
 | 	fprintf(stderr, "%s errno = %d (%s)\n", | 
 | 		__FILE__, errno, strerror(errno)); | 
 | 	return FAIL; | 
 |     } | 
 |     return PASS; | 
 | } | 
 |  | 
 | static void init_ctl(int64_t tests[][6], int32_t index) | 
 | { | 
 |     ctl.test= (int32_t)tests[index][TEST_NUM]; | 
 |     ctl.command = (int32_t)tests[index][COMMAND]; | 
 |     ctl.offset = tests[index][OFFSET]; | 
 |     ctl.length = tests[index][LENGTH]; | 
 |     ctl.index = index; | 
 |     ctl.result = (int32_t)tests[index][RESULT]; | 
 |     ctl.error = 0; | 
 | } | 
 |  | 
 | void | 
 | send_ctl(void) | 
 | { | 
 |     int         nwrite; | 
 |  | 
 |     if (debug) { | 
 | 	fprintf(stderr, "send_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",  | 
 |                 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length,ctl.result, ctl.error); | 
 |     } | 
 |  | 
 |     ctl.test= bswap_uint32(ctl.test); | 
 |     ctl.command = bswap_uint32(ctl.command); | 
 |     ctl.offset = bswap_uint64(ctl.offset); | 
 |     ctl.length = bswap_uint64(ctl.length); | 
 |     ctl.result = bswap_uint32(ctl.result); | 
 |     ctl.index= bswap_uint32(ctl.index); | 
 |     ctl.error = bswap_uint32(ctl.error); | 
 |     nwrite = SOCKET_WRITE(c_fd, (char*)&ctl, sizeof(ctl)); | 
 |  | 
 |     ctl.test= bswap_uint32(ctl.test); | 
 |     ctl.command = bswap_uint32(ctl.command); | 
 |     ctl.offset = bswap_uint64(ctl.offset); | 
 |     ctl.length = bswap_uint64(ctl.length); | 
 |     ctl.result = bswap_uint32(ctl.result); | 
 |     ctl.index= bswap_uint32(ctl.index); | 
 |     ctl.error= bswap_uint32(ctl.error); | 
 |     if (nwrite != sizeof(ctl)) { | 
 |         if (nwrite < 0) | 
 |             perror("send_ctl: write"); | 
 |         else | 
 |             fprintf(stderr, "send_ctl[%d]: write() returns %d, not %zu as expected\n",  | 
 |                     ctl.test, nwrite, sizeof(ctl)); | 
 |         exit(1); | 
 |         /*NOTREACHED*/ | 
 |     } | 
 | } | 
 |  | 
 | void recv_ctl(void) | 
 | { | 
 |     int         nread; | 
 |  | 
 | again: | 
 |     if ((nread = SOCKET_READ(c_fd, (char*)&ctl, sizeof(ctl))) != sizeof(ctl)) { | 
 |         if (nread < 0) { | 
 | 	    if (errno == EINTR) | 
 | 		goto again; | 
 |             perror("recv_ctl: read"); | 
 |         } else { | 
 |             fprintf(stderr, "recv_ctl[%d]: read() returns %d, not %zu as expected\n",  | 
 |                     ctl.test, nread, sizeof(ctl)); | 
 | 	    fprintf(stderr, "socket might has been closed by other locktest\n"); | 
 | 	}  | 
 |         exit(1); | 
 |         /*NOTREACHED*/ | 
 |     } | 
 |     ctl.test= bswap_uint32(ctl.test); | 
 |     ctl.command = bswap_uint32(ctl.command); | 
 |     ctl.offset = bswap_uint64(ctl.offset); | 
 |     ctl.length = bswap_uint64(ctl.length); | 
 |     ctl.result = bswap_uint32(ctl.result); | 
 |     ctl.index= bswap_uint32(ctl.index); | 
 |     ctl.error= bswap_uint32(ctl.error); | 
 |  | 
 |     if (debug) { | 
 | 	fprintf(stderr, "recv_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",  | 
 |                 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length, ctl.result, ctl.error); | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | cleanup(void) | 
 | { | 
 |     if (f_fd>=0) | 
 |         CLOSE(f_fd); | 
 |      | 
 |     if (c_fd>=0) | 
 |         SOCKET_CLOSE(c_fd); | 
 |      | 
 |     if (s_fd>=0) | 
 |         SOCKET_CLOSE(s_fd); | 
 |      | 
 |     PLATFORM_CLEANUP(); | 
 | } | 
 |  | 
 | int | 
 | run(int64_t tests[][6], char *descriptions[]); | 
 |  | 
 | int | 
 | main(int argc, char *argv[]) | 
 | { | 
 |     int		i, sts; | 
 |     int		c; | 
 |     struct sockaddr_in	myAddr; | 
 |     struct linger	noLinger = {1, 0}; | 
 |     char	*host = NULL; | 
 |     char	*endnum; | 
 |     int		errflag = 0; | 
 |     char	*p; | 
 |     extern char	*optarg; | 
 |     extern int	optind; | 
 |     int fail_count = 0; | 
 |     int run_leases = 0; | 
 |     int test_setlease = 0; | 
 |      | 
 |     atexit(cleanup); | 
 |      | 
 |     PLATFORM_INIT(); | 
 |  | 
 |     /* trim command name of leading directory components */ | 
 |     prog = argv[0]; | 
 |     for (p = prog; *p; p++) { | 
 | 	if (*p == '/') | 
 | 	    prog = p+1; | 
 |     } | 
 |  | 
 |     while ((c = getopt(argc, argv, "dLn:h:p:t?")) != EOF) { | 
 | 	switch (c) { | 
 |  | 
 | 	case 'd':	/* debug flag */ | 
 | 	    debug++; | 
 | 	    break; | 
 |  | 
 | 	case 'L':	/* Lease testing */ | 
 | 	    run_leases = 1; | 
 | 	    break; | 
 |  | 
 | 	case 'h':	/* (server) hostname */ | 
 | 	    server = 0; | 
 | 	    host = optarg; | 
 | 	    break; | 
 |  | 
 | 	case 'n': | 
 | 	    testnumber = atoi(optarg); | 
 | 	    break; | 
 |  | 
 | 	case 'p':	/* TCP/IP port */ | 
 | 	    port = (int)strtol(optarg, &endnum, 10); | 
 | 	    if (*endnum != '\0') { | 
 | 		fprintf(stderr, "%s: -p argument must be a numeric\n",  | 
 |                         prog); | 
 | 		exit(1); | 
 | 		/*NOTREACHED*/ | 
 | 	    } | 
 | 	    break; | 
 |  | 
 | 	case 't': | 
 | 	    test_setlease = 1; | 
 | 	    break; | 
 |  | 
 | 	case '?': | 
 | 	default: | 
 | 	    errflag++; | 
 | 	    break; | 
 | 	} | 
 |     } | 
 |  | 
 |     if (errflag || optind != argc-1) { | 
 | 	usage(); | 
 | 	/*NOTREACHED*/ | 
 |     } | 
 |  | 
 |     filename=argv[optind]; | 
 |     if (debug) | 
 | 	fprintf(stderr, "Working on file : %s\n", filename); | 
 |     if (do_open(O_RDWR) == FAIL) | 
 | 	exit(1); | 
 |  | 
 |     if (test_setlease == 1) { | 
 | 	fcntl(f_fd, F_SETLEASE, F_UNLCK); | 
 | 	saved_errno = errno; | 
 | 	close(f_fd); | 
 | 	exit(saved_errno); | 
 |     } | 
 |  | 
 |     setbuf(stderr, NULL); | 
 |  | 
 |     if (server) { | 
 |         int one = 1; | 
 |          | 
 | 	s_fd = socket(AF_INET, SOCK_STREAM, 0); | 
 | 	if (s_fd == INVALID_SOCKET) { | 
 | 	    perror("socket"); | 
 | 	    exit(1); | 
 | 	    /*NOTREACHED*/ | 
 | 	} | 
 | 	if (setsockopt(s_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) < 0) { | 
 | 	    perror("setsockopt(nodelay)"); | 
 | 	    exit(1); | 
 | 	    /*NOTREACHED*/ | 
 | 	} | 
 |         if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one))<0) { | 
 |             perror("setsockopt(reuseaddr)"); | 
 |             exit(1); | 
 |             /*NOTREACHED*/ | 
 |         } | 
 | #ifdef SO_REUSEPORT | 
 |         if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&one, sizeof(one))<0) { | 
 |             perror("setsockopt(reuseport)"); | 
 |             exit(1); | 
 |             /*NOTREACHED*/ | 
 |         } | 
 | #endif | 
 |  | 
 | 	memset(&myAddr, 0, sizeof(myAddr)); | 
 | 	myAddr.sin_family = AF_INET; | 
 | 	myAddr.sin_addr.s_addr = htonl(INADDR_ANY); | 
 | 	myAddr.sin_port = htons((short)port); | 
 | 	sts = bind(s_fd, (struct sockaddr*)&myAddr, sizeof(myAddr)); | 
 | 	if (sts < 0) { | 
 | 	    perror("bind"); | 
 | 	    exit(1); | 
 | 	    /*NOTREACHED*/ | 
 | 	} | 
 |  | 
 | 	sts = listen(s_fd, 5);	/* Max. of 5 pending connection requests */ | 
 | 	if (sts == -1) { | 
 | 	    perror("listen"); | 
 | 	    exit(1); | 
 | 	    /*NOTREACHED*/ | 
 | 	} | 
 |  | 
 | 	if (port == 0) { | 
 | 	        socklen_t addr_len = sizeof(myAddr); | 
 |  | 
 | 		if (getsockname(s_fd, &myAddr, &addr_len)) { | 
 | 		    perror("getsockname"); | 
 | 		    exit(1); | 
 | 		} | 
 |  | 
 | 		port = ntohs(myAddr.sin_port); | 
 | 	} | 
 |  | 
 | 	printf("server port: %d\n", port); | 
 | 	fflush(stdout); | 
 |  | 
 | 	c_fd = accept(s_fd, NULL, NULL); | 
 | 	if (c_fd == INVALID_SOCKET) { | 
 | 	    perror("accept"); | 
 | 	    exit(1); | 
 | 	    /*NOTREACHED*/ | 
 | 	} | 
 |  | 
 | 	if (debug) fprintf(stderr, "Client accepted\n"); | 
 | 	SRAND(12345L); | 
 |     } | 
 |     else { | 
 |         struct hostent  *servInfo; | 
 |  | 
 |         if ((servInfo = gethostbyname(host)) == NULL) { | 
 | 	    fprintf(stderr, "Couldn't get hostbyname for %s", host); | 
 | 	    if (h_errno == HOST_NOT_FOUND) | 
 | 		fprintf(stderr, ": host not found"); | 
 | 	    fprintf(stderr, "\n"); | 
 |             exit(1); | 
 |             /*NOTREACHED*/ | 
 |         } | 
 |  | 
 |         c_fd = socket(AF_INET, SOCK_STREAM, 0); | 
 |         if (c_fd == INVALID_SOCKET) { | 
 |             perror("socket"); | 
 |             exit(1); | 
 |             /*NOTREACHED*/ | 
 |         } | 
 |         /* avoid 200 ms delay */ | 
 |         if (setsockopt(c_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) { | 
 |             perror("setsockopt(nodelay)"); | 
 |             exit(1); | 
 |             /*NOTREACHED*/ | 
 |         } | 
 |         /* Don't linger on close */ | 
 |         if (setsockopt(c_fd, SOL_SOCKET, SO_LINGER, (char *)&noLinger, sizeof(noLinger)) < 0) { | 
 |             perror("setsockopt(nolinger)"); | 
 |             exit(1); | 
 |             /*NOTREACHED*/ | 
 |         } | 
 |  | 
 | 	memset(&myAddr, 0, sizeof(myAddr));	/* Arrgh! &myAddr, not myAddr */ | 
 | 	myAddr.sin_family = AF_INET; | 
 | 	memcpy(&myAddr.sin_addr, servInfo->h_addr, servInfo->h_length); | 
 | 	myAddr.sin_port = htons((short)port); | 
 |  | 
 | 	if (connect(c_fd, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0) { | 
 |             perror("unable to connect"); | 
 |             fprintf(stderr, "Server might still initializing the shared file\n "); | 
 |             exit(1); | 
 |             /*NOTREACHED*/ | 
 | 	} | 
 |  | 
 | 	if (debug) fprintf(stderr, "Connected to server\n"); | 
 | 	SRAND(6789L); | 
 |     } | 
 |  | 
 |     if (server) | 
 | 	/* only server need do shared file */ | 
 | 	initialize(f_fd); | 
 |  | 
 |     /* | 
 |      * TCP/IP connection to be established, safe to proceed. | 
 |      * | 
 |      * real work is in here ... | 
 |      */ | 
 |     if (run_leases) | 
 | 	fail_count = run(lease_tests, lease_descriptions); | 
 |     else | 
 | 	fail_count = run(lock_tests, lock_descriptions); | 
 |  | 
 |     exit(fail_count); | 
 |     /*NOTREACHED*/ | 
 | } | 
 |  | 
 | int run(int64_t tests[][6], char *descriptions[]) | 
 | { | 
 |     int index = 0; | 
 |     int end = 0; | 
 |     int result = 0; | 
 |     int last_test = 0; | 
 |     int test_count = -1; | 
 |     int fail_flag = 0; | 
 |     int fail_count = 0; | 
 |     while(!end) { | 
 | 	if (server) { | 
 | 	    if(testnumber > 0) { | 
 | 		last_test = testnumber - 1; | 
 | 		while(tests[index][TEST_NUM] != testnumber && tests[index][TEST_NUM] != 0) { | 
 | 		    index++; | 
 | 		} | 
 | 	    } | 
 | 	    /* If we have a server command, deal with it */ | 
 | 	    if(tests[index][WHO] == SERVER) { | 
 | 		if(debug) | 
 | 		    fprintf(stderr, "Got a server command (%d)\n", index); | 
 | 		if(tests[index][TEST_NUM] == 0) { | 
 | 		    index++; | 
 | 		    continue; | 
 | 		}  | 
 | 		memset(&ctl, 0, sizeof(ctl)); | 
 | 		ctl.test = tests[index][TEST_NUM]; | 
 |  | 
 | 		if(tests[index][TEST_NUM] != 0) { | 
 | 		    switch(tests[index][COMMAND]) { | 
 | 			case CMD_WRLOCK: | 
 | 			    result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]); | 
 | 			    break; | 
 | 			case CMD_RDLOCK: | 
 | 			    result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]); | 
 | 			    break; | 
 | 			case CMD_UNLOCK: | 
 | 			    result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]); | 
 | 			    break; | 
 | 			case CMD_CLOSE: | 
 | 			    result = do_close(); | 
 | 			    break; | 
 | 			case CMD_OPEN: | 
 | 			    result = do_open(tests[index][FLAGS]); | 
 | 			    break; | 
 | 			case CMD_WRTEST: | 
 | 			    result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]); | 
 | 			    break; | 
 | 			case CMD_RDTEST: | 
 | 			    result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]); | 
 | 			    break; | 
 | 			case CMD_SETLEASE: | 
 | 			    result = do_lease(F_SETLEASE, tests[index][ARG], 0); | 
 | 			    break; | 
 | 			case CMD_GETLEASE: | 
 | 			    result = do_lease(F_GETLEASE, tests[index][ARG], tests[index][ARG]); | 
 | 			    break; | 
 | 			case CMD_SIGIO: | 
 | 			    result = do_setup_sigio(f_fd); | 
 | 			    break; | 
 | 			case CMD_WAIT_SIGIO: | 
 | 			    result = do_wait_sigio(tests[index][TIME]); | 
 | 			    break; | 
 | 			case CMD_TRUNCATE: | 
 | 			    result = do_truncate(tests[index][OFFSET]); | 
 | 			    break; | 
 | 		    } | 
 | 		    if( result != tests[index][RESULT]) { | 
 | 			fail_flag++; | 
 | 			/* We have a failure */ | 
 | 			fprintf(stderr, "     ***** Server failure *****\n"); | 
 | 			fprintf(stderr, "     in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n", | 
 | 				ctl.test, get_cmd_str(tests[index][COMMAND]), | 
 | 				(long long)tests[index][OFFSET], | 
 | 				(long long)tests[index][LENGTH], | 
 | 				saved_errno, strerror(saved_errno)); | 
 | 			fprintf(stderr, "     %d:%s\n", | 
 | 					ctl.test, descriptions[ctl.test - 1]); | 
 | 		    } | 
 | 		} | 
 | 	    /* else send it off to the client */ | 
 | 	    } else if (tests[index][WHO] == CLIENT) { | 
 | 		if(tests[index][TEST_NUM] == 0) { | 
 | 		    ctl.test = 0; | 
 | 		    end=1; | 
 | 		}  | 
 | 		/* get the client to do something */ | 
 | 		init_ctl(tests, index); | 
 | 		if(debug) | 
 | 		    fprintf(stderr, "Sending command to client (%d) - %s - %lld:%lld\n",  | 
 | 					index, | 
 | 					get_cmd_str(ctl.command), | 
 | 					(long long)tests[index][OFFSET], | 
 | 					(long long)tests[index][LENGTH]); | 
 | 		/* get the client to do something */ | 
 | 		ctl.index = index; | 
 | 		send_ctl(); | 
 | 		if(ctl.test != 0) { | 
 | 		    /* Get the clients response */ | 
 | 		    recv_ctl(); | 
 | 		    /* this is the whether the test passed or failed, | 
 | 		     * not what the command returned */ | 
 | 		    if( ctl.result == FAIL ) { | 
 | 			fail_flag++; | 
 | 			fprintf(stderr, "     ***** Client failure *****\n"); | 
 | 			fprintf(stderr, "     in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n", | 
 | 					ctl.test, get_cmd_str(ctl.command), | 
 | 					(long long)ctl.offset, (long long)ctl.length, | 
 | 					ctl.error, strerror(ctl.error)); | 
 | 			fprintf(stderr, "     %d:%s\n", | 
 | 					ctl.test, descriptions[ctl.test - 1]); | 
 | 		    } | 
 | 		} | 
 | 	    } | 
 |  | 
 | 	    if(last_test != tests[index][TEST_NUM]) { | 
 | 	        test_count++; | 
 | 	        if(fail_flag) | 
 | 		    fail_count++; | 
 | 	        fail_flag = 0; | 
 | 	        last_test = tests[index][TEST_NUM]; | 
 | 	    } | 
 | 		 | 
 | 	    index++; | 
 | 	} else { /* CLIENT */ | 
 | 	    if(debug) | 
 | 		fprintf(stderr,"client: waiting...\n"); | 
 | 	    /* wait for the server to do something */ | 
 | 	    recv_ctl(); | 
 |  | 
 | 	    /* check for a client command */ | 
 | 	    index = ctl.index; | 
 | 	    if (tests[index][WHO] != CLIENT) {  | 
 | 		fprintf(stderr, "not a client command index (%d)\n", index); | 
 | 		exit(1); | 
 | 	    } | 
 | 		 | 
 | 	    if(ctl.test == 0) { | 
 | 		end = 1; | 
 | 		break; | 
 | 	    } | 
 |  | 
 | 	    switch(ctl.command) { | 
 | 		case CMD_WRLOCK: | 
 | 		    result = do_lock(F_SETLK, F_WRLCK, ctl.offset, ctl.length); | 
 | 		    break; | 
 | 		case CMD_RDLOCK: | 
 | 		    result = do_lock(F_SETLK, F_RDLCK, ctl.offset, ctl.length); | 
 | 		    break; | 
 | 		case CMD_UNLOCK: | 
 | 		    result = do_lock(F_SETLK, F_UNLCK, ctl.offset, ctl.length); | 
 | 		    break; | 
 | 		case CMD_CLOSE: | 
 | 		    result = do_close(); | 
 | 		    break; | 
 | 		case CMD_OPEN: | 
 | 		    result = do_open(tests[index][FLAGS]); | 
 | 		    break; | 
 | 		case CMD_WRTEST: | 
 | 		    result = do_lock(F_GETLK, F_WRLCK, ctl.offset, ctl.length); | 
 | 		    break; | 
 | 		case CMD_RDTEST: | 
 | 		    result = do_lock(F_GETLK, F_RDLCK, ctl.offset, ctl.length); | 
 | 		    break; | 
 | 		/* NOTE offset carries the argument values */ | 
 | 		case CMD_SETLEASE: | 
 | 		    result = do_lease(F_SETLEASE, ctl.offset, 0); | 
 | 		    break; | 
 | 		case CMD_GETLEASE: | 
 | 		    result = do_lease(F_GETLEASE, ctl.offset, ctl.offset); | 
 | 		    break; | 
 | 		case CMD_SIGIO: | 
 | 		    result = do_setup_sigio(f_fd); | 
 | 		    break; | 
 | 		case CMD_WAIT_SIGIO: | 
 | 		    result = do_wait_sigio(ctl.offset); | 
 | 		    break; | 
 | 		case CMD_TRUNCATE: | 
 | 		    result = do_truncate(ctl.offset); | 
 | 		    break; | 
 | 	    } | 
 | 	    if( result != ctl.result ) { | 
 | 		fprintf(stderr,"Failure in %d:%s\n", | 
 | 			ctl.test, descriptions[ctl.test - 1]); | 
 | 		fprintf(stderr,"     Got %d, wanted %d\n", | 
 | 			result, ctl.result); | 
 | 		ctl.result = FAIL; | 
 | 		ctl.error = saved_errno; | 
 | 		fail_count++; | 
 | 	    } else { | 
 | 		ctl.result = PASS; | 
 | 		ctl.error = 0; | 
 | 	    } | 
 | 	    if(debug) | 
 | 		fprintf(stderr,"client: sending result to server (%d)\n", ctl.index); | 
 | 	    /* Send result to the server */ | 
 | 	    send_ctl(); | 
 | 	    if(last_test != tests[index][TEST_NUM]) { | 
 | 		test_count++; | 
 | 		last_test = tests[index][TEST_NUM]; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |     fprintf(stderr, "%d tests run, %d failed\n", test_count, fail_count); | 
 |  | 
 |     return fail_count; | 
 | } |