view src/lock.c @ 129:6b2b93288caa noffle

[svn] Fix potential lock bug
author bears
date Wed, 09 Aug 2000 22:20:12 +0100
parents 3c71e28c8eef
children 8ea6b5ddc5a5
line wrap: on
line source

/*
  lock.c

  $Id: lock.c 183 2000-07-25 12:14:54Z bears $
*/

#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include "lock.h"
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif

#include <unistd.h>
#include "configfile.h"
#include "log.h"
#include "database.h"
#include "group.h"
#include "request.h"
#include "portable.h"

struct Lock
{
    const char *name;
    int lockFd;
    Str lockFile;
};

struct Lock globalLock = { "global", -1, "" };
struct Lock fetchLock = { "fetch", -1, "" };

/* Check the global lock held. */
static Bool
gotLock( struct Lock *lock )
{
    return ( lock->lockFd != -1 );    
}

static Bool
waitLock( struct Lock *lock, enum LockRequestWait wait )
{
    int fd;
    struct flock l;

    ASSERT( ! gotLock( lock ) );
    Log_dbg( "Waiting for lock %s ...", lock->name );
    if ( lock->lockFile[ 0 ] == '\0' )
	snprintf( lock->lockFile, MAXCHAR, "%s/lock/%s",
		  Cfg_spoolDir(), lock->name );
    if ( ( fd = open( lock->lockFile, O_WRONLY | O_CREAT, 0644 ) ) < 0 )
    {
        Log_err( "Cannot open %s (%s)", lock->lockFile, strerror( errno ) );
        return FALSE;
    }
    l.l_type = F_WRLCK;
    l.l_start = 0;
    l.l_whence = SEEK_SET;
    l.l_len = 0;
    if ( wait == LOCK_WAIT )
    {
	if ( fcntl( fd, F_SETLKW, &l ) < 0 )
	{
	    Log_err( "Cannot lock %s: %s", lock->lockFile, strerror( errno ) );
	    close( lock->lockFd );
	    return FALSE;
	}
    }
    else
    {
	if ( fcntl( fd, F_SETLK, &l ) < 0 )
	{
	    close( lock->lockFd );
	    return FALSE;
	}
    }
	
    lock->lockFd = fd;
    Log_dbg( "Lock successful" );
    return TRUE;
}

static void
releaseLock( struct Lock *lock )
{
    struct flock l;

    ASSERT( gotLock( lock ) );    
    l.l_type = F_UNLCK;
    l.l_start = 0;
    l.l_whence = SEEK_SET;
    l.l_len = 0;
    if ( fcntl( lock->lockFd, F_SETLK, &l ) < 0 )
        Log_err( "Cannot release %s: %s", lock->lockFile,
                 strerror( errno ) );
    close( lock->lockFd );
    lock->lockFd = -1;
    Log_dbg( "Releasing lock" );
}


/* Open all databases and set global lock. */
Bool
Lock_openDatabases( void )
{
    if ( ! waitLock( &globalLock, LOCK_WAIT ) )
    {
	Log_err( "Could not get write lock" );
	return FALSE;
    }
    if ( ! Db_open() )
    {
	Log_err( "Could not open database" );
	releaseLock( &globalLock );
	return FALSE;
    }
    if ( ! Grp_open() )
    {
	Log_err( "Could not open groupinfo" );
	Db_close();
	releaseLock( &globalLock );
	return FALSE;
    }
    if ( ! Req_open() )
    {
	Log_err( "Could not initialize request database" );
	Grp_close();
	Db_close();
	releaseLock( &globalLock );
	return FALSE;
    }

    return TRUE;
}


/* Close all databases and release global lock. */
void
Lock_closeDatabases( void )
{
    Grp_close();
    Db_close();
    Req_close();
    releaseLock( &globalLock );
}

/* Check the global lock held. */
Bool
Lock_gotLock( void )
{
    return gotLock( &globalLock );
}

/* Get fetch lock. */
Bool
Lock_getFetchLock( enum LockRequestWait wait )
{
    return waitLock( &fetchLock, wait );
}

/* Release fetch lock. */
void
Lock_releaseFetchLock( void )
{
    releaseLock( &fetchLock );
}

/* Check the fetch lock held. */
Bool
Lock_fetchLock( void )
{
    return gotLock( &fetchLock );
}