459 lines
9.6 KiB
C
459 lines
9.6 KiB
C
/* Copyright (c) 1984 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "@(#)uucp:ulockf.c 2.7"
|
|
|
|
#include "uucp.h"
|
|
|
|
#ifdef V7
|
|
#define O_RDONLY 0
|
|
#endif
|
|
|
|
#ifdef sgi
|
|
void stlock(char*);
|
|
char lock_pid[SIZEOFPID+2]; /* +2 for '\n' and NULL */
|
|
#else
|
|
static void stlock();
|
|
#endif
|
|
static int onelock(char*, char*, char*);
|
|
|
|
/*
|
|
* create a lock file (file).
|
|
* If one already exists, send a signal 0 to the process--if
|
|
* it fails, then unlink it and make a new one.
|
|
*
|
|
* input:
|
|
* file - name of the lock file
|
|
* atime - is unused, but we keep it for lint compatibility with non-ATTSVKILL
|
|
*
|
|
* return:
|
|
* 0 -> success
|
|
* FAIL -> failure
|
|
*/
|
|
/* ARGSUSED */
|
|
ulockf(char *file, time_t atime)
|
|
{
|
|
static char tempfile[MAXNAMESIZE];
|
|
|
|
/* SLIP needs to change its PID.
|
|
* It might be ok to generate the lock string every time,
|
|
* but I do not know if uucico might not play games with
|
|
* children locking on behalf of parents.
|
|
*/
|
|
if (lock_pid[0] == '\0') {
|
|
(void) sprintf(lock_pid, LOCKPID_PAT, getpid());
|
|
(void) sprintf(tempfile, "%s/LTMP.%d", X_LOCKDIR, getpid());
|
|
}
|
|
if (onelock(lock_pid, tempfile, file) == -1) {
|
|
(void) unlink(tempfile);
|
|
if (checkLock(file))
|
|
return(FAIL);
|
|
else {
|
|
if (onelock(lock_pid, tempfile, file)) {
|
|
(void) unlink(tempfile);
|
|
DEBUG0(4,"ulockf failed in onelock()\n");
|
|
return(FAIL);
|
|
}
|
|
}
|
|
}
|
|
|
|
stlock(file);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* check to see if the lock file exists and is still active
|
|
* - use kill(pid,0) - (this only works on ATTSV and some hacked
|
|
* BSD systems at this time)
|
|
* return:
|
|
* 0 -> success (lock file removed - no longer active
|
|
* FAIL -> lock file still active
|
|
*/
|
|
checkLock(char *file)
|
|
{
|
|
register int ret;
|
|
#ifdef sgi
|
|
char *p;
|
|
#endif
|
|
int lpid = -1;
|
|
char alpid[SIZEOFPID+2]; /* +2 for '\n' and NULL */
|
|
int fd;
|
|
extern int errno;
|
|
|
|
DEBUG(4, "ulockf file %s\n", file);
|
|
fd = open(file, O_RDONLY);
|
|
if (fd == -1) {
|
|
if (errno == ENOENT) /* file does not exist -- OK */
|
|
return(0);
|
|
DEBUG(4,"Lock File--can't read (errno %d) --remove it!\n", errno);
|
|
goto unlk;
|
|
}
|
|
#ifdef sgi
|
|
bzero(alpid,sizeof(alpid));
|
|
ret = read(fd, (char *) alpid, SIZEOFPID+1); /* +1 for '\n' */
|
|
(void) close(fd);
|
|
if (ret < 2) {
|
|
DEBUG0(4, "Lock File--bad format--remove it!\n");
|
|
goto unlk;
|
|
}
|
|
lpid = (int)strtoul(alpid, &p, 10);
|
|
if (lpid == 0 || *p != '\n') {
|
|
DEBUG(4, "Lock File--invalid contents \'%s\'--remove it.\n",
|
|
alpid);
|
|
goto unlk;
|
|
}
|
|
#else
|
|
ret = read(fd, (char *) alpid, SIZEOFPID+1); /* +1 for '\n' */
|
|
(void) close(fd);
|
|
if (ret != (SIZEOFPID+1)) {
|
|
|
|
DEBUG(4, "Lock File--bad format--remove it!\n", "");
|
|
goto unlk;
|
|
}
|
|
lpid = atoi(alpid);
|
|
#endif /* sgi */
|
|
if ((ret=kill(lpid, 0)) == 0 || errno == EPERM) {
|
|
#ifdef sgi
|
|
DEBUG(4, "Lock File--process %d still active--not removed\n",lpid);
|
|
#else
|
|
DEBUG(4, "Lock File--process still active--not removed\n","");
|
|
#endif
|
|
return(FAIL);
|
|
}
|
|
else { /* process no longer active */
|
|
DEBUG(4, "kill pid (%d), ", lpid);
|
|
DEBUG(4, "returned %d", ret);
|
|
DEBUG(4, "--ok to remove lock file (%s)\n", file);
|
|
}
|
|
unlk:
|
|
|
|
if (unlink(file) != 0) {
|
|
DEBUG0(4,"ulockf failed in unlink()\n");
|
|
return(FAIL);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
#define MAXLOCKS 10 /* maximum number of lock files */
|
|
char *Lockfile[MAXLOCKS];
|
|
int Nlocks = 0;
|
|
|
|
/*
|
|
* put name in list of lock files
|
|
* return:
|
|
* none
|
|
*/
|
|
void
|
|
stlock(char *name)
|
|
{
|
|
register int i;
|
|
char *p;
|
|
|
|
for (i = 0; i < Nlocks; i++) {
|
|
if (Lockfile[i] == NULL)
|
|
break;
|
|
}
|
|
ASSERT(i < MAXLOCKS, "TOO MANY LOCKS", "", i);
|
|
if (i >= Nlocks)
|
|
i = Nlocks++;
|
|
p = calloc((unsigned) strlen(name) + 1, sizeof (char));
|
|
ASSERT(p != NULL, "CAN NOT ALLOCATE FOR", name, 0);
|
|
(void) strcpy(p, name);
|
|
Lockfile[i] = p;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* remove all lock files in list
|
|
* return:
|
|
* none
|
|
*/
|
|
void
|
|
rmlock(register char *name)
|
|
{
|
|
register int i;
|
|
#ifdef V8
|
|
char *cp;
|
|
|
|
cp = rindex(name, '/');
|
|
if (cp++ != CNULL)
|
|
if (strlen(cp) > DIRSIZ)
|
|
*(cp+DIRSIZ) = NULLCHAR;
|
|
#endif /* V8 */
|
|
|
|
|
|
for (i = 0; i < Nlocks; i++) {
|
|
if (Lockfile[i] == NULL)
|
|
continue;
|
|
if (name == NULL || EQUALS(name, Lockfile[i])) {
|
|
(void) unlink(Lockfile[i]);
|
|
(void) free(Lockfile[i]);
|
|
Lockfile[i] = NULL;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* remove a lock file
|
|
* return:
|
|
* 0 -> success
|
|
* FAIL -> failure
|
|
*/
|
|
void
|
|
delock(char *s)
|
|
{
|
|
char ln[MAXNAMESIZE];
|
|
|
|
#ifdef sgi
|
|
if (!lockname(s,ln,sizeof(ln)))
|
|
return;
|
|
#else
|
|
(void) sprintf(ln, "%s.%s", LOCKPRE, s);
|
|
BASENAME(ln, '/')[MAXBASENAME] = '\0';
|
|
#endif
|
|
rmlock(ln);
|
|
}
|
|
|
|
|
|
#ifdef sgi
|
|
int
|
|
lockname(char *name,
|
|
char *tgt,
|
|
int tgtlen)
|
|
{
|
|
static struct {
|
|
char *nm1;
|
|
char *nm2;
|
|
} spcl[] = {
|
|
{"isdn/modem_", "isdn_"},
|
|
{"vsc/wsty", "vsc_"},
|
|
{"isc/wsty", "isc_"},
|
|
{"gsc/wsty", "gsc_"},
|
|
{"psc/wsty", "psc_"},
|
|
{"pri/pri", "pri_"}
|
|
};
|
|
# define SPCL_LEN sizeof(spcl)/sizeof(spcl[0])
|
|
int i;
|
|
|
|
if (!strncmp(name,"/dev/",5))
|
|
name += 5;
|
|
|
|
tgtlen -= sizeof(LOCKPRE ".");
|
|
if (tgtlen <= 0) {
|
|
tgt[0] = '\0';
|
|
return 0;
|
|
}
|
|
(void)strcpy(tgt, LOCKPRE ".");
|
|
|
|
/* Allow "LCK..isdn/modem_foo" and "/dev/[vig]sc" by converting to
|
|
* isdn-foo. That allows programs such as uustat to work.
|
|
*/
|
|
if (strchr(name, '/')) {
|
|
i = 0;
|
|
for (;;) {
|
|
if (i >= SPCL_LEN) {
|
|
tgt[0] = '\0';
|
|
return 0;
|
|
}
|
|
if (!strncmp(name,spcl[i].nm1,strlen(spcl[i].nm1))) {
|
|
tgtlen -= strlen(spcl[i].nm2);
|
|
if (tgtlen <= 0) {
|
|
tgt[0] = '\0';
|
|
return 0;
|
|
}
|
|
name += strlen(spcl[i].nm1);
|
|
(void)strcat(tgt, spcl[i].nm2);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (tgtlen <= strlen(name)) {
|
|
tgt[0] = '\0';
|
|
return 0;
|
|
}
|
|
(void)strcat(tgt, name);
|
|
return 1;
|
|
}
|
|
|
|
|
|
#endif /* sgi */
|
|
/*
|
|
* create system or device lock
|
|
* return:
|
|
* 0 -> success
|
|
* FAIL -> failure
|
|
*/
|
|
mmlock(char *name)
|
|
{
|
|
char lname[MAXNAMESIZE];
|
|
|
|
/*
|
|
* if name has a '/' in it, then it's a device name and it's
|
|
* not in /dev (i.e., it's a remotely-mounted device or it's
|
|
* in a subdirectory of /dev). in either case, creating our normal
|
|
* lockfile (/usr/spool/locks/LCK..<dev>) is going to bomb if
|
|
* <dev> is "/remote/dev/tty14" or "/dev/net/foo/clone", so never
|
|
* mind. since we're using advisory filelocks on the devices
|
|
* themselves, it'll be safe.
|
|
*
|
|
* of course, programs and people who are used to looking at the
|
|
* lockfiles to find out what's going on are going to be a trifle
|
|
* misled. we really need to re-consider the lockfile naming structure
|
|
* to accomodate devices in directories other than /dev ... maybe in
|
|
* the next release.
|
|
*/
|
|
#ifdef sgi
|
|
if (!lockname(name,lname,sizeof(lname)))
|
|
return(0);
|
|
#else
|
|
if ( strchr(name, '/') != NULL )
|
|
return(0);
|
|
(void) sprintf(lname, "%s.%s", LOCKPRE, name);
|
|
#endif
|
|
BASENAME(lname, '/')[MAXBASENAME] = '\0';
|
|
return(ulockf(lname, SLCKTIME) < 0 ? FAIL : 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* update access and modify times for lock files
|
|
* return:
|
|
* none
|
|
*/
|
|
void
|
|
ultouch(void)
|
|
{
|
|
register int i;
|
|
#ifdef sgi
|
|
struct utimbuf ut;
|
|
#else
|
|
time_t time();
|
|
|
|
struct ut {
|
|
time_t actime;
|
|
time_t modtime;
|
|
} ut;
|
|
#endif /* sgi */
|
|
|
|
ut.actime = time(&ut.modtime);
|
|
for (i = 0; i < Nlocks; i++) {
|
|
if (Lockfile[i] == NULL)
|
|
continue;
|
|
utime(Lockfile[i], &ut);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* makes a lock on behalf of pid.
|
|
* input:
|
|
* pid - process id
|
|
* tempfile - name of a temporary in the same file system
|
|
* name - lock file name (full path name)
|
|
* return:
|
|
* -1 - failed
|
|
* 0 - lock made successfully
|
|
*/
|
|
static
|
|
onelock(char *pid,char *tempfile,char *name)
|
|
{
|
|
register int fd;
|
|
char cb[100];
|
|
|
|
fd=creat(tempfile, 0444);
|
|
if(fd < 0){
|
|
(void) sprintf(cb, "%s %s %d",tempfile, name, errno);
|
|
logent("ULOCKC", cb);
|
|
if((errno == EMFILE) || (errno == ENFILE))
|
|
(void) unlink(tempfile);
|
|
return(-1);
|
|
}
|
|
(void) write(fd, pid, SIZEOFPID+1); /* +1 for '\n' */
|
|
(void) chmod(tempfile,0444);
|
|
(void) chown(tempfile, UUCPUID, UUCPGID);
|
|
(void) close(fd);
|
|
if(link(tempfile,name)<0){
|
|
DEBUG(4, "%s: ", sys_errlist[errno]);
|
|
DEBUG(4, "link(%s, ", tempfile);
|
|
DEBUG(4, "%s)\n", name);
|
|
if(unlink(tempfile)< 0){
|
|
(void) sprintf(cb, "ULK err %s %d", tempfile, errno);
|
|
logent("ULOCKLNK", cb);
|
|
}
|
|
return(-1);
|
|
}
|
|
if(unlink(tempfile)<0){
|
|
(void) sprintf(cb, "%s %d",tempfile,errno);
|
|
logent("ULOCKF", cb);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
#ifdef ATTSV
|
|
|
|
/*
|
|
* filelock(fd) sets advisory file lock on file descriptor fd
|
|
*
|
|
* returns SUCCESS if all's well; else returns value returned by fcntl()
|
|
*
|
|
* needed to supplement /usr/spool/locks/LCK..<device> because can now
|
|
* have remotely-mounted devices using RFS. without filelock(), uucico's
|
|
* or cu's on 2 different machines could access the same remotely-mounted
|
|
* device, since /usr/spool/locks is purely local.
|
|
*
|
|
*/
|
|
|
|
int
|
|
filelock(int fd)
|
|
{
|
|
register int lockrtn, locktry = 0;
|
|
struct flock lck;
|
|
|
|
lck.l_type = F_WRLCK; /* setting a write lock */
|
|
lck.l_whence = 0; /* offset l_start from beginning of file */
|
|
lck.l_start = 0L;
|
|
lck.l_len = 0L; /* until the end of the file address space */
|
|
|
|
/* place advisory file locks */
|
|
while ( (lockrtn = fcntl(fd, F_SETLK, &lck)) < 0 ) {
|
|
|
|
DEBUG(7, "filelock: F_SETLK returns %d\n", lockrtn);
|
|
|
|
switch (lockrtn) {
|
|
#ifdef EACCESS
|
|
case EACCESS: /* already locked */
|
|
/* no break */
|
|
#endif /* EACCESS */
|
|
case EAGAIN: /* already locked */
|
|
if ( locktry++ < MAX_LOCKTRY ) {
|
|
sleep(2);
|
|
continue;
|
|
}
|
|
logent("filelock","F_SETLK failed - lock exists");
|
|
return(lockrtn);
|
|
case ENOLCK: /* no more locks available */
|
|
logent("filelock","F_SETLK failed -- ENOLCK");
|
|
return(lockrtn);
|
|
case EFAULT: /* &lck is outside program address space */
|
|
logent("filelock","F_SETLK failed -- EFAULT");
|
|
return(lockrtn);
|
|
default:
|
|
logent("filelock","F_SETLK failed");
|
|
return(lockrtn);
|
|
}
|
|
}
|
|
DEBUG0(7, "filelock: ok\n");
|
|
return(SUCCESS);
|
|
}
|
|
#endif /* ATTSV */
|