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:
Pasi Kallinen
2015-03-07 15:11:41 +02:00
parent 7fa05c6311
commit 66a1f0ced4
2 changed files with 62 additions and 4 deletions

View File

@@ -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.

View File

@@ -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--;