Implement fcntl(2) file locking
If you run a server, then you know of the somewhat annoying perm_lock errors that creep up, requiring your attention before anyone else can start a game. This patch properly implements fcntl(2) locking on systems that can handle it (*nix systems), that results in the lock being automatically released on program termination, whether abnormal or not. Original patch by Drew Streib, update by Edoardo Spadolini
This commit is contained in:
@@ -217,6 +217,12 @@
|
||||
|
||||
#define FCMASK 0660 /* file creation mask */
|
||||
|
||||
/* fcntl(2) is a POSIX-portable call for manipulating file descriptors.
|
||||
* Comment out the USE_FCNTL if for some reason you have a strange
|
||||
* OS/filesystem combination for which fcntl(2) does not work. */
|
||||
#ifdef POSIX_TYPES
|
||||
# define USE_FCNTL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The remainder of the file should not need to be changed.
|
||||
|
||||
60
src/files.c
60
src/files.c
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)
|
||||
#if (!defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)) || defined(USE_FCNTL)
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
@@ -185,7 +185,9 @@ STATIC_DCL void FDECL(docompress_file, (const char *,BOOLEAN_P));
|
||||
#if defined(ZLIB_COMP)
|
||||
STATIC_DCL boolean FDECL(make_compressed_name, (const char *, char *));
|
||||
#endif
|
||||
#ifndef USE_FCNTL
|
||||
STATIC_DCL char *FDECL(make_lockname, (const char *,char *));
|
||||
#endif
|
||||
STATIC_DCL FILE *FDECL(fopen_config_file, (const char *, int));
|
||||
STATIC_DCL int FDECL(get_uchars,
|
||||
(FILE *,char *,char *,uchar *,BOOLEAN_P,int,const char *));
|
||||
@@ -1537,12 +1539,16 @@ boolean uncomp;
|
||||
|
||||
static int nesting = 0;
|
||||
|
||||
#ifdef NO_FILE_LINKS /* implies UNIX */
|
||||
#if defined(NO_FILE_LINKS) || defined(USE_FCNTL) /* implies UNIX */
|
||||
static int lockfd; /* for lock_file() to pass to unlock_file() */
|
||||
#endif
|
||||
#ifdef USE_FCNTL
|
||||
struct flock sflock; /* for unlocking, same as above */
|
||||
#endif
|
||||
|
||||
#define HUP if (!program_state.done_hup)
|
||||
|
||||
#ifndef USE_FCNTL
|
||||
STATIC_OVL char *
|
||||
make_lockname(filename, lockname)
|
||||
const char *filename;
|
||||
@@ -1574,6 +1580,7 @@ char *lockname;
|
||||
return (char*)0;
|
||||
#endif
|
||||
}
|
||||
#endif /* !USE_FCNTL */
|
||||
|
||||
/* lock a file */
|
||||
boolean
|
||||
@@ -1585,8 +1592,10 @@ int retryct;
|
||||
#if defined(PRAGMA_UNUSED) && !(defined(UNIX) || defined(VMS)) && !(defined(AMIGA) || defined(WIN32) || defined(MSDOS))
|
||||
# pragma unused(retryct)
|
||||
#endif
|
||||
#ifndef USE_FCNTL
|
||||
char locknambuf[BUFSZ];
|
||||
const char *lockname;
|
||||
#endif
|
||||
|
||||
nesting++;
|
||||
if (nesting > 1) {
|
||||
@@ -1594,18 +1603,50 @@ int retryct;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifndef USE_FCNTL
|
||||
lockname = make_lockname(filename, locknambuf);
|
||||
filename = fqname(filename, whichprefix, 0);
|
||||
#ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */
|
||||
lockname = fqname(lockname, LOCKPREFIX, 2);
|
||||
#endif
|
||||
#endif
|
||||
filename = fqname(filename, whichprefix, 0);
|
||||
#ifdef USE_FCNTL
|
||||
lockfd = open(filename,O_RDWR);
|
||||
if (lockfd == -1) {
|
||||
HUP raw_printf("Cannot open file %s. This is a program bug.",
|
||||
filename);
|
||||
}
|
||||
sflock.l_type = F_WRLCK;
|
||||
sflock.l_whence = SEEK_SET;
|
||||
sflock.l_start = 0;
|
||||
sflock.l_len = 0;
|
||||
#endif
|
||||
|
||||
#if defined(UNIX) || defined(VMS)
|
||||
# ifdef USE_FCNTL
|
||||
while (fcntl(lockfd,F_SETLK,&sflock) == -1) {
|
||||
# else
|
||||
# ifdef NO_FILE_LINKS
|
||||
while ((lockfd = open(lockname, O_RDWR|O_CREAT|O_EXCL, 0666)) == -1) {
|
||||
# else
|
||||
while (link(filename, lockname) == -1) {
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#ifdef USE_FCNTL
|
||||
if (retryct--) {
|
||||
HUP raw_printf(
|
||||
"Waiting for release of fcntl lock on %s. (%d retries left).",
|
||||
filename, retryct);
|
||||
sleep(1);
|
||||
} else {
|
||||
HUP (void) raw_print("I give up. Sorry.");
|
||||
HUP raw_printf("Some other process has an unnatural grip on %s.",
|
||||
filename);
|
||||
nesting--;
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
register int errnosv = errno;
|
||||
|
||||
switch (errnosv) { /* George Barbanis */
|
||||
@@ -1660,11 +1701,12 @@ int retryct;
|
||||
nesting--;
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* USE_FCNTL */
|
||||
|
||||
}
|
||||
#endif /* UNIX || VMS */
|
||||
|
||||
#if defined(AMIGA) || defined(WIN32) || defined(MSDOS)
|
||||
#if (defined(AMIGA) || defined(WIN32) || defined(MSDOS)) && !defined(USE_FCNTL)
|
||||
# ifdef AMIGA
|
||||
#define OPENFAILURE(fd) (!fd)
|
||||
lockptr = 0;
|
||||
@@ -1711,10 +1753,19 @@ void
|
||||
unlock_file(filename)
|
||||
const char *filename;
|
||||
{
|
||||
#ifndef USE_FCNTL
|
||||
char locknambuf[BUFSZ];
|
||||
const char *lockname;
|
||||
#endif
|
||||
|
||||
if (nesting == 1) {
|
||||
#ifdef USE_FCNTL
|
||||
sflock.l_type = F_UNLCK;
|
||||
if (fcntl(lockfd,F_SETLK,&sflock) == -1) {
|
||||
HUP raw_printf("Can't remove fcntl lock on %s.", filename);
|
||||
(void) close(lockfd);
|
||||
}
|
||||
#else
|
||||
lockname = make_lockname(filename, locknambuf);
|
||||
#ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */
|
||||
lockname = fqname(lockname, LOCKPREFIX, 2);
|
||||
@@ -1734,6 +1785,7 @@ const char *filename;
|
||||
DeleteFile(lockname);
|
||||
lockptr = 0;
|
||||
#endif /* AMIGA || WIN32 || MSDOS */
|
||||
#endif /* USE_FCNTL */
|
||||
}
|
||||
|
||||
nesting--;
|
||||
|
||||
Reference in New Issue
Block a user