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

1048 lines
26 KiB
C

/*
* file operations:
*
* open
* close
* lock
* unlock
* check for locks
* verify lock
*/
#include <sys/param.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <string.h>
#if !SVR4
#include <strings.h>
#endif /* !SVR4 */
#include <stdlib.h>
#include <assert.h>
#include <rpc/rpc.h>
#include "lk_test.h"
#include "print.h"
#include "util.h"
#include "fileops.h"
#define IOBUFLEN 1024
#define HASHSIZE 11
#define MATCH_LOCK_TYPE( lp, type ) ((lp)->ld_type == (type))
struct filerec {
int fr_fd;
int fr_hash;
char fr_name[MAXPATHLEN];
struct filerec *fr_next;
struct filerec *fr_prev;
};
#if SVR4
#define bzero(s,n) (void)memset(s,0,n)
#endif /* SVR4 */
static struct filerec *filehash[HASHSIZE];
static int Fileinit_done = 0;
extern int errno;
extern char *Progname;
extern int Verbose;
extern int AlternateVerify;
/*
* File open/close functions
*/
int
open_file_init(void)
{
if ( !Fileinit_done ) {
bzero( filehash, HASHSIZE*sizeof(struct filerec *) );
Fileinit_done = 1;
}
}
static int
hash( char *strp )
{
int hv = 0;
assert( valid_addresses( (caddr_t)strp, (int)1 ) );
while ( *strp++ ) {
hv ^= *strp;
}
return( hv % HASHSIZE );
}
static struct filerec *
hash_search( pathstr file_name )
{
struct filerec *frp = NULL;
if ( Verbose > 2 ) {
(void)printf( "%s: hash_search: file %s\n", Progname, file_name );
(void)fflush( stdout );
}
assert( valid_addresses( (caddr_t)file_name, 1 ) );
for ( frp = filehash[ hash( file_name ) ]; frp; frp = frp->fr_next ) {
if ( strcmp( file_name, frp->fr_name ) == 0 ) {
break;
}
}
if ( Verbose > 2 ) {
if ( frp ) {
(void)printf( "%s: hash_search: success\n", Progname );
} else {
(void)printf( "%s: hash_search: failed for %s\n", Progname,
file_name );
}
(void)fflush( stdout );
}
return( frp );
}
static void
hash_insert( struct filerec *frp )
{
int hv = hash( frp->fr_name );
struct filerec *hp = filehash[hv];
assert( valid_addresses( (caddr_t)frp, sizeof(struct filerec) ) );
if ( Verbose > 2 ) {
(void)printf( "%s: hash_insert: file %s, fd %d, hash %d\n",
Progname, frp->fr_name, frp->fr_fd, hv );
(void)fflush( stdout );
}
frp->fr_prev = NULL;
frp->fr_hash = hv;
if ( hp ) {
frp->fr_next = hp;
hp->fr_prev = frp;
filehash[hv] = frp;
} else {
frp->fr_next = NULL;
filehash[hv] = frp;
}
}
static void
hash_remove( struct filerec *frp )
{
struct filerec *tfrp = filehash[frp->fr_hash];
assert( valid_addresses( (caddr_t)frp, sizeof(struct filerec) ) );
if ( Verbose > 2 ) {
(void)printf( "%s: hash_remove: file %s, fd %d, hash %d\n",
Progname, frp->fr_name, frp->fr_fd, frp->fr_hash );
(void)fflush( stdout );
}
if ( frp == tfrp ) {
filehash[frp->fr_hash] = frp->fr_next;
if ( frp->fr_next ) {
frp->fr_next->fr_prev = NULL;
}
} else {
if ( frp->fr_next ) {
frp->fr_next->fr_prev = frp->fr_prev;
}
if ( frp->fr_prev ) {
frp->fr_prev->fr_next = frp->fr_next;
}
}
}
int
open_file( pathstr file_name, int flags, int mode )
{
int fd = -1;
struct filerec *frp;
if ( Verbose > 1 ) {
printf( "%s: open_file( %s, 0x%x )\n", Progname, file_name, flags );
}
assert( Fileinit_done );
assert( valid_addresses( (caddr_t)file_name, 1 ) );
if ( frp = hash_search( file_name ) ) {
fd = frp->fr_fd;
} else if ( (fd = open( file_name, flags, mode )) == -1 ) {
perror( "open_file: open" );
} else if ( frp = (struct filerec *)malloc( sizeof(struct filerec) ) ) {
frp->fr_fd = fd;
strcpy( frp->fr_name, file_name );
hash_insert( frp );
} else {
perror( "open_file: malloc" );
close( fd );
fd = -1;
}
if ( Verbose > 1 ) {
printf( "%s: open_file: return %d\n", Progname, fd );
}
return( fd );
}
int
close_file( pathstr file_name )
{
int status = 0;
struct filerec *frp;
if ( Verbose > 1 ) {
printf( "%s: close_file( %s )\n", Progname, file_name );
}
assert( Fileinit_done );
assert( valid_addresses( (caddr_t)file_name, 1 ) );
if ( frp = hash_search( file_name ) ) {
(void)close( frp->fr_fd );
hash_remove( frp );
free( frp );
} else {
(void)fprintf( stderr, "%s: close_file: %s not found in hash\n",
Progname, file_name );
status = -1;
}
if ( Verbose > 1 ) {
printf( "%s: close_file: return %d\n", Progname, status );
}
return( status );
}
/*
* close all open files
*/
void
closeall(void)
{
struct filerec *frp;
int hv;
for ( hv = 0; hv < HASHSIZE; hv++ ) {
while ( frp = filehash[hv] ) {
(void)close( frp->fr_fd );
hash_remove( frp );
free( frp );
}
}
}
bool_t
locks_held( pathstr file_name )
{
int status = 1;
int fd = -1;
struct flock fl;
assert( valid_addresses( (caddr_t)file_name, 1 ) );
if ( Verbose > 1 ) {
(void)printf("%s: locks_held\n", Progname);
}
if ( (fd = open_file( file_name, OPEN_FLAGS, DEFAULT_MODE )) == -1 ) {
(void)fprintf( stderr, "%s: locks_held: unable to open %s\n",
Progname, file_name );
} else if (AlternateVerify) {
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
if ( fcntl( fd, F_SETLK, &fl ) ) {
switch (errno) {
case EAGAIN:
case EACCES:
status = 1;
break;
default:
perror( "locks_held: fcntl" );
status = 0;
}
} else {
status = 0;
fl.l_type = F_UNLCK;
if ( fcntl( fd, F_SETLK, &fl) ) {
perror( "locks_held: fcntl" );
}
}
} else {
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
if ( fcntl( fd, F_GETLK, &fl ) ) {
perror( "locks_held: fcntl" );
status = 0;
} else {
status = (fl.l_type != F_UNLCK);
}
}
if ( Verbose > 1 ) {
printf( "%s: locks_held: return %d\n", Progname, status );
}
return( status );
}
static int
alternate_verify_fcntl(struct verifyargs *vap, fcntlargs *fargs,
off_t region_start, off_t region_len, off_t filesize)
{
int status = 1;
int error;
int flags;
if ( Verbose > 1 ) {
(void)printf("%s: alternate_verify_fcntl\n", Progname);
}
/*
* If the locked region does not start at offset 0, a lock preceding
* the existing one can be acquired.
*/
if (region_start != 0) {
/*
* verify that we can lock everything up to the start of the
* existing lock
*/
fargs->fa_lock.ld_offset = 0;
fargs->fa_lock.ld_len = region_start;
error = local_fcntl( fargs );
switch ( error ) {
case 0: /* expected case */
fargs->fa_lock.ld_type = F_UNLCK;
if ( error = local_fcntl( fargs ) ) {
errno = error;
perror( "alternate_verify_fcntl: local_fcntl(F_UNLCK)" );
return( 0 );
}
break;
case EACCES:
case EAGAIN:
if ( Verbose ) {
printf( "%s: alternate_verify_fcntl: unable to "
"acquire preceding lock\n", Progname );
}
return(0);
default:
errno = error;
perror( "alternate_verify_fcntl: local_fcntl" );
return( 0 );
}
}
fargs->fa_lock = vap->va_lock;
/*
* If the locked region does not extend to the end of the file,
* a lock following the existing one can be acquired.
*/
if (region_len != filesize) {
/*
* verify that we can lock everything from the end of the
* existing lock to the ed of the file
*/
fargs->fa_lock.ld_offset = region_start + region_len;
fargs->fa_lock.ld_len = 0;
error = local_fcntl( fargs );
switch ( error ) {
case 0: /* expected case */
fargs->fa_lock.ld_type = F_UNLCK;
if ( error = local_fcntl( fargs ) ) {
errno = error;
perror( "alternate_verify_fcntl: local_fcntl(F_UNLCK)" );
return( 0 );
}
break;
case EACCES:
case EAGAIN:
status = 0;
if ( Verbose ) {
printf( "%s: alternate_verify_fcntl: unable to "
"acquire following lock\n", Progname );
}
break;
default:
errno = error;
perror( "alternate_verify_fcntl: local_fcntl" );
return( 0 );
}
}
if ( Verbose > 1 ) {
printf( "%s: alternate_verify_fcntl: return %d\n", Progname, status );
}
return(status);
}
static int
verify_fcntl(struct verifyargs *vap)
{
int status = 1;
struct stat statbuf;
int error;
int flags;
off_t region_start;
off_t region_len;
fcntlargs fargs;
/*
* stat the file to get its size
*/
if ( stat( vap->va_name, &statbuf ) == -1 ) {
fprintf( stderr, "%s: verify_fcntl: unable to stat file: ",
Progname );
perror( vap->va_name );
return( 0 );
}
region_start = vap->va_lock.ld_offset;
region_len = vap->va_lock.ld_len ? vap->va_lock.ld_len :
statbuf.st_size - vap->va_lock.ld_offset;
fargs.fa_name = vap->va_name;
fargs.fa_lock = vap->va_lock;
fargs.fa_lock.ld_type = F_WRLCK;
if (AlternateVerify) {
fargs.fa_cmd = F_SETLK;
if (!alternate_verify_fcntl(vap, &fargs, region_start, region_len,
statbuf.st_size)) {
return(0);
}
} else {
/*
* first, verify that the lock is set as expected
* use fcntl to do this
*/
fargs.fa_cmd = F_GETLK;
if ( error = local_fcntl( &fargs ) ) {
errno = error;
perror( "verify_fcntl: local_fcntl" );
return( 0 );
} else if ( (fargs.fa_lock.ld_offset != region_start) ||
(fargs.fa_lock.ld_len != vap->va_lock.ld_len) ||
!MATCH_LOCK_TYPE( &fargs.fa_lock, vap->va_lock.ld_type ) ) {
if ( Verbose ) {
printf( "%s: verify_fcntl: lock mismatch\n", Progname );
printf( "%s: verify_fcntl: offset = 0x%x(expected 0x%x)\n",
Progname, fargs.fa_lock.ld_offset, region_start );
printf( "%s: verify_fcntl: len = %d(expected %d)\n",
Progname, fargs.fa_lock.ld_len, vap->va_lock.ld_len );
printf( "%s: verify_fcntl: type = %s(expected %s)\n",
Progname, locktype_to_str( fargs.fa_lock.ld_type ),
locktype_to_str( vap->va_lock.ld_type ) );
}
return( 0 );
}
/*
* it is assumed that the lock being verified is the only lock
* verify that this is the case
* first, try to lock the entire file. fcntl should return an flock
* structure which matches the one described by the lock arguments (fap)
* this verification works for both shared and exclusive locks
*/
fargs.fa_lock.ld_offset = 0;
fargs.fa_lock.ld_len = 0;
fargs.fa_lock.ld_type = F_WRLCK;
if ( error = local_fcntl( &fargs ) == -1 ) {
errno = error;
perror( "verify_fcntl: fcntl" );
return( 0 );
} else if ( (fargs.fa_lock.ld_offset != region_start) ||
(fargs.fa_lock.ld_len != vap->va_lock.ld_len) ||
!MATCH_LOCK_TYPE( &fargs.fa_lock, vap->va_lock.ld_type ) ) {
if ( Verbose ) {
printf( "%s: verify_fcntl: lock mismatch\n", Progname );
printf( "%s: verify_fcntl: offset = 0x%x(expected 0x%x)\n",
Progname, fargs.fa_lock.ld_offset, region_start );
printf( "%s: verify_fcntl: len = %d(expected %d)\n",
Progname, fargs.fa_lock.ld_len, vap->va_lock.ld_len );
printf( "%s: verify_fcntl: type = %s(expected %s)\n",
Progname, locktype_to_str( fargs.fa_lock.ld_type ),
locktype_to_str( vap->va_lock.ld_type ) );
}
return( 0 );
}
/*
* for a shared lock, make sure that a shared lock of the whole
* file will be successful
*/
if ( vap->va_lock.ld_type == F_RDLCK ) {
fargs.fa_lock.ld_offset = 0;
fargs.fa_lock.ld_len = 0;
fargs.fa_lock.ld_type = F_RDLCK;
if ( error = local_fcntl( &fargs ) ) {
errno = error;
perror( "verify_fcntl: fcntl" );
return( 0 );
} else if ( fargs.fa_lock.ld_type != F_UNLCK ) {
if ( Verbose ) {
printf( "%s: verify_fcntl: lock mismatch\n", Progname );
printf( "%s: verify_fcntl: offset = 0x%x(expected 0x%x)\n",
Progname, fargs.fa_lock.ld_offset, region_start );
printf( "%s: verify_fcntl: len = %d(expected %d)\n",
Progname, fargs.fa_lock.ld_len, vap->va_lock.ld_len );
printf( "%s: verify_fcntl: type = %s(expected %s)\n",
Progname, locktype_to_str( fargs.fa_lock.ld_type ),
locktype_to_str( vap->va_lock.ld_type ) );
}
return( 0 );
}
}
/*
* reset the flock structure (it was overwritten by fcntl)
* if the offset of the lock being verified is non-zero, verify that
* the region preceding the lock can be exclusively locked
*/
fargs.fa_lock.ld_offset = 0;
fargs.fa_lock.ld_type = F_WRLCK;
if ( region_start ) {
fargs.fa_lock.ld_len = region_start;
if ( error = local_fcntl( &fargs ) ) {
errno = error;
perror( "verify_fcntl: fcntl" );
return( 0 );
} else if ( fargs.fa_lock.ld_type != F_UNLCK ) {
if ( Verbose ) {
printf( "%s: verify_fcntl: extra lock at front of file\n",
Progname );
printf( "%s: verify_fcntl: offset = 0x%x\n", Progname,
fargs.fa_lock.ld_offset );
printf( "%s: verify_fcntl: len = %d\n", Progname,
fargs.fa_lock.ld_len );
printf( "%s: verify_fcntl: type = %s\n", Progname,
locktype_to_str( fargs.fa_lock.ld_type ) );
}
return( 0 );
}
}
/*
* reset the flock structure (it was overwritten by fcntl)
* if there is some room at the end of the file following the locked
* region, verify that the region following the lock can be exclusively
* locked
*/
fargs.fa_lock = vap->va_lock;
fargs.fa_lock.ld_type = F_WRLCK;
if ( vap->va_lock.ld_len &&
(vap->va_lock.ld_len + region_start < statbuf.st_size) ) {
fargs.fa_lock.ld_offset = region_start + vap->va_lock.ld_len;
fargs.fa_lock.ld_len = 0;
if ( error = local_fcntl( &fargs) ) {
errno = error;
perror( "verify_fcntl: fcntl" );
return( 0 );
} else if ( fargs.fa_lock.ld_type != F_UNLCK ) {
if ( Verbose ) {
printf( "%s: verify_fcntl: extra lock at end of file\n",
Progname );
printf( "%s: verify_fcntl: offset = 0x%x\n", Progname,
fargs.fa_lock.ld_offset );
printf( "%s: verify_fcntl: len = %d\n", Progname,
fargs.fa_lock.ld_len );
printf( "%s: verify_fcntl: type = %s\n", Progname,
locktype_to_str( fargs.fa_lock.ld_type ) );
}
return( 0 );
}
}
}
/*
* now, attempt to acquire some conflicting locks
* first, try an identical exclusive lock
* expect to fail
*/
fargs.fa_lock = vap->va_lock;
fargs.fa_lock.ld_type = F_WRLCK;
fargs.fa_cmd = F_SETLK;
switch ( error = local_fcntl( &fargs ) ) {
case EAGAIN:
case EACCES:
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
case 0:
(void)fprintf( stderr,
"%s: verify_fcntl: identical lock succeeded (failure expected)\n",
Progname );
print_fcntlargs( &fargs, "\t" );
fargs.fa_lock.ld_type = F_UNLCK;
(void)local_fcntl( &fargs );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
/*
* if the lock is shared, verify that another shared lock will succeed
*/
if ( vap->va_lock.ld_type == F_RDLCK ) {
fargs.fa_lock.ld_type = F_RDLCK;
switch ( error = local_fcntl( &fargs ) ) {
case 0:
fargs.fa_lock.ld_type = F_UNLCK;
if ( error = local_fcntl( &fargs ) ) {
fprintf( stderr,
"%s: verify_fcntl: unable to unlock file\n", Progname );
if ( error ) {
errno = error;
perror( "local_fcntl" );
}
return( 0 );
}
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
}
/*
* next, lock the entire file exclusively
* expect to fail
*/
fargs.fa_lock.ld_offset = 0;
fargs.fa_lock.ld_len = 0;
fargs.fa_lock.ld_type = F_WRLCK;
switch ( error = local_fcntl( &fargs ) ) {
case EAGAIN:
case EACCES:
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
case 0:
(void)fprintf( stderr,
"%s: verify_fcntl: file lock succeeded (failure expected)\n",
Progname );
print_fcntlargs( &fargs, "\t" );
fargs.fa_lock.ld_type = F_UNLCK;
(void)local_fcntl( &fargs );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
/*
* next, lock the entire file shared
* expect to succeed
*/
if ( vap->va_lock.ld_type == F_RDLCK ) {
fargs.fa_lock.ld_type = F_RDLCK;
switch ( error = local_fcntl( &fargs ) ) {
case 0:
fargs.fa_lock.ld_type = F_UNLCK;
if ( error = local_fcntl( &fargs ) ) {
fprintf( stderr,
"%s: verify_fcntl: unable to unlock file\n",
Progname );
if ( error ) {
errno = error;
perror( "local_fcntl" );
}
return( 0 );
}
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
}
/*
* next, try a front-overlapping lock if possible
* expect to fail in the exclusive case and succeed in the shared case
*/
if ( region_start ) {
fargs.fa_lock.ld_offset = region_start - 1;
fargs.fa_lock.ld_len = 2;
fargs.fa_lock.ld_type = F_WRLCK;
switch ( error = local_fcntl( &fargs ) ) {
case EAGAIN:
case EACCES:
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
case 0:
(void)fprintf( stderr,
"%s: verify_fcntl: front-overlapping lock succeeded (failure expected)\n",
Progname );
print_fcntlargs( &fargs, "\t" );
fargs.fa_lock.ld_type = F_UNLCK;
(void)local_fcntl( &fargs );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
if ( vap->va_lock.ld_type == F_RDLCK ) {
fargs.fa_lock.ld_type = F_RDLCK;
switch ( error = local_fcntl( &fargs ) ) {
case 0:
fargs.fa_lock.ld_type = F_UNLCK;
if ( error = local_fcntl( &fargs ) ) {
fprintf( stderr,
"%s: verify_fcntl: unable to unlock file\n",
Progname );
if ( error ) {
errno = error;
perror( "local_fcntl" );
}
return( 0 );
}
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
}
}
/*
* next, try an end-overlapping lock if possible
* expect to fail in the exclusive case and succeed in the shared case
*/
if ( vap->va_lock.ld_len &&
(vap->va_lock.ld_len + region_start < statbuf.st_size) ) {
fargs.fa_lock.ld_offset = vap->va_lock.ld_len + region_start - 1;
fargs.fa_lock.ld_len = 2;
fargs.fa_lock.ld_type = F_WRLCK;
switch ( error = local_fcntl( &fargs ) ) {
case EAGAIN:
case EACCES:
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
case 0:
(void)fprintf( stderr,
"%s: verify_fcntl: end-overlapping lock succeeded (failure expected)\n",
Progname );
print_fcntlargs( &fargs, "\t" );
fargs.fa_lock.ld_type = F_UNLCK;
(void)local_fcntl( &fargs );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
if ( vap->va_lock.ld_type == F_RDLCK ) {
fargs.fa_lock.ld_type = F_RDLCK;
switch ( error = local_fcntl( &fargs ) ) {
case 0:
fargs.fa_lock.ld_type = F_UNLCK;
if ( error = local_fcntl( &fargs ) ) {
fprintf( stderr,
"%s: verify_fcntl: unable to unlock file\n",
Progname );
if ( error ) {
errno = error;
perror( "local_fcntl" );
}
return( 0 );
}
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n",
Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
}
}
/*
* next, try one byte at the end of the lock range
* expect to fail
*/
if ( vap->va_lock.ld_len ) {
fargs.fa_lock.ld_offset = region_start + vap->va_lock.ld_len - 1;
} else {
fargs.fa_lock.ld_offset = statbuf.st_size - 1;
}
fargs.fa_lock.ld_len = 0;
fargs.fa_lock.ld_type = F_WRLCK;
switch ( error = local_fcntl( &fargs ) ) {
case EAGAIN:
case EACCES:
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
case 0:
(void)fprintf( stderr,
"%s: verify_fcntl: last-byte lock succeeded (failure expected)\n",
Progname );
print_fcntlargs( &fargs, "\t" );
fargs.fa_lock.ld_type = F_UNLCK;
(void)local_fcntl( &fargs );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
if ( vap->va_lock.ld_type == F_RDLCK ) {
fargs.fa_lock.ld_type = F_RDLCK;
switch ( error = local_fcntl( &fargs ) ) {
case 0:
fargs.fa_lock.ld_type = F_UNLCK;
if ( error = local_fcntl( &fargs ) ) {
fprintf( stderr,
"%s: verify_fcntl: unable to unlock file\n",
Progname );
if ( error ) {
errno = error;
perror( "local_fcntl" );
}
return( 0 );
}
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
}
/*
* next, try one byte at the front of the lock range
* expect to fail
*/
fargs.fa_lock.ld_offset = region_start;
fargs.fa_lock.ld_len = 1;
fargs.fa_lock.ld_type = F_WRLCK;
switch ( error = local_fcntl( &fargs ) ) {
case EAGAIN:
case EACCES:
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
case 0:
(void)fprintf( stderr,
"%s: verify_fcntl: first-byte lock succeeded (failure expected)\n",
Progname );
print_fcntlargs( &fargs, "\t" );
fargs.fa_lock.ld_type = F_UNLCK;
(void)local_fcntl( &fargs );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
if ( vap->va_lock.ld_type == F_RDLCK ) {
fargs.fa_lock.ld_type = F_RDLCK;
switch ( error = local_fcntl( &fargs ) ) {
case 0:
fargs.fa_lock.ld_type = F_UNLCK;
if ( error = local_fcntl( &fargs ) ) {
fprintf( stderr,
"%s: verify_fcntl: unable to unlock file\n",
Progname );
if ( error ) {
errno = error;
perror( "local_fcntl" );
}
return( 0 );
}
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
}
/*
* next, try a region within the lock range but not identical to the
* lock range
* expect to fail
*/
fargs.fa_lock.ld_len = MAX( 1, region_len/4 );
fargs.fa_lock.ld_offset = region_start + fargs.fa_lock.ld_len;
fargs.fa_lock.ld_type = F_WRLCK;
assert( fargs.fa_lock.ld_len > 0 );
assert( fargs.fa_lock.ld_offset > vap->va_lock.ld_offset );
assert( fargs.fa_lock.ld_offset <= (vap->va_lock.ld_offset + region_len) );
switch ( error = local_fcntl( &fargs ) ) {
case EAGAIN:
case EACCES:
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
return( 0 );
break;
case 0:
(void)fprintf( stderr,
"%s: verify_fcntl: sub-range lock succeeded (failure expected)\n",
Progname );
print_fcntlargs( &fargs, "\t" );
fargs.fa_lock.ld_type = F_UNLCK;
(void)local_fcntl( &fargs );
return( 0 );
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
return( 0 );
}
if ( vap->va_lock.ld_type == F_RDLCK ) {
fargs.fa_lock.ld_type = F_RDLCK;
switch ( error = local_fcntl( &fargs ) ) {
case 0:
fargs.fa_lock.ld_type = F_UNLCK;
if ( error = local_fcntl( &fargs ) ) {
fprintf( stderr,
"%s: verify_fcntl: unable to unlock file\n",
Progname );
if ( error ) {
errno = error;
perror( "local_fcntl" );
}
status = 0;
}
break;
case -1:
(void)fprintf( stderr,
"%s: verify_fcntl: local_fcntl failed\n", Progname );
print_fcntlargs( &fargs, "\t" );
status = 0;
break;
default:
(void)fprintf( stderr,
"%s: verify_fcntl: unexpected error: ", Progname );
errno = error;
perror( "local_fcntl" );
print_fcntlargs( &fargs, "\t" );
status = 0;
}
}
return(status);
}
/*
* verify that the lock is correctly held
* return true or false
*
* the following verifications are done:
* 1. use fcntl to find out what is locked
* 2. attempt to acquire a conflicting lock
* 3. check locked region boundaries
*/
int
verify_lock( struct verifyargs *vap )
{
int status = 1;
int error;
int flags;
assert( valid_addresses( (caddr_t)vap, sizeof(struct verifyargs) ) );
if ( Verbose > 1 ) {
(void)printf("%s: verify_lock\n", Progname);
}
status = verify_fcntl(vap);
if ( Verbose > 1 ) {
printf( "%s: verify_lock: return %d\n", Progname, status );
}
return( status );
}