Home | History | Annotate | Download | only in fcntl
      1 /*
      2  *
      3  *   Copyright (c) International Business Machines  Corp., 2001
      4  *
      5  *   This program is free software;  you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation; either version 2 of the License, or
      8  *   (at your option) any later version.
      9  *
     10  *   This program is distributed in the hope that it will be useful,
     11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     13  *   the GNU General Public License for more details.
     14  *
     15  *   You should have received a copy of the GNU General Public License
     16  *   along with this program;  if not, write to the Free Software
     17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     18  */
     19 
     20 /*
     21  * NAME
     22  *	fcntl16.c
     23  *
     24  * DESCRIPTION
     25  *	Additional file locking test cases for checking proper notifictaion
     26  *	of processes on lock change
     27  *
     28  * ALGORITHM
     29  *	Various test cases are used to lock a file opened without mandatory
     30  *	locking, with madatory locking and mandatory locking with NOBLOCK.
     31  *	Checking that processes waiting on lock boundaries are notified
     32  *	properly when boundaries change
     33  *
     34  * USAGE
     35  *	fcntl16
     36  *
     37  * HISTORY
     38  *	07/2001 Ported by Wayne Boyer
     39  *	04/2002 wjhuie sigset cleanups
     40  *
     41  * RESTRICTIONS
     42  *	None
     43  */
     44 
     45 #include <fcntl.h>
     46 #include <signal.h>
     47 #include <errno.h>
     48 #include "test.h"
     49 #include <sys/stat.h>
     50 #include <sys/types.h>
     51 #include <sys/wait.h>
     52 
     53 
     54 #define SKIPVAL 0x0f00
     55 //#define       SKIP    SKIPVAL, 0, 0L, 0L, IGNORED
     56 #define SKIP 0,0,0L,0L,0
     57 #if (SKIPVAL == F_RDLCK) || (SKIPVAL == F_WRLCK)
     58 #error invalid SKIP, must not be F_RDLCK or F_WRLCK
     59 #endif
     60 
     61 #define	IGNORED		0
     62 #define	NOBLOCK		2	/* immediate success */
     63 #define	WILLBLOCK	3	/* blocks, succeeds, parent unlocks records */
     64 #define	TIME_OUT	10
     65 int NO_NFS = 1;			/* Test on NFS or not */
     66 
     67 typedef struct {
     68 	struct flock parent_a;
     69 	struct flock parent_b;
     70 	struct flock child_a;
     71 	struct flock child_b;
     72 	struct flock parent_c;
     73 	struct flock parent_d;
     74 } testcase;
     75 
     76 static testcase testcases[] = {
     77 	/* #1 Parent_a making a write lock on entire file */
     78 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
     79 	 /* Parent_b skipped */
     80 	 {SKIP},
     81 	 /* Child_a read lock on byte 1 to byte 5 */
     82 	 {F_RDLCK, 0, 0L, 5L, NOBLOCK},
     83 	 /* Child_b read lock on byte 6 to byte 10 */
     84 	 {F_RDLCK, 0, 6L, 5L, NOBLOCK},
     85 	 /*
     86 	  * Parent_c read lock on entire file
     87 	  */
     88 	 {F_RDLCK, 0, 0L, 0L, IGNORED},
     89 	 /* Parent_d skipped */
     90 	 {SKIP},},
     91 
     92 	/* #2 Parent_a making a write lock on entire file */
     93 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
     94 	 /* Parent_b skipped */
     95 	 {SKIP},
     96 	 /* Child_a read lock on byte 1 to byte 5 */
     97 	 {F_RDLCK, 0, 0L, 5L, WILLBLOCK},
     98 	 /* Child_b read lock on byte 6 to byte 10 */
     99 	 {F_RDLCK, 0, 6L, 5L, WILLBLOCK},
    100 	 /*
    101 	  * Parent_c write lock on entire
    102 	  * file
    103 	  */
    104 	 {F_WRLCK, 0, 0L, 0L, IGNORED},
    105 	 /* Parent_d skipped */
    106 	 {SKIP},},
    107 
    108 	/* #3 Parent_a making a write lock on entire file */
    109 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
    110 	 /* Parent_b skipped */
    111 	 {SKIP},
    112 	 /* Child_a read lock on byte 2 to byte 4 */
    113 	 {F_RDLCK, 0, 2L, 3L, WILLBLOCK},
    114 	 /* Child_b read lock on byte 6 to byte 8 */
    115 	 {F_RDLCK, 0, 6L, 3L, WILLBLOCK},
    116 	 /*
    117 	  * Parent_c read lock on byte 3 to
    118 	  * byte 7
    119 	  */
    120 	 {F_RDLCK, 0, 3L, 5L, IGNORED},
    121 	 /* Parent_d skipped */
    122 	 {SKIP},},
    123 
    124 	/* #4 Parent_a making a write lock on entire file */
    125 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
    126 	 /* Parent_b skipped */
    127 	 {SKIP},
    128 	 /* Child_a read lock on byte 2 to byte 4 */
    129 	 {F_RDLCK, 0, 2L, 3L, WILLBLOCK},
    130 	 /* Child_b read lock on byte 6 to byte 8 */
    131 	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
    132 	 /*
    133 	  * Parent_c read lock on byte 5 to
    134 	  * byte 9
    135 	  */
    136 	 {F_RDLCK, 0, 5L, 5L, IGNORED},
    137 	 /* Parent_d skipped */
    138 	 {SKIP},},
    139 
    140 	/* #5 Parent_a making a write lock on entire file */
    141 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
    142 	 /* Parent_b skipped */
    143 	 {SKIP},
    144 	 /* Child_a read lock on byte 3 to byte 7 */
    145 	 {F_RDLCK, 0, 3L, 5L, NOBLOCK},
    146 	 /* Child_b read lock on byte 5 to byte 10 */
    147 	 {F_RDLCK, 0, 5L, 6L, WILLBLOCK},
    148 	 /*
    149 	  * Parent_c read lock on byte 2 to
    150 	  * byte 8
    151 	  */
    152 	 {F_RDLCK, 0, 2L, 7L, IGNORED},
    153 	 /* Parent_d skipped */
    154 	 {SKIP},},
    155 
    156 	/* #6 Parent_a making a write lock on entire file */
    157 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
    158 	 /* Parent_b skipped */
    159 	 {SKIP},
    160 	 /* Child_a read lock on byte 2 to byte 4 */
    161 	 {F_RDLCK, 0, 2L, 3L, WILLBLOCK},
    162 	 /* Child_b write lock on byte 6 to byte 8 */
    163 	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
    164 	 /* Parent_c no lock on byte 3 to 9 */
    165 	 {F_UNLCK, 0, 3L, 7L, IGNORED},
    166 	 /* Parent_d skipped */
    167 	 {SKIP},},
    168 
    169 	/* #7 Parent_a making a write lock on entire file */
    170 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
    171 	 /* Parent_b read lock on byte 3 to byte 7 */
    172 	 {F_RDLCK, 0, 3L, 5L, IGNORED},
    173 	 /* Child_a read lock on byte 2 to byte 4 */
    174 	 {F_RDLCK, 0, 2L, 3L, NOBLOCK},
    175 	 /* Child_b read lock on byte 6 to byte 8 */
    176 	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
    177 	 /*
    178 	  * Parent_c read lock on byte 1 to
    179 	  * byte 9
    180 	  */
    181 	 {F_RDLCK, 0, 1L, 9L, IGNORED},
    182 	 /* Parent_d skipped */
    183 	 {SKIP},},
    184 
    185 	/* #8 Parent_a making a write lock on byte 2 to byte 4 */
    186 	{{F_WRLCK, 0, 2L, 3L, IGNORED},
    187 	 /* Parent_b write lock on byte 6 to byte 8 */
    188 	 {F_WRLCK, 0, 6L, 3L, IGNORED},
    189 	 /* Child_a read lock on byte 3 to byte 7 */
    190 	 {F_RDLCK, 0, 3L, 5L, NOBLOCK},
    191 	 /* Child_b skipped */
    192 	 {SKIP},
    193 	 /*
    194 	  * Parent_c read lock on byte 1 to
    195 	  * byte 5
    196 	  */
    197 	 {F_RDLCK, 0, 1L, 5L, IGNORED},
    198 	 /*
    199 	  * Parent_d read lock on
    200 	  * byte 5 to byte 9
    201 	  */
    202 	 {F_RDLCK, 0, 5L, 5L,
    203 	  IGNORED},},
    204 
    205 	/* #9 Parent_a making a write lock on entire file */
    206 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
    207 	 /* Parent_b read lock on byte 3 to byte 7 */
    208 	 {F_RDLCK, 0, 3L, 5L, IGNORED},
    209 	 /* Child_a read lock on byte 2 to byte 4 */
    210 	 {F_RDLCK, 0, 2L, 3L, NOBLOCK},
    211 	 /* Child_b read lock on byte 6 to byte 8 */
    212 	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
    213 	 /*
    214 	  * Parent_c read lock on byte 1 to
    215 	  * byte 3
    216 	  */
    217 	 {F_RDLCK, 0, 1L, 3L, IGNORED},
    218 	 /*
    219 	  * Parent_d read lock on
    220 	  * byte 7 to byte 9
    221 	  */
    222 	 {F_RDLCK, 0, 7L, 3L,
    223 	  IGNORED},},
    224 
    225 	/* #10 Parent_a making a write lock on entire file */
    226 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
    227 	 /* Parent_b skipped */
    228 	 {SKIP},
    229 	 /* Child_a read lock on byte 2 to byte 4 */
    230 	 {F_RDLCK, 0, 2L, 3L, NOBLOCK},
    231 	 /* Child_b read lock on byte 6 to byte 8 */
    232 	 {F_RDLCK, 0, 6L, 3L, NOBLOCK},
    233 	 /*
    234 	  * Parent_c read lock on byte 1 to
    235 	  * byte 7
    236 	  */
    237 	 {F_RDLCK, 0, 1L, 7L, IGNORED},
    238 	 /*
    239 	  * Parent_d read lock on
    240 	  * byte 3 to byte 9
    241 	  */
    242 	 {F_RDLCK, 0, 3L, 7L,
    243 	  IGNORED},},
    244 
    245 	/* #11 Parent_a making a write lock on entire file */
    246 	{{F_WRLCK, 0, 0L, 0L, IGNORED},
    247 	 /* Parent_b skipped */
    248 	 {SKIP},
    249 	 /* Child_a read lock on byte 3 to byte 7 */
    250 	 {F_RDLCK, 0, 3L, 5L, NOBLOCK},
    251 	 /* Child_b read lock on byte 3 to byte 7 */
    252 	 {F_RDLCK, 0, 3L, 5L, NOBLOCK},
    253 	 /*
    254 	  * Parent_c read lock on byte 3 to
    255 	  * byte 7
    256 	  */
    257 	 {F_RDLCK, 0, 3L, 5L, IGNORED},
    258 	 /* Parent_d skipped */
    259 	 {SKIP},},
    260 };
    261 
    262 static testcase *thiscase;
    263 static struct flock *thislock;
    264 static int parent;
    265 static int child_flag1 = 0;
    266 static int child_flag2 = 0;
    267 static int parent_flag = 0;
    268 static int alarm_flag = 0;
    269 static int child_pid[2], flag[2];
    270 static int fd;
    271 static int test;
    272 static char tmpname[40];
    273 
    274 #define	FILEDATA	"tenbytes!"
    275 
    276 extern void catch_int(int sig);	/* signal catching subroutine */
    277 
    278 char *TCID = "fcntl16";
    279 int TST_TOTAL = 1;
    280 
    281 #ifdef UCLINUX
    282 static char *argv0;
    283 #endif
    284 
    285 /*
    286  * cleanup - performs all the ONE TIME cleanup for this test at completion or
    287  *	premature exit
    288  */
    289 void cleanup(void)
    290 {
    291 	tst_rmdir();
    292 
    293 }
    294 
    295 void dochild(int kid)
    296 {
    297 	/* child process */
    298 	struct sigaction sact;
    299 	sact.sa_flags = 0;
    300 	sact.sa_handler = catch_int;
    301 	sigemptyset(&sact.sa_mask);
    302 	(void)sigaction(SIGUSR1, &sact, NULL);
    303 
    304 	/* Lock should succeed after blocking and parent releases lock */
    305 	if (kid) {
    306 		if ((kill(parent, SIGUSR2)) < 0) {
    307 			tst_resm(TFAIL, "Attempt to send signal to parent "
    308 				 "failed");
    309 			tst_resm(TFAIL, "Test case %d, child %d, errno = %d",
    310 				 test + 1, kid, errno);
    311 			exit(1);
    312 		}
    313 	} else {
    314 		if ((kill(parent, SIGUSR1)) < 0) {
    315 			tst_resm(TFAIL, "Attempt to send signal to parent "
    316 				 "failed");
    317 			tst_resm(TFAIL, "Test case %d, child %d, errno = %d",
    318 				 test + 1, kid, errno);
    319 			exit(1);
    320 		}
    321 	}
    322 
    323 	if ((fcntl(fd, F_SETLKW, thislock)) < 0) {
    324 		if (errno == EINTR && parent_flag) {
    325 			/*
    326 			 * signal received is waiting for lock to clear,
    327 			 * this is expected if flag = WILLBLOCK
    328 			 */
    329 			exit(1);
    330 		} else {
    331 			tst_resm(TFAIL, "Attempt to set child BLOCKING lock "
    332 				 "failed");
    333 			tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
    334 				 errno);
    335 			exit(2);
    336 		}
    337 	}
    338 	exit(0);
    339 }				/* end of child process */
    340 
    341 #ifdef UCLINUX
    342 static int kid_uc;
    343 
    344 void dochild_uc(void)
    345 {
    346 	dochild(kid_uc);
    347 }
    348 #endif
    349 
    350 void catch_alarm(int sig)
    351 {
    352 	alarm_flag = 1;
    353 }
    354 
    355 void catch_usr1(int sig)
    356 {				/* invoked on catching SIGUSR1 */
    357 	/*
    358 	 * Set flag to let parent know that child #1 is ready to have the
    359 	 * lock removed
    360 	 */
    361 	child_flag1 = 1;
    362 }
    363 
    364 void catch_usr2(int sig)
    365 {				/* invoked on catching SIGUSR2 */
    366 	/*
    367 	 * Set flag to let parent know that child #2 is ready to have the
    368 	 * lock removed
    369 	 */
    370 	child_flag2 = 1;
    371 }
    372 
    373 void catch_int(int sig)
    374 {				/* invoked on child catching SIGUSR1 */
    375 	/*
    376 	 * Set flag to interrupt fcntl call in child and force a controlled
    377 	 * exit
    378 	 */
    379 	parent_flag = 1;
    380 }
    381 
    382 void child_sig(int sig, int nkids)
    383 {
    384 	int i;
    385 
    386 	for (i = 0; i < nkids; i++) {
    387 		if (kill(child_pid[i], 0) == 0) {
    388 			if ((kill(child_pid[i], sig)) < 0) {
    389 				tst_resm(TFAIL, "Attempt to signal child %d, "
    390 					 "failed", i + 1);
    391 			}
    392 		}
    393 	}
    394 }
    395 
    396 /*
    397  * setup - performs all ONE TIME steup for this test
    398  */
    399 void setup(void)
    400 {
    401 	struct sigaction sact;
    402 
    403 	tst_sig(FORK, DEF_HANDLER, cleanup);
    404 
    405 	umask(0);
    406 
    407 	/* Pause if option was specified */
    408 	TEST_PAUSE;
    409 
    410 	parent = getpid();
    411 
    412 	tst_tmpdir();
    413 
    414 	/* On NFS or not */
    415 	if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC)
    416 		NO_NFS = 0;
    417 
    418 	/* set up temp filename */
    419 	sprintf(tmpname, "fcntl4.%d", parent);
    420 
    421 	/*
    422 	 * Set up signal handling functions
    423 	 */
    424 	memset(&sact, 0, sizeof(sact));
    425 	sact.sa_handler = catch_usr1;
    426 	sigemptyset(&sact.sa_mask);
    427 	sigaddset(&sact.sa_mask, SIGUSR1);
    428 	sigaction(SIGUSR1, &sact, NULL);
    429 
    430 	memset(&sact, 0, sizeof(sact));
    431 	sact.sa_handler = catch_usr2;
    432 	sigemptyset(&sact.sa_mask);
    433 	sigaddset(&sact.sa_mask, SIGUSR2);
    434 	sigaction(SIGUSR2, &sact, NULL);
    435 
    436 	memset(&sact, 0, sizeof(sact));
    437 	sact.sa_handler = catch_alarm;
    438 	sigemptyset(&sact.sa_mask);
    439 	sigaddset(&sact.sa_mask, SIGALRM);
    440 	sigaction(SIGALRM, &sact, NULL);
    441 }
    442 
    443 int run_test(int file_flag, int file_mode, int start, int end)
    444 {
    445 	int child_count;
    446 	int child;
    447 	int nexited;
    448 	int status, expect_stat;
    449 	int i, fail = 0;
    450 
    451 	/* loop through all test cases */
    452 	for (test = start; test < end; test++) {
    453 		/* open a temp file to lock */
    454 		fd = open(tmpname, file_flag, file_mode);
    455 		if (fd < 0) {
    456 			tst_brkm(TBROK, cleanup, "open failed");
    457 		}
    458 
    459 		/* write some dummy data to the file */
    460 		(void)write(fd, FILEDATA, 10);
    461 
    462 		/* Initialize first parent lock structure */
    463 		thiscase = &testcases[test];
    464 		thislock = &thiscase->parent_a;
    465 
    466 		/* set the initial parent lock on the file */
    467 		if ((fcntl(fd, F_SETLK, thislock)) < 0) {
    468 			tst_resm(TFAIL, "First parent lock failed");
    469 			tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
    470 				 errno);
    471 			close(fd);
    472 			unlink(tmpname);
    473 			return 1;
    474 		}
    475 
    476 		/* Initialize second parent lock structure */
    477 		thislock = &thiscase->parent_b;
    478 
    479 		if ((thislock->l_type) != IGNORED) {	/*SKIPVAL */
    480 			/* set the second parent lock */
    481 			if ((fcntl(fd, F_SETLK, thislock)) < 0) {
    482 				tst_resm(TFAIL, "Second parent lock failed");
    483 				tst_resm(TFAIL, "Test case %d, errno = %d",
    484 					 test + 1, errno);
    485 				close(fd);
    486 				unlink(tmpname);
    487 				return 1;
    488 			}
    489 		}
    490 
    491 		/* Initialize first child lock structure */
    492 		thislock = &thiscase->child_a;
    493 
    494 		/* Initialize child counter and flags */
    495 		alarm_flag = parent_flag = 0;
    496 		child_flag1 = child_flag2 = 0;
    497 		child_count = 0;
    498 
    499 		/* spawn child processes */
    500 		for (i = 0; i < 2; i++) {
    501 			if (thislock->l_type != IGNORED) {
    502 				if ((child = FORK_OR_VFORK()) == 0) {
    503 #ifdef UCLINUX
    504 					if (self_exec(argv0, "ddddd", i, parent,
    505 						      test, thislock, fd) < 0) {
    506 						perror("self_exec failed");
    507 						return 1;
    508 					}
    509 #else
    510 					dochild(i);
    511 #endif
    512 				}
    513 				if (child < 0) {
    514 					perror("Fork failed");
    515 					return 1;
    516 				}
    517 				child_count++;
    518 				child_pid[i] = child;
    519 				flag[i] = thislock->l_pid;
    520 			}
    521 			/* Initialize second child lock structure */
    522 			thislock = &thiscase->child_b;
    523 		}
    524 		/* parent process */
    525 
    526 		/*
    527 		 * Wait for children to signal they are ready. Set a timeout
    528 		 * just in case they don't signal at all.
    529 		 */
    530 		alarm(TIME_OUT);
    531 
    532 		while (!alarm_flag
    533 		       && (child_flag1 + child_flag2 != child_count)) {
    534 			pause();
    535 		}
    536 
    537 		/*
    538 		 * Turn off alarm and unmask signals
    539 		 */
    540 		alarm((unsigned)0);
    541 
    542 		if (child_flag1 + child_flag2 != child_count) {
    543 			tst_resm(TFAIL, "Test case %d: kids didn't signal",
    544 				 test + 1);
    545 			fail = 1;
    546 		}
    547 		child_flag1 = child_flag2 = alarm_flag = 0;
    548 
    549 		thislock = &thiscase->parent_c;
    550 
    551 		/* set the third parent lock on the file */
    552 		if ((fcntl(fd, F_SETLK, thislock)) < 0) {
    553 			tst_resm(TFAIL, "Third parent lock failed");
    554 			tst_resm(TFAIL, "Test case %d, errno = %d",
    555 				 test + 1, errno);
    556 			close(fd);
    557 			unlink(tmpname);
    558 			return 1;
    559 		}
    560 
    561 		/* Initialize fourth parent lock structure */
    562 		thislock = &thiscase->parent_d;
    563 
    564 		if ((thislock->l_type) != IGNORED) {	/*SKIPVAL */
    565 			/* set the fourth parent lock */
    566 			if ((fcntl(fd, F_SETLK, thislock)) < 0) {
    567 				tst_resm(TINFO, "Fourth parent lock failed");
    568 				tst_resm(TINFO, "Test case %d, errno = %d",
    569 					 test + 1, errno);
    570 				close(fd);
    571 				unlink(tmpname);
    572 				return 1;
    573 			}
    574 		}
    575 
    576 		/*
    577 		 * Wait for children to exit, or for timeout to occur.
    578 		 * Timeouts are expected for testcases where kids are
    579 		 * 'WILLBLOCK', In that case, send kids a wakeup interrupt
    580 		 * and wait again for them. If a second timeout occurs, then
    581 		 * something is wrong.
    582 		 */
    583 		alarm_flag = nexited = 0;
    584 		while (nexited < child_count) {
    585 			alarm(TIME_OUT);
    586 			child = wait(&status);
    587 			alarm(0);
    588 
    589 			if (child == -1) {
    590 				if (errno != EINTR || alarm_flag != 1) {
    591 					/*
    592 					 * Some error other than a timeout,
    593 					 * or else this is the second
    594 					 * timeout. Both cases are errors.
    595 					 */
    596 					break;
    597 				}
    598 
    599 				/*
    600 				 * Expected timeout case. Signal kids then
    601 				 * go back and wait again
    602 				 */
    603 				child_sig(SIGUSR1, child_count);
    604 				continue;
    605 			}
    606 
    607 			for (i = 0; i < child_count; i++)
    608 				if (child == child_pid[i])
    609 					break;
    610 			if (i == child_count) {
    611 				/*
    612 				 * Ignore unexpected kid, it could be a
    613 				 * leftover from a previous iteration that
    614 				 * timed out.
    615 				 */
    616 				continue;
    617 			}
    618 
    619 			/* Found the right kid, check his status */
    620 			nexited++;
    621 
    622 			expect_stat = (flag[i] == NOBLOCK) ? 0 : 1;
    623 
    624 			if (!WIFEXITED(status)
    625 			    || WEXITSTATUS(status) != expect_stat) {
    626 				/* got unexpected exit status from kid */
    627 				tst_resm(TFAIL, "Test case %d: child %d %s "
    628 					 "or got bad status (x%x)", test + 1,
    629 					 i, (flag[i] == NOBLOCK) ?
    630 					 "BLOCKED unexpectedly" :
    631 					 "failed to BLOCK", status);
    632 				fail = 1;
    633 			}
    634 		}
    635 
    636 		if (nexited != child_count) {
    637 			tst_resm(TFAIL, "Test case %d, caught %d expected %d "
    638 				 "children", test + 1, nexited, child_count);
    639 			child_sig(SIGKILL, nexited);
    640 			fail = 1;
    641 		}
    642 		close(fd);
    643 	}
    644 	unlink(tmpname);
    645 	if (fail) {
    646 		return 1;
    647 	} else {
    648 		return 0;
    649 	}
    650 	return 0;
    651 }
    652 
    653 int main(int ac, char **av)
    654 {
    655 
    656 	int lc;
    657 
    658 	tst_parse_opts(ac, av, NULL, NULL);
    659 #ifdef UCLINUX
    660 	maybe_run_child(dochild_uc, "ddddd", &kid_uc, &parent, &test,
    661 			&thislock, &fd);
    662 	argv0 = av[0];
    663 #endif
    664 
    665 	setup();		/* global setup */
    666 
    667 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    668 		/* reset tst_count in case we are looping */
    669 		tst_count = 0;
    670 
    671 /* //block1: */
    672 		/*
    673 		 * Check file locks on an ordinary file without
    674 		 * mandatory locking
    675 		 */
    676 		tst_resm(TINFO, "Entering block 1");
    677 		if (run_test(O_CREAT | O_RDWR | O_TRUNC, 0777, 0, 11)) {
    678 			tst_resm(TINFO, "Test case 1: without mandatory "
    679 				 "locking FAILED");
    680 		} else {
    681 			tst_resm(TINFO, "Test case 1: without manadatory "
    682 				 "locking PASSED");
    683 		}
    684 		tst_resm(TINFO, "Exiting block 1");
    685 
    686 /* //block2: */
    687 		/*
    688 		 * Check the file locks on a file with mandatory record
    689 		 * locking
    690 		 */
    691 		tst_resm(TINFO, "Entering block 2");
    692 		if (NO_NFS && run_test(O_CREAT | O_RDWR | O_TRUNC, S_ISGID |
    693 			     S_IRUSR | S_IWUSR, 0, 11)) {
    694 			tst_resm(TINFO, "Test case 2: with mandatory record "
    695 				 "locking FAILED");
    696 		} else {
    697 			if (NO_NFS)
    698 				tst_resm(TINFO, "Test case 2: with mandatory"
    699 					 " record locking PASSED");
    700 			else
    701 				tst_resm(TCONF, "Test case 2: NFS does not"
    702 					 " support mandatory locking");
    703 		}
    704 		tst_resm(TINFO, "Exiting block 2");
    705 
    706 /* //block3: */
    707 		/*
    708 		 * Check file locks on a file with mandatory record locking
    709 		 * and no delay
    710 		 */
    711 		tst_resm(TINFO, "Entering block 3");
    712 		if (NO_NFS && run_test(O_CREAT | O_RDWR | O_TRUNC | O_NDELAY,
    713 			     S_ISGID | S_IRUSR | S_IWUSR, 0, 11)) {
    714 			tst_resm(TINFO, "Test case 3: mandatory locking with "
    715 				 "NODELAY FAILED");
    716 		} else {
    717 			if (NO_NFS)
    718 				tst_resm(TINFO, "Test case 3: mandatory"
    719 					 " locking with NODELAY PASSED");
    720 			else
    721 				tst_resm(TCONF, "Test case 3: NFS does not"
    722 					 " support mandatory locking");
    723 		}
    724 		tst_resm(TINFO, "Exiting block 3");
    725 	}
    726 	cleanup();
    727 	tst_exit();
    728 }
    729