/************************************************************************ * secure exclusive creat/lock v1.4 1992/04/27 * * (works even across NFS, which O_EXCL does *not*) * * * * Created 1990-1992, 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. * * * * Cleaned up 1992, Bart Schaefer, Z-Code Software Corp. * * schaefer@z-code.com * * schaefer@cse.ogi.edu * * Cleanup includes reformatting for readability, * * more comments, and using some file-name macros * * that Mush defines (removed calls to strpbrk() * * and avoided malloc()ing when max. size known). * * Also added XCTEST standalone test program mode. * * * * Usage: int xcreat(char *filename, int mode) * * * * returns 0:success -1:lock busy * * * * sets errno on failure * * * * To remove a `lockfile', simply unlink it. * * * ************************************************************************/ #include "mush.h" /* For OS-specific include files and macros */ #ifdef XCTEST_LOUDLY #ifndef XCTEST #define XCTEST #endif /* XCTEST */ #endif /* XCTEST_LOUDLY */ #ifdef XCTEST #define hostname() "xctest" #else extern char **ourname; #define hostname() ourname[0] #endif /* XCTEST */ #ifdef DECLARE_ERRNO extern int errno; #endif /* DECLARE_ERRNO */ #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 UNIQ_PREFIX '_' /* Any unlikely character works */ #define charsULTOAN 4 /* # of chars output by ultoan() */ #ifndef MAXNAMLEN #if defined(BSD) || defined(IRIX4) || defined(HPUX) #define MAXNAMLEN (MAXPATHLEN/2) /* Any fairly large number works */ #else /* !SYSV */ #define MAXNAMLEN 14 /* 14 is SysVr3 standard */ #endif /* BSD */ #endif /* MAXNAMLEN */ #define HOSTNAMElen (MAXNAMLEN-charsULTOAN-1) /* Define a bit rotation to generate pseudo-unique numbers in "sequence" */ #define bitsSERIAL (6*charsULTOAN) #define maskSERIAL ((1L<>= 6); *dest = '\0'; } /* create unique file name */ static unique(full, p, mode) char *full; char *p; int mode; { unsigned long retry = 3; int i; do { #ifdef XCTEST_LOUDLY printf("Using PID = %d: ", getpid()); #endif /* XCTEST_LOUDLY */ ultoan(XCserialize(getpid(),retry), p + 1); *p = UNIQ_PREFIX; strncat(p, hostname(), HOSTNAMElen); } /* casually check if it already exists (highly unlikely) */ while (0 > (i = copen(full, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, mode)) && errno == EEXIST && retry--); if (i < 0) return 0; close(i); return 1; } /* rename MUST fail if already existent */ static myrename(old, newn) char *old, *newn; { int i, serrno; struct stat stbuf; #ifdef XCTEST_LOUDLY printf("Renaming %s to %s\n", old, newn); #endif /* XCTEST_LOUDLY */ link(old, newn); serrno = errno; i = stat(old, &stbuf); unlink(old); errno = serrno; return stbuf.st_nlink == 2 ? i : -1; } /* an NFS secure exclusive file open */ xcreat(name, mode) char *name; int mode; { char buf[MAXPATHLEN]; char *p, *q; int j = -2, i; q = rindex(name, '/'); if (q) i = q - name; else { i = 0; /* Creating in the current directory */ } p = strncpy(buf, name, i); if (unique(p, p + i, mode)) j = myrename(p, name); /* try and rename it, fails if nonexclusive */ free(p); return j; } #ifdef XCTEST main(argc, argv) int argc; char **argv; { if (argc > 1) exit(xcreat(argv[1], 0444) < 0); } #endif /* XCTEXT */