/*
* Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
* This will be free software, but only when it is finished.
*
* mmap() using region mapping -- gives efficiency at message
* lock accesses
*
* FCNTL-style locking by Matti Aarnio <mea@nic.funet.fi>
* Theory: On system where it works, it makes LESS IO
*/
/*
* Common routine to fiddle control file tag characters.
*/
#include "hostenv.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include "mail.h"
#include "ta.h"
#include "libc.h"
#undef HAVE_FCNTL /* No, sorry, not really defined locking method! */
#ifndef SEEK_SET
#define SEEK_SET 0
#endif /* SEEK_SET */
static const char *ta_lockmode = NULL;
int
lockaddr(fd, map, offset, was, new, file, host, mypid)
int fd;
char *map;
int offset;
int was;
int new;
const char *file, *host;
const int mypid;
{
char lockbuf[16]; /* FIXME: MAGIC SIZE KNOWLEDGE! */
int newlock = 0;
if (!ta_lockmode) {
ta_lockmode = getzenv("TALOCKMODE");
#if defined(HAVE_MMAP)
if (!ta_lockmode && ta_use_mmap > 0)
ta_lockmode = "M"; /* MMAP */
#else
#ifdef HAVE_FCNTL
if (!ta_lockmode) ta_lockmode = "F"; /* FCNTL */
#else
if (!ta_lockmode) ta_lockmode = "W"; /* WRITE */
#endif
#endif
}
#ifdef HAVE_FCNTL
if (*ta_lockmode == 'F') {
struct flock fl;
int rc = 0;
fl.l_type = F_WRLCK;
fl.l_start = offset;
fl.l_whence = SEEK_SET;
fl.l_len = 10; /* fixed.. */
if (new == _CFTAG_LOCK || new == _CFTAG_DEFER) {
rc = fcntl(fd,F_GETLK,&fl);
if (rc == -1) {
warning("lockaddr: fcntl() lock error");
return 0;
}
}
lockbuf[1] = ' ';
if (was == _CFTAG_NORMAL) {
if (fl.l_type == F_UNLCK)
lockbuf[0] = was;
else
lockbuf[0] = _CFTAG_LOCK;
} else if (was == _CFTAG_LOCK) {
if (fl.l_type == F_UNLCK)
lockbuf[0] = new;
else
lockbuf[0] = was; /* XXX: Hmm... */
}
}
#endif
if (map && *ta_lockmode == 'M') {
/* MMAP()ed block helps.. */
memcpy(lockbuf,map+offset,sizeof(lockbuf));
} else {
if (lseek(fd, offset, SEEK_SET) < 0L) {
warning("lockaddr: lseek() failure");
return 0;
}
if (read(fd, lockbuf, sizeof(lockbuf)) != sizeof(lockbuf)) {
warning("lockaddr: read() failure");
return 0;
}
}
newlock = ((lockbuf[1] == ' ') ||
(lockbuf[1] >= '0' && lockbuf[1] <= '9'));
if (lockbuf[0] == was) {
if (!map && lseek(fd, offset, SEEK_SET) < 0L) {
warning("lockaddr: lseek() failure 2");
return 0;
}
lockbuf[0] = new;
if (newlock) {
if (new == _CFTAG_LOCK) {
/* Mark the lock with client process-id */
sprintf(lockbuf+1, "%*d", _CFTAG_RCPTPIDSIZE, mypid);
if (map && *ta_lockmode == 'M')
memcpy(map+offset, lockbuf, _CFTAG_RCPTPIDSIZE+1);
else if (write(fd,lockbuf,
_CFTAG_RCPTPIDSIZE+1) != _CFTAG_RCPTPIDSIZE+1)
return 0;
} else if (new == _CFTAG_DEFER) {
#ifdef HAVE_FCNTL
/* Using FCNTL region locking */
#else
/* Clear the lock location */
memset(lockbuf+1, ' ', _CFTAG_RCPTPIDSIZE);
if (map && *ta_lockmode == 'M')
memcpy(map+offset, lockbuf, _CFTAG_RCPTPIDSIZE+1);
else if (write(fd,lockbuf,
_CFTAG_RCPTPIDSIZE+1) != _CFTAG_RCPTPIDSIZE+1)
return 0;
#endif
} else {
/* Clear the lock location */
if (!(was == _CFTAG_NORMAL && new == _CFTAG_OK))
/* ... but not when the scheduler calls this to mark off
the diagnostics lines. */
memset(lockbuf+1, ' ', _CFTAG_RCPTPIDSIZE);
if (map && *ta_lockmode == 'M')
memcpy(map+offset, lockbuf, _CFTAG_RCPTPIDSIZE+1);
else if (write(fd,lockbuf,
_CFTAG_RCPTPIDSIZE+1) != _CFTAG_RCPTPIDSIZE+1)
return 0;
}
}
return 1;
}
if (host == NULL) host = "-";
warning("lockaddr: file '%s' host '%s' expected '%c' found '%c'\n", file, host, was, new);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1