727 lines
17 KiB
C
727 lines
17 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
|
|
* fcntl16.c
|
|
*
|
|
* DESCRIPTION
|
|
* Additional file locking test cases for checking proper notifictaion
|
|
* of processes on lock change
|
|
*
|
|
* ALGORITHM
|
|
* Various test cases are used to lock a file opened without mandatory
|
|
* locking, with madatory locking and mandatory locking with NOBLOCK.
|
|
* Checking that processes waiting on lock boundaries are notified
|
|
* properly when boundaries change
|
|
*
|
|
* USAGE
|
|
* fcntl16
|
|
*
|
|
* HISTORY
|
|
* 07/2001 Ported by Wayne Boyer
|
|
* 04/2002 wjhuie sigset cleanups
|
|
*
|
|
* RESTRICTIONS
|
|
* None
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include "test.h"
|
|
#include "safe_macros.h"
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
|
|
|
|
#define SKIPVAL 0x0f00
|
|
//#define SKIP SKIPVAL, 0, 0L, 0L, IGNORED
|
|
#define SKIP 0,0,0L,0L,0
|
|
#if (SKIPVAL == F_RDLCK) || (SKIPVAL == F_WRLCK)
|
|
#error invalid SKIP, must not be F_RDLCK or F_WRLCK
|
|
#endif
|
|
|
|
#define IGNORED 0
|
|
#define NOBLOCK 2 /* immediate success */
|
|
#define WILLBLOCK 3 /* blocks, succeeds, parent unlocks records */
|
|
#define TIME_OUT 10
|
|
int NO_NFS = 1; /* Test on NFS or not */
|
|
|
|
typedef struct {
|
|
struct flock parent_a;
|
|
struct flock parent_b;
|
|
struct flock child_a;
|
|
struct flock child_b;
|
|
struct flock parent_c;
|
|
struct flock parent_d;
|
|
} testcase;
|
|
|
|
static testcase testcases[] = {
|
|
/* #1 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b skipped */
|
|
{SKIP},
|
|
/* Child_a read lock on byte 1 to byte 5 */
|
|
{F_RDLCK, 0, 0L, 5L, NOBLOCK},
|
|
/* Child_b read lock on byte 6 to byte 10 */
|
|
{F_RDLCK, 0, 6L, 5L, NOBLOCK},
|
|
/*
|
|
* Parent_c read lock on entire file
|
|
*/
|
|
{F_RDLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_d skipped */
|
|
{SKIP},},
|
|
|
|
/* #2 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b skipped */
|
|
{SKIP},
|
|
/* Child_a read lock on byte 1 to byte 5 */
|
|
{F_RDLCK, 0, 0L, 5L, WILLBLOCK},
|
|
/* Child_b read lock on byte 6 to byte 10 */
|
|
{F_RDLCK, 0, 6L, 5L, WILLBLOCK},
|
|
/*
|
|
* Parent_c write lock on entire
|
|
* file
|
|
*/
|
|
{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_d skipped */
|
|
{SKIP},},
|
|
|
|
/* #3 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b skipped */
|
|
{SKIP},
|
|
/* Child_a read lock on byte 2 to byte 4 */
|
|
{F_RDLCK, 0, 2L, 3L, WILLBLOCK},
|
|
/* Child_b read lock on byte 6 to byte 8 */
|
|
{F_RDLCK, 0, 6L, 3L, WILLBLOCK},
|
|
/*
|
|
* Parent_c read lock on byte 3 to
|
|
* byte 7
|
|
*/
|
|
{F_RDLCK, 0, 3L, 5L, IGNORED},
|
|
/* Parent_d skipped */
|
|
{SKIP},},
|
|
|
|
/* #4 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b skipped */
|
|
{SKIP},
|
|
/* Child_a read lock on byte 2 to byte 4 */
|
|
{F_RDLCK, 0, 2L, 3L, WILLBLOCK},
|
|
/* Child_b read lock on byte 6 to byte 8 */
|
|
{F_RDLCK, 0, 6L, 3L, NOBLOCK},
|
|
/*
|
|
* Parent_c read lock on byte 5 to
|
|
* byte 9
|
|
*/
|
|
{F_RDLCK, 0, 5L, 5L, IGNORED},
|
|
/* Parent_d skipped */
|
|
{SKIP},},
|
|
|
|
/* #5 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b skipped */
|
|
{SKIP},
|
|
/* Child_a read lock on byte 3 to byte 7 */
|
|
{F_RDLCK, 0, 3L, 5L, NOBLOCK},
|
|
/* Child_b read lock on byte 5 to byte 10 */
|
|
{F_RDLCK, 0, 5L, 6L, WILLBLOCK},
|
|
/*
|
|
* Parent_c read lock on byte 2 to
|
|
* byte 8
|
|
*/
|
|
{F_RDLCK, 0, 2L, 7L, IGNORED},
|
|
/* Parent_d skipped */
|
|
{SKIP},},
|
|
|
|
/* #6 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b skipped */
|
|
{SKIP},
|
|
/* Child_a read lock on byte 2 to byte 4 */
|
|
{F_RDLCK, 0, 2L, 3L, WILLBLOCK},
|
|
/* Child_b write lock on byte 6 to byte 8 */
|
|
{F_RDLCK, 0, 6L, 3L, NOBLOCK},
|
|
/* Parent_c no lock on byte 3 to 9 */
|
|
{F_UNLCK, 0, 3L, 7L, IGNORED},
|
|
/* Parent_d skipped */
|
|
{SKIP},},
|
|
|
|
/* #7 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b read lock on byte 3 to byte 7 */
|
|
{F_RDLCK, 0, 3L, 5L, IGNORED},
|
|
/* Child_a read lock on byte 2 to byte 4 */
|
|
{F_RDLCK, 0, 2L, 3L, NOBLOCK},
|
|
/* Child_b read lock on byte 6 to byte 8 */
|
|
{F_RDLCK, 0, 6L, 3L, NOBLOCK},
|
|
/*
|
|
* Parent_c read lock on byte 1 to
|
|
* byte 9
|
|
*/
|
|
{F_RDLCK, 0, 1L, 9L, IGNORED},
|
|
/* Parent_d skipped */
|
|
{SKIP},},
|
|
|
|
/* #8 Parent_a making a write lock on byte 2 to byte 4 */
|
|
{{F_WRLCK, 0, 2L, 3L, IGNORED},
|
|
/* Parent_b write lock on byte 6 to byte 8 */
|
|
{F_WRLCK, 0, 6L, 3L, IGNORED},
|
|
/* Child_a read lock on byte 3 to byte 7 */
|
|
{F_RDLCK, 0, 3L, 5L, NOBLOCK},
|
|
/* Child_b skipped */
|
|
{SKIP},
|
|
/*
|
|
* Parent_c read lock on byte 1 to
|
|
* byte 5
|
|
*/
|
|
{F_RDLCK, 0, 1L, 5L, IGNORED},
|
|
/*
|
|
* Parent_d read lock on
|
|
* byte 5 to byte 9
|
|
*/
|
|
{F_RDLCK, 0, 5L, 5L,
|
|
IGNORED},},
|
|
|
|
/* #9 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b read lock on byte 3 to byte 7 */
|
|
{F_RDLCK, 0, 3L, 5L, IGNORED},
|
|
/* Child_a read lock on byte 2 to byte 4 */
|
|
{F_RDLCK, 0, 2L, 3L, NOBLOCK},
|
|
/* Child_b read lock on byte 6 to byte 8 */
|
|
{F_RDLCK, 0, 6L, 3L, NOBLOCK},
|
|
/*
|
|
* Parent_c read lock on byte 1 to
|
|
* byte 3
|
|
*/
|
|
{F_RDLCK, 0, 1L, 3L, IGNORED},
|
|
/*
|
|
* Parent_d read lock on
|
|
* byte 7 to byte 9
|
|
*/
|
|
{F_RDLCK, 0, 7L, 3L,
|
|
IGNORED},},
|
|
|
|
/* #10 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b skipped */
|
|
{SKIP},
|
|
/* Child_a read lock on byte 2 to byte 4 */
|
|
{F_RDLCK, 0, 2L, 3L, NOBLOCK},
|
|
/* Child_b read lock on byte 6 to byte 8 */
|
|
{F_RDLCK, 0, 6L, 3L, NOBLOCK},
|
|
/*
|
|
* Parent_c read lock on byte 1 to
|
|
* byte 7
|
|
*/
|
|
{F_RDLCK, 0, 1L, 7L, IGNORED},
|
|
/*
|
|
* Parent_d read lock on
|
|
* byte 3 to byte 9
|
|
*/
|
|
{F_RDLCK, 0, 3L, 7L,
|
|
IGNORED},},
|
|
|
|
/* #11 Parent_a making a write lock on entire file */
|
|
{{F_WRLCK, 0, 0L, 0L, IGNORED},
|
|
/* Parent_b skipped */
|
|
{SKIP},
|
|
/* Child_a read lock on byte 3 to byte 7 */
|
|
{F_RDLCK, 0, 3L, 5L, NOBLOCK},
|
|
/* Child_b read lock on byte 3 to byte 7 */
|
|
{F_RDLCK, 0, 3L, 5L, NOBLOCK},
|
|
/*
|
|
* Parent_c read lock on byte 3 to
|
|
* byte 7
|
|
*/
|
|
{F_RDLCK, 0, 3L, 5L, IGNORED},
|
|
/* Parent_d skipped */
|
|
{SKIP},},
|
|
};
|
|
|
|
static testcase *thiscase;
|
|
static struct flock *thislock;
|
|
static int parent;
|
|
static int child_flag1 = 0;
|
|
static int child_flag2 = 0;
|
|
static int parent_flag = 0;
|
|
static int alarm_flag = 0;
|
|
static int child_pid[2], flag[2];
|
|
static int fd;
|
|
static int test;
|
|
static char tmpname[40];
|
|
|
|
#define FILEDATA "tenbytes!"
|
|
|
|
extern void catch_int(int sig); /* signal catching subroutine */
|
|
|
|
char *TCID = "fcntl16";
|
|
int TST_TOTAL = 1;
|
|
|
|
#ifdef UCLINUX
|
|
static char *argv0;
|
|
#endif
|
|
|
|
/*
|
|
* cleanup - performs all the ONE TIME cleanup for this test at completion or
|
|
* premature exit
|
|
*/
|
|
void cleanup(void)
|
|
{
|
|
tst_rmdir();
|
|
|
|
}
|
|
|
|
void dochild(int kid)
|
|
{
|
|
/* child process */
|
|
struct sigaction sact;
|
|
sact.sa_flags = 0;
|
|
sact.sa_handler = catch_int;
|
|
sigemptyset(&sact.sa_mask);
|
|
(void)sigaction(SIGUSR1, &sact, NULL);
|
|
|
|
/* Lock should succeed after blocking and parent releases lock */
|
|
if (kid) {
|
|
if ((kill(parent, SIGUSR2)) < 0) {
|
|
tst_resm(TFAIL, "Attempt to send signal to parent "
|
|
"failed");
|
|
tst_resm(TFAIL, "Test case %d, child %d, errno = %d",
|
|
test + 1, kid, errno);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if ((kill(parent, SIGUSR1)) < 0) {
|
|
tst_resm(TFAIL, "Attempt to send signal to parent "
|
|
"failed");
|
|
tst_resm(TFAIL, "Test case %d, child %d, errno = %d",
|
|
test + 1, kid, errno);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if ((fcntl(fd, F_SETLKW, thislock)) < 0) {
|
|
if (errno == EINTR && parent_flag) {
|
|
/*
|
|
* signal received is waiting for lock to clear,
|
|
* this is expected if flag = WILLBLOCK
|
|
*/
|
|
exit(1);
|
|
} else {
|
|
tst_resm(TFAIL, "Attempt to set child BLOCKING lock "
|
|
"failed");
|
|
tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
|
|
errno);
|
|
exit(2);
|
|
}
|
|
}
|
|
exit(0);
|
|
} /* end of child process */
|
|
|
|
#ifdef UCLINUX
|
|
static int kid_uc;
|
|
|
|
void dochild_uc(void)
|
|
{
|
|
dochild(kid_uc);
|
|
}
|
|
#endif
|
|
|
|
void catch_alarm(int sig)
|
|
{
|
|
alarm_flag = 1;
|
|
}
|
|
|
|
void catch_usr1(int sig)
|
|
{ /* invoked on catching SIGUSR1 */
|
|
/*
|
|
* Set flag to let parent know that child #1 is ready to have the
|
|
* lock removed
|
|
*/
|
|
child_flag1 = 1;
|
|
}
|
|
|
|
void catch_usr2(int sig)
|
|
{ /* invoked on catching SIGUSR2 */
|
|
/*
|
|
* Set flag to let parent know that child #2 is ready to have the
|
|
* lock removed
|
|
*/
|
|
child_flag2 = 1;
|
|
}
|
|
|
|
void catch_int(int sig)
|
|
{ /* invoked on child catching SIGUSR1 */
|
|
/*
|
|
* Set flag to interrupt fcntl call in child and force a controlled
|
|
* exit
|
|
*/
|
|
parent_flag = 1;
|
|
}
|
|
|
|
void child_sig(int sig, int nkids)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nkids; i++) {
|
|
if (kill(child_pid[i], 0) == 0) {
|
|
if ((kill(child_pid[i], sig)) < 0) {
|
|
tst_resm(TFAIL, "Attempt to signal child %d, "
|
|
"failed", i + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* setup - performs all ONE TIME steup for this test
|
|
*/
|
|
void setup(void)
|
|
{
|
|
struct sigaction sact;
|
|
|
|
tst_sig(FORK, DEF_HANDLER, cleanup);
|
|
|
|
umask(0);
|
|
|
|
/* Pause if option was specified */
|
|
TEST_PAUSE;
|
|
|
|
parent = getpid();
|
|
|
|
tst_tmpdir();
|
|
|
|
/* On NFS or not */
|
|
if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC)
|
|
NO_NFS = 0;
|
|
|
|
/* set up temp filename */
|
|
sprintf(tmpname, "fcntl4.%d", parent);
|
|
|
|
/*
|
|
* Set up signal handling functions
|
|
*/
|
|
memset(&sact, 0, sizeof(sact));
|
|
sact.sa_handler = catch_usr1;
|
|
sigemptyset(&sact.sa_mask);
|
|
sigaddset(&sact.sa_mask, SIGUSR1);
|
|
sigaction(SIGUSR1, &sact, NULL);
|
|
|
|
memset(&sact, 0, sizeof(sact));
|
|
sact.sa_handler = catch_usr2;
|
|
sigemptyset(&sact.sa_mask);
|
|
sigaddset(&sact.sa_mask, SIGUSR2);
|
|
sigaction(SIGUSR2, &sact, NULL);
|
|
|
|
memset(&sact, 0, sizeof(sact));
|
|
sact.sa_handler = catch_alarm;
|
|
sigemptyset(&sact.sa_mask);
|
|
sigaddset(&sact.sa_mask, SIGALRM);
|
|
sigaction(SIGALRM, &sact, NULL);
|
|
}
|
|
|
|
int run_test(int file_flag, int file_mode, int start, int end)
|
|
{
|
|
int child_count;
|
|
int child;
|
|
int nexited;
|
|
int status, expect_stat;
|
|
int i, fail = 0;
|
|
|
|
/* loop through all test cases */
|
|
for (test = start; test < end; test++) {
|
|
/* open a temp file to lock */
|
|
fd = SAFE_OPEN(cleanup, tmpname, file_flag, file_mode);
|
|
|
|
/* write some dummy data to the file */
|
|
(void)write(fd, FILEDATA, 10);
|
|
|
|
/* Initialize first parent lock structure */
|
|
thiscase = &testcases[test];
|
|
thislock = &thiscase->parent_a;
|
|
|
|
/* set the initial parent lock on the file */
|
|
if ((fcntl(fd, F_SETLK, thislock)) < 0) {
|
|
tst_resm(TFAIL, "First parent lock failed");
|
|
tst_resm(TFAIL, "Test case %d, errno = %d", test + 1,
|
|
errno);
|
|
close(fd);
|
|
unlink(tmpname);
|
|
return 1;
|
|
}
|
|
|
|
/* Initialize second parent lock structure */
|
|
thislock = &thiscase->parent_b;
|
|
|
|
if ((thislock->l_type) != IGNORED) { /*SKIPVAL */
|
|
/* set the second parent lock */
|
|
if ((fcntl(fd, F_SETLK, thislock)) < 0) {
|
|
tst_resm(TFAIL, "Second parent lock failed");
|
|
tst_resm(TFAIL, "Test case %d, errno = %d",
|
|
test + 1, errno);
|
|
close(fd);
|
|
unlink(tmpname);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* Initialize first child lock structure */
|
|
thislock = &thiscase->child_a;
|
|
|
|
/* Initialize child counter and flags */
|
|
alarm_flag = parent_flag = 0;
|
|
child_flag1 = child_flag2 = 0;
|
|
child_count = 0;
|
|
|
|
/* spawn child processes */
|
|
for (i = 0; i < 2; i++) {
|
|
if (thislock->l_type != IGNORED) {
|
|
if ((child = FORK_OR_VFORK()) == 0) {
|
|
#ifdef UCLINUX
|
|
if (self_exec(argv0, "ddddd", i, parent,
|
|
test, thislock, fd) < 0) {
|
|
perror("self_exec failed");
|
|
return 1;
|
|
}
|
|
#else
|
|
dochild(i);
|
|
#endif
|
|
}
|
|
if (child < 0) {
|
|
perror("Fork failed");
|
|
return 1;
|
|
}
|
|
child_count++;
|
|
child_pid[i] = child;
|
|
flag[i] = thislock->l_pid;
|
|
}
|
|
/* Initialize second child lock structure */
|
|
thislock = &thiscase->child_b;
|
|
}
|
|
/* parent process */
|
|
|
|
/*
|
|
* Wait for children to signal they are ready. Set a timeout
|
|
* just in case they don't signal at all.
|
|
*/
|
|
alarm(TIME_OUT);
|
|
|
|
while (!alarm_flag
|
|
&& (child_flag1 + child_flag2 != child_count)) {
|
|
pause();
|
|
}
|
|
|
|
/*
|
|
* Turn off alarm and unmask signals
|
|
*/
|
|
alarm((unsigned)0);
|
|
|
|
if (child_flag1 + child_flag2 != child_count) {
|
|
tst_resm(TFAIL, "Test case %d: kids didn't signal",
|
|
test + 1);
|
|
fail = 1;
|
|
}
|
|
child_flag1 = child_flag2 = alarm_flag = 0;
|
|
|
|
thislock = &thiscase->parent_c;
|
|
|
|
/* set the third parent lock on the file */
|
|
if ((fcntl(fd, F_SETLK, thislock)) < 0) {
|
|
tst_resm(TFAIL, "Third parent lock failed");
|
|
tst_resm(TFAIL, "Test case %d, errno = %d",
|
|
test + 1, errno);
|
|
close(fd);
|
|
unlink(tmpname);
|
|
return 1;
|
|
}
|
|
|
|
/* Initialize fourth parent lock structure */
|
|
thislock = &thiscase->parent_d;
|
|
|
|
if ((thislock->l_type) != IGNORED) { /*SKIPVAL */
|
|
/* set the fourth parent lock */
|
|
if ((fcntl(fd, F_SETLK, thislock)) < 0) {
|
|
tst_resm(TINFO, "Fourth parent lock failed");
|
|
tst_resm(TINFO, "Test case %d, errno = %d",
|
|
test + 1, errno);
|
|
close(fd);
|
|
unlink(tmpname);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Wait for children to exit, or for timeout to occur.
|
|
* Timeouts are expected for testcases where kids are
|
|
* 'WILLBLOCK', In that case, send kids a wakeup interrupt
|
|
* and wait again for them. If a second timeout occurs, then
|
|
* something is wrong.
|
|
*/
|
|
alarm_flag = nexited = 0;
|
|
while (nexited < child_count) {
|
|
alarm(TIME_OUT);
|
|
child = wait(&status);
|
|
alarm(0);
|
|
|
|
if (child == -1) {
|
|
if (errno != EINTR || alarm_flag != 1) {
|
|
/*
|
|
* Some error other than a timeout,
|
|
* or else this is the second
|
|
* timeout. Both cases are errors.
|
|
*/
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Expected timeout case. Signal kids then
|
|
* go back and wait again
|
|
*/
|
|
child_sig(SIGUSR1, child_count);
|
|
continue;
|
|
}
|
|
|
|
for (i = 0; i < child_count; i++)
|
|
if (child == child_pid[i])
|
|
break;
|
|
if (i == child_count) {
|
|
/*
|
|
* Ignore unexpected kid, it could be a
|
|
* leftover from a previous iteration that
|
|
* timed out.
|
|
*/
|
|
continue;
|
|
}
|
|
|
|
/* Found the right kid, check his status */
|
|
nexited++;
|
|
|
|
expect_stat = (flag[i] == NOBLOCK) ? 0 : 1;
|
|
|
|
if (!WIFEXITED(status)
|
|
|| WEXITSTATUS(status) != expect_stat) {
|
|
/* got unexpected exit status from kid */
|
|
tst_resm(TFAIL, "Test case %d: child %d %s "
|
|
"or got bad status (x%x)", test + 1,
|
|
i, (flag[i] == NOBLOCK) ?
|
|
"BLOCKED unexpectedly" :
|
|
"failed to BLOCK", status);
|
|
fail = 1;
|
|
}
|
|
}
|
|
|
|
if (nexited != child_count) {
|
|
tst_resm(TFAIL, "Test case %d, caught %d expected %d "
|
|
"children", test + 1, nexited, child_count);
|
|
child_sig(SIGKILL, nexited);
|
|
fail = 1;
|
|
}
|
|
close(fd);
|
|
}
|
|
unlink(tmpname);
|
|
if (fail) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main(int ac, char **av)
|
|
{
|
|
|
|
int lc;
|
|
|
|
tst_parse_opts(ac, av, NULL, NULL);
|
|
#ifdef UCLINUX
|
|
maybe_run_child(dochild_uc, "ddddd", &kid_uc, &parent, &test,
|
|
&thislock, &fd);
|
|
argv0 = av[0];
|
|
#endif
|
|
|
|
setup(); /* global setup */
|
|
|
|
for (lc = 0; TEST_LOOPING(lc); lc++) {
|
|
/* reset tst_count in case we are looping */
|
|
tst_count = 0;
|
|
|
|
/* //block1: */
|
|
/*
|
|
* Check file locks on an ordinary file without
|
|
* mandatory locking
|
|
*/
|
|
tst_resm(TINFO, "Entering block 1");
|
|
if (run_test(O_CREAT | O_RDWR | O_TRUNC, 0777, 0, 11)) {
|
|
tst_resm(TINFO, "Test case 1: without mandatory "
|
|
"locking FAILED");
|
|
} else {
|
|
tst_resm(TINFO, "Test case 1: without manadatory "
|
|
"locking PASSED");
|
|
}
|
|
tst_resm(TINFO, "Exiting block 1");
|
|
|
|
/* //block2: */
|
|
/*
|
|
* Check the file locks on a file with mandatory record
|
|
* locking
|
|
*/
|
|
tst_resm(TINFO, "Entering block 2");
|
|
if (NO_NFS && run_test(O_CREAT | O_RDWR | O_TRUNC, S_ISGID |
|
|
S_IRUSR | S_IWUSR, 0, 11)) {
|
|
tst_resm(TINFO, "Test case 2: with mandatory record "
|
|
"locking FAILED");
|
|
} else {
|
|
if (NO_NFS)
|
|
tst_resm(TINFO, "Test case 2: with mandatory"
|
|
" record locking PASSED");
|
|
else
|
|
tst_resm(TCONF, "Test case 2: NFS does not"
|
|
" support mandatory locking");
|
|
}
|
|
tst_resm(TINFO, "Exiting block 2");
|
|
|
|
/* //block3: */
|
|
/*
|
|
* Check file locks on a file with mandatory record locking
|
|
* and no delay
|
|
*/
|
|
tst_resm(TINFO, "Entering block 3");
|
|
if (NO_NFS && run_test(O_CREAT | O_RDWR | O_TRUNC | O_NDELAY,
|
|
S_ISGID | S_IRUSR | S_IWUSR, 0, 11)) {
|
|
tst_resm(TINFO, "Test case 3: mandatory locking with "
|
|
"NODELAY FAILED");
|
|
} else {
|
|
if (NO_NFS)
|
|
tst_resm(TINFO, "Test case 3: mandatory"
|
|
" locking with NODELAY PASSED");
|
|
else
|
|
tst_resm(TCONF, "Test case 3: NFS does not"
|
|
" support mandatory locking");
|
|
}
|
|
tst_resm(TINFO, "Exiting block 3");
|
|
}
|
|
cleanup();
|
|
tst_exit();
|
|
}
|