From: Pasi Kallinen Date: Sat, 7 Mar 2015 13:11:41 +0000 (+0200) Subject: Implement fcntl(2) file locking X-Git-Tag: NetHack-3.6.0_RC01~625 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1609081320968a41e1f96713e3f844cefcbb8797;p=nethack 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 --- diff --git a/include/unixconf.h b/include/unixconf.h index c85611c2a..9feefd2c8 100644 --- a/include/unixconf.h +++ b/include/unixconf.h @@ -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. diff --git a/src/files.c b/src/files.c index 71fd0c217..2cae9fb7f 100644 --- a/src/files.c +++ b/src/files.c @@ -12,7 +12,7 @@ #include -#if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C) +#if (!defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)) || defined(USE_FCNTL) #include #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--;