freebsd-dev/usr.bin/uucp/uuq/uuq.c
1994-05-27 12:33:43 +00:00

436 lines
10 KiB
C

/*-
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)uuq.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* uuq - looks at uucp queues
*
* Lou Salkind
* New York University
*
*/
#include "uucp.h"
#include <stdio.h>
#ifdef NDIR
#include "libndir/ndir.h"
#else !NDIR
#include <sys/dir.h>
#endif !NDIR
#include <sys/stat.h>
#define NOSYS (struct sys *)0
#define W_TYPE wrkvec[0]
#define W_FILE1 wrkvec[1]
#define W_FILE2 wrkvec[2]
#define W_USER wrkvec[3]
#define W_OPTNS wrkvec[4]
#define W_DFILE wrkvec[5]
#define W_MODE wrkvec[6]
#define WSUFSIZE 5 /* work file name suffix size */
struct sys {
char s_name[8];
int s_njobs;
off_t s_bytes;
struct job *s_jobp;
struct sys *s_sysp;
};
struct job {
int j_files;
int j_flags;
char j_jobno[WSUFSIZE];
char j_user[22];
char j_fname[128];
char j_grade;
off_t j_bytes;
time_t j_date;
struct job *j_jobp;
};
struct sys *syshead;
struct sys *getsys();
int jcompare();
char *sysname;
char *user;
char *rmjob;
int hflag;
int lflag;
char *malloc(), *calloc();
double atof();
float baudrate = 2400.;
char Username[BUFSIZ];
char Filename[BUFSIZ];
int Maxulen = 0;
struct timeb Now;
main(argc, argv)
int argc;
char **argv;
{
register int i;
register struct sys *sp;
register struct job *jp;
struct job **sortjob;
int nsys;
extern char *optarg;
extern int optind;
strcpy(Progname, "uuq");
uucpname(Myname);
while ((i = getopt(argc, argv, "r:S:s:u:d:b:hl")) != EOF)
switch (i) {
case 'r':
case 'S':
Spool = optarg;
break;
case 's':
sysname = optarg;
if (strlen(sysname) > SYSNSIZE)
sysname[SYSNSIZE] = '\0';
break;
case 'u':
user = optarg;
break;
case 'd':
rmjob = optarg;
break;
case 'b':
baudrate = atof(optarg);
break;
case 'h':
hflag++;
break;
case 'l':
lflag++;
break;
default:
fprintf(stderr,
"usage: uuq [-l] [-h] [-ssystem] [-uuser] [-djobno] [-rspool] [-bbaudrate]\n");
exit(0);
}
subchdir(Spool);
baudrate *= 0.7; /* reduce speed because of protocol overhead */
baudrate *= 7.5; /* convert to chars/minute (60/8) */
gather();
nsys = 0;
for (sp = syshead; sp; sp = sp->s_sysp) {
if (sp->s_njobs == 0)
continue;
if (!hflag && nsys++ > 0)
putchar('\n');
printf("%s: %d %s", sp->s_name,
sp->s_njobs, sp->s_njobs > 1 ? "jobs" : "job");
if (lflag) {
float minutes;
int hours;
/* The 80 * njobs is because of the uucp handshaking */
minutes = (float)(sp->s_bytes + 80 * sp->s_njobs)/baudrate;
hours = minutes/60;
printf(", %ld bytes, ", sp->s_bytes);
if (minutes > 60){
printf("%d hour%s, ",hours,
hours > 1 ? "s": "");
minutes -= 60 * hours;
}
printf("%3.1f minutes (@ effective baudrate of %d)",
minutes,(int)(baudrate/6));
}
putchar('\n');
if (hflag)
continue;
/* sort them babies! */
sortjob = (struct job **)calloc(sp->s_njobs, sizeof (struct job *));
for (i=0, jp=sp->s_jobp; i < sp->s_njobs; i++, jp=jp->j_jobp)
sortjob[i] = jp;
qsort(sortjob, sp->s_njobs, sizeof (struct job *), jcompare);
for (i = 0; i < sp->s_njobs; i++) {
jp = sortjob[i];
if (lflag) {
printf("%s %2d %-*s%7ld%5.1f %-12.12s %c %.*s\n",
jp->j_jobno, jp->j_files, Maxulen, jp->j_user, jp->j_bytes, jp->j_bytes/baudrate,
ctime(&jp->j_date) + 4, jp->j_flags, sizeof (jp->j_fname), jp->j_fname
);
} else {
printf("%s", jp->j_jobno);
putchar((i+1)%10 ? '\t' : '\n');
}
/* There's no need to keep the force poll if jobs > 1*/
if (sp->s_njobs > 1 && strcmp("POLL", jp->j_jobno)==0) {
char pbuf[BUFSIZ];
sprintf(pbuf,"%s/%c.%s%cPOLL",
subdir(Spool, CMDPRE), CMDPRE,
sp->s_name, jp->j_grade);
(void) unlink(pbuf);
}
}
if (!lflag && (sp->s_njobs%10))
putchar('\n');
}
exit(0);
}
jcompare(j1, j2)
struct job **j1, **j2;
{
int delta;
delta = (*j1)->j_grade - (*j2)->j_grade;
if (delta)
return delta;
return(strcmp((*j1)->j_jobno,(*j2)->j_jobno));
}
/*
* Get all the command file names
*/
gather()
{
struct direct *d;
DIR *df;
/*
* Find all the spool files in the spooling directory
*/
if ((df = opendir(subdir(Spool, CMDPRE))) == NULL) {
fprintf(stderr, "can't examine spooling area\n");
exit(1);
}
for (;;) {
if ((d = readdir(df)) == NULL)
break;
if (d->d_namlen <= 2 || d->d_name[0] != CMDPRE ||
d->d_name[1] != '.')
continue;
if (analjob(d->d_name) < 0) {
fprintf(stderr, "out of memory\n");
break;
}
}
closedir(df);
}
/*
* analjob does the grunge work of verifying jobs
*/
#include <pwd.h>
analjob(filename)
char *filename;
{
struct job *jp;
struct sys *sp;
char sbuf[MAXNAMLEN+1], str[256], nbuf[256];
char *jptr, *wrkvec[20];
char grade;
FILE *fp, *df;
struct stat statb;
int files, gotname, i;
off_t bytes;
strncpy(sbuf, filename, MAXNAMLEN);
sbuf[MAXNAMLEN] = '\0';
jptr = sbuf + strlen(sbuf) - WSUFSIZE;
grade = *jptr;
*jptr++ = 0;
/*
* sbuf+2 now points to sysname name (null terminated)
* jptr now points to job number (null terminated)
*/
if (rmjob) {
if (strcmp(rmjob, jptr))
return(0);
} else {
if ((sp = getsys(sbuf+2)) == NOSYS)
return(0);
if (!lflag) {
/* SHOULD USE A SMALLER STRUCTURE HERE */
jp = (struct job *)malloc(sizeof(struct job));
if (jp == (struct job *)0)
return(-1);
strcpy(jp->j_jobno, jptr);
jp->j_jobp = sp->s_jobp;
jp->j_grade = grade;
sp->s_jobp = jp;
sp->s_njobs++;
return(1);
}
}
if ((fp = fopen(subfile(filename), "r")) == NULL) {
perror(subfile(filename));
return(0);
}
files = 0;
bytes = 0;
gotname = 0;
while (fgets(str, sizeof str, fp)) {
if (getargs(str, wrkvec, 20) <= 0)
continue;
if (rmjob) {
int myuid;
struct passwd *pw;
/*
* Make sure person who is removing data files is
* the person who created it or root.
*/
myuid = getuid();
pw = getpwnam(W_USER);
if (myuid && (pw == NULL || myuid != pw->pw_uid)) {
fprintf(stderr, "Permission denied.\n");
exit(1);
}
if (W_TYPE[0] == 'S' && !index(W_OPTNS, 'c')) {
unlink(subfile(W_DFILE));
fprintf(stderr, "Removing data file %s\n", W_DFILE);
}
continue;
}
if (user && (W_TYPE[0] == 'X' || !prefix(user, W_USER))) {
fclose(fp);
return(0);
}
files++;
if (W_TYPE[0] == 'S') {
if (strcmp(W_DFILE, "D.0") &&
stat(subfile(W_DFILE), &statb) >= 0)
bytes += statb.st_size;
else if (stat(subfile(W_FILE1), &statb) >= 0)
bytes += statb.st_size;
}
/* amusing heuristic */
#define isXfile(s) (s[0]=='D' && s[strlen(s)-WSUFSIZE]=='X')
if (gotname == 0 && isXfile(W_FILE1)) {
if ((df = fopen(subfile(W_FILE1), "r")) == NULL)
continue;
while (fgets(nbuf, sizeof nbuf, df)) {
nbuf[strlen(nbuf) - 1] = '\0';
if (nbuf[0] == 'C' && nbuf[1] == ' ') {
strcpy(Filename, nbuf+2);
gotname++;
} else if (nbuf[0] == 'R' && nbuf[1] == ' ') {
register char *p, *q, *r;
r = q = p = nbuf+2;
do {
if (*p == '!' || *p == '@'){
r = q;
q = p+1;
}
} while (*p++);
strcpy(Username, r);
W_USER = Username;
}
}
fclose(df);
}
}
fclose(fp);
if (rmjob) {
unlink(subfile(filename));
fprintf(stderr, "Removing command file %s\n", filename);
exit(0);
}
if (files == 0) {
static char *wtype = "X";
static char *wfile = "forced poll";
if (strcmp("POLL", &filename[strlen(filename)-4])) {
fprintf(stderr, "%.14s: empty command file\n", filename);
return(0);
}
W_TYPE = wtype;
W_FILE1 = wfile;
}
jp = (struct job *)malloc(sizeof(struct job));
if (jp == (struct job *)0)
return(-1);
strcpy(jp->j_jobno, jptr);
jp->j_files = files;
jp->j_bytes = bytes;
jp->j_grade = grade;
jp->j_flags = W_TYPE[0];
strncpy(jp->j_user, W_TYPE[0]=='X' ? "---" : W_USER, 20 );
jp->j_user[20] = '\0';
i = strlen(jp->j_user);
if (i > Maxulen)
Maxulen = i;
/* SHOULD ADD ALL INFORMATION IN THE WHILE LOOP */
if (gotname)
strncpy(jp->j_fname, Filename, sizeof jp->j_fname);
else
strncpy(jp->j_fname, W_FILE1, sizeof jp->j_fname);
stat(subfile(filename), &statb);
jp->j_date = statb.st_mtime;
jp->j_jobp = sp->s_jobp;
sp->s_jobp = jp;
sp->s_njobs++;
sp->s_bytes += jp->j_bytes;
return(1);
}
struct sys *
getsys(s)
register char *s;
{
register struct sys *sp;
for (sp = syshead; sp; sp = sp->s_sysp)
if (strcmp(s, sp->s_name) == 0)
return(sp);
if (sysname && !prefix(sysname, s))
return(NOSYS);
sp = (struct sys *)malloc(sizeof(struct sys));
if (sp == NOSYS)
return(NOSYS);
strcpy(sp->s_name, s);
sp->s_njobs = 0;
sp->s_jobp = (struct job *)0;
sp->s_sysp = syshead;
sp->s_bytes = 0;
syshead = sp;
return(sp);
}