AUSAM/source/S/look.c
/*
* Big-brother-is-watching-YOU program.
* Prints out procs that are currently active on the given device,
* or accessing the given file. Options allow for killing those procs,
* exec'ing chk, and sorting the output.
*
* The program assumes that raw devices live in /dev (for chk),
* and are formed by adding 'r' to the block device name.
*
* Kevin Hill
*/
#include <local-system>
#include <stat16.h>
#define IFCHR 020000
#include <param.h>
#include <proc.h>
#include <user.h>
#define NTEXT 1 /* as otherwise the next 3 includes */
#define NFILE 1 /* declare rather large arrays */
#define NINODE 1
#include <text.h>
#include <file.h>
#include <inode.h>
#include <tty.h>
char partab[1]; /* declared in tty.h */
#include <param.h> /* restore NTEXT NFILE NINODE */
int inodes[NINODE]; /* store inumber of actual file */
int files[NFILE];
int texts[NTEXT];
#define SIG 14 /* sent to procs if k-flag set */
#ifdef EECF1140
#define TTYS 20 /* max. nr. ttys in /dev */
#else
#define TTYS 65 /* max. nr. ttys in /dev */
#endif EECF1140
char ttyc[TTYS + 1]; /* tty char */
int ttyd[TTYS + 1]; /* tty dev */
int ttyp[TTYS + 1]; /* p->ttyp */
int ttyi[TTYS + 1]; /* index into ttyc & ttyd */
#define NI 40 /* max nr. args to chk */
int list[NI], li;
char mem[] "mem";
int memfd;
char swap[] "swap";
int swapfd;
char devdir[] "/dev";
int devfd;
char unix[] "/unix";
char sort[] "/bin/sort";
#define SORT 5 /* offset to skip bin above */
char cant[] "Can't find %s\n";
char warning[] "\007Warning: too many %s: recompile\n";
#ifdef EECF
char chk[] "/etc/bin/chk";
#define CHK 9 /* offset to skip etc bin above */
#else
char chk[] "/etc/chk";
#define CHK 5
#endif EECF
int dev, inum;
int heading, col; /* output listing controls */
int pid, uid;
struct tty *tty;
char blkfile[16] "r"; /* block-file name corresponding to given arg */
int killflag, chkflag, fileflag, sortflag;
char args[256];
struct { unsigned unsd; };
struct { char *ptr; };
extern fout;
struct nl
{
int name[4];
int type;
unsigned value;
}
nl[]
{
'_i', 'no', 'de', '\0\0', 0, 0,
#define PINODE 0
'_f', 'il', 'e\0', '\0\0', 0, 0,
#define PFILE 1
'_t', 'ex', 't\0', '\0\0', 0, 0,
#define PTEXT 2
'_p', 'ro', 'c\0', '\0\0', 0, 0,
#define PPROC 3
0
};
main(ac, av)
register char **av;
{
register char *cp;
register struct nl *nlp;
fout = 1;
while (av[1][0] == '-')
{
switch((*++av)[1])
{
case 'f': fileflag++; break;
case 'k': printf("\n\tk flag: are you EXTREMELY sure?? ");
if ((cp = getchar()) == 'y') killflag++;
if (cp && cp != '\n') while (getchar() != '\n');
break;
case 'n': chkflag++; break;
case 's': sortflag++; break;
}
ac--;
}
if (ac != 2)
{
printf("Usage: look [-f][-k][-n][-s] file\n");
return 1;
}
if (newstat(cp = *++av, args) < 0 || chdir(cp = devdir) < 0 ||
((memfd = open(cp = mem, 0)) < 0) ||
((swapfd = open(cp = swap, 0)) < 0) ||
((devfd = open(cp = devdir, 0)) < 0))
{
printf(cant, cp);
return 1;
}
inum = args->sb_inumber;
dev = args->sb_major << 8 | (args->sb_minor & 0377);
if (fileflag == 0)
if ((args->sb_flags & IFTYP) == IFTYP)
{
cp = av[0];
dev = args->sb_addr[0];
while ((blkfile[++col] = *cp++) && col < 14)
if ((blkfile[col]) == '/') col = 0;
blkfile[col + 1] = 0;
col = 0;
}
else if (inum != 1)
{
printf("%s: illegal file\n", *av);
return 1;
}
initdev();
nlist(unix, nl);
for (nlp = nl; nlp->name[0]; nlp++)
if (nlp->type == 0)
{
printf("Bad namelist\n");
return 1;
}
nice(-60);
setexit(); /* reset from `scanprocs' if inconsistent user found */
heading = li = 0;
scaninodes();
scanprocs();
nice(-10);
if (heading)
{
flush();
close(fout);
if (sortflag) while (waitx(&sortflag) != -1);
fout = 1;
flush();
if (chkflag && li)
{
if (blkfile[1] == 0)
{
printf("Can't match dev %d/%d\n", (dev >> 8) & 0377, dev & 0377);
exit(1);
}
if (newstat(blkfile, args) < 0) callchk(&blkfile[1]);
else callchk(blkfile);
}
}
else if (! killflag) printf("Inode active, yet no procs found??\n");
return 0;
}
initdev()
{
register n, *ip;
register char *cp;
int buf[256];
while ((n = read(devfd, buf, sizeof buf)) > 0)
{
for (ip = buf; ip != &buf[n]; ip =+ 8)
{
cp = &ip[1];
if (*ip == 0 || ip[1] == 'sw' && ip[2] == 'ap' && cp[4] == 0) continue;
if (ip[1] == 'tt' && cp[2] == 'y' && cp[4] == 0)
{
if (newstat(ip + 1, args) < 0 || (args->sb_flags & IFTYP) != IFCHR) continue;
ttyc[li] = cp[3];
ttyd[li] = args->sb_addr[0]; /* major & minor tty numbers */
if (++li >= TTYS)
{
printf(warning, "ttys");
exit(1);
}
continue;
}
if (blkfile[1] == 0 && newstat(ip + 1, args) >= 0 &&
(args->sb_flags & IFTYP) == IFTYP && args->sb_addr[0] == dev)
{
col = 1;
while ((blkfile[col] = *cp++) && col++ < 14);
blkfile[col] = 0;
col = 0;
}
}
}
ttyd[li] = -1; /* end-of-list sentinel */
li = 0;
}
scaninodes()
{
register i, j;
j = 1;
seek(memfd, nl[PINODE].value, 0);
for (i = 0; i < NINODE; i++)
{
read(memfd, inode, 6);
if (inode->i_count != 0 && inode->i_dev == dev &&
(! fileflag || inode->i_number == inum))
{
j = 0;
inodes[i] = inode->i_number;
}
seek(memfd, sizeof inode[0] - 6, 1);
}
if (j)
{
printf("No active inode(s) found\n");
exit(0);
}
seek(memfd, &(nl[PTEXT].value.ptr->x_iptr), 0);
for (i = 0; i < NTEXT; i++)
{
read(memfd, &(text->x_iptr), 3);
if (text->x_count != 0)
texts[i] = inodes[(text->x_iptr.unsd - nl[PINODE].value)/sizeof inode[0]];
seek(memfd, sizeof text[0] - 3, 1);
}
seek(memfd, nl[PFILE].value, 0);
for (i = 0; i < NFILE; i++)
{
read(memfd, file, sizeof file[0]);
if (file->f_count != 0)
files[i] = inodes[(file->f_inode.unsd - nl[PINODE].value)/sizeof inode[0]];
}
}
scanprocs()
{
register struct proc *p;
register i, j;
if ((i = gprocs(proc)) >= NPROC)
{
printf(warning, "procs");
exit(1);
}
p = &proc[i];
while (--p >= proc)
{
if (p->p_stat == 0 || p->p_stat == SZOMB) continue;
i = (p->p_textp.unsd - nl[PTEXT].value) / sizeof text[0];
pid = p->p_pid;
uid = p->p_uid;
tty = p->p_ttyp;
if (p->p_textp != 0 && texts[i])
{
if (killflag) { kill(p->p_pid, SIG); continue; }
print(1, texts[i]);
}
readuser(p);
i = (u.u_procp.unsd - nl[PPROC].value) / sizeof proc[0];
if (i != p - proc)
{ /* Inconsistent: p->p_addr->u_procp != p */
if (sortflag)
{
kill(sortflag, 9);
close(fout);
fout = 1;
flush();
}
printf("Retrying...\n");
reset();
}
i = (u.u_cdir.unsd - nl[PINODE].value) / sizeof inode[0];
if (inodes[i])
{
if (killflag) { kill(p->p_pid, SIG); continue; }
print(2, inodes[i]);
}
for (i = 0; i < NOFILE; i++)
{
if (u.u_ofile[i] == 0) continue;
j = (u.u_ofile[i].unsd - nl[PFILE].value) / sizeof file[0];
if (files[j])
{
if (killflag) { kill(p->p_pid, SIG); continue; }
print(3, files[j]);
}
}
if (col) { putchar('\n'); col = 0; }
}
}
readuser(p)
register struct proc *p;
{
long ln, useraddr;
if (p->p_flag & SLOAD)
{
useraddr = p->p_addr;
useraddr =<< 6;
ln = &(0->u_procp);
ln =+ useraddr;
lseek(memfd, ln, 0);
read(memfd, &u.u_procp, 2);
ln = &(0->u_cdir);
ln =+ useraddr;
lseek(memfd, ln, 0);
read(memfd, &u.u_cdir, 2);
ln = &(0->u_ofile[0]);
ln =+ useraddr;
lseek(memfd, ln, 0);
read(memfd, &u.u_ofile[0], NOFILE * 2);
}
else
{
seek(swapfd, p->p_addr, 3);
read(swapfd, &u, sizeof u);
}
}
print(newcol, inum)
register newcol;
{
register char *cp;
int fdes[2];
if (heading == 0)
{
printf("TTY PID UID TEXT CDIR FILES ...\n");
heading++;
if (sortflag)
{
pipe(fdes);
if ((sortflag = fork()) < 0)
{
close(fdes[0]);
close(fdes[1]);
fout = dup(1);
printf(cant, sort);
sortflag = 0;
}
else if (sortflag == 0) /* child */
{
nice(-10);
close(0);
close(memfd);
close(swapfd);
close(devfd);
dup(fdes[0]);
close(fdes[0]);
close(fdes[1]);
execl(sort, &sort[SORT], 0);
printf(cant, sort);
exit(1);
}
else /* parent */
{
close(fdes[0]);
fout = fdes[1];
}
}
else fout = dup(1);
}
if (col == 0)
{
printf("%c: %5d %5d", findtty(), pid, uid);
col = 1;
}
while (col++ < newcol) printf(" ");
printf(" %5d", inum);
if (chkflag) addtolist(inum);
}
findtty()
{
register m, n, p;
int ttydev;
if (tty == 0) return '?';
n = 0;
while (m = ttyp[n])
{
if (m == tty.unsd) return ttyc[ttyi[n]];
n++;
}
if (n != TTYS)
{
seek(memfd, &tty->t_dev, 0);
read(memfd, &ttydev, 2);
m = 0;
while ((p = ttyd[m]) != -1)
{
if (p == ttydev)
{
ttyp[n] = tty;
return ttyc[ttyi[n] = m];
}
m++;
}
}
return '!';
}
addtolist(inum)
register inum;
{
register *lp;
for (lp = list; lp != &list[li] && *lp != inum; lp++);
if (lp == &list[li] && li != NI)
{
*lp = inum;
li++;
}
}
char *itoa(p, n)
char *p;
register unsigned n;
{
register char *sp, *rp;
char stack[6];
rp = p;
sp = stack; *sp++ = 0;
while (n) { *sp++ = n % 10 + '0'; n =/ 10; }
while (*rp++ = *--sp)
if (rp >= &args[sizeof args]) return p;
return rp;
}
callchk(filsys)
register char *filsys;
{
register i;
register char *cp;
char *arglist[NI + 4];
close(memfd);
close(swapfd);
close(devfd);
arglist[0] = &chk[CHK];
arglist[1] = "-i";
arglist[(i = li) + 2] = filsys;
arglist[i + 3] = 0;
cp = args;
while (i--)
{
arglist[i + 2] = cp;
cp = itoa(cp, list[i]);
}
for (i = 0; arglist[i] != 0; printf(" %s", arglist[i++]));
putchar('\n');
execv(chk, arglist);
printf(cant, chk);
exit(1);
}