/*
 * Worldvisions Weaver Software:
 *   Copyright (C) 1997, 1998 Worldvisions Computer Technology, Inc.
 *
 * Some handy functions to create/remove /var/lock lockfiles.
 */
#include "wvlockfile.h"
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>


WvLockFile::WvLockFile(const char *devicename)
{
    const char *p = strrchr(devicename, '/');
    if (p)
	p++;
    else
	p = devicename;
    
    lock_count = 0;
    filename = WvString("/var/lock/LCK..%s", p);
}


WvLockFile::~WvLockFile()
{
    if (lock_count)
    {
	lock_count = 1;
	unlock();
    }
}


// note: this function uses the O_EXCL flag to open(), and thus assumes
// that /var/lock is not an NFS-mounted drive (according to the open() man
// page, you need to follow a special procedure to ensure successful NFS
// locking)
//
// Actually there may be other race conditions that we should look into.
bool WvLockFile::lock()
{
    int	fd;
    pid_t pid;
    
    if (lock_count) {
	lock_count++;
    	return true;
    }
    
    fd = open( filename.str, O_RDWR | O_EXCL | O_CREAT, 0644 );
    if( fd != -1 ) {
    	// We made a lock file...
	WvString output( "%10s\n", getpid() );
    	write( fd, output.str, strlen( output.str ) );
    	close( fd );
	// debug( "Creating lockfile %s...\n", filename);
    } else {
	char inbuf[20];
	
    	// Lock file is already there!  Check for staleness...
    	sleep( 1 );	// preventing race condition...
 	fd = open( filename.str, O_RDONLY );
 	read( fd, inbuf, 19 );
	inbuf[19] = 0;
 	sscanf( inbuf, "%d", &pid );
 	if( kill( pid, 0 ) == -1 && errno == ESRCH ) {
 	    // we can create a lockfile now
 	    close( fd );
 	    unlink( filename.str );
 	    fd = open( filename.str, O_RDWR | O_EXCL | O_CREAT, 0644 );
	    WvString output( "%10s\n", getpid() );
 	    write( fd, output.str, strlen( output.str ) );
	    close( fd );
	    //debug( "Overriding stale lockfile %s, owned by %s...\n",
	    //        lockfile, pid );
 	} else {
 	    return false;
 	}
    }

    lock_count++;
    return true;
}



void WvLockFile::unlock()
{
    if (!lock_count) return;

    if (!--lock_count)
    {
	unlink( filename.str );
	//debug( "Removed lock file %s\n", filename );
    }
}


