V10/cmd/uucp/uustat.c
/* @(#)uustat.c 1.14
*/
#include "uucp.h"
VERSION(@(#)uustat.c 1.14)
#ifdef V7
#define O_RDONLY 0
#endif
#define USAGE1 "[-a] [-q] or [-m] or [-kJOB] or [-rJOB] or [-p]"
#define USAGE2 "[-sSYSTEM] [-uUSER]"
#define STST_MAX 132
struct m {
char mach[15]; /* machine name */
char locked;
int ccount, xcount;
int count, type;
long retrytime;
time_t lasttime;
short c_age; /* age of oldest C. file */
short x_age; /* age of oldest X. file */
char stst[STST_MAX];
} M[UUSTAT_TBL+2];
extern long atol();
extern void qsort(); /* qsort(3) and comparison test */
int sortcnt = -1;
extern int machcmp();
extern int _age(); /* find the age of a file */
extern char Jobid[]; /* jobid for status or kill option */
short Kill; /* == 1 if -k specified */
short Rejuvenate; /* == 1 for -r specified */
short Uopt; /* == 1 if -u option specified */
short Sysopt; /* == 1 if -s option specified */
short Summary; /* == 1 if -q or -m is specified */
short Queue; /* == 1 if -q option set - queue summary */
short Machines; /* == 1 if -m option set - machines summary */
short Psopt; /* == 1 if -p option set - output "ps" of LCK pids */
main(argc, argv, envp)
char *argv[];
char **envp;
{
struct m *m, *machine();
DIR *spooldir, *subdir;
char *str, *strrchr();
char f[256], subf[256];
char *c, lckdir[BUFSIZ];
char buf[BUFSIZ];
char chkname[MAXFULLNAME];
char *vec[7];
int i, chkid;
User[0] = '\0';
Rmtname[0] = '\0';
Jobid[0] = '\0';
Psopt=Machines=Summary=Queue=Kill=Rejuvenate=Uopt=Sysopt=0;
(void) strcpy(Progname, "uustat");
Uid = getuid();
Euid = geteuid();
guinfo(Uid, Loginuser);
uucpname(Myname);
while ((i = getopt(argc, argv, "ak:mpr:qs:u:x:")) != EOF) {
switch(i){
case 'a':
Sysopt = 1;
break;
case 'k':
(void) strncpy(Jobid, optarg, NAMESIZE);
Jobid[NAMESIZE] = '\0';
Kill = 1;
break;
case 'm':
Machines = Summary = 1;
break;
case 'p':
Psopt = 1;
break;
case 'r':
(void) strncpy(Jobid, optarg, NAMESIZE);
Jobid[NAMESIZE] = '\0';
Rejuvenate = 1;
break;
case 'q':
Queue = Summary = 1;
break;
case 's':
(void) strncpy(Rmtname, optarg, MAXBASENAME);
Rmtname[MAXBASENAME] = '\0';
#if NOTDEF
if (versys(Rmtname, 0)) {
fprintf(stderr, "Invalid system\n");
exit(1);
}
#endif
Sysopt = 1;
break;
case 'u':
(void) strncpy(User, optarg, 8);
User[8] = '\0';
if(gninfo(User, &chkid, chkname)) {
fprintf(stderr, "Invalid user\n");
exit(1);
}
Uopt = 1;
break;
case 'x':
Debug = atoi(optarg);
if (Debug <= 0)
Debug = 1;
break;
default:
(void) fprintf(stderr, "\tusage: %s %s\n",
Progname, USAGE1);
(void) fprintf(stderr, "or\n\tusage: %s %s\n",
Progname, USAGE2);
exit(1);
}
}
if (argc != optind) {
(void) fprintf(stderr, "\tusage: %s %s\n", Progname, USAGE1);
(void) fprintf(stderr, "or\n\tusage: %s %s\n",
Progname, USAGE2);
exit(1);
}
DEBUG(9, "Progname (%s): STARTED\n", Progname);
DEBUG(9, "User=%s, ", User);
DEBUG(9, "Loginuser=%s, ", Loginuser);
DEBUG(9, "Jobid=%s, ", Jobid);
DEBUG(9, "Rmtname=%s\n", Rmtname);
if ((Psopt + Machines + Queue + Kill + Rejuvenate + (Uopt|Sysopt)) >1) {
/* only -u and -s can be used together */
printf("\tusage: %s %s\n", Progname, USAGE1);
printf("or\n\tusage: %s %s\n", Progname, USAGE2);
exit(1);
}
if ( !(Kill | Rejuvenate | Uopt | Sysopt | Queue | Machines) ) {
(void) strcpy(User, Loginuser);
Uopt = 1;
}
if (Psopt) {
/* do "ps -flp" or pids in LCK files */
lckpid();
/* lckpid will not return */
}
if (Summary) {
/* Gather data for Summary option report */
if (chdir(STATDIR) || (spooldir = opendir(STATDIR)) == NULL)
exit(101); /* good old code 101 */
while (gnamef(spooldir, f) == TRUE) {
if (freopen(f, "r", stdin) == NULL)
continue;
m = machine(f);
if (fgets(buf, sizeof(buf), stdin) == NULL)
continue;
if ((str = strchr(buf, '\n')) != NULL)
*str = 0;
if (getargs(buf, vec, 5) < 5)
continue;
m->type = atoi(vec[0]);
m->count = atoi(vec[1]);
m->lasttime = atol(vec[2]);
m->retrytime = atol(vec[3]);
(void) strncpy(m->stst, vec[4], STST_MAX);
str = strrchr(m->stst, ' ');
(void) machine(++str); /* longer name? */
*str = '\0';
}
closedir(spooldir);
}
if (Summary) {
/* search for LCK machines */
(void) strcpy(lckdir, LOCKPRE);
*strrchr(lckdir, '/') = '\0';
/* open lock directory */
if (chdir(lckdir) != 0 || (subdir = opendir(lckdir)) == NULL)
exit(101); /* good old code 101 */
while (gnamef(subdir, f) == TRUE) {
if (EQUALSN("LCK..", f, 5)) {
if (!EQUALSN(f + 5, "cul", 3)
&& !EQUALSN(f + 5, "tty", 3)
&& !EQUALSN(f + 5, "dtsw", 4)
&& !EQUALSN(f + 5, "vadic", 5)
&& !EQUALSN(f + 5, "micom", 5))
machine(f + 5)->locked++;
}
}
}
if (chdir(SPOOL) != 0 || (spooldir = opendir(SPOOL)) == NULL)
exit(101); /* good old code 101 */
while (gnamef(spooldir, f) == TRUE) {
if (EQUALSN("LCK..", f, 5))
continue;
if (*Rmtname && !EQUALSN(Rmtname, f, SYSNSIZE))
continue;
if ( (Kill || Rejuvenate)
&& (!EQUALSN(f, Jobid, strlen(Jobid)-5)) )
continue;
if (DIRECTORY(f) && (subdir = opendir(f))) {
m = machine(f);
while (gnamef(subdir, subf) == TRUE)
if (subf[1] == '.') {
if (subf[0] == CMDPRE) {
m->ccount++;
if (Kill || Rejuvenate)
kprocessC(f, subf);
else if (Uopt | Sysopt)
uprocessC(f, subf);
else /* get the age of the C. file */
if ( (i = _age(f, subf))>m->c_age)
m->c_age = i;
}
else if (subf[0] == XQTPRE) {
m->xcount++;
if ( (i = _age(f, subf)) > m->x_age)
m->x_age = i;
}
}
closedir(subdir);
}
}
/* for Kill or Rejuvenate - will not get here unless it failed */
if (Kill || Rejuvenate) {
printf("Can't find Job %s; Not %s\n", Jobid,
Kill ? "killed" : "rejuvenated");
exit(1);
}
/* Make sure the overflow entry is null since it may be incorrect */
M[UUSTAT_TBL].mach[0] = NULLCHAR;
if (Summary) {
for((sortcnt = 0, m = &M[0]);*(m->mach) != NULL;(sortcnt++,m++))
;
qsort((char *)M, (unsigned int)sortcnt, sizeof(struct m), machcmp);
for (m = M; m->mach[0] != NULLCHAR; m++)
printit(m);
}
exit(0);
}
/*
* uprocessC - get information about C. file
*
*/
uprocessC(dir, file)
char *file, *dir;
{
struct stat s;
register struct tm *tp;
char fullname[MAXFULLNAME], buf[BUFSIZ], user[9];
char xfullname[MAXFULLNAME];
char file1[BUFSIZ], file2[BUFSIZ], file3[BUFSIZ], type[2], opt[256];
FILE *fp, *xfp;
short first = 1;
extern long fsize();
DEBUG(9, "uprocessC(%s, ", dir);
DEBUG(9, "%s);\n", file);
if (Jobid[0] != '\0' && (!EQUALS(Jobid, &file[2])) ) {
/* kill job - not this one */
return;
}
(void) sprintf(fullname, "%s/%s", dir, file);
if (stat(fullname, &s) != 0) {
/* error - can't stat */
DEBUG(4, "Can't stat file (%s),", fullname);
DEBUG(4, " errno (%d) -- skip it!\n", errno);
}
fp = fopen(fullname, "r");
if (fp == NULL) {
DEBUG(4, "Can't open file (%s), ", fullname);
DEBUG(4, "errno=%d -- skip it!\n", errno);
return;
}
tp = localtime(&s.st_mtime);
if (s.st_size == 0 && User[0] == '\0') { /* dummy D. for polling */
printf("%-12s %2.2d/%2.2d-%2.2d:%2.2d:%2.2d (POLL)\n",
&file[2], tp->tm_mon + 1, tp->tm_mday, tp->tm_hour,
tp->tm_min, tp->tm_sec);
}
else while (fgets(buf, BUFSIZ, fp) != NULL) {
if (sscanf(buf,"%s%s%s%s%s%s", type, file1, file2,
user, opt, file3) <5) {
DEBUG(4, "short line (%s)\n", buf);
continue;
}
DEBUG(9, "type (%s), ", type);
DEBUG(9, "file1 (%s)", file1);
DEBUG(9, "file2 (%s)", file2);
DEBUG(9, "file3 (%s)", file3);
DEBUG(9, "user (%s)", user);
if (User[0] != '\0' && (!EQUALS(User, user)) )
continue;
/*
if ( (*file2 != 'X')
&& (*file1 != '/' && *file1 != '~')
&& (*file2 != '/' && *file2!= '~') )
continue;
*/
if (first)
printf("%-12s %2.2d/%2.2d-%2.2d:%2.2d ",
&file[2], tp->tm_mon + 1, tp->tm_mday, tp->tm_hour,
tp->tm_min);
else
printf("%-12s %2.2d/%2.2d-%2.2d:%2.2d ",
"", tp->tm_mon + 1, tp->tm_mday, tp->tm_hour,
tp->tm_min);
first = 0;
printf("%s %s ", type, dir);
if (*type == 'R')
printf("%s %s\n", user, file1);
else if (file2[0] != 'X')
printf("%s %ld %s\n", user, fsize(dir, file3, file1), file1);
else if (*type == 'S' && file2[0] == 'X') {
(void) sprintf(xfullname, "%s/%s", dir, file1);
xfp = fopen(xfullname, "r");
if (xfp == NULL) { /* program error */
DEBUG(4, "Can't read %s, ", xfullname);
DEBUG(4, "errno=%d -- skip it!\n", errno);
printf("%s %s %s ", type, dir, user);
printf("????\n");
}
else {
char command[BUFSIZ], uline_u[BUFSIZ], uline_m[BUFSIZ];
char retaddr[BUFSIZ], *username;
*retaddr = *uline_u = *uline_m = '\0';
while (fgets(buf, BUFSIZ, xfp) != NULL) {
switch(buf[0]) {
case 'C':
strcpy(command, buf + 2);
break;
case 'U':
sscanf(buf + 2, "%s%s", uline_u, uline_m);
break;
case 'R':
sscanf(buf+2, "%s", retaddr);
break;
}
}
username = user;
if (*uline_u != '\0')
username = uline_u;
if (*retaddr != '\0')
username = retaddr;
if (!EQUALS(uline_m, Myname))
printf("%s!", uline_m);
printf("%s %s", username, command);
}
if (xfp != NULL)
fclose(xfp);
}
}
fclose(fp);
return;
}
/*
* kprocessC - process kill or rejuvenate job
*/
kprocessC(dir, file)
char *file, *dir;
{
struct stat s;
register struct tm *tp;
extern struct tm *localtime();
extern int errno;
char fullname[MAXFULLNAME], buf[BUFSIZ], user[9];
char rfullname[MAXFULLNAME];
char file1[BUFSIZ], file2[BUFSIZ], file3[BUFSIZ], type[2], opt[256];
FILE *fp, *xfp;
time_t times[2];
short ret;
short first = 1;
DEBUG(9, "kprocessC(%s, ", dir);
DEBUG(9, "%s);\n", file);
if ((!EQUALS(Jobid, &file[2])) ) {
/* kill job - not this one */
return;
}
(void) sprintf(fullname, "%s/%s", dir, file);
if (stat(fullname, &s) != 0) {
/* error - can't stat */
fprintf(stderr, "Can't stat:%s, errno (%d)--can't %s it!\n",
fullname, errno, Kill ? "kill" : "rejuvenate");
exit(1);
}
fp = fopen(fullname, "r");
if (fp == NULL) {
fprintf(stderr, "Can't read:%s, errno (%d)--can't %s it!\n",
fullname, errno, Kill ? "kill" : "rejuvenate");
exit(1);
}
times[0] = times[1] = time((time_t *)NULL);
while (fgets(buf, BUFSIZ, fp) != NULL) {
if (sscanf(buf,"%s%s%s%s%s%s", type, file1, file2,
user, opt, file3) <6) {
fprintf(stderr, "Bad format:%s, errno (%d)--can't %s it!\n",
fullname, errno, Kill ? "kill" : "rejuvenate");
exit(1);
}
DEBUG(9, "type (%s) ", type);
DEBUG(9, "file1 (%s) ", file1);
DEBUG(9, "file2 (%s) ", file2);
DEBUG(9, "file3 (%s) ", file3);
DEBUG(9, "user (%s)\n", user);
if (first) {
if (Uid != 0
&& !PREFIX(Loginuser, user)
&& !PREFIX(user, Loginuser) ) {
/* not allowed - not owner or root */
fprintf(stderr,
"Not owner or root - can't %s job %s\n",
Kill ? "kill" : "rejuvenate", Jobid);
exit(1);
}
first = 0;
}
/* remove D. file */
(void) sprintf(rfullname, "%s/%s", dir, file3);
DEBUG(4, "Remove %s\n", rfullname);
if (Kill)
ret = unlink(rfullname);
else /* Rejuvenate */
ret = utime(rfullname, times);
/*
* who cares if we can't?
* the C. is the file that matters,
* and the D. is sometimes a dummy
* we should check specifically but i'm lazy
*/
#if NOTDEF
if (ret != 0 && errno != ENOENT) {
/* program error?? */
fprintf(stderr, "Error: Can't %s, File (%s), errno (%d)\n",
Kill ? "kill" : "rejuvenate", rfullname, errno);
exit(1);
}
#endif
}
DEBUG(4, "Remove %s\n", fullname);
if (Kill)
ret = unlink(fullname);
else /* Rejuvenate */
ret = utime(fullname, times);
if (ret != 0) {
/* program error?? */
fprintf(stderr, "Error: Can't %s, File ( %s), errno (%d)\n",
Kill ? "kill" : "rejuvenate", fullname, errno);
exit(1);
}
fclose(fp);
printf("Job: %s successfully %s\n", Jobid,
Kill ? "killed" : "rejuvenated");
exit(0);
}
/*
* fsize - return the size of f1 or f2 (if f1 does not exist)
* f1 is the local name
*
*/
long
fsize(dir, f1, f2)
char *dir, *f1, *f2;
{
struct stat s;
char fullname[BUFSIZ];
(void) sprintf(fullname, "%s/%s", dir, f1);
if (stat(fullname, &s) == 0) {
return(s.st_size);
}
if (stat(f2, &s) == 0) {
return(s.st_size);
}
return(-99999);
}
cleanup(){}
void logent(){} /* to load ulockf.c */
void systat(){} /* to load utility.c */
struct m *
machine(name)
char *name;
{
struct m *m;
int namelen;
DEBUG(9, "machine(%s), ", name);
namelen = strlen(name);
for (m = M; m->mach[0] != NULLCHAR; m++)
/* match on overlap? */
if (EQUALSN(name, m->mach, SYSNSIZE)) {
/* use longest name */
if (namelen > strlen(m->mach))
(void) strcpy(m->mach, name);
return(m);
}
/*
* The table is set up with 2 extra entries
* When we go over by one, output error to errors log
* When more than one over, just reuse the previous entry
*/
DEBUG(9, "m-M=%d\n", m-M);
if (m-M >= UUSTAT_TBL) {
if (m-M == UUSTAT_TBL) {
errent("MACHINE TABLE FULL", "", UUSTAT_TBL,
sccsid, __FILE__, __LINE__);
(void) fprintf(stderr,
"WARNING: Table Overflow--output not complete\n");
}
else
/* use the last entry - overwrite it */
m = &M[UUSTAT_TBL];
}
(void) strcpy(m->mach, name);
m->c_age= m->x_age= m->lasttime= m->locked= m->ccount= m->xcount= 0;
m->stst[0] = '\0';
return(m);
}
printit(m)
struct m *m;
{
register struct tm *tp;
time_t t;
int min;
extern struct tm *localtime();
if (m->ccount == 0
&& m->xcount == 0
/*&& m->stst[0] == '\0'*/
&& m->locked == 0
&& Queue
&& m->type == 0)
return;
printf("%-10s", m->mach);
if (m->ccount)
printf("%3dC", m->ccount);
else
printf(" ");
if (m->c_age)
printf("(%d)", m->c_age);
else
printf(" ");
if (m->xcount)
printf("%4dX", m->xcount);
else
printf(" ");
if (m->x_age)
printf("(%d) ", m->x_age);
else
printf(" ");
if (m->lasttime) {
tp = localtime(&m->lasttime);
printf("%2.2d/%2.2d-%2.2d:%2.2d ",
tp->tm_mon + 1, tp->tm_mday, tp->tm_hour,
tp->tm_min);
}
/* if (m->locked && m->type != SS_INPROGRESS) */
if (m->locked)
printf("Locked ");
if (m->stst[0] != '\0') {
printf("%s", m->stst);
switch (m->type) {
case SS_SEQBAD:
case SS_LOGIN_FAILED:
case SS_DIAL_FAILED:
case SS_BAD_LOG_MCH:
case SS_BADSYSTEM:
case SS_CANT_ACCESS_DEVICE:
case SS_DEVICE_FAILED:
case SS_WRONG_MCH:
case SS_RLOCKED:
case SS_RUNKNOWN:
case SS_RLOGIN:
case SS_UNKNOWN_RESPONSE:
case SS_STARTUP:
case SS_CHAT_FAILED:
case SS_CONVERSATION:
(void) time(&t);
t = m->retrytime - (t - m->lasttime);
if (t > 0) {
min = (t + 59) / 60;
printf("Retry: %d:%2.2d", min/60, min%60);
}
if (m->count > 1)
printf(" Count: %d", m->count);
}
}
putchar('\n');
}
#define MAXLOCKS 100 /* Maximum number of lock files this will handle */
lckpid()
{
register i;
long pid, ret, fd;
#ifdef ASCIILOCKS
char alpid[SIZEOFPID+2]; /* +2 for '\n' and null */
#endif
long list[MAXLOCKS];
char buf[BUFSIZ], f[MAXBASENAME];
char *c, lckdir[BUFSIZ];
DIR *dir;
DEBUG(9, "lckpid() - entered\n", "");
for (i=0; i<MAXLOCKS; i++)
list[i] = -1;
(void) strcpy(lckdir, LOCKPRE);
*strrchr(lckdir, '/') = '\0';
DEBUG(9, "lockdir (%s)\n", lckdir);
/* open lock directory */
if (chdir(lckdir) != 0 || (dir = opendir(lckdir)) == NULL)
exit(101); /* good old code 101 */
while (gnamef(dir, f) == TRUE) {
/* find all lock files */
DEBUG(9, "f (%s)\n", f);
if (EQUALSN("LCK.", f, 4)) {
/* read LCK file */
fd = open(f, O_RDONLY);
printf("%s: ", f);
#ifdef ASCIILOCKS
ret = read(fd, alpid, SIZEOFPID+2); /* +2 for '\n' and null */
pid = atoi(alpid);
#else
ret = read(fd, &pid, sizeof (int));
#endif
(void) close(fd);
if (ret != -1) {
printf("%d\n", pid);
for(i=0; i<MAXLOCKS; i++) {
if (list[i] == pid)
break;
if (list[i] == -1) {
list[i] = pid;
break;
}
}
}
else
printf("????\n");
}
}
fflush(stdout);
*buf = NULLCHAR;
for (i=0; i<MAXLOCKS; i++) {
if( list[i] == -1)
break;
(void) sprintf(&buf[strlen(buf)], "%d ", list[i]);
}
if (i > 0)
#ifdef V7
execlp(UUPS, "uustat-ps", buf, 0);
#else
execl("/bin/ps", "ps", "-flp", buf, 0);
#endif
exit(0);
}
int machcmp(a,b)
char *a,*b;
{
return(strcmp(((struct m *) a)->mach,((struct m *) b)->mach));
}
static long _sec_per_day = 86400L;
/*
* _age - find the age of "file" in days
* return:
* age of file
* 0 - if stat fails
*/
int
_age(dir, file)
char * file; /* the file name */
char * dir; /* system spool directory */
{
char fullname[MAXFULLNAME];
static time_t ptime = 0;
time_t time();
struct stat stbuf;
if (!ptime)
(void) time(&ptime);
(void) sprintf(fullname, "%s/%s", dir, file);
if (stat(fullname, &stbuf) != -1) {
return ((int)((ptime - stbuf.st_mtime)/_sec_per_day));
}
else
return(0);
}