1993-08-05 18:28:27 +00:00
|
|
|
|
/* lock.c
|
|
|
|
|
Lock and unlock a file name.
|
|
|
|
|
|
1995-08-19 21:30:30 +00:00
|
|
|
|
Copyright (C) 1991, 1992, 1993, 1995 Ian Lance Taylor
|
1993-08-05 18:28:27 +00:00
|
|
|
|
|
|
|
|
|
This file is part of the Taylor UUCP package.
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
|
published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
1995-08-19 21:30:30 +00:00
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
1993-08-05 18:28:27 +00:00
|
|
|
|
|
|
|
|
|
The author of the program may be contacted at ian@airs.com or
|
1995-08-19 21:30:30 +00:00
|
|
|
|
c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
|
1993-08-05 18:28:27 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "uucp.h"
|
|
|
|
|
|
|
|
|
|
#if USE_RCS_ID
|
1999-08-27 23:37:10 +00:00
|
|
|
|
const char lock_rcsid[] = "$FreeBSD$";
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "uudefs.h"
|
|
|
|
|
#include "sysdep.h"
|
|
|
|
|
#include "system.h"
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
1995-08-19 21:30:30 +00:00
|
|
|
|
#include <ctype.h>
|
1993-08-05 18:28:27 +00:00
|
|
|
|
|
|
|
|
|
#if HAVE_FCNTL_H
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#else
|
|
|
|
|
#if HAVE_SYS_FILE_H
|
|
|
|
|
#include <sys/file.h>
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if TM_IN_SYS_TIME
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
|
#include <sys/psinfo.h>
|
|
|
|
|
#include <sys/seginfo.h>
|
|
|
|
|
#include <sys/vc.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#ifndef O_RDONLY
|
|
|
|
|
#define O_RDONLY 0
|
|
|
|
|
#define O_WRONLY 1
|
|
|
|
|
#define O_RDWR 2
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef O_NOCTTY
|
|
|
|
|
#define O_NOCTTY 0
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef SEEK_SET
|
|
|
|
|
#define SEEK_SET 0
|
|
|
|
|
#endif
|
1994-05-07 18:14:43 +00:00
|
|
|
|
|
|
|
|
|
#ifndef localtime
|
|
|
|
|
extern struct tm *localtime ();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
static boolean fsqnx_stale P((unsigned long ipid, unsigned long inme,
|
|
|
|
|
unsigned long inid, boolean *pferr));
|
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
|
|
|
|
|
/* Lock something. If the fspooldir argument is TRUE, the argument is
|
|
|
|
|
a file name relative to the spool directory; otherwise the argument
|
|
|
|
|
is a simple file name which should be created in the system lock
|
|
|
|
|
directory (under HDB this is /etc/locks). */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
fsdo_lock (zlock, fspooldir, pferr)
|
|
|
|
|
const char *zlock;
|
|
|
|
|
boolean fspooldir;
|
|
|
|
|
boolean *pferr;
|
|
|
|
|
{
|
|
|
|
|
char *zfree;
|
|
|
|
|
const char *zpath, *zslash;
|
|
|
|
|
size_t cslash;
|
|
|
|
|
pid_t ime;
|
|
|
|
|
char *ztempfile;
|
1994-05-07 18:14:43 +00:00
|
|
|
|
char abtempfile[sizeof "TMP12345678901234567890"];
|
1993-08-05 18:28:27 +00:00
|
|
|
|
int o;
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
nid_t inme;
|
|
|
|
|
char ab[23];
|
|
|
|
|
char *zend;
|
|
|
|
|
#else
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#if HAVE_V2_LOCKFILES
|
|
|
|
|
int i;
|
|
|
|
|
#else
|
|
|
|
|
char ab[12];
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#endif
|
|
|
|
|
int cwrote;
|
|
|
|
|
const char *zerr;
|
|
|
|
|
boolean fret;
|
|
|
|
|
|
|
|
|
|
if (pferr != NULL)
|
|
|
|
|
*pferr = TRUE;
|
|
|
|
|
|
|
|
|
|
if (fspooldir)
|
|
|
|
|
{
|
|
|
|
|
zfree = NULL;
|
|
|
|
|
zpath = zlock;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
zfree = zsysdep_in_dir (zSlockdir, zlock);
|
|
|
|
|
zpath = zfree;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ime = getpid ();
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
inme = getnid ();
|
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
|
|
|
|
|
/* We do the actual lock by creating a file and then linking it to
|
|
|
|
|
the final file name we want. This avoids race conditions due to
|
|
|
|
|
one process checking the file before we have finished writing it,
|
|
|
|
|
and also works even if we are somehow running as root.
|
|
|
|
|
|
|
|
|
|
First, create the file in the right directory (we must create the
|
|
|
|
|
file in the same directory since otherwise we might attempt a
|
|
|
|
|
cross-device link). */
|
|
|
|
|
zslash = strrchr (zpath, '/');
|
|
|
|
|
if (zslash == NULL)
|
|
|
|
|
cslash = 0;
|
|
|
|
|
else
|
|
|
|
|
cslash = zslash - zpath + 1;
|
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
sprintf (abtempfile, "TMP%010lx%010lx", (unsigned long) ime,
|
|
|
|
|
(unsigned long) inme);
|
|
|
|
|
#else
|
1993-08-05 18:28:27 +00:00
|
|
|
|
sprintf (abtempfile, "TMP%010lx", (unsigned long) ime);
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
ztempfile = zbufalc (cslash + sizeof abtempfile);
|
|
|
|
|
memcpy (ztempfile, zpath, cslash);
|
|
|
|
|
memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile);
|
|
|
|
|
|
|
|
|
|
o = creat (ztempfile, IPUBLIC_FILE_MODE);
|
|
|
|
|
if (o < 0)
|
|
|
|
|
{
|
|
|
|
|
if (errno == ENOENT)
|
|
|
|
|
{
|
|
|
|
|
if (! fsysdep_make_dirs (ztempfile, FALSE))
|
|
|
|
|
{
|
|
|
|
|
ubuffree (zfree);
|
|
|
|
|
ubuffree (ztempfile);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
o = creat (ztempfile, IPUBLIC_FILE_MODE);
|
|
|
|
|
}
|
|
|
|
|
if (o < 0)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "creat (%s): %s", ztempfile, strerror (errno));
|
|
|
|
|
ubuffree (zfree);
|
|
|
|
|
ubuffree (ztempfile);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
1995-08-19 21:30:30 +00:00
|
|
|
|
sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inme);
|
1994-05-07 18:14:43 +00:00
|
|
|
|
cwrote = write (o, ab, strlen (ab));
|
|
|
|
|
#else
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#if HAVE_V2_LOCKFILES
|
1994-05-07 18:14:43 +00:00
|
|
|
|
i = (int) ime;
|
1993-08-05 18:28:27 +00:00
|
|
|
|
cwrote = write (o, &i, sizeof i);
|
|
|
|
|
#else
|
1994-05-07 18:14:43 +00:00
|
|
|
|
sprintf (ab, "%10ld\n", (long) ime);
|
1993-08-05 18:28:27 +00:00
|
|
|
|
cwrote = write (o, ab, strlen (ab));
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
zerr = NULL;
|
|
|
|
|
if (cwrote < 0)
|
|
|
|
|
zerr = "write";
|
|
|
|
|
if (close (o) < 0)
|
|
|
|
|
zerr = "close";
|
|
|
|
|
if (zerr != NULL)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "%s (%s): %s", zerr, ztempfile, strerror (errno));
|
|
|
|
|
(void) remove (ztempfile);
|
|
|
|
|
ubuffree (zfree);
|
|
|
|
|
ubuffree (ztempfile);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now try to link the file we just created to the lock file that we
|
|
|
|
|
want. If it fails, try reading the existing file to make sure
|
|
|
|
|
the process that created it still exists. We do this in a loop
|
|
|
|
|
to make it easy to retry if the old locking process no longer
|
|
|
|
|
exists. */
|
|
|
|
|
fret = TRUE;
|
|
|
|
|
if (pferr != NULL)
|
|
|
|
|
*pferr = FALSE;
|
|
|
|
|
o = -1;
|
|
|
|
|
zerr = NULL;
|
|
|
|
|
|
|
|
|
|
while (link (ztempfile, zpath) != 0)
|
|
|
|
|
{
|
|
|
|
|
int cgot;
|
1994-05-07 18:14:43 +00:00
|
|
|
|
pid_t ipid;
|
1993-08-05 18:28:27 +00:00
|
|
|
|
boolean freadonly;
|
1994-05-07 18:14:43 +00:00
|
|
|
|
struct stat st;
|
|
|
|
|
char abtime[sizeof "1991-12-31 12:00:00"];
|
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
nid_t inid;
|
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
|
|
|
|
|
fret = FALSE;
|
|
|
|
|
|
|
|
|
|
if (errno != EEXIST)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "link (%s, %s): %s", ztempfile, zpath,
|
|
|
|
|
strerror (errno));
|
|
|
|
|
if (pferr != NULL)
|
|
|
|
|
*pferr = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
freadonly = FALSE;
|
|
|
|
|
o = open ((char *) zpath, O_RDWR | O_NOCTTY, 0);
|
|
|
|
|
if (o < 0)
|
|
|
|
|
{
|
|
|
|
|
if (errno == EACCES)
|
|
|
|
|
{
|
|
|
|
|
freadonly = TRUE;
|
|
|
|
|
o = open ((char *) zpath, O_RDONLY, 0);
|
|
|
|
|
}
|
|
|
|
|
if (o < 0)
|
|
|
|
|
{
|
|
|
|
|
if (errno == ENOENT)
|
|
|
|
|
{
|
|
|
|
|
/* The file was presumably removed between the link
|
|
|
|
|
and the open. Try the link again. */
|
|
|
|
|
fret = TRUE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
zerr = "open";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The race starts here. See below for a discussion. */
|
|
|
|
|
|
|
|
|
|
#if HAVE_V2_LOCKFILES
|
|
|
|
|
cgot = read (o, &i, sizeof i);
|
|
|
|
|
#else
|
|
|
|
|
cgot = read (o, ab, sizeof ab - 1);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (cgot < 0)
|
|
|
|
|
{
|
|
|
|
|
zerr = "read";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1995-08-19 21:30:30 +00:00
|
|
|
|
#if DEBUG > 0
|
|
|
|
|
#if HAVE_V2_LOCKFILES
|
|
|
|
|
{
|
|
|
|
|
char ab[10];
|
|
|
|
|
|
|
|
|
|
if (read (o, ab, sizeof ab) > 4
|
|
|
|
|
&& isdigit (BUCHAR (ab[0])))
|
|
|
|
|
ulog (LOG_ERROR,
|
|
|
|
|
"Lock file %s may be HDB format; check LOCKFILES in policy.h",
|
|
|
|
|
zpath);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (cgot == 4)
|
|
|
|
|
ulog (LOG_ERROR,
|
|
|
|
|
"Lock file %s may be V2 format; check LOCKFILES in policy.h",
|
|
|
|
|
zpath);
|
|
|
|
|
#endif
|
|
|
|
|
#endif /* DEBUG > 0 */
|
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
ab[cgot] = '\0';
|
|
|
|
|
ipid = (pid_t) strtol (ab, &zend, 10);
|
|
|
|
|
inid = (nid_t) strtol (zend, (char **) NULL, 10);
|
|
|
|
|
#else
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#if HAVE_V2_LOCKFILES
|
1994-05-07 18:14:43 +00:00
|
|
|
|
ipid = (pid_t) i;
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#else
|
|
|
|
|
ab[cgot] = '\0';
|
1994-05-07 18:14:43 +00:00
|
|
|
|
ipid = (pid_t) strtol (ab, (char **) NULL, 10);
|
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* On NFS, the link might have actually succeeded even though we
|
|
|
|
|
got a failure return. This can happen if the original
|
|
|
|
|
acknowledgement was lost or delayed and the operation was
|
|
|
|
|
retried. In this case the pid will be our own. This
|
|
|
|
|
introduces a rather improbable race condition: if a stale
|
|
|
|
|
lock was left with our process ID in it, and another process
|
|
|
|
|
just did the kill, below, but has not yet changed the lock
|
|
|
|
|
file to hold its own process ID, we could start up and make
|
|
|
|
|
it all the way to here and think we have the lock. I'm not
|
|
|
|
|
going to worry about this possibility. */
|
|
|
|
|
if (ipid == ime)
|
|
|
|
|
{
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
if (inid == inme)
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
fret = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
1993-08-05 18:28:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-08-19 21:30:30 +00:00
|
|
|
|
/* If the lock file is empty (cgot == 0), we assume that it is
|
|
|
|
|
stale. This can happen if the system crashed after the lock
|
|
|
|
|
file was created but before the process ID was written out. */
|
|
|
|
|
if (cgot > 0)
|
|
|
|
|
{
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
1995-08-19 21:30:30 +00:00
|
|
|
|
if (! fsqnx_stale ((unsigned long) ipid, (unsigned long) inme,
|
|
|
|
|
(unsigned long) inid, pferr))
|
|
|
|
|
break;
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#else
|
1995-08-19 21:30:30 +00:00
|
|
|
|
/* If the process still exists, we will get EPERM rather
|
|
|
|
|
than ESRCH. We then return FALSE to indicate that we
|
|
|
|
|
cannot make the lock. */
|
|
|
|
|
if (kill (ipid, 0) == 0 || errno == EPERM)
|
|
|
|
|
break;
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#endif
|
1995-08-19 21:30:30 +00:00
|
|
|
|
}
|
1993-08-05 18:28:27 +00:00
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
if (fstat (o, &st) < 0)
|
|
|
|
|
strcpy (abtime, "unknown");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
time_t itm;
|
|
|
|
|
struct tm *q;
|
|
|
|
|
|
|
|
|
|
itm = (time_t) st.st_mtime;
|
|
|
|
|
q = localtime (&itm);
|
|
|
|
|
sprintf (abtime, "%04d-%02d-%02d %02d:%02d:%02d",
|
|
|
|
|
q->tm_year + 1900, q->tm_mon + 1, q->tm_mday, q->tm_hour,
|
|
|
|
|
q->tm_min, q->tm_sec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
ulog (LOG_ERROR,
|
|
|
|
|
"Stale lock %s held by process %ld on node %ld created %s",
|
|
|
|
|
zpath, (long) ipid, (long) inid, abtime);
|
|
|
|
|
#else
|
|
|
|
|
ulog (LOG_ERROR, "Stale lock %s held by process %ld created %s",
|
|
|
|
|
zpath, (long) ipid, abtime);
|
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
|
|
|
|
|
/* This is a stale lock, created by a process that no longer
|
|
|
|
|
exists.
|
|
|
|
|
|
|
|
|
|
Now we could remove the file (and, if the file mode disallows
|
|
|
|
|
writing, that's what we have to do), but we try to avoid
|
|
|
|
|
doing so since it causes a race condition. If we remove the
|
|
|
|
|
file, and are interrupted any time after we do the read until
|
|
|
|
|
we do the remove, another process could get in, open the
|
|
|
|
|
file, find that it was a stale lock, remove the file and
|
|
|
|
|
create a new one. When we regained control we would remove
|
|
|
|
|
the file the other process just created.
|
|
|
|
|
|
|
|
|
|
These files are being generated partially for the benefit of
|
|
|
|
|
cu, and it would be nice to avoid the race however cu avoids
|
|
|
|
|
it, so that the programs remain compatible. Unfortunately,
|
|
|
|
|
nobody seems to know how cu avoids the race, or even if it
|
|
|
|
|
tries to avoid it at all.
|
|
|
|
|
|
|
|
|
|
There are a few ways to avoid the race. We could use kernel
|
|
|
|
|
locking primitives, but they may not be available. We could
|
|
|
|
|
link to a special file name, but if that file were left lying
|
|
|
|
|
around then no stale lock could ever be broken (Henry Spencer
|
|
|
|
|
would think this was a good thing).
|
|
|
|
|
|
|
|
|
|
Instead I've implemented the following procedure: seek to the
|
|
|
|
|
start of the file, write our pid into it, sleep for five
|
|
|
|
|
seconds, and then make sure our pid is still there. Anybody
|
|
|
|
|
who checks the file while we're asleep will find our pid
|
|
|
|
|
there and fail the lock. The only race will come from
|
|
|
|
|
another process which has done the read by the time we do our
|
|
|
|
|
write. That process will then have five seconds to do its
|
|
|
|
|
own write. When we wake up, we'll notice that our pid is no
|
|
|
|
|
longer in the file, and retry the lock from the beginning.
|
|
|
|
|
|
|
|
|
|
This relies on the atomicity of write(2). If it possible for
|
|
|
|
|
the writes of two processes to be interleaved, the two
|
|
|
|
|
processes could livelock. POSIX unfortunately leaves this
|
|
|
|
|
case explicitly undefined; however, given that the write is
|
|
|
|
|
of less than a disk block, it's difficult to imagine an
|
|
|
|
|
interleave occurring.
|
|
|
|
|
|
|
|
|
|
Note that this is still a race. If it takes the second
|
|
|
|
|
process more than five seconds to do the kill, the lseek, and
|
|
|
|
|
the write, both processes will think they have the lock.
|
|
|
|
|
Perhaps the length of time to sleep should be configurable.
|
|
|
|
|
Even better, perhaps I should add a configuration option to
|
|
|
|
|
use a permanent lock file, which eliminates any race and
|
|
|
|
|
forces the installer to be aware of the existence of the
|
|
|
|
|
permanent lock file.
|
|
|
|
|
|
|
|
|
|
We stat the file after the sleep, to make sure some other
|
|
|
|
|
program hasn't deleted it for us. */
|
|
|
|
|
if (freadonly)
|
|
|
|
|
{
|
|
|
|
|
(void) close (o);
|
|
|
|
|
o = -1;
|
|
|
|
|
(void) remove (zpath);
|
1994-05-07 18:14:43 +00:00
|
|
|
|
fret = TRUE;
|
1993-08-05 18:28:27 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lseek (o, (off_t) 0, SEEK_SET) != 0)
|
|
|
|
|
{
|
|
|
|
|
zerr = "lseek";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
1995-08-19 21:30:30 +00:00
|
|
|
|
sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inme);
|
1994-05-07 18:14:43 +00:00
|
|
|
|
cwrote = write (o, ab, strlen (ab));
|
|
|
|
|
#else
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#if HAVE_V2_LOCKFILES
|
1994-05-07 18:14:43 +00:00
|
|
|
|
i = (int) ime;
|
1993-08-05 18:28:27 +00:00
|
|
|
|
cwrote = write (o, &i, sizeof i);
|
|
|
|
|
#else
|
1994-05-07 18:14:43 +00:00
|
|
|
|
sprintf (ab, "%10ld\n", (long) ime);
|
1993-08-05 18:28:27 +00:00
|
|
|
|
cwrote = write (o, ab, strlen (ab));
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (cwrote < 0)
|
|
|
|
|
{
|
|
|
|
|
zerr = "write";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(void) sleep (5);
|
|
|
|
|
|
|
|
|
|
if (lseek (o, (off_t) 0, SEEK_SET) != 0)
|
|
|
|
|
{
|
|
|
|
|
zerr = "lseek";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if HAVE_V2_LOCKFILES
|
|
|
|
|
cgot = read (o, &i, sizeof i);
|
|
|
|
|
#else
|
|
|
|
|
cgot = read (o, ab, sizeof ab - 1);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (cgot < 0)
|
|
|
|
|
{
|
|
|
|
|
zerr = "read";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
ab[cgot] = '\0';
|
|
|
|
|
ipid = (pid_t) strtol (ab, &zend, 10);
|
|
|
|
|
inid = (nid_t) strtol (zend, (char **) NULL, 10);
|
|
|
|
|
#else
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#if HAVE_V2_LOCKFILES
|
1994-05-07 18:14:43 +00:00
|
|
|
|
ipid = (pid_t) i;
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#else
|
|
|
|
|
ab[cgot] = '\0';
|
1994-05-07 18:14:43 +00:00
|
|
|
|
ipid = (pid_t) strtol (ab, (char **) NULL, 10);
|
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (ipid == ime)
|
|
|
|
|
{
|
1994-05-07 18:14:43 +00:00
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
if (inid == inme)
|
|
|
|
|
#endif
|
1993-08-05 18:28:27 +00:00
|
|
|
|
{
|
1994-05-07 18:14:43 +00:00
|
|
|
|
struct stat sfile, sdescriptor;
|
|
|
|
|
|
|
|
|
|
/* It looks like we have the lock. Do the final stat
|
|
|
|
|
check. */
|
|
|
|
|
if (stat ((char *) zpath, &sfile) < 0)
|
1993-08-05 18:28:27 +00:00
|
|
|
|
{
|
1994-05-07 18:14:43 +00:00
|
|
|
|
if (errno != ENOENT)
|
|
|
|
|
{
|
|
|
|
|
zerr = "stat";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* Loop around and try again. */
|
1993-08-05 18:28:27 +00:00
|
|
|
|
}
|
1994-05-07 18:14:43 +00:00
|
|
|
|
else
|
1993-08-05 18:28:27 +00:00
|
|
|
|
{
|
1994-05-07 18:14:43 +00:00
|
|
|
|
if (fstat (o, &sdescriptor) < 0)
|
1993-08-05 18:28:27 +00:00
|
|
|
|
{
|
1994-05-07 18:14:43 +00:00
|
|
|
|
zerr = "fstat";
|
1993-08-05 18:28:27 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
if (sfile.st_ino == sdescriptor.st_ino
|
|
|
|
|
&& sfile.st_dev == sdescriptor.st_dev)
|
|
|
|
|
{
|
|
|
|
|
/* Close the file before assuming we've
|
|
|
|
|
succeeded to pick up any trailing errors. */
|
|
|
|
|
if (close (o) < 0)
|
|
|
|
|
{
|
|
|
|
|
zerr = "close";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
o = -1;
|
|
|
|
|
|
|
|
|
|
/* We have the lock. */
|
|
|
|
|
fret = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
1993-08-05 18:28:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Loop around and try the lock again. We keep doing this until
|
|
|
|
|
the lock file holds a pid that exists. */
|
|
|
|
|
(void) close (o);
|
|
|
|
|
o = -1;
|
|
|
|
|
fret = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (zerr != NULL)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "%s (%s): %s", zerr, zpath, strerror (errno));
|
|
|
|
|
if (pferr != NULL)
|
|
|
|
|
*pferr = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (o >= 0)
|
|
|
|
|
(void) close (o);
|
|
|
|
|
|
|
|
|
|
ubuffree (zfree);
|
|
|
|
|
|
|
|
|
|
/* It would be nice if we could leave the temporary file around for
|
|
|
|
|
future calls, but considering that we create lock files in
|
|
|
|
|
various different directories it's probably more trouble than
|
|
|
|
|
it's worth. */
|
|
|
|
|
if (remove (ztempfile) != 0)
|
|
|
|
|
ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno));
|
|
|
|
|
|
|
|
|
|
ubuffree (ztempfile);
|
|
|
|
|
|
|
|
|
|
return fret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Unlock something. The fspooldir argument is as in fsdo_lock. */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
fsdo_unlock (zlock, fspooldir)
|
|
|
|
|
const char *zlock;
|
|
|
|
|
boolean fspooldir;
|
|
|
|
|
{
|
|
|
|
|
char *zfree;
|
|
|
|
|
const char *zpath;
|
|
|
|
|
|
|
|
|
|
if (fspooldir)
|
|
|
|
|
{
|
|
|
|
|
zfree = NULL;
|
|
|
|
|
zpath = zlock;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
zfree = zsysdep_in_dir (zSlockdir, zlock);
|
|
|
|
|
zpath = zfree;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (remove (zpath) == 0
|
|
|
|
|
|| errno == ENOENT)
|
|
|
|
|
{
|
|
|
|
|
ubuffree (zfree);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "remove (%s): %s", zpath, strerror (errno));
|
|
|
|
|
ubuffree (zfree);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
1994-05-07 18:14:43 +00:00
|
|
|
|
|
|
|
|
|
#if HAVE_QNX_LOCKFILES
|
|
|
|
|
|
|
|
|
|
/* Return TRUE if the lock is stale. */
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
fsqnx_stale (ipid, inme, inid, pferr)
|
|
|
|
|
unsigned long ipid;
|
|
|
|
|
unsigned long inme;
|
|
|
|
|
unsigned long inid;
|
|
|
|
|
boolean *pferr;
|
|
|
|
|
{
|
|
|
|
|
/* A virtual process ID. This virtual process ID, which will exist
|
|
|
|
|
on the local node, will represent the process ID of the process
|
|
|
|
|
manager process (Proc) on the remote node. */
|
|
|
|
|
pid_t ivid;
|
|
|
|
|
/* The return value of the qnx_psinfo function. This is either a
|
|
|
|
|
process ID which might or might not be the same as the process
|
|
|
|
|
being looked for, or -1 to indicate no process found. */
|
|
|
|
|
pid_t ifound_pid;
|
|
|
|
|
/* This holds the actual result of qnx_psinfo. We will ignore
|
|
|
|
|
almost all the fields since we're just checking for existence. */
|
|
|
|
|
struct _psinfo spsdata;
|
|
|
|
|
|
|
|
|
|
/* Establish connection with a remote process manager if necessary. */
|
|
|
|
|
if (inid != inme)
|
|
|
|
|
{
|
|
|
|
|
ivid = qnx_vc_attach (inid /* remote node ID */,
|
|
|
|
|
PROC_PID /* pid of process manager */,
|
|
|
|
|
1000 /* initial buffer size */,
|
|
|
|
|
0 /* flags */);
|
|
|
|
|
if (ivid < 0)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "qnx_vc_attach (%lu, PROC_PID): %s",
|
|
|
|
|
inid, strerror (errno));
|
|
|
|
|
if (pferr != NULL)
|
|
|
|
|
*pferr = TRUE;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Use the local pid of the local process manager. */
|
|
|
|
|
ivid = PROC_PID;
|
|
|
|
|
}
|
1995-08-19 21:30:30 +00:00
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
/* Request the process information. */
|
|
|
|
|
ifound_pid = qnx_psinfo (ivid /* process manager handling request */,
|
|
|
|
|
ipid /* get info on this process */,
|
|
|
|
|
&spsdata /* put info in this struct */,
|
|
|
|
|
0 /* unused */,
|
|
|
|
|
(struct _seginfo *) NULL /* unused */);
|
|
|
|
|
|
|
|
|
|
/* Deallocate the virtual connection before continuing. */
|
|
|
|
|
{
|
|
|
|
|
int isaved_errno = errno;
|
|
|
|
|
if (qnx_vc_detach (ivid) < 0)
|
|
|
|
|
ulog (LOG_ERROR, "qnx_vd_detach (%ld): %s", (long) ivid,
|
|
|
|
|
strerror (errno));
|
|
|
|
|
errno = isaved_errno;
|
|
|
|
|
}
|
1995-08-19 21:30:30 +00:00
|
|
|
|
|
1994-05-07 18:14:43 +00:00
|
|
|
|
/* If the returned pid matches then the process still holds the lock. */
|
|
|
|
|
if ((ifound_pid == ipid) && (spsdata.pid == ipid))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* If the returned pid is positive and doesn't match, then the
|
|
|
|
|
process doesn't exist and the lock is stale. Continue. */
|
|
|
|
|
|
|
|
|
|
/* If the returned pid is negative (-1) and errno is EINVAL (or ESRCH
|
|
|
|
|
in older versions of QNX), then the process doesn't exist and the
|
|
|
|
|
lock is stale. Continue. */
|
|
|
|
|
|
|
|
|
|
/* Check for impossible errors. */
|
|
|
|
|
if ((ifound_pid < 0) && (errno != ESRCH) && (errno != EINVAL))
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "qnx_psinfo (%ld, %ld): %s", (long) ivid,
|
|
|
|
|
(long) ipid, strerror (errno));
|
|
|
|
|
/* Since we don't know what the hell this means, and we don't
|
|
|
|
|
want our system to freeze, we treat this case as a stale
|
|
|
|
|
lock. Continue on. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* HAVE_QNX_LOCKFILES */
|