SysIII/usr/src/cmd/ps.c
/*
* ps - process status
* examine and print certain things about processes
*/
#include <stdio.h>
#include <a.out.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/var.h>
#include <core.h>
#define NTTYS 20
#define SIZ 30
#define TSIZE 100
#define ARGSIZ 30
struct nlist nl[] = {
{ "_proc" },
{ "_swplo" },
{ "_v" },
{ 0 },
};
union {
struct proc mprc;
struct xproc zprc;
} prc;
#define mproc prc.mprc
#define zproc prc.zprc
struct var v;
#ifdef pdp11
struct user u;
#endif
#ifdef vax
union { struct user yy;
int xx[128] [UPAGES];
} zz;
#define u zz.yy
int pagetbl[128];
int mf;
#endif
int retcode=1;
int c;
int lflg;
int eflg;
int uflg;
int aflg;
int dflg;
int pflg;
int fflg;
int gflg;
int tflg;
int sflg;
int errflg;
char *gettty();
char *ttyname();
int mem;
int swmem;
int swap;
daddr_t swplo;
char argbuf[ARGSIZ];
char *parg;
char *p1;
char *coref;
char *memf;
long lseek();
int ndev;
struct devl {
char dname[DIRSIZ];
dev_t dev;
} devl[256];
static int uid_num[TSIZE]; /* for u option */
static char *uid_name[TSIZE];
static int uidn = 0;
int uid_tbl[SIZ];
int nuids = 0;
char *tty[NTTYS]; /* for t option */
int ntty = 0;
int pid[SIZ]; /* for p option */
int npid = 0;
int grpid[SIZ]; /* for g option */
int ngrpid = 0;
main(argc, argv)
char **argv;
{
register char **ttyp = tty;
char *system, *name;
char *p;
int puid, ppid, ppgrp;
int i, found;
extern char *optarg;
extern int optind;
char *getstr;
char *usage="ps [ -edalf ] [ -c corefile ] [ -s swapdev ] [ -n namelist ] [ -t tlist ]";
char *usage2=" [ -p plist ] [ -u ulist ] [ -g glist ]";
char *malloc();
unsigned size;
getstr = "lfeadn:s:c:t:p:g:u:";
system = "/unix";
#ifdef vax
coref = "/dev/kmem";
memf = "/dev/mem";
#else
coref = "/dev/mem";
memf = coref;
#endif
while ((c = getopt(argc,argv,getstr)) != EOF)
switch(c) {
case 'l': /* long listing */
lflg++;
break;
case 'f': /* full listing */
fflg++;
break;
case 'e': /* list for every process */
eflg++;
tflg = uflg = pflg = gflg = 0;
break;
case 'a': /* same as e except no proc grp leaders */
aflg++; /* and no non-terminal processes */
break;
case 'd': /* same as e except no proc grp leaders */
dflg++;
break;
case 'n': /* alternate namelist */
system = optarg;
break;
case 'c': /* core file given */
coref = optarg;
memf = coref;
break;
case 's': /* swap device given */
sflg++;
if ((swap = open(optarg, 0)) < 0 ) {
fprintf(stderr, "ps: cannot open %s\n",optarg);
done(1);
}
break;
case 't': /* terminals */
tflg++;
p1 = optarg;
do {
parg = argbuf;
if (ntty >= NTTYS)
break;
getarg();
if (strncmp(parg,"tty",3) == 0)
parg += 3;
size = strlen(parg);
if ((p = malloc(++size)) == 0) {
fprintf(stderr,"ps: no memory\n");
done(1);
}
strcpy(p,parg);
*ttyp++ = p;
ntty++;
}
while (*p1);
break;
case 'p': /* proc ids */
pflg++;
p1 = optarg;
parg = argbuf;
do {
if (npid >= SIZ)
break;
getarg();
pid[npid++] = atoi(parg);
}
while (*p1);
break;
case 'g': /* proc group */
gflg++;
p1 = optarg;
parg = argbuf;
do {
if (ngrpid >= SIZ)
break;
getarg();
grpid[ngrpid++] = atoi(parg);
}
while (*p1);
break;
case 'u': /* user name or number */
uflg++;
p1 = optarg;
parg = argbuf;
do {
getarg();
uopt(parg);
}
while (*p1);
break;
case '?': /* error */
errflg++;
break;
}
if ( errflg || (optind < argc)) {
fprintf(stderr,"usage: %s\n%s\n",usage,usage2);
done(1);
}
if (tflg)
*ttyp = 0;
/* if specifying options not used, current terminal is default */
if ( !(aflg || eflg || dflg || uflg || tflg || pflg || gflg )) {
name = ttyname(2);
if (strncmp(name+5,"tty",3)==0)
*ttyp++ = name+8;
else
*ttyp++ = name+5;
*ttyp = 0;
ntty++;
tflg++;
}
if (eflg)
tflg = uflg = pflg = gflg = aflg = dflg = 0;
if (aflg || dflg)
tflg = 0;
nlist(system, nl);
if(nl[0].n_type==0||nl[1].n_type==0||nl[2].n_type==0) {
fprintf(stderr, "ps: no namelist\n");
done(1);
}
#ifdef vax
nl[0].n_value = ((int)nl[0].n_value & 0x3fffffff);
nl[1].n_value = ((int)nl[1].n_value & 0x3fffffff);
nl[2].n_value = ((int)nl[2].n_value & 0x3fffffff);
#endif
if ((mem = open(coref, 0)) < 0) {
fprintf(stderr, "ps: no mem\n");
done(1);
}
if ((swmem = open(memf,0)) < 0) {
fprintf(stderr, "ps: no mem\n");
done(1);
}
if (chdir("/dev") < 0) {
fprintf(stderr, "ps: cannot change to /dev\n");
done(1);
}
/*
* Find base of swap
*/
l_lseek(mem, (long)nl[1].n_value, 0);
r_read(mem, (char *)&swplo, sizeof(swplo));
/*
* read to find proc table size
*/
l_lseek(mem, (long)nl[2].n_value, 0);
r_read(mem, (char *)&v, sizeof(v));
/*
* Locate proc table
*/
l_lseek(mem, (long)nl[0].n_value, 0);
getdev();
if (fflg && lflg )
printf(" F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME COMD\n");
else if (fflg)
printf(" UID PID PPID C STIME TTY TIME COMMAND\n");
else if (lflg)
printf(" F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME COMD\n");
else
printf(" PID TTY TIME COMMAND\n");
/* determine which processes to print info about */
for (i=0; i<v.v_proc; i++) {
found = 0;
r_read(mem, (char *)&mproc, sizeof(mproc));
if (mproc.p_stat == 0)
continue;
puid = mproc.p_uid;
ppid = mproc.p_pid;
ppgrp = mproc.p_pgrp;
if ((ppid == ppgrp) && (dflg || aflg))
continue;
if (eflg || dflg)
found++;
else if (pflg && search(pid, npid, ppid))
found++;
else if (uflg && ufind(puid))
found++;
else if (gflg && search(grpid, ngrpid, ppgrp))
found++;
if ( !found && !tflg && !aflg )
continue;
if (prcom(puid,found)) {
printf("\n");
retcode =0;
}
}
done(retcode);
}
/* getdev reads in the open devices (terminals) and stores */
/* info in the devl structure. /dev/swap is opened */
getdev()
{
#include <sys/stat.h>
register FILE *df;
struct stat sbuf;
struct direct dbuf;
if ((df = fopen("/dev", "r")) == NULL) {
fprintf(stderr, "ps: cannot open /dev\n");
done(1);
}
ndev = 0;
while (fread((char *)&dbuf, sizeof(dbuf), 1, df) == 1) {
if(dbuf.d_ino == 0)
continue;
if(stat(dbuf.d_name, &sbuf) < 0)
continue;
if ((sbuf.st_mode&S_IFMT) != S_IFCHR)
continue;
strcpy(devl[ndev].dname, dbuf.d_name);
devl[ndev].dev = sbuf.st_rdev;
ndev++;
}
fclose(df);
if ( !sflg ) {
if ((swap = open("/dev/swap", 0)) < 0) {
fprintf(stderr, "ps: cannot open /dev/swap\n");
done(1);
}
}
}
/* getarg finds next argument in list and copies arg into argbuf */
/* p1 first pts to arg passed back from getopt routine. p1 is then */
/* bumped to next character that is not a comma or blank - p1 null */
/* indicates end of list */
getarg()
{
char *parga;
parga = argbuf;
while(*p1 && *p1 != ',' && *p1 != ' ')
*parga++ = *p1++;
*parga = '\0';
while( *p1 && ( *p1 == ',' || *p1 == ' ') )
p1++;
}
/* gettty returns the user's tty number or ? if none */
char *gettty()
{
register i;
register char *p;
if (u.u_ttyp==0)
return("?");
for (i=0; i<ndev; i++) {
if (devl[i].dev == u.u_ttyd) {
p = devl[i].dname;
if (strncmp(p,"tty",3) == 0)
p += 3;
return(p);
}
}
return("?");
}
#ifdef pdp11
long round(a,b)
long a, b;
{
long w = ((a+b-1)/b)*b;
return(w);
}
#endif
typedef unsigned pos;
struct map {
long b1, e1; long f1;
long b2, e2; long f2;
};
struct map datmap;
int file;
/* print info about the process */
prcom(puid,found)
int puid,found;
{
int abuf[BSIZE/sizeof(int)];
long addr;
register int *ip;
register char *cp, *cp1;
char *cp2;
char *ctime();
time_t time();
time_t *clock, *tloc;
time_t tim;
char timbuf[26];
char *curtim = timbuf;
char *sttim, *s1;
long tm;
int c, nbad, badflg;
register char *tp;
long txtsiz, datsiz, stksiz;
int septxt;
int match, i;
int nbytes;
int uzero = 0;
register char **ttyp, *str;
int lw=(lflg?35:80);
/* if process is zombie, call print routine and return */
if (mproc.p_stat==SZOMB) {
if ( tflg && !found)
return(0);
else {
przom(puid);
return(1);
}
}
/* Determine if process is in memory or swap space */
/* and read in user block */
#ifdef vax
if ((mproc.p_flag& (SLOAD | SSPART)) == 0) {
addr = (mproc.p_swaddr+swplo)<<9;
mf = swap;
l_lseek(mf, addr, 0);
if ((nbytes = read(mf, (char *)&u, sizeof(u))) != sizeof(u)) {
if (( nbytes == 0) && sflg) {
uzero++;
for ( i = 0, tp = (char *) &u; i < sizeof(u); i++)
*tp++ = '\0';
}
else
return(0);
}
} else {
for(c=0; c<UPAGES; c++) {
l_lseek(swmem,(long)mproc.p_addr[c]<<9,0);
if (read(swmem,(char *)(((int *)&u)+128*c),512) != 512) /* get u page */
return(0);
}
}
#endif
#ifdef pdp11
if (mproc.p_flag&SLOAD) {
addr = ctob((long)mproc.p_addr);
file = swmem;
} else {
addr = (mproc.p_addr+swplo)<<9;
file = swap;
}
l_lseek(file, addr, 0);
if ((nbytes = read(file, (char *)&u, sizeof(u))) != sizeof(u))
if (( nbytes == 0) && sflg && (file == swap)) {
uzero++;
for ( i = 0, tp = (char *) &u; i < sizeof(u); i++)
*tp++ = '\0';
} else
return(0);
#endif
/* get current terminal - if none (?) and aflg is set */
/* then don't print info - if tflg is set, check if term */
/* is in list of desired terminals and print if so */
tp = gettty();
if ( aflg && (*tp == '?' ))
return(0);
if(tflg && !found) { /* the t option */
for (ttyp=tty, match=0; (str = *ttyp) !=0 && !match; ttyp++)
if (strcmp(tp,str) == 0)
match++;
if(!match)
return(0);
}
if (lflg)
printf("%3o %c", mproc.p_flag&0377, "OSWRIZT"[mproc.p_stat]); /* F S */
if (fflg) {
i = getunam(puid);
if (i >= 0)
printf("%7s", uid_name[i]);
else
printf("%7d", puid);
}
else if (lflg)
printf("%6d", puid);
printf("%6u",mproc.p_pid); /* PID */
if (lflg || fflg)
printf("%6u%3d", mproc.p_ppid, mproc.p_cpu&0377); /* PPID CPU */
if (lflg) {
printf("%4d%3d",mproc.p_pri, mproc.p_nice); /* PRI NICE */
#ifdef vax
printf("%8x%3d", mproc.p_addr[0], mproc.p_size); /* ADDR SZ */
if (mproc.p_wchan)
printf("%9x",mproc.p_wchan); /* WCHAN */
else
printf(" ");
#endif
#ifdef pdp11
printf("%8o%3d", mproc.p_addr, (mproc.p_size+7)>>3);
if (mproc.p_wchan)
printf("%9o", mproc.p_wchan);
else
printf(" ");
#endif
}
if (uzero) /* u-block zeroed out so return */
return(1);
if (fflg) { /* STIME*/
clock = &u.u_start;
tim = time((time_t *) 0);
tloc = &tim;
s1 = ctime(tloc);
strcpy(curtim,s1);
sttim = ctime(clock);
prtim(curtim, sttim);
}
printf(" %2.2s", tp); /* TTY */
tm = (u.u_utime + u.u_stime + 30)/60; /* TIME */
printf(" %2ld:", tm/60);
tm %= 60;
printf(tm<10?"0%ld":"%ld", tm);
if (mproc.p_pid==0) {
printf(" swapper");
return(1);
}
/* if fflg not set, print command from u_block */
if (!fflg) { /* CMD */
printf(" %.8s", u.u_comm);
return(1);
}
/* set up address maps for user pcs */
#ifdef pdp11
txtsiz = ctob(u.u_tsize);
datsiz = ctob(u.u_dsize);
stksiz = ctob(u.u_ssize);
septxt = u.u_sep;
datmap.b1 = (septxt ? 0 : round(txtsiz,TXTRNDSIZ));
datmap.e1=datmap.b1+datsiz;
datmap.f1 = ctob(USIZE)+addr;
datmap.b2 = stackbas(stksiz);
datmap.e2 = stacktop(stksiz);
datmap.f2 = ctob(USIZE)+(datmap.e1-datmap.b1)+addr;
/* determine if process is a shell or not */
/* if last word is null then shell */
addr += ctob(mproc.p_size) - BSIZE;
l_lseek(file, addr+BSIZE-sizeof(int), 0);
if (read(file, (char *)abuf, sizeof(int)) != sizeof(int))
return(1);
if (abuf[0]&0177400) {
char b[82];
char *bp = b;
char **ap = abuf[0];
char *cp;
*bp++ = ' ';
badflg = 0;
while((cp=(char *)getword(ap++)) != -1 && cp && (bp < b+lw)){
nbad = 0;
while((c = getbyte(cp++)) && (int)(cp) != 0177777 && (bp < b + lw)){
badflg++;
if (c < ' ' || c > '~') {
if (nbad++ > 3)
break;
continue;
}
*bp++ = c;
}
*bp++ = ' ';
}
*bp++ = '\0';
if ( badflg == 0 || nbad != 0 || *b == '\0' )
printf(" [ %.8s ]",u.u_comm);
else
printf("%.20s",b);
return(1);
}
l_lseek(file, addr, 0);
if (read(file, (char *)abuf, sizeof(abuf)) != sizeof(abuf))
return(1);
#endif
#ifdef vax
c = mproc.p_size - btoc(512);
if ((mproc.p_flag & SLOAD) == 0) {
addr += ctob(c);
l_lseek(mf, addr, 0);
if (read(mf, (char *)abuf, sizeof(abuf)) != sizeof(abuf))
return(1);
} else {
if (u.u_pcb.pcb_szpt<1 || u.u_pcb.pcb_szpt>20)
return(1);
c = ctob((u.u_ptable[u.u_pcb.pcb_szpt-1] & 0x1fffff));
l_lseek(swmem,(long)c,0);
if (read(swmem,(char *)pagetbl,512) != 512) /* get last page table */
return(1);
l_lseek(swmem,ctob((pagetbl[127] & 0x1fffff)),0);
if (read(swmem,(char *)abuf,sizeof(abuf)) != sizeof(abuf))
return(1);
}
#endif
badflg = 0;
for (ip = &abuf[BSIZE/sizeof(int)-sizeof(int)]; ip > abuf;) {
if (*--ip == -1 || *ip == 0) {
cp = (char *)(ip+1);
if (*cp==0)
cp++;
nbad = 0;
for (cp2 = cp1 = cp; cp1 < (char *)&abuf[BSIZE/sizeof(int)]; cp1++) {
badflg++;
c = *cp1&0177;
if (c==0) {
*cp1 = ' ';
cp2 = cp1;
}
else if (c < ' ' || c > '~') {
if (++nbad >= 3) {
*cp1++ = ' ';
break;
}
*cp1 = '?';
}
if (c == '=') {
cp1 = cp2;
*cp1++ = 0;
break;
}
}
while (*--cp1==' ')
*cp1 = 0;
if ( badflg == 0 || nbad != 0 || *cp == '\0')
printf(" [ %.8s ]",u.u_comm);
else
printf(lflg?" %.35s":" %.80s", cp);
return(1);
}
}
printf(" [ %.8s ]",u.u_comm);
return(1);
}
/* file handling and access routines */
getbyte(adr)
pos adr;
{
return((int)access(adr,1));
}
getword(adr)
pos adr;
{
return((int)access(adr,sizeof(int*)));
}
access(aadr,size)
pos aadr;
int size;
{
int *word = 0;
register struct map *amap = &datmap;
long adr = aadr;
if(!within(aadr,amap->b1,amap->e1)) {
if(within(aadr,amap->b2,amap->e2))
adr += (amap->f2)-(amap->b2);
else
return(0);
}
else {
adr += (amap->f1)-(amap->b1);
}
if(lseek(file,adr,0)==-1 || read(file,(char *)&word,size)<size) {
return(0);
}
return(word);
}
within(adr,lbd,ubd)
pos adr;
long lbd, ubd;
{
return(adr>=lbd && adr<ubd);
}
done(exitno)
{
exit(exitno);
}
/* search returns 1 if arg is found in array arr */
/* which has length num, and returns 0 if not found */
search(arr, num, arg)
int arr[];
int num;
int arg;
{
int i;
for (i = 0; i < num; i++)
if (arg == arr[i])
return(1);
return(0);
}
/* uopt is used for the fancy version of the u option where either */
/* user name or number may be an argument. The arrays uid_name & */
/* uid_num store the associated names and numbers. ( these arrays are */
/* later used for printing UID ). The array uid_tbl stores */
/* ptrs (index) into the name & number arrays for arguments */
/* after the u option */
#include <pwd.h>
uopt(oarg)
char *oarg;
{
int found = -1;
struct passwd *pwd, *getpwuid(), *getpwname();
char *pwname;
char *p, *malloc();
unsigned size;
int pwuid;
int i;
/* search thru name array for oarg */
for (i=0; i<uidn; i++) {
if (strcmp(oarg,uid_name[i])==0) {
found = i;
break;
}
}
/* if not found then search through number array */
if (found < 0) {
pwuid = atoi(oarg);
for (i=0; i<uidn; i++) {
if (pwuid == uid_num[i]) {
found = i;
break;
}
}
}
/* if found then enter found index into tbl array */
if ( found != -1 ) {
if (nuids >= SIZ) return;
uid_tbl[nuids++] = found;
return;
}
/* oarg was not found in uid arrays so search through /etc/passwd */
/* for name and number. If found, enter name and number in arrays */
/* and then put values in table */
pwname = oarg;
if(pwd = getpwname(pwname)) { /* not null so found */
pwuid = pwd->pw_uid;
}
else {
pwuid = atoi(oarg);
/* rewrite an atoi - this is kludge */
if (( pwuid == 0) && (strcmp(oarg,"0") != 0))
return;
if (pwd = getpwuid(pwuid)) {
pwname = pwd->pw_name;
}
else {
/* not found so name or number is invalid */
return;
}
}
/* put nuid name and number in table */
if (( uidn >= TSIZE) || (nuids >= SIZ))
return;
uid_num[uidn] = pwuid;
size = strlen(pwname);
if ((p = malloc(++size)) == 0) {
fprintf(stderr,"ps: no memory\n");
done(1);
}
strcpy(p,pwname);
uid_name[uidn] = p;
uid_tbl[nuids++] = uidn;
uidn++;
return;
}
/* for full command (-f flag) print user name instead of number */
/* search thru existing table of userid numbers and if puid is found, */
/* return corresponding name. Else search thru /etc/passwd */
getunam(puid)
int puid;
{
struct passwd *pwd, *getpwuid();
char *p, *malloc();
unsigned size;
char *uname;
int i;
for (i=0; i<uidn; i++)
if (uid_num[i] == puid)
return(i);
/* not found in table so search thru /etc/passwd for number & return name */
if (pwd = getpwuid(puid))
uname = pwd->pw_name;
else
return(-1);
if (uidn >= TSIZE) return(-1);
uid_num[uidn] = puid;
size = strlen(uname);
if ((p = malloc(++size)) == 0) {
fprintf(stderr,"ps: no memory\n");
done(1);
}
strcpy(p,uname);
uid_name[uidn++] = p;
return(uidn-1);
}
/* ufind will return 1 if puid is in table ; if not return 0 */
ufind(puid)
int puid;
{
int i, j;
for (i=0; i<nuids; i++){
j = uid_tbl[i];
if (uid_num[j] == puid)
return(1);
}
return(0);
}
/* lseek with error checking */
l_lseek(fd, offset, whence)
int fd, whence;
long offset;
{
if (lseek(fd, offset, whence) == -1) {
fprintf(stderr, "ps: error on lseek\n");
done(1);
}
}
/* read with error checking */
r_read (fd, buf, nbytes)
int fd, nbytes;
char *buf;
{
if (read(fd, buf, nbytes) != nbytes) {
fprintf(stderr, "ps: error on read\n");
done(1);
}
}
/* print starting time of process unless process started more */
/* than 24 hours ago in which case date is printed */
/* sttim is start time and it is compared to curtim (current time ) */
prtim(curtim, sttim)
char *curtim, *sttim;
{
char *p1, *p2;
char dayst[3], daycur[3];
if ( strncmp(curtim, sttim, 11) == 0) {
p1 = sttim + 11;
p2 = p1 + 8;
}
else {
p1 = sttim + 4;
p2 = p1 + 7;
/* if time is < 24 hours different, then print time */
if (strncmp(curtim+4, sttim+4, 3) == 0) {
strncpy(dayst,sttim+8, 2);
strcat(dayst,"");
strncpy(daycur,curtim+8,2);
strcat(daycur,"");
if ((atoi(dayst) +1 == atoi(daycur)) &&
(strncmp(curtim+11,sttim+11,8)<=0)) {
p1 = sttim + 11;
p2 = p1 + 8;
}
}
}
*p2 = '\0';
printf("%9s",p1);
}
przom(puid)
/* print zombie process - zproc overlays mproc */
int puid;
{
int i;
long tm;
if (lflg)
printf("%3o %c", zproc.xp_flag&0377, "OSWRIZT"[zproc.xp_stat]); /* F S */
if (fflg) {
i = getunam(puid);
if (i >= 0)
printf("%7s", uid_name[i]);
else
printf("%7d", puid);
}
else if (lflg)
printf("%6d", puid);
printf("%6u",zproc.xp_pid); /* PID */
if (lflg || fflg)
printf("%6u%3d", zproc.xp_ppid, zproc.xp_cpu&0377); /* PPID CPU */
if (lflg)
printf("%4d%3d",zproc.xp_pri, zproc.xp_nice); /* PRI NICE */
if (fflg) printf(" ");
if (lflg) printf(" ");
tm = (zproc.xp_utime + zproc.xp_stime + 30)/60; /* TIME */
printf(" %2ld:", tm/60);
tm %= 60;
printf(tm<10?"0%ld":"%ld", tm);
printf(" <defunct>");
return;
}