lkml.org 
[lkml]   [1996]   [Sep]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: patch: NFS and O_EXCL. Also: is O_EXCL really atomic?

This has probably been seen before. Apologies for any repitition. Just
to let you know that this problem has been successfully dealt with already.
This is the secure-creation routine used by procmail for its lockfiles.

Phil
=========================================================================

/**** Made happy and readable by pedwards@valhalla.cs.wright.edu 5Jan96 */
/************************************************************************
* secure exclusive creat/lock v1.6 1995/05/05 *
* (works even across NFS, which O_EXCL does *not*) *
* *
* Created 1990-1995, S.R. van den Berg, The Netherlands *
* berg@pool.informatik.rwth-aachen.de *
* berg@physik.tu-muenchen.de *
* *
* This file is donated to the public domain. *
* *
* Usage: int xcreat(const char*filename,mode_t mode) *
* *
* returns 0:success -1:lock busy *
* -2:parameter error or out of memory *
* *
* sets errno on failure *
* *
* To remove a `lockfile', simply unlink it. *
* *
************************************************************************/
#define HOSTNAMElen 9 /* significant characters for hostname */
/*#define NOuname uncomment if uname is not available */
/*#define NOstrpbrk uncomment if strpbrk is not available */
/*#define strchr(s,c) index(s,c) uncomment if strchr is not available */
#define const /* can be undefined for ANSI compilers */
static const char dirsep[]="/"; /* directory separators */

#include <unistd.h> /* open() close() link() unlink() getpid() */
#include <fcntl.h> /* O_WRONLY O_CREAT O_EXCL */
#include <stdlib.h> /* malloc() free() */
#include <string.h> /* strncpy() strcat() strpbrk() */
#include <sys/stat.h> /* stat() struct stat */
#ifndef NOuname
#include <sys/utsname.h> /* uname() struct utsname */
#endif
#include <errno.h>

#ifndef O_SYNC
#define O_SYNC 0
#endif
#ifndef O_CREAT
#define copen(path,type,mode) creat(path,mode)
#else
#define copen(path,type,mode) open(path,type,mode)
#endif
#define log(string) /* should log string to stderr */
#define UNIQ_PREFIX '_'
#define charsSERIAL 4
#define UNIQnamelen (1+charsSERIAL+HOSTNAMElen+1)
#define bitsSERIAL (6*charsSERIAL)
#define maskSERIAL ((1L<<bitsSERIAL)-1)
#define rotbSERIAL 2
#define irotbSERIAL (1L<<bitsSERIAL-rotbSERIAL)
#define mrotbSERIAL ((maskSERIAL&irotbSERIAL-1)+irotbSERIAL)

/* extern errno; Bad Things -- already declared in errno.h */

#ifdef NOstrpbrk
char*
strpbrk(const char* const st, *del)
{
const char *f=0, *t;
for(f=0; *del; )
if((t=strchr(st,*del++))&&(!f||t<f))
f=t;
return (char*)f;
}
#endif

static const char*hostname()
{ static char name[HOSTNAMElen+1];
#ifdef NOuname
gethostname(name,HOSTNAMElen+1);
#else
struct utsname names;
uname(&names);strncpy(name,names.nodename,HOSTNAMElen);
#endif
name[HOSTNAMElen]='\0';return name;
}

static void ultoan(val,dest)unsigned long val;char*dest; /* convert to a number */
{ register i; /* within the set [0-9A-Za-z-_] */
do
{ i=val&0x3f;
*dest++=i+(i<10?'0':i<10+26?'A'-10:i<10+26+26?'a'-10-26:
i==10+26+26?'-'-10-26-26:'_'-10-26-27);
}
while(val>>=6);
*dest='\0';
}


/* create unique file name */
static
int
unique (const char* const full, char* const p, const mode_t mode)
{
unsigned long retry = mrotbSERIAL;
int i;
do {
ultoan(maskSERIAL&(retry-=irotbSERIAL)+(long)getpid(),p+1);
*p = UNIQ_PREFIX;
strcat(p,hostname());
}
while (0>(i=copen(full,O_WRONLY|O_CREAT|O_EXCL|O_SYNC,mode))&&errno==EEXIST&&
retry); /* casually check if it already exists (highly unlikely) */

if (i<0) {
log("Error while writing to \"");
log(full);
log("\"\n");
return 0;
}
close(i);
return 1;
}


/* rename MUST fail if already existent */
static
int
myrename (const char* const old, const char* const newn)
{
int i, serrno;
struct stat stbuf;
if (!link(old,newn)) {
unlink(old);
return 0;
}
serrno = errno;
i = stat(old, &stbuf);
unlink(old);
errno = serrno;
return stbuf.st_nlink==2 ? i : -1;
}


/* an NFS secure exclusive file open */
int
xcreat (char *name, const mode_t mode)
{
char *p, *q;
int j=-2, i;

for (q=name; p=strpbrk(q,dirsep); q=p+1); /* find last DIRSEP */
if (!(p=malloc((i=q-name)+UNIQnamelen))) return j; /* Out of memory */
strncpy(p,name,i);
/* try and rename it, fails if nonexclusive */
if (unique(p,p+i,mode)) j=myrename(p,name);
free(p);
return j;
}



\
 
 \ /
  Last update: 2005-03-22 13:38    [W:0.044 / U:1.768 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site