Subject: File locking
To: None <netbsd-users@NetBSD.ORG>
From: D'Arcy J.M. Cain <darcy@druid.com>
List: netbsd-users
Date: 04/23/1997 21:29:47
Here is the file lock program I mentioned in a previous post. The uulock
function that follows uses this to do UUCP locking.
/*
filelock.c
Written by D'Arcy J.M. Cain
darcy@druid.com
Copyright 1991, 1992, 1996
This code may be used on any computer system for any purpose by anyone.
Just give me credit.
implements file locking
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
static int
rmlock(char *file, int me)
{
int r, fd, pid;
char buf[12];
/* make sure it wasn't removed already somehow */
if ((fd = open(file, O_RDONLY)) == -1)
{
if (errno == ENOENT)
return(0);
}
else
{
/* get PID of process that locked file */
r = read(fd, buf, 11);
close(fd);
/* can't remove lock of another active process unless it is gone */
if (r == 11 && (pid = atoi(buf)) != 0 && pid != me && !kill(pid, 0))
return(EPERM);
}
/* OK to remove lock if we can */
return(unlink(file));
}
static int
try2lock(char *chkstr, char *tempfile, char *realfile)
{
int fd;
int ret = 0;
int cmask = umask(0);
/* create the temporary file if we can */
if ((fd = creat(tempfile, 0444)) < 0)
{
if((errno == EMFILE) || (errno == ENFILE))
unlink(tempfile);
umask(cmask);
return(errno);
}
/* write our PID to the file */
write(fd, chkstr, strlen(chkstr));
close(fd);
umask(cmask);
/* try to link the file to the actual lock file */
if (link(tempfile, realfile) < 0)
ret = errno;
/* in any case remove the temporary file */
unlink(tempfile);
return(ret);
}
int
fileunlock(const char *lockdir, const char *file)
{
char realfile[BUFSIZ];
sprintf(realfile, "%s/%s", lockdir, file);
return(rmlock(realfile, getpid()));
}
int
filelock(const char *lockdir, const char *file)
{
char chkstr[12], tempfile[BUFSIZ], realfile[BUFSIZ];
int pid = getpid(), k = -1;
sprintf(chkstr, "%10.10d\n", pid);
if (lockdir == NULL)
{
strcpy(realfile, file);
sprintf(tempfile, "TL.%10.010d", pid);
}
else
{
sprintf(realfile, "%s/%s", lockdir, file);
sprintf(tempfile, "%s/TL.%10.010d", lockdir, pid);
}
/* see if simple lock works */
if ((k = try2lock(chkstr, tempfile, realfile)) == 0)
return(0);
/* file exists only acceptable error */
if (k != EEXIST)
return(k);
/* check if process with lock still active) */
if ((k = rmlock(realfile, pid)) != 0)
return(k);
else
return(try2lock(chkstr, tempfile, realfile));
}
And here is the uulock function.
/*
uulock.c
Written by D'Arcy J.M. Cain
darcy@druid.com
Copyright 1991, 1992, 1996
SVR4 & NetBSD stuff - I'll ifdef in any other versions if the same syntax used
*/
#include <stdio.h>
#include <string.h>
#include <uucp.h>
extern int filelock(const char *, const char *);
extern int fileunlock(const char *, const char *);
#ifdef SVR4
#include <sys/stat.h>
#undef getmajor
#undef getminor
#define getmajor(x) (x >> 18)
#define getminor(x) (x & 0xff)
#endif
/* note: assumes only one device locked at a time by this program */
int
uu_lock(const char *tty)
{
static char buf[128] = "";
#ifdef NetBSD
const char *p;
#else
struct stat st_buf;
#endif
if (*buf)
fileunlock(LOCKDIR, buf);
*buf = 0;
if (!tty)
return(0);
uu_debug(5, "Locking device %s\n", tty);
#ifdef NetBSD
if ((p = strrchr(tty, '/')) == NULL)
p = tty;
else
p++;
sprintf(buf, "LCK..%s", p);
#else
if (stat(tty, &st_buf))
return(1);
sprintf(buf, "LK.000.%3.03lu.%3.03lu",
getmajor(st_buf.st_rdev), getminor(st_buf.st_rdev));
#endif
uu_debug(7, "Lock file " LOCKDIR "/%s\n", buf);
return(filelock(LOCKDIR, buf));
}
--
D'Arcy J.M. Cain | Democracy is three wolves
darcy@{druid.com|vex.net} | and a sheep voting on
+1 416 943 5281 (DoD#0082) (eNTP) | what's for dinner.
-- http://www.druid.com/darcy --