#include "uucp.h"
#if USE_RCS_ID
const char lock_rcsid[] = "$Id: lock.c,v 1.23 2002/03/05 19:10:42 ian Rel $";
#endif
#include "uudefs.h"
#include "sysdep.h"
#include "system.h"
#include <errno.h>
#include <ctype.h>
#if HAVE_FCNTL_H
#include <fcntl.h>
#else
#if HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#endif
#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
#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
#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
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;
char abtempfile[sizeof "TMP12345678901234567890"];
int o;
#if HAVE_QNX_LOCKFILES
nid_t inme;
char ab[23];
char *zend;
#else
#if HAVE_V2_LOCKFILES
int i;
#else
char ab[12];
#endif
#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 ();
#if HAVE_QNX_LOCKFILES
inme = getnid ();
#endif
zslash = strrchr (zpath, '/');
if (zslash == NULL)
cslash = 0;
else
cslash = zslash - zpath + 1;
#if HAVE_QNX_LOCKFILES
sprintf (abtempfile, "TMP%010lx%010lx", (unsigned long) ime,
(unsigned long) inme);
#else
sprintf (abtempfile, "TMP%010lx", (unsigned long) ime);
#endif
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 during lock (%s in %s as uid %d): %s", ztempfile, getwd(NULL), getuid(), strerror (errno));
ubuffree (zfree);
ubuffree (ztempfile);
return FALSE;
}
}
#if HAVE_QNX_LOCKFILES
sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inme);
cwrote = write (o, ab, strlen (ab));
#else
#if HAVE_V2_LOCKFILES
i = (int) ime;
cwrote = write (o, &i, sizeof i);
#else
sprintf (ab, "%10ld\n", (long) ime);
cwrote = write (o, ab, strlen (ab));
#endif
#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;
}
fret = TRUE;
if (pferr != NULL)
*pferr = FALSE;
o = -1;
zerr = NULL;
while (link (ztempfile, zpath) != 0)
{
int cgot;
pid_t ipid;
boolean freadonly;
struct stat st;
char abtime[sizeof "1991-12-31 12:00:00"];
#if HAVE_QNX_LOCKFILES
nid_t inid;
#endif
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)
{
fret = TRUE;
continue;
}
zerr = "open";
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;
}
#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
#if HAVE_QNX_LOCKFILES
ab[cgot] = '\0';
ipid = (pid_t) strtol (ab, &zend, 10);
inid = (nid_t) strtol (zend, (char **) NULL, 10);
#else
#if HAVE_V2_LOCKFILES
ipid = (pid_t) i;
#else
ab[cgot] = '\0';
ipid = (pid_t) strtol (ab, (char **) NULL, 10);
#endif
#endif
if (ipid == ime)
{
#if HAVE_QNX_LOCKFILES
if (inid == inme)
#endif
{
fret = TRUE;
break;
}
}
if (cgot > 0)
{
#if HAVE_QNX_LOCKFILES
if (! fsqnx_stale ((unsigned long) ipid, (unsigned long) inme,
(unsigned long) inid, pferr))
break;
#else
if (kill (ipid, 0) == 0 || errno == EPERM)
break;
#endif
}
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
if (freadonly)
{
(void) close (o);
o = -1;
if (remove (zpath) != 0)
{
zerr = "remove";
break;
}
fret = TRUE;
continue;
}
if (lseek (o, (off_t) 0, SEEK_SET) != 0)
{
zerr = "lseek";
break;
}
#if HAVE_QNX_LOCKFILES
sprintf (ab, "%10ld %10ld\n", (long) ime, (long) inme);
cwrote = write (o, ab, strlen (ab));
#else
#if HAVE_V2_LOCKFILES
i = (int) ime;
cwrote = write (o, &i, sizeof i);
#else
sprintf (ab, "%10ld\n", (long) ime);
cwrote = write (o, ab, strlen (ab));
#endif
#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;
}
#if HAVE_QNX_LOCKFILES
ab[cgot] = '\0';
ipid = (pid_t) strtol (ab, &zend, 10);
inid = (nid_t) strtol (zend, (char **) NULL, 10);
#else
#if HAVE_V2_LOCKFILES
ipid = (pid_t) i;
#else
ab[cgot] = '\0';
ipid = (pid_t) strtol (ab, (char **) NULL, 10);
#endif
#endif
if (ipid == ime)
{
#if HAVE_QNX_LOCKFILES
if (inid == inme)
#endif
{
struct stat sfile, sdescriptor;
if (stat ((char *) zpath, &sfile) < 0)
{
if (errno != ENOENT)
{
zerr = "stat";
break;
}
}
else
{
if (fstat (o, &sdescriptor) < 0)
{
zerr = "fstat";
break;
}
if (sfile.st_ino == sdescriptor.st_ino
&& sfile.st_dev == sdescriptor.st_dev)
{
if (close (o) < 0)
{
zerr = "close";
break;
}
o = -1;
fret = TRUE;
break;
}
}
}
}
(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);
if (remove (ztempfile) != 0)
ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno));
ubuffree (ztempfile);
return fret;
}
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;
}
}
#if HAVE_QNX_LOCKFILES
static boolean
fsqnx_stale (ipid, inme, inid, pferr)
unsigned long ipid;
unsigned long inme;
unsigned long inid;
boolean *pferr;
{
pid_t ivid;
pid_t ifound_pid;
struct _psinfo spsdata;
if (inid != inme)
{
ivid = qnx_vc_attach (inid ,
PROC_PID ,
1000 ,
0 );
if (ivid < 0)
{
ulog (LOG_ERROR, "qnx_vc_attach (%lu, PROC_PID): %s",
inid, strerror (errno));
if (pferr != NULL)
*pferr = TRUE;
return FALSE;
}
}
else
{
ivid = PROC_PID;
}
ifound_pid = qnx_psinfo (ivid ,
ipid ,
&spsdata ,
0 ,
(struct _seginfo *) NULL );
{
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;
}
if ((ifound_pid == ipid) && (spsdata.pid == ipid))
return FALSE;
if ((ifound_pid < 0) && (errno != ESRCH) && (errno != EINVAL))
{
ulog (LOG_ERROR, "qnx_psinfo (%ld, %ld): %s", (long) ivid,
(long) ipid, strerror (errno));
}
return TRUE;
}
#endif