607 lines
12 KiB
Plaintext
607 lines
12 KiB
Plaintext
|
/* sys7.unx
|
|||
|
System dependent routines for uustat.
|
|||
|
|
|||
|
Copyright (C) 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|||
|
|
|||
|
The author of the program may be contacted at ian@airs.com or
|
|||
|
c/o AIRS, P.O. Box 520, Waltham, MA 02254.
|
|||
|
|
|||
|
$Log: sys7.unx,v $
|
|||
|
Revision 1.1.1.1 1993/03/21 09:45:37 cgd
|
|||
|
initial import of 386bsd-0.1 sources
|
|||
|
|
|||
|
Revision 1.11 1992/03/28 04:19:39 ian
|
|||
|
Niels Baggesen, Gerben Wierda: minor patches
|
|||
|
|
|||
|
Revision 1.10 1992/03/16 22:22:35 ian
|
|||
|
Adjusted external declarations
|
|||
|
|
|||
|
Revision 1.9 1992/03/15 01:54:46 ian
|
|||
|
All execs are now done in isspawn, all waits are done in iswait
|
|||
|
|
|||
|
Revision 1.8 1992/03/12 19:54:43 ian
|
|||
|
Debugging based on types rather than number
|
|||
|
|
|||
|
Revision 1.7 1992/03/11 22:21:19 ian
|
|||
|
Permit uucp user to delete jobs
|
|||
|
|
|||
|
Revision 1.6 1992/02/27 19:53:26 ian
|
|||
|
Added some extern definitions
|
|||
|
|
|||
|
Revision 1.5 1992/02/24 20:07:43 ian
|
|||
|
John Theus: some systems don't have <fcntl.h>
|
|||
|
|
|||
|
Revision 1.4 1992/02/23 16:21:26 ian
|
|||
|
Handle systems on which NULL second argument to utime fails
|
|||
|
|
|||
|
Revision 1.3 1992/02/23 03:26:51 ian
|
|||
|
Overhaul to use automatic configure shell script
|
|||
|
|
|||
|
Revision 1.2 1992/02/20 04:40:07 ian
|
|||
|
Make sure only the submitter or the superuser can cancel a request
|
|||
|
|
|||
|
Revision 1.1 1992/02/20 04:18:59 ian
|
|||
|
Initial revision
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
#include "uucp.h"
|
|||
|
|
|||
|
#if USE_RCS_ID
|
|||
|
char sys7_unx_rcsid[] = "$Id: sys7.unx,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
|
|||
|
#endif
|
|||
|
|
|||
|
#include <errno.h>
|
|||
|
|
|||
|
#if USE_STDIO && HAVE_UNISTD_H
|
|||
|
#include <unistd.h>
|
|||
|
#endif
|
|||
|
|
|||
|
#include "system.h"
|
|||
|
#include "sysdep.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
|
|||
|
|
|||
|
#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 */
|
|||
|
|
|||
|
#ifdef UTIME_NULL_MISSING
|
|||
|
#if HAVE_TIME_H
|
|||
|
#include <time.h>
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
|
|||
|
#if HAVE_UTIME_H
|
|||
|
#include <utime.h>
|
|||
|
#endif
|
|||
|
|
|||
|
/* External functions. */
|
|||
|
extern int fclose (), fflush ();
|
|||
|
extern int read (), close (), utime (), stat ();
|
|||
|
extern uid_t getuid (), geteuid ();
|
|||
|
|
|||
|
/* Local functions. */
|
|||
|
|
|||
|
static boolean fskill_or_rejuv P((const char *zid, boolean fkill));
|
|||
|
|
|||
|
/* Set file access time to the present. On most systems this can be a
|
|||
|
macro, but some apparently do not support utime correctly. */
|
|||
|
|
|||
|
#ifndef UTIME_NULL_MISSING
|
|||
|
|
|||
|
#define ussettime(z) utime((z), (struct utimbuf *) NULL)
|
|||
|
|
|||
|
#else /* defined (UTIME_NULL_MISSING) */
|
|||
|
|
|||
|
static int
|
|||
|
ussettime(z)
|
|||
|
const char *z;
|
|||
|
{
|
|||
|
time_t inow;
|
|||
|
|
|||
|
inow = time ((time_t *) NULL);
|
|||
|
|
|||
|
{
|
|||
|
#if HAVE_UTIME_H
|
|||
|
struct utimbuf s;
|
|||
|
|
|||
|
s.actime = inow;
|
|||
|
s.modtime = inow;
|
|||
|
return utime (z, &s);
|
|||
|
#else
|
|||
|
time_t ai[2];
|
|||
|
|
|||
|
ai[0] = inow;
|
|||
|
ai[1] = inow;
|
|||
|
return utime (z, ai);
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endif /* defined (UTIME_NULL_MISSING) */
|
|||
|
|
|||
|
/* Kill a job, given the jobid. */
|
|||
|
|
|||
|
boolean
|
|||
|
fsysdep_kill_job (zid)
|
|||
|
const char *zid;
|
|||
|
{
|
|||
|
return fskill_or_rejuv (zid, TRUE);
|
|||
|
}
|
|||
|
|
|||
|
/* Rejuvenate a job, given the jobid. */
|
|||
|
|
|||
|
boolean
|
|||
|
fsysdep_rejuvenate_job (zid)
|
|||
|
const char *zid;
|
|||
|
{
|
|||
|
return fskill_or_rejuv (zid, FALSE);
|
|||
|
}
|
|||
|
|
|||
|
/* Kill or rejuvenate a job, given the jobid. */
|
|||
|
|
|||
|
static boolean
|
|||
|
fskill_or_rejuv (zid, fkill)
|
|||
|
const char *zid;
|
|||
|
boolean fkill;
|
|||
|
{
|
|||
|
const char *zfile;
|
|||
|
const char *zsys;
|
|||
|
char *zcopy;
|
|||
|
struct ssysteminfo ssys;
|
|||
|
const struct ssysteminfo *qsys;
|
|||
|
FILE *e;
|
|||
|
boolean fret;
|
|||
|
char *zline;
|
|||
|
int isys;
|
|||
|
|
|||
|
zfile = zsjobid_to_file (zid, &zsys);
|
|||
|
zcopy = (char *) alloca (strlen (zfile) + 1);
|
|||
|
strcpy (zcopy, zfile);
|
|||
|
zfile = zcopy;
|
|||
|
zcopy = (char *) alloca (strlen (zsys) + 1);
|
|||
|
strcpy (zcopy, zsys);
|
|||
|
zsys = zcopy;
|
|||
|
|
|||
|
if (fread_system_info (zsys, &ssys))
|
|||
|
qsys = &ssys;
|
|||
|
else
|
|||
|
{
|
|||
|
if (! fUnknown_ok)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "%s: Bad job id", zid);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
sUnknown.zname = zsys;
|
|||
|
qsys = &sUnknown;
|
|||
|
}
|
|||
|
|
|||
|
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));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
/* Now we have to read through the file to identify any temporary
|
|||
|
files. */
|
|||
|
|
|||
|
fret = TRUE;
|
|||
|
while ((zline = zfgets (e, FALSE)) != NULL)
|
|||
|
{
|
|||
|
struct scmd s;
|
|||
|
|
|||
|
if (! fparse_cmd (zline, &s))
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "Bad line in command file %s", zfile);
|
|||
|
fret = FALSE;
|
|||
|
xfree ((pointer) zline);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
/* You are only permitted to delete a job if you submitted it or
|
|||
|
if you are root or uucp. We check for uucp by seeing if the
|
|||
|
real user ID and the effective user ID are the same; this
|
|||
|
works because we should be suid to uucp, so our effective
|
|||
|
user ID will always be uucp while our real user ID will be
|
|||
|
whoever ran the program. */
|
|||
|
if (strcmp (s.zuser, zsysdep_login_name ()) != 0
|
|||
|
&& getuid () != 0
|
|||
|
&& getuid () != geteuid ())
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "%s: Not submitted by you", zid);
|
|||
|
xfree ((pointer) zline);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (s.bcmd == 'S')
|
|||
|
{
|
|||
|
const char *ztemp;
|
|||
|
|
|||
|
ztemp = zsysdep_spool_file_name (qsys, s.ztemp);
|
|||
|
if (ztemp == NULL)
|
|||
|
fret = FALSE;
|
|||
|
else
|
|||
|
{
|
|||
|
if (fkill)
|
|||
|
isys = remove (ztemp);
|
|||
|
else
|
|||
|
isys = ussettime (ztemp);
|
|||
|
|
|||
|
if (isys != 0 && errno != ENOENT)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "%s (%s): %s",
|
|||
|
fkill ? "remove" : "utime", ztemp,
|
|||
|
strerror (errno));
|
|||
|
fret = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
xfree ((pointer) zline);
|
|||
|
}
|
|||
|
|
|||
|
(void) fclose (e);
|
|||
|
|
|||
|
if (fkill)
|
|||
|
isys = remove (zfile);
|
|||
|
else
|
|||
|
isys = ussettime (zfile);
|
|||
|
|
|||
|
if (isys != 0 && errno != ENOENT)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "%s (%s): %s", fkill ? "remove" : "utime",
|
|||
|
zfile, strerror (errno));
|
|||
|
fret = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return fret;
|
|||
|
}
|
|||
|
|
|||
|
/* Get the time a work job was queued. */
|
|||
|
|
|||
|
long
|
|||
|
isysdep_work_time (qsys, pseq)
|
|||
|
const struct ssysteminfo *qsys;
|
|||
|
pointer pseq;
|
|||
|
{
|
|||
|
return isysdep_file_time (zsjobid_to_file (zsysdep_jobid (qsys, pseq),
|
|||
|
(const char **) NULL));
|
|||
|
}
|
|||
|
|
|||
|
/* Get the time a file was created (actually, the time it was last
|
|||
|
modified). */
|
|||
|
|
|||
|
long
|
|||
|
isysdep_file_time (zfile)
|
|||
|
const char *zfile;
|
|||
|
{
|
|||
|
struct stat s;
|
|||
|
|
|||
|
if (stat (zfile, &s) < 0)
|
|||
|
{
|
|||
|
if (errno != ENOENT)
|
|||
|
ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
|
|||
|
return isysdep_time ((long *) NULL);
|
|||
|
}
|
|||
|
|
|||
|
return (long) s.st_mtime;
|
|||
|
}
|
|||
|
|
|||
|
/* Get the size in bytes of a file. */
|
|||
|
|
|||
|
long
|
|||
|
csysdep_size (zfile)
|
|||
|
const char *zfile;
|
|||
|
{
|
|||
|
struct stat s;
|
|||
|
|
|||
|
if (stat (zfile, &s) < 0)
|
|||
|
{
|
|||
|
if (errno != ENOENT)
|
|||
|
ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
return s.st_size;
|
|||
|
}
|
|||
|
|
|||
|
/* 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. */
|
|||
|
|
|||
|
const 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 ssysteminfo 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.zname = qentry->d_name;
|
|||
|
if (fsysdep_get_status (&ssys, qstat))
|
|||
|
return zscopy (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 ()
|
|||
|
{
|
|||
|
const char *zdir;
|
|||
|
DIR *qdir;
|
|||
|
struct dirent *qentry;
|
|||
|
int calc;
|
|||
|
int *pai;
|
|||
|
int cgot;
|
|||
|
int aidescs[3];
|
|||
|
char *zcopy, *ztok;
|
|||
|
int cargs, iarg;
|
|||
|
char **pazargs;
|
|||
|
|
|||
|
#ifdef LOCKDIR
|
|||
|
zdir = LOCKDIR;
|
|||
|
#else
|
|||
|
zdir = ".";
|
|||
|
#endif
|
|||
|
|
|||
|
qdir = opendir ((char *) zdir);
|
|||
|
if (qdir == NULL)
|
|||
|
{
|
|||
|
ulog (LOG_ERROR, "opendir (%s): %s", zdir, 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;
|
|||
|
while ((qentry = readdir (qdir)) != NULL)
|
|||
|
{
|
|||
|
const char *zname;
|
|||
|
int o;
|
|||
|
#if HAVE_V2_LOCKFILES
|
|||
|
int i;
|
|||
|
#else
|
|||
|
char ab[12];
|
|||
|
#endif
|
|||
|
int cread;
|
|||
|
int ierr;
|
|||
|
int ipid;
|
|||
|
|
|||
|
if (strncmp (qentry->d_name, "LCK..", sizeof "LCK.." - 1) != 0)
|
|||
|
continue;
|
|||
|
|
|||
|
zname = zsappend (zdir, qentry->d_name);
|
|||
|
o = open (zname, O_RDONLY, 0);
|
|||
|
if (o < 0)
|
|||
|
{
|
|||
|
if (errno != ENOENT)
|
|||
|
ulog (LOG_ERROR, "open (%s): %s", zname, strerror (errno));
|
|||
|
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));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
#if HAVE_V2_LOCKFILES
|
|||
|
ipid = i;
|
|||
|
#else
|
|||
|
ab[cread] = '\0';
|
|||
|
ipid = atoi (ab);
|
|||
|
#endif
|
|||
|
|
|||
|
printf ("%s: %d\n", qentry->d_name, ipid);
|
|||
|
|
|||
|
if (cgot >= calc)
|
|||
|
{
|
|||
|
calc += 10;
|
|||
|
pai = (int *) xrealloc ((pointer) pai, calc * sizeof (int));
|
|||
|
}
|
|||
|
|
|||
|
pai[cgot] = ipid;
|
|||
|
++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 = (char *) alloca (sizeof PS_PROGRAM);
|
|||
|
strcpy (zcopy, PS_PROGRAM);
|
|||
|
|
|||
|
cargs = 0;
|
|||
|
for (ztok = strtok (zcopy, " \t");
|
|||
|
ztok != NULL;
|
|||
|
ztok = strtok ((char *) NULL, " \t"))
|
|||
|
++cargs;
|
|||
|
|
|||
|
pazargs = (char **) alloca ((cargs + 1) * sizeof (char *));
|
|||
|
|
|||
|
strcpy (zcopy, 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;
|
|||
|
|
|||
|
zlast = pazargs[cargs - 1];
|
|||
|
zset = (char *) alloca (strlen (zlast) + 20);
|
|||
|
for (i = 0; i < cgot; i++)
|
|||
|
{
|
|||
|
pid_t ipid;
|
|||
|
|
|||
|
sprintf (zset, "%s%d", zlast, pai[i]);
|
|||
|
pazargs[cargs - 1] = zset;
|
|||
|
|
|||
|
ipid = isspawn ((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, "isspawn: %s", strerror (errno));
|
|||
|
else
|
|||
|
(void) iswait ((unsigned long) ipid, PS_PROGRAM);
|
|||
|
}
|
|||
|
}
|
|||
|
#else
|
|||
|
{
|
|||
|
char *zlast;
|
|||
|
int i;
|
|||
|
pid_t ipid;
|
|||
|
|
|||
|
zlast = (char *) alloca (strlen (pazargs[cargs - 1]) + cgot * 20 + 1);
|
|||
|
strcpy (zlast, pazargs[cargs - 1]);
|
|||
|
for (i = 0; i < cgot; i++)
|
|||
|
{
|
|||
|
char ab[20];
|
|||
|
|
|||
|
sprintf (ab, "%d", pai[i]);
|
|||
|
strcat (zlast, ab);
|
|||
|
if (i + 1 < cgot)
|
|||
|
strcat (zlast, ",");
|
|||
|
}
|
|||
|
pazargs[cargs - 1] = zlast;
|
|||
|
|
|||
|
ipid = isspawn ((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, "isspawn: %s", strerror (errno));
|
|||
|
else
|
|||
|
(void) iswait ((unsigned long) ipid, PS_PROGRAM);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
Local variables:
|
|||
|
mode:c
|
|||
|
End:
|
|||
|
*/
|