home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume16
/
deliver
/
part02
/
lock.c
< prev
Wrap
C/C++ Source or Header
|
1988-11-14
|
7KB
|
360 lines
/* $Header: lock.c,v 1.2 88/08/30 16:13:14 network Exp $
*
* Mailbox locking.
* Local hacks for mailbox access should be grafted here.
*
* $Log: lock.c,v $
* Revision 1.2 88/08/30 16:13:14 network
* Portability fixes from Ronald Karr <tron@uts.amdahl.com>.
*
* Revision 1.1 88/06/06 09:38:48 chip
* Initial revision
*
*/
#include "deliver.h"
/*
* Validate the locking configuration.
*/
#if (defined(ML_FCNTL) + defined(ML_LOCKF) + defined(ML_LOCKING)) > 1
lose! "Only one of ML_FCNTL, ML_LOCKF and ML_LOCKING may be defined.";
#endif
/*
* Support for the lockf() system call.
*/
#ifdef ML_LOCKF
#include <unistd.h>
#define SIMPLE_LOCK "lockf"
#define LOCKFD(fd, size) lockf(fd, F_LOCK, size)
#define UNLOCKFD(fd, size) lockf(fd, F_ULOCK, size)
#endif /* ML_LOCKF */
/*
* Setup for the locking() system call.
*/
#ifdef ML_LOCKING
#include <sys/types.h>
#include <sys/locking.h>
#define SIMPLE_LOCK "locking"
#define LOCKFD(fd, size) locking(fd, LK_LOCK, size)
#define UNLOCKFD(fd, size) locking(fd, LK_UNLOCK, size)
#endif
/*
* Local functions.
*/
#ifdef ML_DOTLOCK
static char *dotlock_name();
#endif
#ifdef ML_DOTMLK
static char *dotmlk_name();
#endif
/*----------------------------------------------------------------------
* Lock a mailbox by name.
*
* This code looks quite hairy with all the ifdefs. In fact, the only
* somewhat strange thing here is that neither, either, or both of
* ML_DOTLOCK and ML_DOTMLK may be defined, and we have to allow for it.
*/
int
lock_name(name)
char *name;
{
#ifdef ML_DOTLOCK
char *dotlock;
#endif
#ifdef ML_DOTMLK
char *dotmlk;
#endif
#ifdef ML_DOTLOCK
if ((dotlock = dotlock_name(name)) == NULL
|| create_lockfile(dotlock) < 0)
return -1;
#endif /* ML_DOTLOCK */
#ifdef ML_DOTMLK
if ((dotmlk = dotmlk_name(name)) == NULL
|| create_lockfile(dotmlk) < 0)
{
#ifdef ML_DOTLOCK
(void) remove_lockfile(dotlock); /* don't leave me hanging */
#endif
return -1;
}
#endif /* ML_DOTMLK */
return 0;
}
/*----------------------------------------------------------------------
* Unlock a mailbox by name.
*/
int
unlock_name(name)
char *name;
{
int ret = 0;
#ifdef ML_DOTLOCK
char *dotlock;
#endif
#ifdef ML_DOTMLK
char *dotmlk;
#endif
#ifdef ML_DOTLOCK
if ((dotlock = dotlock_name(name)) == NULL
|| remove_lockfile(dotlock) < 0)
ret = -1;
#endif /* ML_DOTLOCK */
#ifdef ML_DOTMLK
if ((dotmlk = dotmlk_name(name)) == NULL
|| remove_lockfile(dotmlk) < 0)
ret = -1;
#endif /* ML_DOTMLK */
return ret;
}
/*----------------------------------------------------------------------
* Lock a file descriptor.
*/
int
lock_fd(fd)
int fd;
{
#ifdef ML_FCNTL
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = 0;
fl.l_start = 0L;
fl.l_len = 0L;
if (fcntl(fd, F_SETLKW, &fl) == -1)
{
syserr("can't lock with fcntl()");
return -1;
}
if (verbose)
message("locked mailbox with fcntl()\n");
#endif /* ML_FCNTL */
#ifdef SIMPLE_LOCK
long pos;
if ((pos = lseek(fd, 0L, 0)) == -1)
{
syserr("can't seek in mailbox");
return -1;
}
if (LOCKFD(fd, 0L) == -1)
{
syserr("can't lock with %s()", SIMPLE_LOCK);
return -1;
}
if (lseek(fd, pos, 0) == -1)
{
syserr("can't seek in mailbox");
return -1;
}
if (verbose)
message("locked mailbox with %s()\n", SIMPLE_LOCK);
#endif /* SIMPLE_LOCK */
/* Default: success */
return 0;
}
/*----------------------------------------------------------------------
* Unlock a file descriptor.
*/
int
unlock_fd(fd)
int fd;
{
#ifdef ML_FCNTL
struct flock fl;
fl.l_type = F_UNLCK;
fl.l_whence = 0;
fl.l_start = 0L;
fl.l_len = 0L;
if (fcntl(fd, F_SETLKW, &fl) == -1)
{
syserr("can't unlock with fcntl()");
return -1;
}
if (verbose)
message("unlocked mailbox with fcntl()\n");
#endif /* ML_FCNTL */
#ifdef SIMPLE_LOCK
long pos;
if ((pos = lseek(fd, 0L, 0)) == -1)
{
syserr("can't seek in mailbox");
return -1;
}
if (LOCKFD(fd, 0L) == -1)
{
syserr("can't unlock with %s()", SIMPLE_LOCK);
return -1;
}
if (lseek(fd, pos, 0) == -1)
{
syserr("can't seek in mailbox");
return -1;
}
if (verbose)
message("unlocked mailbox with %s()\n", SIMPLE_LOCK);
#endif /* SIMPLE_LOCK */
/* Default: success */
return 0;
}
/*----------------------------------------------------------------------
* Return the name of the appropriate ".lock" file for a mailbox.
*/
#ifdef ML_DOTLOCK
static char *
dotlock_name(name)
char *name;
{
static char *lname = NULL;
static int lsize = 0;
char *p;
int n, i;
n = strlen(name);
if (lsize < n + 8)
{
if (lname)
free(lname);
lsize = n + 32;
lname = zalloc(lsize);
}
(void) strcpy(lname, name);
/*
* We want as much of `basename.lock' as will fit in a string
* MAX_NAMESIZE long.
*/
for (i = 0, p = basename(lname); (i < MAX_NAMESIZE - 5) && (*p); ++i)
++p;
(void) strcpy(p, ".lock");
return lname;
}
#endif /* ML_DOTLOCK */
/*----------------------------------------------------------------------
* Return the name of the appropriate ".mlk" file for a mailbox.
*/
#ifdef ML_DOTMLK
static char *
dotmlk_name(name)
char *name;
{
static char lname[MAX_NAMESIZE + 16];
char *p, *d;
int i;
/*
* To explain the below: If we ass_u_me that MAX_NAMESIZE is 14,
* then this code is like `printf(lname, "/tmp/%.10s.mlk", ...)'.
* In other words, we want as much of `basename.mlk' as will fit
* in a string MAX_NAMESIZE long.
*/
d = lname;
for (p = "/tmp/"; *p; )
*d++ = *p++;
for (i = 0, p = basename(name); (i < MAX_NAMESIZE - 4) && (*p); ++i)
*d++ = *p++;
(void) strcpy(d, ".mlk");
return lname;
}
#endif /* ML_DOTMLK */
/*----------------------------------------------------------------------
* Create a lockfile.
*/
int
create_lockfile(name)
char *name;
{
int tries, fd;
for (tries = 0; tries < 10; ++tries)
{
if (tries)
snooze(3);
if ((fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0)) >= 0)
{
(void) close(fd);
if (verbose)
message("created lockfile %s\n", name);
return 0;
}
if (verbose && (tries == 0))
{
message("Waiting to create %s (try #%d)\n",
name, tries + 1);
}
}
syserr("can't create lockfile %s", name);
return -1;
}
/*----------------------------------------------------------------------
* Remove a lockfile.
*/
int
remove_lockfile(name)
char *name;
{
if (unlink(name) == -1)
{
syserr("can't remove lockfile %s", name);
return -1;
}
if (verbose)
message("removed lockfile %s\n", name);
return 0;
}