1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
/************************************************************************
* secure exclusive creat/lock v1.6 1995/05/05 *
* (works even across NFS, which O_EXCL does *not*) *
* *
* Created 1990-1997, S.R. van den Berg, The Netherlands *
* srb@cuci.nl *
* *
* This file is donated to the public domain. *
* Customised for cucipop. *
* *
* 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 */
#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>
/************************************************************************
* Only edit below this line if you *think* you know what you are doing *
************************************************************************/
#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;
#ifdef NOstrpbrk
char*strpbrk(st,del)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;
}
/* convert to a number */
static void ultoan(val,dest)unsigned long val;char*dest;
{ 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';
}
static int unique(full,p,mode)const char*const full;char*const p;
const mode_t mode;
{ unsigned long retry=mrotbSERIAL;int i; /* create unique file name */
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) */
write(i,"0",1); /* put in a fake pid */
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(old,newn)const char*const old,*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(name,mode)char*name;const mode_t mode;
{ char*p,*q;int j= -2,i;
for(q=name;p=strchr(q,'/');q=p+1); /* find last DIRSEP */
if(!(p=malloc((i=q-name)+UNIQnamelen))) /* out of memory */
return j;
strncpy(p,name,i);
if(unique(p,p+i,mode))
j=myrename(p,name); /* try and rename it, fails if nonexclusive */
free(p);return j;
}
|