635 lines
14 KiB
C
635 lines
14 KiB
C
/* statsb.c
|
||
System dependent routines for uustat.
|
||
|
||
Copyright (C) 1992, 1993, 1994 Ian Lance Taylor
|
||
|
||
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
|
||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
||
The author of the program may be contacted at ian@airs.com or
|
||
c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
|
||
*/
|
||
|
||
#include "uucp.h"
|
||
|
||
#if USE_RCS_ID
|
||
const char statsb_rcsid[] = "$Id: statsb.c,v 1.19 1995/06/21 19:20:39 ian Rel $";
|
||
#endif
|
||
|
||
#include "uudefs.h"
|
||
#include "uuconf.h"
|
||
#include "sysdep.h"
|
||
#include "system.h"
|
||
|
||
#include <errno.h>
|
||
|
||
#if HAVE_FCNTL_H
|
||
#include <fcntl.h>
|
||
#else
|
||
#if HAVE_SYS_FILE_H
|
||
#include <sys/file.h>
|
||
#endif
|
||
#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
|
||
|
||
#if HAVE_OPENDIR
|
||
#if HAVE_DIRENT_H
|
||
#include <dirent.h>
|
||
#else /* ! HAVE_DIRENT_H */
|
||
#include <sys/dir.h>
|
||
#define dirent direct
|
||
#endif /* ! HAVE_DIRENT_H */
|
||
#endif /* HAVE_OPENDIR */
|
||
|
||
#if HAVE_TIME_H
|
||
#include <time.h>
|
||
#endif
|
||
|
||
#if HAVE_UTIME_H
|
||
#include <utime.h>
|
||
#endif
|
||
|
||
/* Local functions. */
|
||
|
||
static int issettime P((const char *z, time_t inow));
|
||
static boolean fskill_or_rejuv P((pointer puuconf, const char *zid,
|
||
boolean fkill));
|
||
|
||
/* Set file access time to the present. On many systems this could be
|
||
done by passing NULL to utime, but on some that doesn't work. This
|
||
routine is not time critical, so we never rely on NULL. */
|
||
|
||
static int
|
||
issettime(z, inow)
|
||
const char *z;
|
||
time_t inow;
|
||
{
|
||
#if HAVE_UTIME_H
|
||
struct utimbuf s;
|
||
|
||
s.actime = inow;
|
||
s.modtime = inow;
|
||
return utime ((char *) z, &s);
|
||
#else
|
||
time_t ai[2];
|
||
|
||
ai[0] = inow;
|
||
ai[1] = inow;
|
||
return utime ((char *) z, ai);
|
||
#endif
|
||
}
|
||
|
||
/* Kill a job, given the jobid. */
|
||
|
||
boolean
|
||
fsysdep_kill_job (puuconf, zid)
|
||
pointer puuconf;
|
||
const char *zid;
|
||
{
|
||
return fskill_or_rejuv (puuconf, zid, TRUE);
|
||
}
|
||
|
||
/* Rejuvenate a job, given the jobid. */
|
||
|
||
boolean
|
||
fsysdep_rejuvenate_job (puuconf, zid)
|
||
pointer puuconf;
|
||
const char *zid;
|
||
{
|
||
return fskill_or_rejuv (puuconf, zid, FALSE);
|
||
}
|
||
|
||
/* Kill or rejuvenate a job, given the jobid. */
|
||
|
||
static boolean
|
||
fskill_or_rejuv (puuconf, zid, fkill)
|
||
pointer puuconf;
|
||
const char *zid;
|
||
boolean fkill;
|
||
{
|
||
char *zfile;
|
||
char *zsys;
|
||
char bgrade;
|
||
time_t inow = 0;
|
||
int iuuconf;
|
||
struct uuconf_system ssys;
|
||
FILE *e;
|
||
boolean fret;
|
||
char *zline;
|
||
size_t cline;
|
||
int isys;
|
||
|
||
zfile = zsjobid_to_file (zid, &zsys, &bgrade);
|
||
if (zfile == NULL)
|
||
return FALSE;
|
||
|
||
if (! fkill)
|
||
inow = time ((time_t *) NULL);
|
||
|
||
iuuconf = uuconf_system_info (puuconf, zsys, &ssys);
|
||
if (iuuconf == UUCONF_NOT_FOUND)
|
||
{
|
||
if (! funknown_system (puuconf, zsys, &ssys))
|
||
{
|
||
ulog (LOG_ERROR, "%s: Bad job id", zid);
|
||
ubuffree (zfile);
|
||
ubuffree (zsys);
|
||
return FALSE;
|
||
}
|
||
}
|
||
else if (iuuconf != UUCONF_SUCCESS)
|
||
{
|
||
ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
|
||
ubuffree (zfile);
|
||
ubuffree (zsys);
|
||
return FALSE;
|
||
}
|
||
|
||
e = fopen (zfile, "r");
|
||
if (e == NULL)
|
||
{
|
||
if (errno == ENOENT)
|
||
ulog (LOG_ERROR, "%s: Job not found", zid);
|
||
else
|
||
ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno));
|
||
(void) uuconf_system_free (puuconf, &ssys);
|
||
ubuffree (zfile);
|
||
ubuffree (zsys);
|
||
return FALSE;
|
||
}
|
||
|
||
/* Now we have to read through the file to identify any temporary
|
||
files. */
|
||
fret = TRUE;
|
||
zline = NULL;
|
||
cline = 0;
|
||
while (getline (&zline, &cline, e) > 0)
|
||
{
|
||
struct scmd s;
|
||
|
||
if (! fparse_cmd (zline, &s))
|
||
{
|
||
ulog (LOG_ERROR, "Bad line in command file %s", zfile);
|
||
fret = FALSE;
|
||
continue;
|
||
}
|
||
|
||
/* You are only permitted to delete a job if you submitted it or
|
||
if you are root or uucp. */
|
||
if (strcmp (s.zuser, zsysdep_login_name ()) != 0
|
||
&& ! fsysdep_privileged ())
|
||
{
|
||
ulog (LOG_ERROR, "%s: Not submitted by you", zid);
|
||
xfree ((pointer) zline);
|
||
(void) fclose (e);
|
||
(void) uuconf_system_free (puuconf, &ssys);
|
||
ubuffree (zfile);
|
||
ubuffree (zsys);
|
||
return FALSE;
|
||
}
|
||
|
||
if (s.bcmd == 'S' || s.bcmd == 'E')
|
||
{
|
||
char *ztemp;
|
||
|
||
ztemp = zsfind_file (s.ztemp, ssys.uuconf_zname, bgrade);
|
||
if (ztemp == NULL)
|
||
fret = FALSE;
|
||
else
|
||
{
|
||
if (fkill)
|
||
isys = remove (ztemp);
|
||
else
|
||
isys = issettime (ztemp, inow);
|
||
|
||
if (isys != 0 && errno != ENOENT)
|
||
{
|
||
ulog (LOG_ERROR, "%s (%s): %s",
|
||
fkill ? "remove" : "utime", ztemp,
|
||
strerror (errno));
|
||
fret = FALSE;
|
||
}
|
||
|
||
ubuffree (ztemp);
|
||
}
|
||
}
|
||
}
|
||
|
||
xfree ((pointer) zline);
|
||
(void) fclose (e);
|
||
(void) uuconf_system_free (puuconf, &ssys);
|
||
ubuffree (zsys);
|
||
|
||
if (fkill)
|
||
isys = remove (zfile);
|
||
else
|
||
isys = issettime (zfile, inow);
|
||
|
||
if (isys != 0 && errno != ENOENT)
|
||
{
|
||
ulog (LOG_ERROR, "%s (%s): %s", fkill ? "remove" : "utime",
|
||
zfile, strerror (errno));
|
||
fret = FALSE;
|
||
}
|
||
|
||
ubuffree (zfile);
|
||
|
||
return fret;
|
||
}
|
||
|
||
/* Get the time a work job was queued. */
|
||
|
||
long
|
||
ixsysdep_work_time (qsys, pseq)
|
||
const struct uuconf_system *qsys;
|
||
pointer pseq;
|
||
{
|
||
char *zjobid, *zfile;
|
||
long iret;
|
||
|
||
zjobid = zsysdep_jobid (qsys, pseq);
|
||
zfile = zsjobid_to_file (zjobid, (char **) NULL, (char *) NULL);
|
||
if (zfile == NULL)
|
||
return 0;
|
||
ubuffree (zjobid);
|
||
iret = ixsysdep_file_time (zfile);
|
||
ubuffree (zfile);
|
||
return iret;
|
||
}
|
||
|
||
/* Get the time a file was created (actually, the time it was last
|
||
modified). */
|
||
|
||
long
|
||
ixsysdep_file_time (zfile)
|
||
const char *zfile;
|
||
{
|
||
struct stat s;
|
||
|
||
if (stat ((char *) zfile, &s) < 0)
|
||
{
|
||
if (errno != ENOENT)
|
||
ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
|
||
return ixsysdep_time ((long *) NULL);
|
||
}
|
||
|
||
return (long) s.st_mtime;
|
||
}
|
||
|
||
/* Set the time of a file to the current time. */
|
||
|
||
boolean
|
||
fsysdep_touch_file (zfile)
|
||
const char *zfile;
|
||
{
|
||
if (issettime (zfile, time ((time_t *) NULL)) != 0)
|
||
{
|
||
ulog (LOG_ERROR, "utime (%s): %s", zfile, strerror (errno));
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* Start getting the status files. */
|
||
|
||
boolean
|
||
fsysdep_all_status_init (phold)
|
||
pointer *phold;
|
||
{
|
||
DIR *qdir;
|
||
|
||
qdir = opendir ((char *) ".Status");
|
||
if (qdir == NULL)
|
||
{
|
||
ulog (LOG_ERROR, "opendir (.Status): %s", strerror (errno));
|
||
return FALSE;
|
||
}
|
||
|
||
*phold = (pointer) qdir;
|
||
return TRUE;
|
||
}
|
||
|
||
/* Get the next status file. */
|
||
|
||
char *
|
||
zsysdep_all_status (phold, pferr, qstat)
|
||
pointer phold;
|
||
boolean *pferr;
|
||
struct sstatus *qstat;
|
||
{
|
||
DIR *qdir = (DIR *) phold;
|
||
struct dirent *qentry;
|
||
|
||
while (TRUE)
|
||
{
|
||
errno = 0;
|
||
qentry = readdir (qdir);
|
||
if (qentry == NULL)
|
||
{
|
||
if (errno == 0)
|
||
*pferr = FALSE;
|
||
else
|
||
{
|
||
ulog (LOG_ERROR, "readdir: %s", strerror (errno));
|
||
*pferr = TRUE;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
if (qentry->d_name[0] != '.')
|
||
{
|
||
struct uuconf_system ssys;
|
||
|
||
/* Hack seriously; fsysdep_get_status only looks at the
|
||
zname element of the qsys argument, so if we fake that we
|
||
can read the status file. This should really be done
|
||
differently. */
|
||
ssys.uuconf_zname = qentry->d_name;
|
||
if (fsysdep_get_status (&ssys, qstat, (boolean *) NULL))
|
||
return zbufcpy (qentry->d_name);
|
||
|
||
/* If fsysdep_get_status fails, it will output an error
|
||
message. We just continue with the next entry, so that
|
||
most of the status files will be displayed. */
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Finish getting the status file. */
|
||
|
||
void
|
||
usysdep_all_status_free (phold)
|
||
pointer phold;
|
||
{
|
||
DIR *qdir = (DIR *) phold;
|
||
|
||
(void) closedir (qdir);
|
||
}
|
||
|
||
/* Get the status of all processes holding lock files. We do this by
|
||
invoking ps after we've figured out the process entries to use. */
|
||
|
||
boolean
|
||
fsysdep_lock_status ()
|
||
{
|
||
DIR *qdir;
|
||
struct dirent *qentry;
|
||
int calc;
|
||
pid_t *pai;
|
||
#if HAVE_QNX_LOCKFILES
|
||
nid_t *painid;
|
||
#endif
|
||
int cgot;
|
||
int aidescs[3];
|
||
char *zcopy, *ztok;
|
||
int cargs, iarg;
|
||
char **pazargs;
|
||
|
||
qdir = opendir ((char *) zSlockdir);
|
||
if (qdir == NULL)
|
||
{
|
||
ulog (LOG_ERROR, "opendir (%s): %s", zSlockdir, strerror (errno));
|
||
return FALSE;
|
||
}
|
||
|
||
/* We look for entries that start with "LCK.." and ignore everything
|
||
else. This won't find all possible lock files, but it should
|
||
find all the locks on terminals and systems. */
|
||
|
||
calc = 0;
|
||
pai = NULL;
|
||
cgot = 0;
|
||
#if HAVE_QNX_LOCKFILES
|
||
painid = NULL;
|
||
#endif
|
||
while ((qentry = readdir (qdir)) != NULL)
|
||
{
|
||
char *zname;
|
||
int o;
|
||
#if HAVE_QNX_LOCKFILES
|
||
nid_t inid;
|
||
char ab[23];
|
||
char *zend;
|
||
#else
|
||
#if HAVE_V2_LOCKFILES
|
||
int i;
|
||
#else
|
||
char ab[12];
|
||
#endif
|
||
#endif
|
||
int cread;
|
||
int ierr;
|
||
pid_t ipid;
|
||
int icheck;
|
||
|
||
if (strncmp (qentry->d_name, "LCK..", sizeof "LCK.." - 1) != 0)
|
||
continue;
|
||
|
||
zname = zsysdep_in_dir (zSlockdir, qentry->d_name);
|
||
o = open ((char *) zname, O_RDONLY | O_NOCTTY, 0);
|
||
if (o < 0)
|
||
{
|
||
if (errno != ENOENT)
|
||
ulog (LOG_ERROR, "open (%s): %s", zname, strerror (errno));
|
||
ubuffree (zname);
|
||
continue;
|
||
}
|
||
|
||
#if HAVE_V2_LOCKFILES
|
||
cread = read (o, &i, sizeof i);
|
||
#else
|
||
cread = read (o, ab, sizeof ab - 1);
|
||
#endif
|
||
|
||
ierr = errno;
|
||
(void) close (o);
|
||
|
||
if (cread < 0)
|
||
{
|
||
ulog (LOG_ERROR, "read %s: %s", zname, strerror (ierr));
|
||
ubuffree (zname);
|
||
continue;
|
||
}
|
||
|
||
ubuffree (zname);
|
||
|
||
#if HAVE_QNX_LOCKFILES
|
||
ab[cread] = '\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[cread] = '\0';
|
||
ipid = (pid_t) strtol (ab, (char **) NULL, 10);
|
||
#endif
|
||
#endif
|
||
|
||
#if HAVE_QNX_LOCKFILES
|
||
printf ("%s: %ld %ld\n", qentry->d_name, (long) inid, (long) ipid);
|
||
#else
|
||
printf ("%s: %ld\n", qentry->d_name, (long) ipid);
|
||
#endif
|
||
|
||
for (icheck = 0; icheck < cgot; icheck++)
|
||
if (pai[icheck] == ipid)
|
||
break;
|
||
if (icheck < cgot)
|
||
continue;
|
||
|
||
if (cgot >= calc)
|
||
{
|
||
calc += 10;
|
||
pai = (pid_t *) xrealloc ((pointer) pai, calc * sizeof (pid_t));
|
||
#if HAVE_QNX_LOCKFILES
|
||
painid = (nid_t *) xrealloc ((pointer) painid,
|
||
calc * sizeof (nid_t));
|
||
#endif
|
||
}
|
||
|
||
pai[cgot] = ipid;
|
||
#if HAVE_QNX_LOCKFILES
|
||
painid[cgot] = inid;
|
||
#endif
|
||
++cgot;
|
||
}
|
||
|
||
if (cgot == 0)
|
||
return TRUE;
|
||
|
||
aidescs[0] = SPAWN_NULL;
|
||
aidescs[1] = 1;
|
||
aidescs[2] = 2;
|
||
|
||
/* Parse PS_PROGRAM into an array of arguments. */
|
||
zcopy = zbufcpy (PS_PROGRAM);
|
||
|
||
cargs = 0;
|
||
for (ztok = strtok (zcopy, " \t");
|
||
ztok != NULL;
|
||
ztok = strtok ((char *) NULL, " \t"))
|
||
++cargs;
|
||
|
||
pazargs = (char **) xmalloc ((cargs + 1) * sizeof (char *));
|
||
|
||
memcpy (zcopy, PS_PROGRAM, sizeof PS_PROGRAM);
|
||
for (ztok = strtok (zcopy, " \t"), iarg = 0;
|
||
ztok != NULL;
|
||
ztok = strtok ((char *) NULL, " \t"), ++iarg)
|
||
pazargs[iarg] = ztok;
|
||
pazargs[iarg] = NULL;
|
||
|
||
#if ! HAVE_PS_MULTIPLE
|
||
/* We have to invoke ps multiple times. */
|
||
{
|
||
int i;
|
||
char *zlast, *zset;
|
||
#if HAVE_QNX_LOCKFILES
|
||
char *zpenultimate, *zsetnid;
|
||
#endif /* HAVE_QNX_LOCKFILES */
|
||
|
||
zlast = pazargs[cargs - 1];
|
||
zset = zbufalc (strlen (zlast) + 20);
|
||
|
||
#if HAVE_QNX_LOCKFILES
|
||
/* We assume in this case that PS_PROGRAM ends with " -n -p".
|
||
Thus, the last argument is "-p" and the second-to-last
|
||
(penultimate) argument is "-n". We modify them to read "-n###"
|
||
and "-p###" where "###" is the node ID and the process ID,
|
||
respectively. This seems like quite a roundabout way of doing
|
||
things. Why don't we just leave the " -n -p" part out of
|
||
PS_PROGRAM and construct the "-n###" and "-p###" arguments here
|
||
from scratch? Because that would not fit as well with how the
|
||
code works for the other systems and would require larger
|
||
changes. */
|
||
zpenultimate = pazargs[cargs - 2];
|
||
zsetnid = zbufalc (strlen (zpenultimate) + 20);
|
||
#endif
|
||
|
||
for (i = 0; i < cgot; i++)
|
||
{
|
||
pid_t ipid;
|
||
|
||
sprintf (zset, "%s%ld", zlast, (long) pai[i]);
|
||
pazargs[cargs - 1] = zset;
|
||
|
||
#if HAVE_QNX_LOCKFILES
|
||
sprintf (zsetnid, "%s%ld", zpenultimate, (long) painid[i]);
|
||
pazargs[cargs - 2] = zsetnid;
|
||
#endif
|
||
|
||
ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE,
|
||
(const char *) NULL, FALSE, TRUE,
|
||
(const char *) NULL, (const char *) NULL,
|
||
(const char *) NULL);
|
||
if (ipid < 0)
|
||
ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
|
||
else
|
||
(void) ixswait ((unsigned long) ipid, PS_PROGRAM);
|
||
}
|
||
ubuffree (zset);
|
||
#if HAVE_QNX_LOCKFILES
|
||
ubuffree (zsetnid);
|
||
#endif
|
||
}
|
||
#else
|
||
{
|
||
char *zlast;
|
||
int i;
|
||
pid_t ipid;
|
||
|
||
zlast = zbufalc (strlen (pazargs[cargs - 1]) + cgot * 20 + 1);
|
||
strcpy (zlast, pazargs[cargs - 1]);
|
||
for (i = 0; i < cgot; i++)
|
||
{
|
||
char ab[20];
|
||
|
||
sprintf (ab, "%ld", (long) pai[i]);
|
||
strcat (zlast, ab);
|
||
if (i + 1 < cgot)
|
||
strcat (zlast, ",");
|
||
}
|
||
pazargs[cargs - 1] = zlast;
|
||
|
||
ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE,
|
||
(const char *) NULL, FALSE, TRUE,
|
||
(const char *) NULL, (const char *) NULL,
|
||
(const char *) NULL);
|
||
if (ipid < 0)
|
||
ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
|
||
else
|
||
(void) ixswait ((unsigned long) ipid, PS_PROGRAM);
|
||
ubuffree (zlast);
|
||
}
|
||
#endif
|
||
|
||
ubuffree (zcopy);
|
||
xfree ((pointer) pazargs);
|
||
|
||
return TRUE;
|
||
}
|