1158 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1158 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  *
 | |
|  *   Copyright (c) International Business Machines  Corp., 2001
 | |
|  *
 | |
|  *   This program is free software;  you can redistribute it and/or modify
 | |
|  *   it under the terms of the GNU General Public License as published by
 | |
|  *   the Free Software Foundation; either version 2 of the License, or
 | |
|  *   (at your option) any later version.
 | |
|  *
 | |
|  *   This program is distributed in the hope that it will be useful,
 | |
|  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 | |
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 | |
|  *   the GNU General Public License for more details.
 | |
|  *
 | |
|  *   You should have received a copy of the GNU General Public License
 | |
|  *   along with this program;  if not, write to the Free Software
 | |
|  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * NAME
 | |
|  *	fcntl14.c
 | |
|  *
 | |
|  * DESCRIPTION
 | |
|  *	File locking test cases for fcntl. In Linux, S_ENFMT is not implemented
 | |
|  *	in the kernel. However all standard Unix kernels define S_ENFMT as
 | |
|  *	S_ISGID. So this test defines S_ENFMT as S_ISGID.
 | |
|  *
 | |
|  * ALGORITHM
 | |
|  *	Various test cases are used to lock a file opened without mandatory
 | |
|  *	locking, with mandatory locking and mandatory locking with NOBLOCK
 | |
|  *
 | |
|  * USAGE
 | |
|  *	fcntl14
 | |
|  *
 | |
|  * HISTORY
 | |
|  *	07/2001 Ported by Wayne Boyer
 | |
|  *
 | |
|  * RESTRICTIONS
 | |
|  *	None
 | |
|  */
 | |
| #define _GNU_SOURCE 1
 | |
| #include <fcntl.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <signal.h>
 | |
| #include <errno.h>
 | |
| #include <sys/wait.h>
 | |
| #include <inttypes.h>
 | |
| #include "test.h"
 | |
| #include "safe_macros.h"
 | |
| 
 | |
| #define SKIP 0x0c00
 | |
| #if SKIP == F_RDLCK || SKIP== F_WRLCK
 | |
| #error invalid value for SKIP, must be distinct from F_RDLCK and F_WRLCK
 | |
| #endif
 | |
| #ifndef S_ENFMT
 | |
| #define S_ENFMT S_ISGID
 | |
| #endif
 | |
| 
 | |
| /* NOBLOCK - immediate success */
 | |
| #define NOBLOCK 2
 | |
| 
 | |
| /* WILLBLOCK - blocks, then succeeds (parent must unlock records) */
 | |
| #define WILLBLOCK 3
 | |
| 
 | |
| #define TIME_OUT 60
 | |
| 
 | |
| typedef struct {
 | |
| 	short a_type;
 | |
| 	short a_whence;
 | |
| 	long a_start;
 | |
| 	long a_len;
 | |
| 	short b_type;		/* SKIP means suppress fcntl call */
 | |
| 	short b_whence;
 | |
| 	long b_start;
 | |
| 	long b_len;
 | |
| 	short c_type;
 | |
| 	int c_whence;
 | |
| 	long c_start;
 | |
| 	long c_len;
 | |
| 	short c_flag;
 | |
| } testcase;
 | |
| 
 | |
| static testcase testcases[] = {
 | |
| 	/* Test cases: entire boundary */
 | |
| 	/* #1 Parent making a write lock on entire file */
 | |
| 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock on entire file */
 | |
| 	 F_RDLCK, 0, 0L, 0L, WILLBLOCK},
 | |
| 
 | |
| 	/* #2 Parent making a write lock on entire file */
 | |
| 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock on entire file */
 | |
| 	 F_WRLCK, 0, 0L, 0L, WILLBLOCK},
 | |
| 
 | |
| 	/* #3 Parent making a read lock on entire file */
 | |
| 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock on entire file */
 | |
| 	 F_RDLCK, 0, 0L, 0L, NOBLOCK},
 | |
| 
 | |
| 	/* #4 Parent making a read lock on entire file */
 | |
| 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock on entire file */
 | |
| 	 F_WRLCK, 0, 0L, 0L, WILLBLOCK},
 | |
| 
 | |
| 	/* Test case: start boundary */
 | |
| 	/* #5 Parent making a write lock on entire file */
 | |
| 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /*
 | |
| 	  * Child attempting a read lock from beginning of
 | |
| 	  * file for 5 bytes
 | |
| 	  */
 | |
| 	 F_RDLCK, 0, 0L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/* #6 Parent making a write lock on entire file */
 | |
| 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /*
 | |
| 	  * Child attempting a write lock from beginning of
 | |
| 	  * file for 5 bytes
 | |
| 	  */
 | |
| 	 F_WRLCK, 0, 0L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/* #7 Parent making a read lock on entire file */
 | |
| 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /*
 | |
| 	  * Child attempting a read lock from beginning of
 | |
| 	  * file for 5 bytes
 | |
| 	  */
 | |
| 	 F_RDLCK, 0, 0L, 5L, NOBLOCK},
 | |
| 
 | |
| 	/* #8 Parent making a read lock on entire file */
 | |
| 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /*
 | |
| 	  * Child attempting a write lock from beginning of
 | |
| 	  * file for 5 bytes
 | |
| 	  */
 | |
| 	 F_WRLCK, 0, 0L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/* Test cases: end boundary */
 | |
| 	/* #9 Parent making a write lock on entire file */
 | |
| 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from byte 7 to end of file */
 | |
| 	 F_RDLCK, 0, 7L, 0L, WILLBLOCK},
 | |
| 
 | |
| 	/* #10 Parent making a write lock on entire file */
 | |
| 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 7 to end of file */
 | |
| 	 F_WRLCK, 0, 7L, 0L, WILLBLOCK},
 | |
| 
 | |
| 	/* #11 Parent making a read lock on entire file */
 | |
| 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from byte 7 to end of file */
 | |
| 	 F_RDLCK, 0, 7L, 0L, NOBLOCK},
 | |
| 
 | |
| 	/* #12 Parent making a read lock on entire file */
 | |
| 	{F_RDLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 7 to end of file */
 | |
| 	 F_WRLCK, 0, 7L, 0L, WILLBLOCK},
 | |
| 
 | |
| 	/* Test cases: entire boundary ( less than entire file) */
 | |
| 	/*
 | |
| 	 * #13 Parent making a write lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /*
 | |
| 	  * Child attempting a read lock from beginning of
 | |
| 	  * file for 5 bytes
 | |
| 	  */
 | |
| 	 F_RDLCK, 0, 0L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #14 Parent making a write lock from beginning of file
 | |
| 	 * for 5 bytes
 | |
| 	 */
 | |
| 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /*
 | |
| 	  * Child attempting a write lock from beginning of
 | |
| 	  * file for 5 bytes
 | |
| 	  */
 | |
| 	 F_WRLCK, 0, 0L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #15 Parent making a read lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /*
 | |
| 	  * Child attempting a read lock from beginning of
 | |
| 	  * file for 5 bytes
 | |
| 	  */
 | |
| 	 F_RDLCK, 0, 0L, 5L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #16 Parent making a read lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /*
 | |
| 	  * Child attempting a write lock from beginning
 | |
| 	  * of file for 5 bytes
 | |
| 	  */
 | |
| 	 F_WRLCK, 0, 0L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/* Test cases: inside boundary */
 | |
| 	/*
 | |
| 	 * #17 Parent making a write lock from beginning
 | |
| 	 * of file for 5 bytes
 | |
| 	 */
 | |
| 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from byte 2 to byte 4 */
 | |
| 	 F_RDLCK, 0, 1L, 3L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #18 Parent making a write lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 2 to byte 4 */
 | |
| 	 F_WRLCK, 0, 1L, 3L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #19 Parent making a read lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from byte 2 to byte 4 */
 | |
| 	 F_RDLCK, 0, 1L, 3L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #20 Parent making a read lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 2 to byte 4 */
 | |
| 	 F_WRLCK, 0, 1L, 3L, WILLBLOCK},
 | |
| 
 | |
| 	/* Test cases: cross boundary (inside to after) */
 | |
| 	/*
 | |
| 	 * #21 Parent making a write lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from byte 3 to byte 7 */
 | |
| 	 F_RDLCK, 0, 2L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #22 Parent making a write lock from beginning
 | |
| 	 * of file for 5 bytes
 | |
| 	 */
 | |
| 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 3 to byte 7 */
 | |
| 	 F_WRLCK, 0, 2L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #23 Parent making a read lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from byte 3 to byte 7 */
 | |
| 	 F_RDLCK, 0, 2L, 5L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #24 Parent making a read lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 3 to byte 7 */
 | |
| 	 F_WRLCK, 0, 2L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/* Test cases: outside boundary (after) */
 | |
| 
 | |
| 	/*
 | |
| 	 * #25 Parent making a write lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /*  Child attempting a read lock from byte 7 to end of file */
 | |
| 	 F_RDLCK, 0, 6L, 0L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #26 Parent making a write lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_WRLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 7 to end of file */
 | |
| 	 F_WRLCK, 0, 6L, 0L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #27 Parent making a read lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from byte 7 to end of file */
 | |
| 	 F_RDLCK, 0, 6L, 0L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #28 Parent making a read lock from beginning of
 | |
| 	 * file for 5 bytes
 | |
| 	 */
 | |
| 	{F_RDLCK, 0, 0L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 7 to end of file */
 | |
| 	 F_WRLCK, 0, 6L, 0L, NOBLOCK},
 | |
| 
 | |
| 	/* Test cases: outside boundary (before) */
 | |
| 
 | |
| 	/* #29 Parent making a write lock from byte 3 to byte 7 */
 | |
| 	{F_WRLCK, 0, 2L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from beginning of file to byte 2 */
 | |
| 	 F_RDLCK, 0, 0L, 2L, NOBLOCK},
 | |
| 
 | |
| 	/* #30 Parent making a write lock from byte 3 to byte 7 */
 | |
| 	{F_WRLCK, 0, 2L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from beginning of file to byte 2 */
 | |
| 	 F_WRLCK, 0, 0L, 2L, NOBLOCK},
 | |
| 
 | |
| 	/* #31 Parent making a write lock from byte 3 to byte 7 */
 | |
| 	{F_RDLCK, 0, 2L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from beginning of file to byte 2 */
 | |
| 	 F_RDLCK, 0, 0L, 2L, NOBLOCK},
 | |
| 
 | |
| 	/* #32 Parent making a write lock from byte 3 to byte 7 */
 | |
| 	{F_RDLCK, 0, 2L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from beginning of file to byte 2 */
 | |
| 	 F_WRLCK, 0, 0L, 2L, NOBLOCK},
 | |
| 
 | |
| 	/* Test cases: cross boundary (before to inside) */
 | |
| 	/* #33 Parent making a write lock from byte 5 to end of file */
 | |
| 	{F_WRLCK, 0, 4L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from byte 3 to byte 7 */
 | |
| 	 F_RDLCK, 0, 2L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/* #34 Parent making a write lock from byte 5 to end of file */
 | |
| 	{F_WRLCK, 0, 4L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 3 to byte 7 */
 | |
| 	 F_WRLCK, 0, 2L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/* #35 Parent making a read lock from byte 5 to end of file */
 | |
| 	{F_RDLCK, 0, 4L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a read lock from byte 3 to byte 7 */
 | |
| 	 F_RDLCK, 0, 2L, 5L, NOBLOCK},
 | |
| 
 | |
| 	/* #36 Parent making a read lock from byte 5 to end of file */
 | |
| 	{F_RDLCK, 0, 4L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting a write lock from byte 3 to byte 7 */
 | |
| 	 F_WRLCK, 0, 2L, 5L, WILLBLOCK},
 | |
| 
 | |
| 	/* Start of negative L_start and L_len test cases */
 | |
| 	/*
 | |
| 	 * #37 Parent making write lock from byte 2 to byte 3
 | |
| 	 * with L_start = -3
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -3L, 2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 1 */
 | |
| 	 F_WRLCK, 0, 1L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #38 Parent making write lock from byte 2 to byte 3
 | |
| 	 * with L_start = -3
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -3L, 2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 4 */
 | |
| 	 F_WRLCK, 0, 4L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #39 Parent making write lock from byte 2 to byte 3
 | |
| 	 * with L_start = -3
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -3L, 2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 2 */
 | |
| 	 F_WRLCK, 0, 2L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #40 Parent making write lock from byte 2 to byte 3
 | |
| 	 * with L_start = -3
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -3L, 2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 3 */
 | |
| 	 F_WRLCK, 0, 3L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #41 Parent making write lock from byte 2 to byte 6
 | |
| 	 * with L_start = -3
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 1 */
 | |
| 	 F_WRLCK, 0, 1L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #42 Parent making write lock from byte 2 to byte 6
 | |
| 	 * with L_start = -3
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 7 */
 | |
| 	 F_WRLCK, 0, 1L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #43 Parent making write lock from byte 2 to byte 6
 | |
| 	 * with L_start = -3
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 2 */
 | |
| 	 F_WRLCK, 0, 2L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #44 Parent making write lock from byte 2 to byte 6
 | |
| 	 * with L_start = -3
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 5 */
 | |
| 	 F_WRLCK, 0, 5L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #45 Parent making write lock from byte 2 to byte 6
 | |
| 	 * with L_start = -3
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -3L, 5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 6 */
 | |
| 	 F_WRLCK, 0, 6L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #46 Parent making write lock from byte 2 to byte 3 with
 | |
| 	 * L_start = -2 and L_len = -2
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 1 */
 | |
| 	 F_WRLCK, 0, 1L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #47 Parent making write lock from byte 2 to byte 3 with
 | |
| 	 * L_start = -2 and L_len = -2
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -2L, -2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 4 */
 | |
| 	 F_WRLCK, 0, 4L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #48 Parent making write lock from byte 2 to byte 3 with
 | |
| 	 * L_start = -2 and L_len = -2
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -2L, -2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 2 */
 | |
| 	 F_WRLCK, 0, 2L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #49 Parent making write lock from byte 2 to byte 3 with
 | |
| 	 * L_start = -2 and L_len = -2
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, -2L, -2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 3 */
 | |
| 	 F_WRLCK, 0, 3L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #50 Parent making write lock from byte 6 to byte 7 with
 | |
| 	 * L_start = 2 and L_len = -2
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 5 */
 | |
| 	 F_WRLCK, 0, 5L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #51 Parent making write lock from byte 6 to byte 7 with
 | |
| 	 * L_start = 2 and L_len = -2
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 8 */
 | |
| 	 F_WRLCK, 0, 8L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #52 Parent making write lock from byte 6 to byte 7 with
 | |
| 	 * L_start = 2 and L_len = -2
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 6 */
 | |
| 	 F_WRLCK, 0, 6L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #53 Parent making write lock from byte 6 to byte 7 with
 | |
| 	 * L_start = 2 and L_len = -2
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -2L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 7 */
 | |
| 	 F_WRLCK, 0, 7L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #54 Parent making write lock from byte 3 to byte 7 with
 | |
| 	 * L_start = 2 and L_len = -5
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 2 */
 | |
| 	 F_WRLCK, 0, 2L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #55 Parent making write lock from byte 3 to byte 7 with
 | |
| 	 * L_start = 2 and L_len = -5
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 8 */
 | |
| 	 F_WRLCK, 0, 8L, 1L, NOBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #56 Parent making write lock from byte 3 to byte 7 with
 | |
| 	 * L_start = 2 and L_len = -5
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 3 */
 | |
| 	 F_WRLCK, 0, 3L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #57 Parent making write lock from byte 3 to byte 7 with
 | |
| 	 * L_start = 2 and L_len = -5
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 5 */
 | |
| 	 F_WRLCK, 0, 5L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/*
 | |
| 	 * #58 Parent making write lock from byte 3 to byte 7 with
 | |
| 	 * L_start = 2 and L_len = -5
 | |
| 	 */
 | |
| 	{F_WRLCK, 1, 2L, -5L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 7 */
 | |
| 	 F_WRLCK, 0, 7L, 1L, WILLBLOCK},
 | |
| 
 | |
| 	/* Test case for block 4 */
 | |
| 	/* #59 Parent making write lock on entire file */
 | |
| 	{F_WRLCK, 0, 0L, 0L, SKIP, 0, 0L, 0L,
 | |
| 	 /* Child attempting write lock on byte 15 to end of file */
 | |
| 	 F_WRLCK, 0, 15L, 0L, WILLBLOCK},
 | |
| };
 | |
| 
 | |
| static testcase *thiscase;
 | |
| static struct flock flock;
 | |
| static int parent, child, status, fail = 0;
 | |
| static int got1 = 0;
 | |
| static int fd;
 | |
| static int test;
 | |
| static char tmpname[40];
 | |
| 
 | |
| #define FILEDATA	"ten bytes!"
 | |
| 
 | |
| void catch1(int sig);
 | |
| void catch_alarm(int sig);
 | |
| 
 | |
| char *TCID = "fcntl14";
 | |
| int TST_TOTAL = 1;
 | |
| int NO_NFS = 1;
 | |
| 
 | |
| #ifdef UCLINUX
 | |
| static char *argv0;
 | |
| #endif
 | |
| 
 | |
| void cleanup(void)
 | |
| {
 | |
| 	tst_rmdir();
 | |
| }
 | |
| 
 | |
| void setup(void)
 | |
| {
 | |
| 	struct sigaction act;
 | |
| 
 | |
| 	tst_sig(FORK, DEF_HANDLER, cleanup);
 | |
| 	signal(SIGHUP, SIG_IGN);
 | |
| 	umask(0);
 | |
| 	TEST_PAUSE;
 | |
| 	tst_tmpdir();
 | |
| 	parent = getpid();
 | |
| 
 | |
| 	sprintf(tmpname, "fcntl2.%d", parent);
 | |
| 
 | |
| 	/* setup signal handler for signal from child */
 | |
| 	memset(&act, 0, sizeof(act));
 | |
| 	act.sa_handler = catch1;
 | |
| 	sigemptyset(&act.sa_mask);
 | |
| 	sigaddset(&act.sa_mask, SIGUSR1);
 | |
| 	if ((sigaction(SIGUSR1, &act, NULL)) < 0) {
 | |
| 		tst_resm(TFAIL, "SIGUSR1 signal setup failed, errno = %d",
 | |
| 			 errno);
 | |
| 		cleanup();
 | |
| 	}
 | |
| 
 | |
| 	memset(&act, 0, sizeof(act));
 | |
| 	act.sa_handler = catch_alarm;
 | |
| 	sigemptyset(&act.sa_mask);
 | |
| 	sigaddset(&act.sa_mask, SIGALRM);
 | |
| 	if ((sigaction(SIGALRM, &act, NULL)) < 0) {
 | |
| 		tst_resm(TFAIL, "SIGALRM signal setup failed");
 | |
| 		cleanup();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void wake_parent(void)
 | |
| {
 | |
| 	if ((kill(parent, SIGUSR1)) < 0) {
 | |
| 		tst_resm(TFAIL, "Attempt to send signal to parent " "failed");
 | |
| 		tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, errno);
 | |
| 		fail = 1;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void do_usleep_child(void)
 | |
| {
 | |
| 	usleep(100000);		/* XXX how long is long enough? */
 | |
| 	wake_parent();
 | |
| 	exit(0);
 | |
| }
 | |
| 
 | |
| void dochild(void)
 | |
| {
 | |
| 	int rc;
 | |
| 	pid_t pid;
 | |
| 
 | |
| 	flock.l_type = thiscase->c_type;
 | |
| 	flock.l_whence = thiscase->c_whence;
 | |
| 	flock.l_start = thiscase->c_start;
 | |
| 	flock.l_len = thiscase->c_len;
 | |
| 	flock.l_pid = 0;
 | |
| 	fail = 0;
 | |
| 
 | |
| 	/*
 | |
| 	 * Check to see if child lock will succeed. If it will, FLOCK
 | |
| 	 * structure will return with l_type changed to F_UNLCK. If it will
 | |
| 	 * not, the parent pid will be returned in l_pid and the type of
 | |
| 	 * lock that will block it in l_type.
 | |
| 	 */
 | |
| 	if ((rc = fcntl(fd, F_GETLK, &flock)) < 0) {
 | |
| 		tst_resm(TFAIL, "Attempt to check lock status failed");
 | |
| 		tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, errno);
 | |
| 		fail = 1;
 | |
| 	} else {
 | |
| 
 | |
| 		if ((thiscase->c_flag) == NOBLOCK) {
 | |
| 			if (flock.l_type != F_UNLCK) {
 | |
| 				tst_resm(TFAIL,
 | |
| 					 "Test case %d, GETLK: type = %d, "
 | |
| 					 "%d was expected", test + 1,
 | |
| 					 flock.l_type, F_UNLCK);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 
 | |
| 			if (flock.l_whence != thiscase->c_whence) {
 | |
| 				tst_resm(TFAIL,
 | |
| 					 "Test case %d, GETLK: whence = %d, "
 | |
| 					 "should have remained %d", test + 1,
 | |
| 					 flock.l_whence, thiscase->c_whence);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 
 | |
| 			if (flock.l_start != thiscase->c_start) {
 | |
| 				tst_resm(TFAIL,
 | |
| 					 "Test case %d, GETLK: start = %" PRId64
 | |
| 					 ", " "should have remained %" PRId64,
 | |
| 					 test + 1, (int64_t) flock.l_start,
 | |
| 					 (int64_t) thiscase->c_start);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 
 | |
| 			if (flock.l_len != thiscase->c_len) {
 | |
| 				tst_resm(TFAIL,
 | |
| 					 "Test case %d, GETLK: len = %" PRId64
 | |
| 					 ", " "should have remained %" PRId64,
 | |
| 					 test + 1, (int64_t) flock.l_len,
 | |
| 					 (int64_t) thiscase->c_len);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 
 | |
| 			if (flock.l_pid != 0) {
 | |
| 				tst_resm(TFAIL,
 | |
| 					 "Test case %d, GETLK: pid = %d, "
 | |
| 					 "should have remained 0", test + 1,
 | |
| 					 flock.l_pid);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 		} else {
 | |
| 			if (flock.l_pid != parent) {
 | |
| 				tst_resm(TFAIL,
 | |
| 					 "Test case %d, GETLK: pid = %d, "
 | |
| 					 "should be parent's id of %d",
 | |
| 					 test + 1, flock.l_pid, parent);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 
 | |
| 			if (flock.l_type != thiscase->a_type) {
 | |
| 				tst_resm(TFAIL,
 | |
| 					 "Test case %d, GETLK: type = %d, "
 | |
| 					 "should be parent's first lock type of %d",
 | |
| 					 test + 1, flock.l_type,
 | |
| 					 thiscase->a_type);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * now try to set the lock, nonblocking
 | |
| 	 * This will succeed for NOBLOCK,
 | |
| 	 * fail for WILLBLOCK
 | |
| 	 */
 | |
| 	flock.l_type = thiscase->c_type;
 | |
| 	flock.l_whence = thiscase->c_whence;
 | |
| 	flock.l_start = thiscase->c_start;
 | |
| 	flock.l_len = thiscase->c_len;
 | |
| 	flock.l_pid = 0;
 | |
| 
 | |
| 	if ((rc = fcntl(fd, F_SETLK, &flock)) < 0) {
 | |
| 		if ((thiscase->c_flag) == NOBLOCK) {
 | |
| 			tst_resm(TFAIL, "Attempt to set child NONBLOCKING "
 | |
| 				 "lock failed");
 | |
| 			tst_resm(TFAIL, "Test case %d, errno = %d",
 | |
| 				 test + 1, errno);
 | |
| 			fail = 1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if ((thiscase->c_flag) == WILLBLOCK) {
 | |
| 		if (rc != -1 || (errno != EACCES && errno != EAGAIN)) {
 | |
| 			tst_resm(TFAIL,
 | |
| 				 "SETLK: rc = %d, errno = %d, -1/EAGAIN or EACCES "
 | |
| 				 "was expected", rc, errno);
 | |
| 			fail = 1;
 | |
| 		}
 | |
| 		if (rc == 0) {
 | |
| 			/* accidentally got the lock */
 | |
| 			/* XXX how to clean up? */
 | |
| 			(void)fcntl(fd, F_UNLCK, &flock);
 | |
| 		}
 | |
| 		/*
 | |
| 		 * Lock should succeed after blocking and parent releases
 | |
| 		 * lock, tell the parent to release the locks.
 | |
| 		 * Do the lock in this process, send the signal in a child
 | |
| 		 * process, so that the SETLKW actually uses the blocking
 | |
| 		 * mechanism in the kernel.
 | |
| 		 *
 | |
| 		 * XXX inherent race: we want to wait until the
 | |
| 		 * F_SETLKW has started, but we don't have a way to
 | |
| 		 * check that reliably in the child.  (We'd
 | |
| 		 * need some way to have fcntl() atomically unblock a
 | |
| 		 * signal and wait for the lock.)
 | |
| 		 */
 | |
| 		pid = FORK_OR_VFORK();
 | |
| 		switch (pid) {
 | |
| 		case -1:
 | |
| 			tst_resm(TFAIL, "Fork failed");
 | |
| 			fail = 1;
 | |
| 			break;
 | |
| 		case 0:
 | |
| #ifdef UCLINUX
 | |
| 			if (self_exec(argv0, "nd", 1, parent) < 0) {
 | |
| 				tst_resm(TFAIL, "self_exec failed");
 | |
| 				break;
 | |
| 			}
 | |
| #else
 | |
| 			do_usleep_child();
 | |
| #endif
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			if ((rc = fcntl(fd, F_SETLKW, &flock)) < 0) {
 | |
| 				tst_resm(TFAIL, "Attempt to set child BLOCKING "
 | |
| 					 "lock failed");
 | |
| 				tst_resm(TFAIL, "Test case %d, errno = %d",
 | |
| 					 test + 1, errno);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 			waitpid(pid, &status, 0);
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 	if (fail) {
 | |
| 		exit(1);
 | |
| 	} else {
 | |
| 		exit(0);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void run_test(int file_flag, int file_mode, int seek, int start, int end)
 | |
| {
 | |
| 	fail = 0;
 | |
| 
 | |
| 	for (test = start; test < end; test++) {
 | |
| 		fd = SAFE_OPEN(cleanup, tmpname, file_flag, file_mode);
 | |
| 
 | |
| 		if (write(fd, FILEDATA, 10) < 0)
 | |
| 			tst_brkm(TBROK, cleanup, "write() failed");
 | |
| 
 | |
| 		if (seek) {
 | |
| 			SAFE_LSEEK(cleanup, fd, seek, 0);
 | |
| 		}
 | |
| 
 | |
| 		thiscase = &testcases[test];
 | |
| 		flock.l_type = thiscase->a_type;
 | |
| 		flock.l_whence = thiscase->a_whence;
 | |
| 		flock.l_start = thiscase->a_start;
 | |
| 		flock.l_len = thiscase->a_len;
 | |
| 
 | |
| 		/* set the initial parent lock on the file */
 | |
| 		if ((fcntl(fd, F_SETLK, &flock)) < 0) {
 | |
| 			tst_resm(TFAIL, "First parent lock failed");
 | |
| 			tst_resm(TFAIL, "Test case %d, errno = %d",
 | |
| 				 test + 1, errno);
 | |
| 			fail = 1;
 | |
| 		}
 | |
| 
 | |
| 		if ((thiscase->b_type) != SKIP) {
 | |
| 			flock.l_type = thiscase->b_type;
 | |
| 			flock.l_whence = thiscase->b_whence;
 | |
| 			flock.l_start = thiscase->b_start;
 | |
| 			flock.l_len = thiscase->b_len;
 | |
| 
 | |
| 			/* set the second parent lock */
 | |
| 			if ((fcntl(fd, F_SETLK, &flock)) < 0) {
 | |
| 				tst_resm(TFAIL, "Second parent lock failed");
 | |
| 				tst_resm(TFAIL, "Test case %d, errno = %d",
 | |
| 					 test + 1, errno);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 		}
 | |
| 		if ((thiscase->c_type) == SKIP) {
 | |
| 			close(fd);
 | |
| 			tst_resm(TINFO, "skipping test %d", test + 1);
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		/* Mask SIG_USR1 before forking child, to avoid race */
 | |
| 		(void)sighold(SIGUSR1);
 | |
| 
 | |
| 		/* flush the stdout to avoid garbled output */
 | |
| 		fflush(stdout);
 | |
| 
 | |
| 		if ((child = FORK_OR_VFORK()) == 0) {
 | |
| #ifdef UCLINUX
 | |
| 			if (self_exec(argv0, "nddddddddd", 2, thiscase->c_type,
 | |
| 				      thiscase->c_whence, thiscase->c_start,
 | |
| 				      thiscase->c_len, thiscase->c_flag,
 | |
| 				      thiscase->a_type, fd, test, parent) < 0) {
 | |
| 				tst_resm(TFAIL, "self_exec failed");
 | |
| 				cleanup();
 | |
| 			}
 | |
| #else
 | |
| 			dochild();
 | |
| #endif
 | |
| 		}
 | |
| 		if (child < 0)
 | |
| 			tst_brkm(TBROK|TERRNO, cleanup, "Fork failed");
 | |
| 
 | |
| 		if ((thiscase->c_flag) == WILLBLOCK) {
 | |
| 			/*
 | |
| 			 * Wait for a signal from the child then remove
 | |
| 			 * blocking lock. Set a 60 second alarm to break the
 | |
| 			 * pause just in case the child never signals us.
 | |
| 			 */
 | |
| 			alarm(TIME_OUT);
 | |
| 			sigpause(SIGUSR1);
 | |
| 
 | |
| 			/* turn off the alarm timer */
 | |
| 			alarm((unsigned)0);
 | |
| 			if (got1 != 1)
 | |
| 				tst_resm(TINFO, "Pause terminated without "
 | |
| 					 "signal SIGUSR1 from child");
 | |
| 			got1 = 0;
 | |
| 
 | |
| 			/*
 | |
| 			 * setup lock structure for parent to delete
 | |
| 			 * blocking lock then wait for child to exit
 | |
| 			 */
 | |
| 			flock.l_type = F_UNLCK;
 | |
| 			flock.l_whence = 0;
 | |
| 			flock.l_start = 0L;
 | |
| 			flock.l_len = 0L;
 | |
| 			if ((fcntl(fd, F_SETLK, &flock)) < 0) {
 | |
| 				tst_resm(TFAIL, "Attempt to release parent "
 | |
| 					 "lock failed");
 | |
| 				tst_resm(TFAIL, "Test case %d, errno = %d",
 | |
| 					 test + 1, errno);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 		}
 | |
| 		/*
 | |
| 		 * set a 60 second alarm to break the wait just in case the
 | |
| 		 * child doesn't terminate on its own accord
 | |
| 		 */
 | |
| 		alarm(TIME_OUT);
 | |
| 
 | |
| 		/* wait for the child to terminate and close the file */
 | |
| 		waitpid(child, &status, 0);
 | |
| 		/* turn off the alarm clock */
 | |
| 		alarm((unsigned)0);
 | |
| 		if (status != 0) {
 | |
| 			tst_resm(TFAIL, "tchild returned status 0x%x", status);
 | |
| 			fail = 1;
 | |
| 		}
 | |
| 		close(fd);
 | |
| 		if (fail)
 | |
| 			tst_resm(TFAIL, "testcase:%d FAILED", test + 1);
 | |
| 		else
 | |
| 			tst_resm(TPASS, "testcase:%d PASSED", test + 1);
 | |
| 	}
 | |
| 	unlink(tmpname);
 | |
| }
 | |
| 
 | |
| void catch_alarm(int sig)
 | |
| {
 | |
| 	/*
 | |
| 	 * Timer has runout and child has not signaled, need
 | |
| 	 * to kill off the child as it appears it will not
 | |
| 	 * on its own accord. Check that it is still around
 | |
| 	 * as it may have terminated abnormally while parent
 | |
| 	 * was waiting for SIGUSR1 signal from it.
 | |
| 	 */
 | |
| 	if (kill(child, 0) == 0) {
 | |
| 		kill(child, SIGKILL);
 | |
| 		perror("The child didnot terminate on its own accord");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void catch1(int sig)
 | |
| {
 | |
| 	struct sigaction act;
 | |
| 
 | |
| 	/*
 | |
| 	 * Set flag to let parent know that child is ready to have lock
 | |
| 	 * removed
 | |
| 	 */
 | |
| 	memset(&act, 0, sizeof(act));
 | |
| 	act.sa_handler = catch1;
 | |
| 	sigemptyset(&act.sa_mask);
 | |
| 	sigaddset(&act.sa_mask, SIGUSR1);
 | |
| 	sigaction(SIGUSR1, &act, NULL);
 | |
| 	got1++;
 | |
| }
 | |
| 
 | |
| static void testcheck_end(int check_fail, char *msg)
 | |
| {
 | |
| 	if (check_fail)
 | |
| 		tst_resm(TFAIL, "%s FAILED", msg);
 | |
| 	else
 | |
| 		tst_resm(TPASS, "%s PASSED", msg);
 | |
| }
 | |
| 
 | |
| int main(int ac, char **av)
 | |
| {
 | |
| 	int lc;
 | |
| 
 | |
| 	tst_parse_opts(ac, av, NULL, NULL);
 | |
| #ifdef UCLINUX
 | |
| 	argv0 = av[0];
 | |
| 
 | |
| 	maybe_run_child(&do_usleep_child, "nd", 1, &parent);
 | |
| 	thiscase = malloc(sizeof(testcase));
 | |
| 
 | |
| 	maybe_run_child(&dochild, "nddddddddd", 2, &thiscase->c_type,
 | |
| 			&thiscase->c_whence, &thiscase->c_start,
 | |
| 			&thiscase->c_len, &thiscase->c_flag, &thiscase->a_type,
 | |
| 			&fd, &test, &parent);
 | |
| #endif
 | |
| 
 | |
| 	setup();
 | |
| 
 | |
| 	if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC)
 | |
| 		NO_NFS = 0;
 | |
| 
 | |
| 	for (lc = 0; TEST_LOOPING(lc); lc++) {
 | |
| 		tst_count = 0;
 | |
| 
 | |
| /* //block1: */
 | |
| 		tst_resm(TINFO, "Enter block 1: without mandatory locking");
 | |
| 		fail = 0;
 | |
| 		/*
 | |
| 		 * try various file locks on an ordinary file without
 | |
| 		 * mandatory locking
 | |
| 		 */
 | |
| 		(void)run_test(O_CREAT | O_RDWR | O_TRUNC, 0777, 0, 0, 36);
 | |
| 		testcheck_end(fail, "Block 1, test 1");
 | |
| 
 | |
| 		/* Now try with negative values for L_start and L_len */
 | |
| 		(void)run_test(O_CREAT | O_RDWR | O_TRUNC, 0777, 5, 36, 45);
 | |
| 		testcheck_end(fail, "Block 1, test 2");
 | |
| 
 | |
| 		tst_resm(TINFO, "Exit block 1");
 | |
| 
 | |
| /* //block2: */
 | |
| 		/*
 | |
| 		 * Skip block2 if test on NFS, since NFS does not support
 | |
| 		 * mandatory locking
 | |
| 		 */
 | |
| 		tst_resm(TINFO, "Enter block 2: with mandatory locking");
 | |
| 		if (NO_NFS) {
 | |
| 			fail = 0;
 | |
| 			/*
 | |
| 			 * Try various locks on a file with mandatory
 | |
| 			 * record locking this should behave the same
 | |
| 			 * as an ordinary file
 | |
| 			 */
 | |
| 			(void)run_test(O_CREAT | O_RDWR | O_TRUNC,
 | |
| 				S_ENFMT | S_IRUSR | S_IWUSR, 0, 0, 36);
 | |
| 			testcheck_end(fail, "Block 2, test 1");
 | |
| 
 | |
| 			/* Now try negative values for L_start and L_len */
 | |
| 			(void)run_test(O_CREAT | O_RDWR | O_TRUNC,
 | |
| 				S_ENFMT | S_IRUSR | S_IWUSR, 5, 36, 45);
 | |
| 			testcheck_end(fail, "Block 2, test 2");
 | |
| 		} else {
 | |
| 			tst_resm(TCONF, "Skip block 2 as NFS does not"
 | |
| 				" support mandatory locking");
 | |
| 		}
 | |
| 
 | |
| 		tst_resm(TINFO, "Exit block 2");
 | |
| 
 | |
| /* //block3: */
 | |
| 		tst_resm(TINFO, "Enter block 3");
 | |
| 		fail = 0;
 | |
| 		/*
 | |
| 		 * Check that proper error status is returned when invalid
 | |
| 		 * argument used for WHENCE (negative value)
 | |
| 		 */
 | |
| 
 | |
| 		fd = SAFE_OPEN(cleanup, tmpname, O_CREAT | O_RDWR | O_TRUNC,
 | |
| 			       0777);
 | |
| 
 | |
| 		if (write(fd, FILEDATA, 10) < 0)
 | |
| 			tst_brkm(TBROK, cleanup, "write failed");
 | |
| 
 | |
| 		flock.l_type = F_WRLCK;
 | |
| 		flock.l_whence = -1;
 | |
| 		flock.l_start = 0L;
 | |
| 		flock.l_len = 0L;
 | |
| 
 | |
| 		if ((fcntl(fd, F_SETLK, &flock)) < 0) {
 | |
| 			if (errno != EINVAL) {
 | |
| 				tst_resm(TFAIL, "Expected %d got %d",
 | |
| 					 EINVAL, errno);
 | |
| 				fail = 1;
 | |
| 			}
 | |
| 		} else {
 | |
| 			tst_resm(TFAIL, "Lock succeeded when it should have "
 | |
| 				 "failed");
 | |
| 			fail = 1;
 | |
| 		}
 | |
| 
 | |
| 		close(fd);
 | |
| 		unlink(tmpname);
 | |
| 
 | |
| 		testcheck_end(fail, "Test with negative whence locking");
 | |
| 		tst_resm(TINFO, "Exit block 3");
 | |
| 
 | |
| /* //block4: */
 | |
| 		tst_resm(TINFO, "Enter block 4");
 | |
| 		fail = 0;
 | |
| 		/*
 | |
| 		 * Check that a lock on end of file is still valid when
 | |
| 		 * additional data is appended to end of file and a new
 | |
| 		 * process attempts to lock new data
 | |
| 		 */
 | |
| 		fd = SAFE_OPEN(cleanup, tmpname, O_CREAT | O_RDWR | O_TRUNC,
 | |
| 			       0777);
 | |
| 
 | |
| 		if (write(fd, FILEDATA, 10) < 0)
 | |
| 			tst_brkm(TBROK, cleanup, "write failed");
 | |
| 
 | |
| 		thiscase = &testcases[58];
 | |
| 		flock.l_type = thiscase->a_type;
 | |
| 		flock.l_whence = thiscase->a_whence;
 | |
| 		flock.l_start = thiscase->a_start;
 | |
| 		flock.l_len = thiscase->a_len;
 | |
| 
 | |
| 		/* Set the initial parent lock on the file */
 | |
| 		if ((fcntl(fd, F_SETLK, &flock)) < 0) {
 | |
| 			tst_resm(TFAIL, "First parent lock failed");
 | |
| 			tst_resm(TFAIL, "Test case %d, errno = %d", 58, errno);
 | |
| 			fail = 1;
 | |
| 		}
 | |
| 
 | |
| 		/* Write some additional data to end of file */
 | |
| 		if (write(fd, FILEDATA, 10) < 0)
 | |
| 			tst_brkm(TBROK, cleanup, "write failed");
 | |
| 
 | |
| 		/* Mask signal to avoid race */
 | |
| 		if (sighold(SIGUSR1) < 0)
 | |
| 			tst_brkm(TBROK, cleanup, "sighold failed");
 | |
| 
 | |
| 		if ((child = FORK_OR_VFORK()) == 0) {
 | |
| #ifdef UCLINUX
 | |
| 			if (self_exec(argv0, "nddddddddd", 2, thiscase->c_type,
 | |
| 				      thiscase->c_whence, thiscase->c_start,
 | |
| 				      thiscase->c_len, thiscase->c_flag,
 | |
| 				      thiscase->a_type, fd, test, parent) < 0) {
 | |
| 				tst_resm(TFAIL, "self_exec failed");
 | |
| 				cleanup();
 | |
| 			}
 | |
| #else
 | |
| 			dochild();
 | |
| #endif
 | |
| 		}
 | |
| 		if (child < 0)
 | |
| 			tst_brkm(TBROK|TERRNO, cleanup, "Fork failed");
 | |
| 
 | |
| 		/*
 | |
| 		 * Wait for a signal from the child then remove blocking lock.
 | |
| 		 * Set a 60 sec alarm to break the pause just in case the
 | |
| 		 * child doesn't terminate on its own accord
 | |
| 		 */
 | |
| 		(void)alarm(TIME_OUT);
 | |
| 
 | |
| 		(void)sigpause(SIGUSR1);
 | |
| 
 | |
| 		/* turn off the alarm timer */
 | |
| 		(void)alarm((unsigned)0);
 | |
| 		if (got1 != 1) {
 | |
| 			tst_resm(TINFO, "Pause terminated without signal "
 | |
| 				 "SIGUSR1 from child");
 | |
| 		}
 | |
| 		got1 = 0;
 | |
| 
 | |
| 		/*
 | |
| 		 * Set up lock structure for parent to delete
 | |
| 		 * blocking lock then wait for child to exit
 | |
| 		 */
 | |
| 		flock.l_type = F_UNLCK;
 | |
| 		flock.l_whence = 0;
 | |
| 		flock.l_start = 0L;
 | |
| 		flock.l_len = 0L;
 | |
| 		if ((fcntl(fd, F_SETLK, &flock)) < 0) {
 | |
| 			tst_resm(TFAIL, "Attempt to release parent lock "
 | |
| 				 "failed");
 | |
| 			tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
 | |
| 				 errno);
 | |
| 			fail = 1;
 | |
| 		}
 | |
| 
 | |
| 		/*
 | |
| 		 * set a 60 sec alarm to break the wait just in case the
 | |
| 		 * child doesn't terminate on its own accord
 | |
| 		 */
 | |
| 		(void)alarm(TIME_OUT);
 | |
| 
 | |
| 		waitpid(child, &status, 0);
 | |
| 		if (WEXITSTATUS(status) != 0) {
 | |
| 			fail = 1;
 | |
| 			tst_resm(TFAIL, "child returned bad exit status");
 | |
| 		}
 | |
| 
 | |
| 		/* turn off the alarm clock */
 | |
| 		(void)alarm((unsigned)0);
 | |
| 		if (status != 0) {
 | |
| 			tst_resm(TFAIL, "child returned status 0x%x", status);
 | |
| 			fail = 1;
 | |
| 		}
 | |
| 		close(fd);
 | |
| 		unlink(tmpname);
 | |
| 
 | |
| 		testcheck_end(fail, "Test of locks on file");
 | |
| 		tst_resm(TINFO, "Exit block 4");
 | |
| 	}
 | |
| 	cleanup();
 | |
| 	tst_exit();
 | |
| }
 |