1
0
Files
irix-657m-src/eoe/cmd/sun/rpc.lockd/tests/sysid/sysid_test.c
2022-09-29 17:59:04 +03:00

1150 lines
29 KiB
C

/*
* This is a test case for lockd sysid management.
*
* Problem:
* If one application acquires a lock in a file and never releases it,
* none of the sysids for remote applications which might at some time
* have locked a portion of the same file are ever released.
*
* The cause of this behavior is the way in which sysids and the file
* descriptor table are managed in lockd. sysid release was linked to
* file descriptor release. File descriptor release was linked to
* there being no locks held in the file, either through the
* underlying local file system or from NFS mounts.
*
* Solution:
* Decouple sysid and file descriptor release by keeping track of how
* many active locks a sysid has. An active lock is one for which
* no corresponding unlock request has been received. There may not
* be as many unlock requests as lock requests. An example of this is
* a process which acquires locks but does not explicitly release them.
* It releases them by default by closing the file.
*
* Demonstration of the problem:
* The problem may be easily demonstrated as follows:
*
* 1. construct a file with two regions to be locked
* 2. one process acquires a read lock on one region
* 3. repeatedly fork a process to lock and unlock the other
* region, continuing until the forked process exits
* with a non-zero status
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/select.h> /* to get FD_SETSIZE */
#include <sys/signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <assert.h>
#if _SUNOS
#include <rpc/rpc.h>
#endif /* _SUNOS */
#include "util.h"
#define OPTSTR "nvr:d:f:p:"
#define DEFAULT_REPEAT 2000
#define DEFAULT_FILENAME "sysid.testfile"
#define DEFAULT_DIR NULL
#define DEFAULT_NOTIFY_COUNT 100
#define TEMPSIZE 256
#define MAX_VERBOSE_LEVEL 2
#define REGION_ONE 1
#define REGION_TWO 2
#define REGION_LEN 1024
#define REGION_ONE_START 0
#define REGION_TWO_START REGION_ONE_START + REGION_LEN
#define REGIONS 2
#define BUFLEN REGIONS * REGION_LEN
#define ERROREXIT -1
#define OPEN_FLAGS O_RDWR
#define CREATE_FLAGS (OPEN_FLAGS | O_CREAT | O_TRUNC)
#define OPEN_MODE \
(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
#define CREATE_MODE OPEN_MODE
int Sigint = 0;
int Sigchld = 0;
char *Progname;
int Verbose = 0;
extern char *optarg;
extern int errno;
void
signal_handler( int sig, int code, struct sigcontext *sc )
{
switch ( sig ) {
case SIGINT:
Sigint = 1;
(void)sigignore( SIGINT );
break;
case SIGCHLD:
Sigchld = 1;
(void)sigignore( SIGCHLD );
break;
}
}
int
closeall( pid_t pid )
{
int fd;
int status = 0;
for ( fd = 3; fd < FD_SETSIZE; fd++ ) {
if ( (status = close( fd )) == -1 ) {
if ( errno == EBADF ) {
status = 0;
} else {
fprintf( stderr, "%s[%d]: closeall: ", Progname, pid );
perror( "closeall" );
status = ERROREXIT;
break;
}
}
}
return( status );
}
int
lock_region( pid_t pid, int fd, int region, int locktype )
{
int status = 0;
struct flock fl;
off_t offset;
long len;
switch ( region ) {
case REGION_ONE:
offset = REGION_ONE_START;
break;
case REGION_TWO:
offset = REGION_TWO_START;
break;
default:
fprintf( stderr, "%s[%d] lock_region: bad region: %d\n", Progname,
pid, (int)region );
errno = EINVAL;
return( -1 );
}
len = REGION_LEN;
if ( Verbose >= MAX_VERBOSE_LEVEL ) {
printf( "%s[%d] lock_region: region %d, len %d, start %d\n", Progname,
pid, region, len, (int)offset );
}
fl.l_whence = SEEK_SET;
fl.l_start = offset;
fl.l_len = len;
fl.l_pid = pid;
fl.l_type = locktype;
if ( fcntl( fd, F_SETLKW, &fl ) == -1 ) {
if ( errno != EINTR ) {
fprintf( stderr, "%s[%d] lock_region: ", Progname, pid );
perror( "fcntl" );
status = ERROREXIT;
}
}
return( status );
}
int
unlock_region( pid_t pid, int fd, int region )
{
int status = 0;
struct flock fl;
off_t offset;
long len;
switch ( region ) {
case REGION_ONE:
offset = REGION_ONE_START;
break;
case REGION_TWO:
offset = REGION_TWO_START;
break;
default:
fprintf( stderr, "%s[%d] unlock_region: bad region: %d\n", Progname,
pid, (int)region );
errno = EINVAL;
return( ERROREXIT );
}
len = REGION_LEN;
if ( Verbose >= MAX_VERBOSE_LEVEL ) {
printf( "%s[%d] unlock_region: region %d, len %d, start %d\n", Progname,
pid, region, len, (int)offset );
}
fl.l_whence = SEEK_SET;
fl.l_start = offset;
fl.l_len = len;
fl.l_pid = pid;
fl.l_type = F_UNLCK;
if ( fcntl( fd, F_SETLK, &fl ) == -1 ) {
if ( errno != EINTR ) {
status = errno;
fprintf( stderr, "%s[%d] unlock_region: ", Progname, pid );
perror( "fcntl" );
status = ERROREXIT;
}
}
return( status );
}
int
test_region( pid_t pid, int fd, int region, struct flock *fl )
{
int status = 0;
off_t offset;
long len;
assert(valid_addresses((caddr_t)fl, sizeof(*fl)));
switch ( region ) {
case REGION_ONE:
offset = REGION_ONE_START;
break;
case REGION_TWO:
offset = REGION_TWO_START;
break;
default:
fprintf( stderr, "%s[%d] test_region: bad region: %d\n", Progname,
pid, (int)region );
errno = EINVAL;
return( ERROREXIT );
}
len = REGION_LEN;
if ( Verbose >= MAX_VERBOSE_LEVEL ) {
printf( "%s[%d] test_region: region %d, len %d, start %d\n", Progname,
pid, region, len, (int)offset );
}
fl->l_whence = SEEK_SET;
fl->l_start = offset;
fl->l_len = len;
fl->l_pid = pid;
fl->l_type = F_WRLCK;
if ( fcntl( fd, F_GETLK, fl ) == -1 ) {
if ( errno != EINTR ) {
fprintf( stderr, "%s[%d] test_region: ", Progname, pid );
perror( "fcntl" );
status = ERROREXIT;
}
}
return( status );
}
int
await_lock( int fd, int region )
{
int status = 0;
struct flock fl;
fl.l_type = F_UNLCK;
while ( (fl.l_type == F_UNLCK) && !status && !Sigint ) {
status = test_region( -1, fd, region, &fl );
}
return( status );
}
void
lock_process1( char *filename )
{
int status = 0;
int fd;
pid_t pid;
assert(valid_addresses((caddr_t)filename, sizeof(*filename)));
if ( signal( SIGINT, signal_handler ) == SIG_ERR ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process1: ", Progname, pid );
perror( "signal(SIGINT,signal_handler)" );
} else if ( (pid = getpid()) == (pid_t)-1 ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process1: ", Progname, pid );
perror( "getpid" );
} else if ( closeall( pid ) == ERROREXIT ) {
status = errno;
} else if ( (fd = open( filename, OPEN_FLAGS, OPEN_MODE )) == -1 ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process1: %s: ", Progname, pid,
filename );
perror( "open" );
} else if ( lock_region( pid, fd, REGION_TWO, F_RDLCK ) == ERROREXIT ) {
status = errno;
} else if ( unlock_region( pid, fd, REGION_TWO ) == ERROREXIT ) {
status = errno;
} else if ( close( fd ) == -1 ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process1: %s: ", Progname, pid,
filename );
perror( "close" );
}
exit( status );
}
void
lock_process2( char *filename )
{
int status = 0;
int fd;
pid_t pid;
assert(valid_addresses((caddr_t)filename, sizeof(*filename)));
if ( signal( SIGINT, signal_handler ) == SIG_ERR ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process2: ", Progname, pid );
perror( "signal(SIGINT,signal_handler)" );
} else if ( (pid = getpid()) == (pid_t)-1 ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process2: ", Progname, pid );
perror( "getpid" );
} else if ( closeall( pid ) == ERROREXIT ) {
status = errno;
} else if ( (fd = open( filename, OPEN_FLAGS, OPEN_MODE )) == -1 ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process2: %s: ", Progname, pid,
filename );
perror( "open" );
} else if ( lock_region( pid, fd, REGION_TWO, F_RDLCK ) == ERROREXIT ) {
status = errno;
} else if ( pause() == -1 ) {
if ( unlock_region( pid, fd, REGION_TWO ) == ERROREXIT ) {
status = errno;
} else if ( close( fd ) == -1 ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process2: %s: ", Progname, pid,
filename );
perror( "close" );
}
}
exit( status );
}
void
lock_process3( char *filename )
{
int status = 0;
int fd;
pid_t pid;
struct flock fl1;
struct flock fl2;
assert(valid_addresses((caddr_t)filename, sizeof(*filename)));
if ( signal( SIGINT, signal_handler ) == SIG_ERR ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process3: ", Progname, pid );
perror( "signal(SIGINT,signal_handler)" );
} else if ( (pid = getpid()) == (pid_t)-1 ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process3: ", Progname, pid );
perror( "getpid" );
} else if ( closeall( pid ) == ERROREXIT ) {
status = errno;
} else if ( (fd = open( filename, OPEN_FLAGS, OPEN_MODE )) == -1 ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process3: %s: ", Progname, pid,
filename );
perror( "open" );
} else if ( test_region( pid, fd, REGION_ONE, &fl1 ) == ERROREXIT ) {
status = errno;
} else if ( test_region( pid, fd, REGION_TWO, &fl2 ) == ERROREXIT ) {
status = errno;
} else if ( close( fd ) == -1 ) {
status = errno;
fprintf( stderr, "%s[%d] lock_process3: %s: ", Progname, pid,
filename );
perror( "close" );
} else {
if ( fl1.l_type != F_RDLCK ) {
printf( "%s[%d] lock_process3: region 1 test failure, result is %s (expected F_RDLCK)\n",
Progname, pid, locktype_to_str( fl1.l_type ) );
status = ERROREXIT;
}
if ( fl2.l_type != F_UNLCK ) {
printf( "%s[%d] lock_process3: region 2 test failure, result is %s (expected F_UNLCK)\n",
Progname, pid, locktype_to_str( fl2.l_type ) );
printf( "%s[%d] lock_process3: region 2 lock offset %d, len %d, pid %d, sysid %d\n",
Progname, pid, fl2.l_start, fl2.l_len, fl2.l_pid,
fl2.l_sysid );
status = ERROREXIT;
}
}
exit( status );
}
void
lock_process4( char *filename )
{
int status = 0;
int fd;
pid_t pid;
int i;
struct flock flk;
assert(valid_addresses((caddr_t)filename, sizeof(*filename)));
if ( signal( SIGINT, signal_handler ) == SIG_ERR ) {
status = ERROREXIT;
fprintf( stderr, "%s[%d] lock_process4: ", Progname, pid );
perror( "signal(SIGINT,signal_handler)" );
} else if ( (pid = getpid()) == (pid_t)-1 ) {
switch ( errno ) {
case EINTR:
break;
default:
status = ERROREXIT;
fprintf( stderr, "%s[%d] lock_process4: ", Progname, pid );
perror( "getpid" );
}
} else if ( closeall( pid ) == ERROREXIT ) {
status = ERROREXIT;
} else if ( (fd = open ( filename , O_RDWR, 0666 )) == -1 ) {
switch ( errno ) {
case EINTR:
break;
default:
fprintf( stderr, "%s[%d] lock_process4: %s: ", Progname, pid,
filename );
perror( "open" );
status = ERROREXIT;
}
} else {
/*
* read lock from offset 2 to the end of the file
*/
flk.l_whence = 0;
flk.l_start = 2;
flk.l_len = 0;
flk.l_type = F_RDLCK;
if (fcntl (fd, F_SETLK, &flk) == -1) {
switch ( errno ) {
case EINTR: /* ignore EINTR */
break;
default:
fprintf ( stderr,
"%s[%d] lock_process4: offset %d, len %d ", Progname,
pid, (int)flk.l_start, (int)flk.l_len );
perror("fcntl F_RDLCK 2 0");
status = ERROREXIT;
}
} else {
/*
* write lock byte 0 of the file
*/
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_WRLCK;
if (fcntl (fd, F_SETLK, &flk) == -1) {
switch ( errno ) {
case EINTR: /* ignore EINTR */
break;
default:
status = ERROREXIT;
fprintf ( stderr,
"%s[%d] lock_process4: offset %d, len %d ",
Progname, pid, (int)flk.l_start, (int)flk.l_len );
perror("fcntl F_WRLCK");
}
} else {
/*
* read lock byte 1
*/
flk.l_whence = 0;
flk.l_start = 1;
flk.l_len = 1;
flk.l_type = F_RDLCK;
if (fcntl (fd, F_SETLK, &flk) == -1) {
switch ( errno ) {
case EINTR: /* ignore EINTR */
break;
default:
status = ERROREXIT;
fprintf ( stderr,
"%s[%d] lock_process4: offset %d, len %d ",
Progname, pid, (int)flk.l_start,
(int)flk.l_len );
perror("fcntl F_RDLCK");
}
} else {
/*
* unlock byte 0
*/
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_UNLCK;
if (fcntl (fd, F_SETLK, &flk) == -1) {
switch ( errno ) {
case EINTR: /* ignore EINTR */
break;
default:
status = ERROREXIT;
fprintf ( stderr,
"%s[%d] lock_process4: offset %d, len %d ",
Progname, pid, (int)flk.l_start,
(int)flk.l_len );
perror("fcntl F_UNLCK");
}
}
}
}
}
if (close (fd) == -1) {
switch ( errno ) {
case EINTR:
break;
default:
fprintf ( stderr, "%s[%d] lock_process4: ", Progname, pid );
perror("close");
status = ERROREXIT;
}
}
}
exit( status );
}
void
lock_process5( char *filename )
{
int status = 0;
int fd;
pid_t pid;
off_t len;
struct flock flk;
assert(valid_addresses((caddr_t)filename, sizeof(*filename)));
if ( signal( SIGINT, signal_handler ) == SIG_ERR ) {
status = ERROREXIT;
fprintf( stderr, "%s[%d] lock_process5: ", Progname, pid );
perror( "signal(SIGINT,signal_handler)" );
} else if ( (pid = getpid()) == (pid_t)-1 ) {
switch ( errno ) {
case EINTR:
break;
default:
status = ERROREXIT;
fprintf( stderr, "%s[%d] lock_process5: ", Progname, pid );
perror( "getpid" );
}
} else if ( closeall( pid ) == ERROREXIT ) {
status = ERROREXIT;
} else {
for ( len = 3; len >= 0; len -- ) {
if ( (fd = open(filename, O_RDWR, 0666)) == -1 ) {
switch ( errno ) {
case EINTR:
break;
default:
status = ERROREXIT;
fprintf( stderr, "%s[%d] lock_process5: %s, len %d: ",
Progname, pid, filename, len );
perror( "open" );
}
} else if ( ftruncate( fd, len ) == -1 ) {
switch ( errno ) {
case EINTR:
break;
default:
status = ERROREXIT;
fprintf( stderr, "%s[%d] lock_process5: %s, len %d: ",
Progname, pid, filename, len );
perror( "ftruncate" );
}
} else {
/*
* read lock from offset 2 to the end of the file
*/
flk.l_whence = 0;
flk.l_start = 2;
flk.l_len = 0;
flk.l_type = F_RDLCK;
if (fcntl (fd, F_SETLK, &flk) == -1) {
switch ( errno ) {
case EINTR:
break;
default:
fprintf ( stderr, "%s[%d] lock_process5: file len "
"%d, lock offset %d, len %d ", Progname, pid,
len, (int)flk.l_start, (int)flk.l_len );
perror("fcntl F_RDLCK");
status = ERROREXIT;
}
} else {
/*
* write lock byte 0 of the file
*/
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_WRLCK;
if (fcntl (fd, F_SETLK, &flk) == -1) {
switch ( errno ) {
case EINTR:
break;
default:
fprintf ( stderr, "%s[%d] lock_process5: file "
"len %d, lock offset %d, len %d ",
Progname, pid, len, (int)flk.l_start,
(int)flk.l_len );
perror("fcntl F_WRLCK");
status = ERROREXIT;
}
} else {
/*
* read lock byte 1
*/
flk.l_whence = 0;
flk.l_start = 1;
flk.l_len = 1;
flk.l_type = F_RDLCK;
if (fcntl (fd, F_SETLK, &flk) == -1) {
switch ( errno ) {
case EINTR:
break;
default:
fprintf ( stderr, "%s[%d] lock_process5: "
"file len %d, lock offset %d, len %d ",
Progname, pid, len, (int)flk.l_start,
(int)flk.l_len );
perror("fcntl F_RDLCK");
status = ERROREXIT;
}
} else {
/*
* unlock byte 0
*/
flk.l_whence = 0;
flk.l_start = 0;
flk.l_len = 1;
flk.l_type = F_UNLCK;
if (fcntl (fd, F_SETLK, &flk) == -1) {
switch ( errno ) {
case EINTR:
break;
default:
fprintf ( stderr,
"%s[%d] lock_process5: file len "
"%d, lock offset %d, len %d ",
Progname, pid, len,
(int)flk.l_start, (int)flk.l_len );
perror("fcntl F_UNLCK 0 1");
status = ERROREXIT;
}
}
}
}
}
if (close (fd) == -1) {
switch ( errno ) {
case EINTR:
break;
default:
fprintf ( stderr, "%s[%d] lock_process5: file len "
"%d ", Progname, pid, len );
perror("close");
status = ERROREXIT;
}
}
}
}
}
exit( status );
}
void
usage(void)
{
char *op = OPTSTR;
fprintf( stderr, "usage %s", Progname );
while ( *op ) {
if ( *(op + 1) == ':' ) {
fprintf( stderr, " [-%c arg]", *op );
op++;
} else {
fprintf( stderr, " [-%c]", *op );
}
op++;
}
fprintf( stderr, "\n" );
}
int
fork_proc( void (*func)(char *), char *filename, pid_t *pid )
{
int status = 0;
assert(valid_addresses((caddr_t)filename, sizeof(*filename)));
assert(valid_addresses((caddr_t)pid, sizeof(*pid)));
switch ( *pid = fork() ) {
case 0: /* child process */
(*func)( filename );
fprintf( stderr, "%s[child] fork_proc: ", Progname );
printf( "%s[%d] fork_one_proc: exiting with status %d\n",
Progname, *pid, ERROREXIT );
exit( ERROREXIT );
break;
case -1: /* fork error */
if ( errno != EINTR ) {
fprintf( stderr, "%s fork_proc: ", Progname );
perror( "fork" );
status = errno;
}
break;
}
return( status );
}
build_file( char *filename, int size )
{
int i;
int status = 0;
int len;
int fd = -1;
char *mbp;
int n;
struct stat statbuf;
char filebuf[BUFLEN];
assert(valid_addresses((caddr_t)filename, sizeof(*filename)));
if ( (status = stat( filename, &statbuf )) ||
(statbuf.st_size < size) ) {
if ( Verbose >= MAX_VERBOSE_LEVEL ) {
(void)printf( "%s: build_file: file %s, size %d\n", Progname,
filename, size );
(void)fflush( stdout );
}
/*
* if the file exists, we need to change its mode
*/
if ( status == 0 ) {
if ( chmod( filename, CREATE_MODE ) == -1 ) {
fprintf( stderr, "%s build_file: %s: ", Progname,
filename );
perror( "chmod" );
status = errno;
return( status );
}
}
status = 0;
if ( (fd = open( filename, CREATE_FLAGS, CREATE_MODE )) == -1 ) {
fprintf( stderr, "%s build_file: %s: ", Progname, filename );
perror( "open" );
status = errno;
} else {
/*
* fill in the file buffer
*/
for ( i = 0; i < BUFLEN; i++ ) {
filebuf[i] = (char)(i % 128);
}
while ( size && !status ) {
/*
* set the write length
* this will be BUFLEN or size
* size indicates the remaining length to
* write
*/
if ( size >= BUFLEN ) {
len = BUFLEN;
} else {
len = size;
}
/*
* decrement the remaining size
*/
size -= len;
/*
* set the buffer pointer
*/
mbp = filebuf;
/*
* keep writing until we hit a zero-length write
* or a write error
*/
do {
n = write( fd, mbp, len );
if ( n == -1 ) {
fprintf( stderr, "%s build_file: %s: ", Progname,
filename );
perror( "write" );
status = errno;
break;
} else if ( n == 0 ) {
fprintf( stderr,
"%s build_file: %s: zero-byte write\n",
Progname, filename );
status = ERROREXIT;
break;
} else {
len -= n;
mbp += n;
}
} while ( len );
}
if ( close( fd ) == -1 ) {
fprintf( stderr, "%s build_file: %s: ", Progname,
filename );
perror( "close" );
status = errno;
} else if ( chmod( filename, CREATE_MODE ) == -1 ) {
fprintf( stderr, "%s build_file: %s: ", Progname,
filename );
perror( "chmod" );
status = errno;
}
}
} else if ( ((statbuf.st_mode & CREATE_MODE) != CREATE_MODE) &&
(chmod( filename, CREATE_MODE ) == -1) ) {
fprintf( stderr, "%s build_file: %s: ", Progname, filename );
perror( "chmod" );
status = errno;
}
return( status );
}
int
reap_process( int expected_sig )
{
int status = 0;
pid_t pid;
int child_status;
int sig;
if ( (pid = wait( &child_status )) == -1 ) {
if ( errno != EINTR ) {
fprintf( stderr, "%s main: ", Progname );
perror( "wait" );
status = errno;
}
} else if ( WIFSTOPPED( child_status ) ) {
fprintf( stderr, "%s: child stopped: pid %d, signal %d\n",
Progname, pid, WSTOPSIG( child_status ) );
fflush( stderr );
status = ERROREXIT;
} else if ( WIFEXITED( child_status ) ) {
status = WEXITSTATUS( child_status );
if ( status != 0 ) {
fprintf( stderr, "child exited: status %d, pid %d\n",
status, pid );
}
} else if ( WIFSIGNALED( child_status ) ) {
sig = WTERMSIG( child_status );
if ( (sig != expected_sig) && (sig != EINTR) ) {
fprintf( stderr, "%s: child terminated on signal %d\n",
Progname, sig );
fflush( stderr );
status = ERROREXIT;
}
} else {
fprintf( stderr, "%s: wait returned unknown status: 0x%x\n",
Progname, child_status );
fflush( stderr );
status = ERROREXIT;
}
return( status );
}
int
verify_lock( int fd, int region, int expect )
{
int status = 0;
struct flock fl1;
struct flock fl2;
if ( region ) {
if ( region == REGION_ONE ) {
if ( test_region( -1, fd, REGION_ONE, &fl1 ) == ERROREXIT ) {
status = errno;
} else if ( fl1.l_type != expect ) {
printf( "%s: verify_lock: region 1 not as expected: got %s, expected %s\n",
Progname, locktype_to_str( fl1.l_type ),
locktype_to_str( expect ) );
status = ERROREXIT;
}
} else if ( region == REGION_TWO ) {
if ( test_region( -1, fd, REGION_TWO, &fl2 ) == ERROREXIT ) {
status = errno;
} else if ( fl2.l_type != expect ) {
printf( "%s: verify_lock: region 2 not as expected: got %s, expected %s\n",
Progname, locktype_to_str( fl2.l_type ),
locktype_to_str( expect ) );
status = ERROREXIT;
}
}
} else if ( (test_region( -1, fd, REGION_ONE, &fl1 ) == ERROREXIT) ||
(test_region( -1, fd, REGION_TWO, &fl2 ) == ERROREXIT) ) {
status = errno;
} else if ( (fl1.l_type != F_UNLCK) || (fl2.l_type != F_UNLCK) ) {
printf(
"%s: verify_lock: region still locked: region 1 %s, region 2 %s\n",
Progname, locktype_to_str( fl1.l_type ),
locktype_to_str( fl2.l_type ) );
status = ERROREXIT;
}
return( status );
}
main( int argc, char **argv )
{
int status = 0;
int opt;
int repeat = DEFAULT_REPEAT;
char *filename = DEFAULT_FILENAME;
char *tempname = "sysidtest.temp";
char *dir = DEFAULT_DIR;
int fd;
pid_t pid;
int i;
int phase = 0;
int notify_count = DEFAULT_NOTIFY_COUNT;
Progname = *argv;
while ( (opt = getopt( argc, argv, OPTSTR )) != EOF ) {
switch ( opt ) {
case 'p':
phase = atoi( optarg );
break;
case 'r':
repeat = atoi( optarg );
break;
case 'f':
filename = optarg;
break;
case 'd':
dir = optarg;
break;
case 'v':
Verbose++;
break;
case 'n':
notify_count = atoi( optarg );
break;
default:
usage();
}
}
printf( "Test Parameters:\n" );
printf( "\t directory = %s\n", dir ? dir : "." );
printf( "\t test file = %s\n", filename );
printf( "\trepeat count = %d\n", repeat );
if ( dir && (chdir( dir ) == -1) ) {
if ( errno != EINTR ) {
status = errno;
fprintf( stderr, "%s: ", Progname );
perror( "chdir" );
}
} else if ( status = build_file( filename, REGIONS * REGION_LEN ) ) {
;
} else if ( (fd = open( filename, OPEN_FLAGS, OPEN_MODE )) == -1 ) {
fprintf( stderr, "%s main: %s: ", Progname, filename );
perror( "open" );
status = errno;
} else if ( lock_region( -1, fd, REGION_ONE, F_RDLCK ) == ERROREXIT ) {
status = errno;
} else if ( repeat == -1 ) {
repeat = 0;
while ( !Sigint && !status ) {
if ( Verbose && ((++repeat % notify_count) == 0) ) {
printf( "Starting pass %d\n", repeat );
}
if ( status = verify_lock( fd, REGION_TWO, F_UNLCK ) ) {
printf( "Test failure in phase 1\n" );
break;
} else if ( status = fork_proc( lock_process1, filename, &pid ) ) {
printf( "Test failure in phase 1\n" );
break;
} else if ( status = reap_process( 0 ) ) {
printf( "Test failure in phase 1\n" );
break;
} else if ( Sigint ) {
break;
} else if ( status = verify_lock( fd, REGION_TWO, F_UNLCK ) ) {
printf( "Test failure in phase 2\n" );
break;
} else if ( status = fork_proc( lock_process2, filename, &pid ) ) {
printf( "Test failure in phase 2\n" );
break;
} else if ( (kill( pid, SIGTERM ) == -1) && (errno != ESRCH) ) {
fprintf( stderr, "%s: ", Progname );
perror( "kill" );
break;
} else if ( status = reap_process( SIGTERM ) ) {
printf( "Test failure in phase 2\n" );
break;
} else if ( Sigint ) {
break;
} else if ( status = verify_lock( fd, REGION_TWO, F_UNLCK ) ) {
printf( "Test failure in phase 3\n" );
break;
} else if ( status = fork_proc( lock_process3, filename, &pid ) ) {
printf( "Test failure in phase 3\n" );
break;
} else if ( status = reap_process( 0 ) ) {
printf( "Test failure in phase 3\n" );
break;
} else if ( Sigint ) {
break;
} else if ( (status = build_file( tempname, TEMPSIZE )) ||
(status = fork_proc( lock_process4, tempname, &pid )) ) {
printf( "Test failure in phase 4\n" );
break;
} else if ( status = reap_process( 0 ) ) {
printf( "Test failure in phase 4\n" );
break;
} else if ( Sigint ) {
break;
} else if ( status = fork_proc( lock_process5, tempname, &pid ) ) {
printf( "Test failure in phase 5\n" );
break;
} else if ( status = reap_process( 0 ) ) {
printf( "Test failure in phase 5\n" );
break;
}
}
} else {
if ( !(status = build_file( tempname, TEMPSIZE )) ) {
/*
* phase 1
*/
if ( (!phase || (phase == 1)) &&
!(status = verify_lock( fd, REGION_TWO, F_UNLCK)) ) {
printf( "Test phase 1\n" );
for ( i = 0; (i < repeat) && !status && !Sigint; i++ ) {
if ( Verbose && ((i % notify_count) == 0) ) {
printf( "Starting pass %d\n", i + 1 );
}
if ( status = fork_proc( lock_process1, filename,
&pid ) ) {
printf( "Test failure on pass %d, phase 1\n",
i + 1 );
break;
} else if ( status = reap_process( 0 ) ) {
printf( "Test failure on pass %d, phase 1\n",
i + 1 );
break;
}
}
}
/*
* phase 2
*/
if ( !status && (!phase || (phase == 2)) &&
!(status = verify_lock( fd, REGION_TWO, F_UNLCK)) ) {
printf( "Test phase 2\n" );
for ( i = 0; (i < repeat) && !status && !Sigint; i++ ) {
if ( Verbose && ((i % notify_count) == 0) ) {
printf( "Starting pass %d\n", i + 1 );
}
if ( status = fork_proc( lock_process2, filename,
&pid ) ) {
printf( "Test failure on pass %d, phase 2\n",
i + 1 );
break;
} else if ( status = await_lock( fd, REGION_TWO ) ) {
printf( "Test failure on pass %d, phase 2\n",
i + 1 );
break;
} else if ( (kill( pid, SIGTERM ) == -1) &&
(errno != ESRCH) ) {
fprintf( stderr, "%s: ", Progname );
perror( "kill" );
printf( "Test failure on pass %d, phase 2\n",
i + 1 );
break;
} else if ( status = reap_process( SIGTERM ) ) {
printf( "Test failure on pass %d, phase 2\n",
i + 1 );
break;
}
}
}
/*
* phase 3
*/
if ( !status && (!phase || (phase == 3)) &&
!(status = verify_lock( fd, REGION_TWO, F_UNLCK)) ) {
printf( "Test phase 3\n" );
for ( i = 0; (i < repeat) && !status && !Sigint; i++ ) {
if ( Verbose && ((i % notify_count) == 0) ) {
printf( "Starting pass %d\n", i + 1 );
}
if ( status = fork_proc( lock_process3, filename,
&pid ) ) {
printf( "Test failure on pass %d, phase 3\n",
i + 1 );
break;
} else if ( status = reap_process( 0 ) ) {
printf( "Test failure on pass %d, phase 3\n",
i + 1 );
break;
}
}
}
/*
* phase 4
*/
if ( !status && (!phase || (phase == 4)) ) {
printf( "Test phase 4\n" );
for ( i = 0; (i < repeat) && !status && !Sigint; i++ ) {
if ( Verbose && ((i % notify_count) == 0) ) {
printf( "Starting pass %d\n", i + 1 );
}
if ( status = fork_proc( lock_process4, tempname, &pid ) ) {
printf( "Test failure on pass %d, phase 4\n", i + 1 );
break;
} else if ( status = reap_process( 0 ) ) {
printf( "Test failure on pass %d, phase 4\n", i + 1 );
break;
}
}
}
/*
* phase 5
*/
if ( !status && (!phase || (phase == 5)) ) {
printf( "Test phase 5\n" );
for ( i = 0; (i < repeat) && !status && !Sigint; i++ ) {
if ( Verbose && ((i % notify_count) == 0) ) {
printf( "Starting pass %d\n", i + 1 );
}
if ( (status = build_file( tempname, TEMPSIZE )) ||
(status = fork_proc( lock_process5, tempname, &pid ))
) {
printf( "Test failure on pass %d, phase 5\n",
i + 1 );
break;
} else if ( status = reap_process( 0 ) ) {
printf( "Test failure on pass %d, phase 5\n", i + 1 );
break;
}
}
}
}
}
sigignore( SIGINT );
kill( 0, SIGINT );
if ( !status ) {
status = verify_lock( fd, REGION_TWO, F_UNLCK );
}
unlock_region( -1, fd, REGION_ONE );
close( fd );
if ( status == 0 ) {
printf( "%s: Test passed\n", Progname );
} else {
printf( "%s: Test failed\n", Progname );
}
unlink( tempname );
exit( status );
}