1646 lines
34 KiB
C
1646 lines
34 KiB
C
/*
|
|
* Copyright (c) 1980 Regents of the University of California.
|
|
* All rights reserved. The Berkeley software License Agreement
|
|
* specifies the terms and conditions for redistribution.
|
|
*/
|
|
|
|
#ifndef lint
|
|
char copyright[] =
|
|
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
|
|
All rights reserved.\n";
|
|
#endif not lint
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)mps.c 1.1 94/10/31 SMI";
|
|
#endif not lint
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <locale.h>
|
|
#include <a.out.h>
|
|
#include <pwd.h>
|
|
#include <fcntl.h>
|
|
#include <kvm.h>
|
|
#define KERNEL
|
|
#include <sys/param.h>
|
|
#undef KERNEL
|
|
#include <sys/ioctl.h>
|
|
#include <sys/dir.h>
|
|
#include <sys/user.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/vm.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/session.h>
|
|
#include <sys/vnode.h>
|
|
#include <vm/page.h>
|
|
#include <math.h>
|
|
|
|
char *nl_names[] = {
|
|
"_proc",
|
|
#define X_PROC 0
|
|
"_ccpu",
|
|
#define X_CCPU 1
|
|
"_nproc",
|
|
#define X_NPROC 2
|
|
"_file",
|
|
#define X_FILE 3
|
|
"_cfree",
|
|
#define X_CFREE 4
|
|
"_callout",
|
|
#define X_CALLOUT 5
|
|
"_kernelmap",
|
|
#define X_KERNELMAP 6
|
|
"_mbmap",
|
|
#define X_MBMAP 7
|
|
"_dquot",
|
|
#define X_DQUOT 8
|
|
"_boottime",
|
|
#define X_BOOTTIME 9
|
|
|
|
/* Symbols related to the new VM system -- may change */
|
|
"_pages",
|
|
#define X_PAGES 10
|
|
"_epages",
|
|
#define X_EPAGES 11
|
|
|
|
#ifdef sun
|
|
"_rconsdev",
|
|
#define X_RCONSDEV 12
|
|
#endif sun
|
|
""
|
|
};
|
|
|
|
#ifndef NCPU
|
|
#define NCPU 4
|
|
#endif
|
|
|
|
struct nlist *nl; /* all because we can't init unions */
|
|
int nllen; /* # of nlist entries */
|
|
|
|
struct savcom {
|
|
union {
|
|
struct jsav *jp;
|
|
struct lsav *lp;
|
|
float u_pctcpu;
|
|
struct vsav *vp;
|
|
} s_un;
|
|
struct asav *ap;
|
|
} *savcom;
|
|
|
|
struct asav {
|
|
char *a_cmdp;
|
|
int a_flag;
|
|
short a_stat;
|
|
short a_cpuid;
|
|
u_short a_pam;
|
|
uid_t a_uid;
|
|
short a_pid, a_nice, a_pri, a_slptime, a_time;
|
|
int a_size, a_rss;
|
|
char a_tty[MAXNAMLEN+1];
|
|
dev_t a_ttyd;
|
|
time_t a_cpu;
|
|
int a_maxrss;
|
|
time_t a_start;
|
|
};
|
|
|
|
char *lhdr, *jhdr;
|
|
int wcwidth; /* width of the wchan field for sprintf */
|
|
struct lsav {
|
|
short l_ppid;
|
|
char l_cpu;
|
|
caddr_t l_wchan;
|
|
};
|
|
struct jsav {
|
|
short j_ppid;
|
|
short j_pgrp;
|
|
short j_sid;
|
|
short j_tpgrp;
|
|
};
|
|
|
|
char *uhdr;
|
|
char *shdr;
|
|
|
|
char *vhdr;
|
|
struct vsav {
|
|
u_int v_majflt;
|
|
int v_swrss;
|
|
float v_pctcpu;
|
|
};
|
|
|
|
#define NPROC 16
|
|
|
|
struct proc *mproc;
|
|
struct timeval boottime;
|
|
time_t now;
|
|
|
|
struct user *u;
|
|
struct sess s;
|
|
|
|
#ifndef PSFILE
|
|
char *psdb = "/etc/psdatabase";
|
|
#else
|
|
char *psdb = PSFILE;
|
|
#endif
|
|
|
|
int chkpid = -1;
|
|
int aflg, cflg, eflg, gflg, kflg, lflg, nflg, rflg,
|
|
uflg, vflg, xflg, Uflg, jflg;
|
|
int nchans; /* total # of wait channels */
|
|
char *tptr;
|
|
char *gettty(), *getcmd(), *getname(), *savestr(), *state();
|
|
char *rindex(), *calloc(), *sbrk(), *strcpy(), *strcat(), *strncat();
|
|
char *strncpy(), *index(), *ttyname(), mytty[MAXPATHLEN+1];
|
|
char *malloc(), *getchan();
|
|
long lseek();
|
|
double pcpu(), pmem();
|
|
int wchancomp();
|
|
int pscomp();
|
|
double ccpu;
|
|
long kccpu;
|
|
dev_t rconsdev;
|
|
int nproc;
|
|
|
|
int nttys;
|
|
|
|
struct ttys {
|
|
dev_t ttyd;
|
|
int cand;
|
|
char name[MAXNAMLEN+1];
|
|
} *allttys;
|
|
int cand[16] = {-1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1};
|
|
struct lttys {
|
|
struct ttys ttys;
|
|
struct lttys *next;
|
|
} *lallttys;
|
|
|
|
/*
|
|
* struct for the symbolic wait channel info
|
|
*
|
|
* WNAMESIZ is the max # of chars saved of the symbolic wchan gleaned
|
|
* from the namelist. Normally, only WSNAMESIZ are printed in the long
|
|
* format, unless the terminal width is greater than WTSIZ wide.
|
|
*/
|
|
#define WNAMESIZ 12
|
|
#define WSNAMESIZ 8
|
|
#define WTSIZ 95
|
|
|
|
struct wchan {
|
|
char wc_name[WNAMESIZ+1]; /* symbolic name */
|
|
caddr_t wc_caddr; /* addr in kmem */
|
|
} *wchanhd; /* an array sorted by wc_caddr */
|
|
|
|
#define NWCINDEX 10 /* the size of the index array */
|
|
|
|
caddr_t wchan_index[NWCINDEX]; /* used to speed searches */
|
|
/*
|
|
* names listed here are not kept as wait channels -- this is used to
|
|
* remove names that confuse ps, like symbols that define the end of an
|
|
* array that happen to be equal to the next symbol.
|
|
*/
|
|
char *wchan_stop_list[] = {
|
|
"umbabeg",
|
|
"umbaend",
|
|
"calimit",
|
|
NULL
|
|
};
|
|
/*
|
|
* names listed here get mapped -- this is because only a guru will
|
|
* necessarily know that something waiting on "selwait" is waiting
|
|
* for a select to finish.
|
|
*/
|
|
struct wchan_map {
|
|
char *map_from;
|
|
char *map_to;
|
|
} wchan_map_list[] = {
|
|
{ "proc", "child" },
|
|
{ "u", "pause" },
|
|
{ "selwait", "select" },
|
|
{ "mbutl", "socket" },
|
|
{ NULL, NULL },
|
|
};
|
|
|
|
int gotwchans; /* 1 if already have the wait channels */
|
|
|
|
int npr;
|
|
|
|
int cmdstart;
|
|
int twidth;
|
|
struct winsize win;
|
|
char *kmemf, *swapf, *nlistf;
|
|
kvm_t *kvm_des;
|
|
int rawcpu, sumcpu;
|
|
char *cmdbuf;
|
|
|
|
#define pgtok(a) ((a)*CLBYTES/1024)
|
|
|
|
main(argc, argv)
|
|
char **argv;
|
|
{
|
|
register int i;
|
|
register char *ap;
|
|
int uid;
|
|
int width;
|
|
|
|
setlocale(LC_CTYPE, ""); /* get locale environment */
|
|
|
|
if (ioctl(1, TIOCGWINSZ, &win) == -1)
|
|
twidth = 80;
|
|
else
|
|
twidth = (win.ws_col == 0 ? 80 : win.ws_col);
|
|
argc--, argv++;
|
|
if (argc > 0) {
|
|
ap = argv[0];
|
|
if (*ap == '-') ap++;
|
|
while (*ap) switch (*ap++) {
|
|
|
|
case 'C':
|
|
rawcpu++;
|
|
break;
|
|
case 'S':
|
|
sumcpu++;
|
|
break;
|
|
|
|
case 'U':
|
|
Uflg++;
|
|
break;
|
|
|
|
case 'a':
|
|
aflg++;
|
|
break;
|
|
case 'c':
|
|
cflg = !cflg;
|
|
break;
|
|
case 'e':
|
|
eflg++;
|
|
break;
|
|
case 'g':
|
|
gflg++;
|
|
break;
|
|
case 'k':
|
|
kflg++;
|
|
break;
|
|
case 'l':
|
|
lflg++;
|
|
break;
|
|
case 'n':
|
|
nflg++;
|
|
break;
|
|
case 'j':
|
|
jflg++;
|
|
break;
|
|
case 'r':
|
|
rflg++;
|
|
break;
|
|
case 't':
|
|
if (*ap)
|
|
tptr = ap;
|
|
else if ((tptr = ttyname(0)) != 0) {
|
|
tptr = strcpy(mytty, tptr);
|
|
if (strncmp(tptr, "/dev/", 5) == 0)
|
|
tptr += 5;
|
|
}
|
|
if (strncmp(tptr, "tty", 3) == 0)
|
|
tptr += 3;
|
|
aflg++;
|
|
gflg++;
|
|
if (tptr && *tptr == '?')
|
|
xflg++;
|
|
while (*ap)
|
|
ap++;
|
|
break;
|
|
case 'u':
|
|
uflg++;
|
|
break;
|
|
case 'v':
|
|
cflg = 1;
|
|
vflg++;
|
|
break;
|
|
case 'w':
|
|
if (twidth < 132)
|
|
twidth = 132;
|
|
else
|
|
twidth = BUFSIZ;
|
|
break;
|
|
case 'x':
|
|
xflg++;
|
|
break;
|
|
case '-':
|
|
break;
|
|
default:
|
|
if (!isdigit(ap[-1])) {
|
|
fprintf(stderr, "ps: %c: unknown option\n", ap[-1]);
|
|
usage();
|
|
exit(1);
|
|
}
|
|
chkpid = atoi(--ap);
|
|
*ap = 0;
|
|
aflg++;
|
|
xflg++;
|
|
break;
|
|
}
|
|
}
|
|
nlistf = argc > 1 ? argv[1] : NULL;
|
|
kmemf = NULL;
|
|
if (kflg)
|
|
kmemf = argc > 2 ? argv[2] : "/vmcore";
|
|
if (kflg == 0 || argc > 3)
|
|
swapf = argc > 3 ? argv[3]: "/dev/drum";
|
|
else
|
|
swapf = NULL;
|
|
getkvars();
|
|
uid = getuid();
|
|
(void) time(&now);
|
|
printhdr();
|
|
nproc = getw(nl[X_NPROC].n_value);
|
|
cmdbuf = malloc(twidth+1);
|
|
savcom = (struct savcom *)calloc((unsigned) nproc, sizeof (*savcom));
|
|
if (cmdbuf == NULL || savcom == NULL) {
|
|
fprintf(stderr, "ps: out of memory allocating savcom\n");
|
|
exit(1);
|
|
}
|
|
kvm_read(kvm_des, nl[X_BOOTTIME].n_value, &boottime,
|
|
sizeof (boottime));
|
|
if (kvm_setproc(kvm_des) < 0) {
|
|
cantread("proc table", kmemf);
|
|
exit(1);
|
|
}
|
|
while ((mproc = kvm_nextproc(kvm_des)) != NULL) {
|
|
if (mproc->p_pgrp == 0 && xflg == 0)
|
|
continue;
|
|
if (tptr == 0 && gflg == 0 && xflg == 0 &&
|
|
mproc->p_ppid == 1)
|
|
continue;
|
|
if (uid != mproc->p_suid && aflg==0)
|
|
continue;
|
|
if (chkpid != -1 && chkpid != mproc->p_pid)
|
|
continue;
|
|
if (vflg && gflg == 0 && xflg == 0 && jflg == 0) {
|
|
if (mproc->p_stat == SZOMB ||
|
|
mproc->p_flag&SWEXIT)
|
|
continue;
|
|
if (mproc->p_slptime > MAXSLP &&
|
|
(mproc->p_stat == SSLEEP ||
|
|
mproc->p_stat == SSTOP))
|
|
continue;
|
|
}
|
|
if (rflg && !(mproc->p_stat == SRUN
|
|
|| mproc->p_pri < PZERO))
|
|
continue;
|
|
save();
|
|
}
|
|
width = twidth - cmdstart - 2;
|
|
if (width < 0)
|
|
width = 0;
|
|
qsort((char *) savcom, npr, sizeof(savcom[0]), pscomp);
|
|
for (i=0; i<npr; i++) {
|
|
register struct savcom *sp = &savcom[i];
|
|
if (lflg)
|
|
lpr(sp);
|
|
else if (jflg)
|
|
jpr(sp);
|
|
else if (vflg)
|
|
vpr(sp);
|
|
else if (uflg)
|
|
upr(sp);
|
|
else
|
|
spr(sp);
|
|
if (sp->ap->a_stat == SZOMB)
|
|
printf(" <defunct>");
|
|
else if (sp->ap->a_flag & SWEXIT)
|
|
printf(" <exiting>");
|
|
else if (sp->ap->a_pid == 0)
|
|
printf(" swapper");
|
|
else if (sp->ap->a_pid == 2)
|
|
printf(" pagedaemon");
|
|
else
|
|
printf(" %.*s", twidth - cmdstart - 2, sp->ap->a_cmdp);
|
|
printf("\n");
|
|
}
|
|
exit(npr == 0);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
getw(loc)
|
|
unsigned long loc;
|
|
{
|
|
int word;
|
|
|
|
if (kvm_read(kvm_des, loc, (char *)&word,
|
|
sizeof (word)) != sizeof (word)) {
|
|
if (kmemf == NULL)
|
|
printf("ps: error reading at %x\n", loc);
|
|
else
|
|
printf("ps: error reading %s at %x\n", kmemf, loc);
|
|
}
|
|
return (word);
|
|
}
|
|
|
|
/*
|
|
* Version allows change of db format w/o temporarily bombing ps's
|
|
*/
|
|
char thisversion[4] = "V3"; /* length must remain 4 */
|
|
|
|
writepsdb(unixname)
|
|
char *unixname;
|
|
{
|
|
register FILE *fp;
|
|
struct lttys *lt;
|
|
struct stat stb;
|
|
|
|
setgid(getgid());
|
|
setuid(getuid());
|
|
if ((fp = fopen(psdb, "w")) == NULL) {
|
|
fprintf(stderr, "ps: ");
|
|
perror(psdb);
|
|
exit(1);
|
|
} else
|
|
fchmod(fileno(fp), 0644);
|
|
|
|
fwrite(thisversion, sizeof thisversion, 1, fp);
|
|
fwrite(unixname, strlen(unixname) + 1, 1, fp);
|
|
if (stat(unixname, &stb) < 0)
|
|
stb.st_mtime = 0;
|
|
fwrite((char *) &stb.st_mtime, sizeof stb.st_mtime, 1, fp);
|
|
|
|
fwrite((char *) &nllen, sizeof nllen, 1, fp);
|
|
fwrite((char *) nl, sizeof (struct nlist), nllen, fp);
|
|
fwrite((char *) cand, sizeof (cand), 1, fp);
|
|
fwrite((char *) &nttys, sizeof nttys, 1, fp);
|
|
for (lt = lallttys ; lt ; lt = lt->next)
|
|
fwrite((char *)<->ttys, sizeof (struct ttys), 1, fp);
|
|
fwrite((char *) &nchans, sizeof nchans, 1, fp);
|
|
fwrite((char *) wchanhd, sizeof (struct wchan), nchans, fp);
|
|
fwrite((char *) wchan_index, sizeof (caddr_t), NWCINDEX, fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
readpsdb(unixname)
|
|
char *unixname;
|
|
{
|
|
register FILE *fp;
|
|
char unamebuf[BUFSIZ];
|
|
char *p = unamebuf;
|
|
char dbversion[sizeof thisversion];
|
|
struct stat stb;
|
|
time_t dbmtime;
|
|
extern int errno;
|
|
|
|
if ((fp = fopen(psdb, "r")) == NULL) {
|
|
if (errno == ENOENT)
|
|
return (0);
|
|
fprintf(stderr, "ps: ");
|
|
perror(psdb);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Does the db file match this unix?
|
|
*/
|
|
fread(dbversion, sizeof dbversion, 1, fp);
|
|
if (bcmp(thisversion, dbversion, sizeof thisversion))
|
|
goto bad;
|
|
while ((*p = getc(fp)) != '\0')
|
|
p++;
|
|
if (strcmp(unixname, unamebuf))
|
|
goto bad;
|
|
fread((char *) &dbmtime, sizeof dbmtime, 1, fp);
|
|
if (stat(unixname, &stb) < 0)
|
|
stb.st_mtime = 0;
|
|
if (stb.st_mtime != dbmtime)
|
|
goto bad;
|
|
|
|
fread((char *) &nllen, sizeof nllen, 1, fp);
|
|
nl = (struct nlist *) malloc (nllen * sizeof (struct nlist));
|
|
if (nl == NULL) {
|
|
fprintf(stderr, "ps: out of memory allocating nlist\n");
|
|
exit(1);
|
|
}
|
|
fread((char *) nl, sizeof (struct nlist), nllen, fp);
|
|
fread((char *) cand, sizeof (cand), 1, fp);
|
|
fread((char *) &nttys, sizeof nttys, 1, fp);
|
|
allttys = (struct ttys *)malloc(sizeof(struct ttys)*nttys);
|
|
if (allttys == NULL) {
|
|
fprintf(stderr, "ps: Can't malloc space for tty table\n");
|
|
exit(1);
|
|
}
|
|
fread((char *) allttys, sizeof (struct ttys), nttys, fp);
|
|
fread((char *) &nchans, sizeof nchans, 1, fp);
|
|
wchanhd = (struct wchan *) malloc(nchans * sizeof (struct wchan));
|
|
if (wchanhd == NULL) {
|
|
fprintf(stderr, "ps: Can't malloc space for wait channels\n");
|
|
nflg++;
|
|
fseek(fp, (long) nchans * sizeof (struct wchan), 1);
|
|
} else {
|
|
fread((char *) wchanhd, sizeof (struct wchan), nchans, fp);
|
|
gotwchans = 1;
|
|
}
|
|
fread((char *) wchan_index, sizeof (caddr_t), NWCINDEX, fp);
|
|
fclose(fp);
|
|
return (1);
|
|
|
|
bad:
|
|
fclose(fp);
|
|
return (0);
|
|
}
|
|
|
|
ps_kvm_open()
|
|
{
|
|
|
|
kvm_des = kvm_open(nlistf, kmemf, swapf, O_RDONLY, "ps");
|
|
if (kvm_des == NULL) {
|
|
if (nlistf == NULL)
|
|
fprintf(stderr, "ps: could not read kernel VM\n");
|
|
else
|
|
fprintf(stderr, "ps: could not read kernel VM for %s\n",
|
|
nlistf);
|
|
exit(1);
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
|
|
getkvars()
|
|
{
|
|
int faildb = 0; /* true if psdatabase init failed */
|
|
register char *realnlistf;
|
|
|
|
if ((realnlistf = nlistf) == NULL)
|
|
realnlistf = "/vmunix";
|
|
|
|
if (Uflg) {
|
|
init_nlist();
|
|
ps_kvm_open();
|
|
kvm_nlist(kvm_des, nl);
|
|
getvchans();
|
|
getdev();
|
|
writepsdb(realnlistf);
|
|
exit (0);
|
|
} else if (!readpsdb(realnlistf)) {
|
|
init_nlist();
|
|
ps_kvm_open();
|
|
faildb = 1;
|
|
kvm_nlist(kvm_des, nl);
|
|
nttys = 0;
|
|
getdev();
|
|
} else {
|
|
ps_kvm_open();
|
|
}
|
|
|
|
if (nl[0].n_type == 0) {
|
|
fprintf(stderr, "ps: %s: No namelist\n", realnlistf);
|
|
exit(1);
|
|
}
|
|
if (faildb)
|
|
getvchans();
|
|
if (kvm_read(kvm_des, nl[X_CCPU].n_value, (char *)&kccpu,
|
|
sizeof (kccpu)) != sizeof (kccpu)) {
|
|
cantread("ccpu", kmemf);
|
|
exit(1);
|
|
}
|
|
ccpu = (double)kccpu / FSCALE;
|
|
#ifdef sun
|
|
if (kvm_read(kvm_des, nl[X_RCONSDEV].n_value, (char *)&rconsdev,
|
|
sizeof (rconsdev)) != sizeof (rconsdev)) {
|
|
cantread("rconsdev", kmemf);
|
|
exit(1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* get the valloc'ed kernel variables for symbolic wait channels
|
|
*/
|
|
getvchans()
|
|
{
|
|
int i, tmp;
|
|
|
|
if (nflg)
|
|
return;
|
|
|
|
#define addv(i) addchan(&nl[i].n_un.n_name[1], getw(nl[i].n_value))
|
|
addv(X_FILE);
|
|
addv(X_PROC);
|
|
addv(X_CFREE);
|
|
addv(X_CALLOUT);
|
|
addv(X_KERNELMAP);
|
|
addv(X_MBMAP);
|
|
if (nl[X_DQUOT].n_value != 0) /* this is #ifdef QUOTA */
|
|
addv(X_DQUOT);
|
|
qsort(wchanhd, nchans, sizeof (struct wchan), wchancomp);
|
|
for (i = 0; i < NWCINDEX; i++) {
|
|
tmp = i * nchans;
|
|
wchan_index[i] = wchanhd[tmp / NWCINDEX].wc_caddr;
|
|
}
|
|
#undef addv
|
|
}
|
|
|
|
printhdr()
|
|
{
|
|
char *hdr;
|
|
|
|
if (lflg+vflg+uflg+jflg > 1) {
|
|
fprintf(stderr, "ps: specify only one of l,v,j and u\n");
|
|
exit(1);
|
|
}
|
|
if (lflg | jflg) {
|
|
if (nflg)
|
|
wcwidth = 8;
|
|
else if (twidth > WTSIZ)
|
|
wcwidth = -WNAMESIZ;
|
|
else
|
|
wcwidth = -WSNAMESIZ;
|
|
if (!(hdr = calloc(1, strlen(lflg ? lhdr : jhdr) + WNAMESIZ))) {
|
|
fprintf(stderr, "ps: out of memory\n");
|
|
exit(1);
|
|
}
|
|
sprintf(hdr, lflg ? lhdr : jhdr, wcwidth, "WCHAN");
|
|
} else if (vflg)
|
|
hdr = vhdr;
|
|
else if (uflg) {
|
|
/* add enough on so that it can hold the sprintf below */
|
|
if ((hdr = malloc(strlen(uhdr) + 10)) == NULL) {
|
|
fprintf(stderr, "ps: out of memory\n");
|
|
exit(1);
|
|
}
|
|
sprintf(hdr, uhdr, nflg ? " UID" : "USER ");
|
|
} else
|
|
hdr = shdr;
|
|
cmdstart = strlen(hdr);
|
|
printf("%s COMMAND\n", hdr);
|
|
(void) fflush(stdout);
|
|
}
|
|
|
|
cantread(what, fromwhat)
|
|
char *what, *fromwhat;
|
|
{
|
|
|
|
if (fromwhat == NULL)
|
|
(void) fprintf(stderr, "ps: error reading %s\n", what);
|
|
else
|
|
(void) fprintf(stderr, "ps: error reading %s from %s\n", what,
|
|
fromwhat);
|
|
}
|
|
|
|
struct direct *dbuf;
|
|
int dialbase;
|
|
|
|
getdev()
|
|
{
|
|
register DIR *df;
|
|
struct ttys *t;
|
|
struct lttys *lt;
|
|
|
|
if (chdir("/dev") < 0) {
|
|
perror("ps: /dev");
|
|
exit(1);
|
|
}
|
|
dialbase = -1;
|
|
if ((df = opendir(".")) == NULL) {
|
|
fprintf(stderr, "ps: ");
|
|
perror("Can't open . in /dev");
|
|
exit(1);
|
|
}
|
|
while ((dbuf = readdir(df)) != NULL)
|
|
maybetty();
|
|
closedir(df);
|
|
allttys = (struct ttys *)malloc(sizeof(struct ttys)*nttys);
|
|
if (allttys == NULL) {
|
|
fprintf(stderr, "ps: Can't malloc space for tty table\n");
|
|
exit(1);
|
|
}
|
|
for (lt = lallttys, t = allttys; lt ; lt = lt->next, t++)
|
|
*t = lt->ttys;
|
|
}
|
|
|
|
/*
|
|
* Attempt to avoid stats by guessing minor device
|
|
* numbers from tty names. Console is known,
|
|
* know that r(hp|up|mt) are unlikely as are different mem's,
|
|
* floppy, null, tty, etc.
|
|
*/
|
|
maybetty()
|
|
{
|
|
register char *cp = dbuf->d_name;
|
|
static struct lttys *dp;
|
|
struct lttys *olddp;
|
|
int x;
|
|
struct stat stb;
|
|
|
|
switch (cp[0]) {
|
|
|
|
case 'c':
|
|
if (!strcmp(cp, "console")) {
|
|
x = 0;
|
|
goto donecand;
|
|
}
|
|
/* cu[la]? are possible!?! don't rule them out */
|
|
break;
|
|
|
|
case 'd':
|
|
if (!strcmp(cp, "drum"))
|
|
return;
|
|
break;
|
|
|
|
case 'f':
|
|
if (!strcmp(cp, "floppy"))
|
|
return;
|
|
break;
|
|
|
|
case 'k':
|
|
cp++;
|
|
if (*cp == 'U')
|
|
cp++;
|
|
goto trymem;
|
|
|
|
case 'r':
|
|
cp++;
|
|
#define is(a,b) cp[0] == 'a' && cp[1] == 'b'
|
|
if (is(h,p) || is(r,a) || is(u,p) || is(h,k)
|
|
|| is(r,b) || is(s,d) || is(x,y) || is(m,t)) {
|
|
cp += 2;
|
|
if (isdigit(*cp) && cp[2] == 0)
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case 'm':
|
|
trymem:
|
|
if (cp[0] == 'm' && cp[1] == 'e' && cp[2] == 'm' && cp[3] == 0)
|
|
return;
|
|
if (cp[0] == 'm' && cp[1] == 't')
|
|
return;
|
|
break;
|
|
|
|
case 'n':
|
|
if (!strcmp(cp, "null"))
|
|
return;
|
|
if (!strncmp(cp, "nrmt", 4))
|
|
return;
|
|
break;
|
|
|
|
case 'p':
|
|
if (cp[1] && cp[1] == 't' && cp[2] == 'y')
|
|
return;
|
|
break;
|
|
|
|
case 'v':
|
|
if ((cp[1] == 'a' || cp[1] == 'p') && isdigit(cp[2]) &&
|
|
cp[3] == 0)
|
|
return;
|
|
break;
|
|
}
|
|
cp = dbuf->d_name + dbuf->d_namlen - 1;
|
|
x = 0;
|
|
if (cp[-1] == 'd') {
|
|
if (dialbase == -1) {
|
|
if (stat("ttyd0", &stb) == 0)
|
|
dialbase = stb.st_rdev & 017;
|
|
else
|
|
dialbase = -2;
|
|
}
|
|
if (dialbase == -2)
|
|
x = 0;
|
|
else
|
|
x = 11;
|
|
}
|
|
if (cp > dbuf->d_name && isdigit(cp[-1]) && isdigit(*cp))
|
|
x += 10 * (cp[-1] - ' ') + cp[0] - '0';
|
|
else if (*cp >= 'a' && *cp <= 'f')
|
|
x += 10 + *cp - 'a';
|
|
else if (isdigit(*cp))
|
|
x += *cp - '0';
|
|
else
|
|
x = -1;
|
|
donecand:
|
|
olddp = dp;
|
|
dp = (struct lttys *)malloc(sizeof(struct lttys));
|
|
if (dp == NULL) {
|
|
fprintf(stderr, "ps: Can't malloc space for tty table\n");
|
|
exit(1);
|
|
}
|
|
if (lallttys == NULL)
|
|
lallttys = dp;
|
|
nttys++;
|
|
if (olddp)
|
|
olddp->next = dp;
|
|
dp->next = NULL;
|
|
(void) strcpy(dp->ttys.name, dbuf->d_name);
|
|
if (Uflg) {
|
|
if (stat(dp->ttys.name, &stb) == 0 &&
|
|
(stb.st_mode&S_IFMT)==S_IFCHR)
|
|
dp->ttys.ttyd = x = stb.st_rdev;
|
|
else {
|
|
nttys--;
|
|
if (lallttys == dp)
|
|
lallttys = NULL;
|
|
free(dp);
|
|
dp = olddp;
|
|
if (dp)
|
|
dp->next = NULL;
|
|
return;
|
|
}
|
|
} else
|
|
dp->ttys.ttyd = -1;
|
|
if (x == -1)
|
|
return;
|
|
x &= 017;
|
|
dp->ttys.cand = cand[x];
|
|
cand[x] = nttys-1;
|
|
}
|
|
|
|
char *
|
|
gettty()
|
|
{
|
|
register char *p;
|
|
register struct ttys *dp;
|
|
struct stat stb;
|
|
int x;
|
|
|
|
if (s.s_vp == (struct vnode*)0) {
|
|
s.s_ttyd = -1;
|
|
return ("?");
|
|
}
|
|
#ifdef sun
|
|
if (s.s_ttyd == rconsdev)
|
|
s.s_ttyd = makedev(0, 0); /* "/dev/console" */
|
|
#endif
|
|
x = s.s_ttyd & 017;
|
|
for (dp = &allttys[cand[x]]; dp != &allttys[-1];
|
|
dp = &allttys[dp->cand]) {
|
|
if (dp->ttyd == -1) {
|
|
if (stat(dp->name, &stb) == 0 &&
|
|
(stb.st_mode&S_IFMT)==S_IFCHR)
|
|
dp->ttyd = stb.st_rdev;
|
|
else
|
|
dp->ttyd = -2;
|
|
}
|
|
if (dp->ttyd == s.s_ttyd)
|
|
goto found;
|
|
}
|
|
/* ick */
|
|
for (dp = allttys; dp < &allttys[nttys]; dp++) {
|
|
if (dp->ttyd == -1) {
|
|
if (stat(dp->name, &stb) == 0 &&
|
|
(stb.st_mode&S_IFMT)==S_IFCHR)
|
|
dp->ttyd = stb.st_rdev;
|
|
else
|
|
dp->ttyd = -2;
|
|
}
|
|
if (dp->ttyd == s.s_ttyd)
|
|
goto found;
|
|
}
|
|
return ("?");
|
|
found:
|
|
p = dp->name;
|
|
if (p[0]=='t' && p[1]=='t' && p[2]=='y')
|
|
p += 3;
|
|
return (p);
|
|
}
|
|
|
|
save()
|
|
{
|
|
register struct savcom *sp;
|
|
register struct asav *ap;
|
|
char *ttyp, *cmdp;
|
|
int save_ttyd;
|
|
|
|
if (mproc->p_stat != SZOMB)
|
|
if ((u = kvm_getu(kvm_des, mproc)) == NULL)
|
|
return;
|
|
kvm_read(kvm_des, mproc->p_sessp, &s, sizeof(s));
|
|
save_ttyd = s.s_ttyd;
|
|
ttyp = gettty();
|
|
if (xflg == 0 && ttyp[0] == '?' || tptr && strncmp(tptr, ttyp, 2))
|
|
return;
|
|
sp = &savcom[npr];
|
|
cmdp = getcmd();
|
|
sp->ap = ap = (struct asav *)calloc(1, sizeof (struct asav));
|
|
if (ap == NULL) {
|
|
fprintf(stderr, "ps: out of memory allocating asav\n");
|
|
exit(1);
|
|
}
|
|
sp->ap->a_cmdp = cmdp;
|
|
#define e(a,b) ap->a = mproc->b
|
|
e(a_flag, p_flag); e(a_stat, p_stat); e(a_nice, p_nice);
|
|
e(a_cpuid, p_cpuid); e(a_pam,p_pam);
|
|
e(a_uid, p_suid);
|
|
e(a_pid, p_pid); e(a_pri, p_pri);
|
|
e(a_slptime, p_slptime); e(a_time, p_time);
|
|
ap->a_tty[0] = ttyp[0];
|
|
ap->a_tty[1] = ttyp[1] ? ttyp[1] : ' ';
|
|
if (ap->a_stat == SZOMB) {
|
|
ap->a_cpu = 0;
|
|
ap->a_ttyd = s.s_ttyd;
|
|
} else {
|
|
ap->a_size = mproc->p_dsize + mproc->p_ssize;
|
|
e(a_rss, p_rssize);
|
|
ap->a_ttyd = s.s_ttyd;
|
|
ap->a_cpu = u->u_ru.ru_utime.tv_sec + u->u_ru.ru_stime.tv_sec;
|
|
if (sumcpu)
|
|
ap->a_cpu += u->u_cru.ru_utime.tv_sec + u->u_cru.ru_stime.tv_sec;
|
|
ap->a_start = u->u_start.tv_sec;
|
|
}
|
|
#undef e
|
|
ap->a_maxrss = mproc->p_maxrss;
|
|
if (jflg) {
|
|
register struct jsav *jp;
|
|
|
|
sp->s_un.jp = jp = (struct jsav *)
|
|
calloc(1, sizeof (struct jsav));
|
|
if (jp == NULL) {
|
|
fprintf(stderr, "ps: out of memory allocating jsav\n");
|
|
exit(1);
|
|
}
|
|
|
|
jp->j_ppid = mproc->p_ppid;
|
|
jp->j_pgrp = mproc->p_pgrp;
|
|
jp->j_sid = s.s_sid;
|
|
if (s.s_ttyp) {
|
|
kvm_read(kvm_des, s.s_ttyp, &jp->j_tpgrp, sizeof(pid_t));
|
|
}
|
|
else
|
|
jp->j_tpgrp = -1;
|
|
}
|
|
else if (lflg) {
|
|
register struct lsav *lp;
|
|
|
|
sp->s_un.lp = lp = (struct lsav *)
|
|
calloc(1, sizeof (struct lsav));
|
|
if (lp == NULL) {
|
|
fprintf(stderr, "ps: out of memory allocating lsav\n");
|
|
exit(1);
|
|
}
|
|
#define e(a,b) lp->a = mproc->b
|
|
e(l_ppid, p_ppid);
|
|
e(l_cpu, p_cpu);
|
|
if (ap->a_stat != SZOMB)
|
|
e(l_wchan, p_wchan);
|
|
#undef e
|
|
} else if (vflg) {
|
|
register struct vsav *vp;
|
|
|
|
sp->s_un.vp = vp = (struct vsav *)
|
|
calloc(1, sizeof (struct vsav));
|
|
if (vp == NULL) {
|
|
fprintf(stderr, "ps: out of memory allocating vsav\n");
|
|
exit(1);
|
|
}
|
|
#define e(a,b) vp->a = mproc->b
|
|
if (ap->a_stat != SZOMB) {
|
|
e(v_swrss, p_swrss);
|
|
vp->v_majflt = u->u_ru.ru_majflt;
|
|
}
|
|
vp->v_pctcpu = pcpu();
|
|
#undef e
|
|
} else if (uflg)
|
|
sp->s_un.u_pctcpu = pcpu();
|
|
|
|
npr++;
|
|
}
|
|
|
|
/*
|
|
* Calculate the percentage of memory to charge to this process.
|
|
*/
|
|
double
|
|
pmem(ap)
|
|
register struct asav *ap;
|
|
{
|
|
double fracmem;
|
|
static int totpages, havepages;
|
|
|
|
/*
|
|
* Lazy evaluation.
|
|
*/
|
|
if (havepages == 0) {
|
|
totpages = (struct page *)getw(nl[X_EPAGES].n_value) -
|
|
(struct page *)getw(nl[X_PAGES].n_value);
|
|
havepages = 1;
|
|
}
|
|
|
|
/*
|
|
* The second clause guards against nlist botches and such.
|
|
*/
|
|
if ((ap->a_flag & SLOAD) == 0 || totpages <= 0)
|
|
fracmem = 0.0;
|
|
else {
|
|
/*
|
|
* Calculate an approximation to the process's
|
|
* memory consumption. Background information:
|
|
* 1) We estimate the total pool of available memory
|
|
* by calculating (epages-pages). When the VM
|
|
* system is generalized to support noncontiguous
|
|
* physical memory, this will have to change.
|
|
* 2) This difference is an overestimate, since some
|
|
* of these pages can go to the kernel and aren't
|
|
* actually available for user processes.
|
|
* 3) We use ap->a_rss as the measure of the process's
|
|
* memory demand. This neglects all shared segments,
|
|
* such as shared libraries. The rss itself isn't
|
|
* particularly accurate either -- this is a deficiency
|
|
* of the initial implementation of the new VM system.
|
|
* 4) We completely neglect u-area pages in the calculations.
|
|
*/
|
|
fracmem = ((double)ap->a_rss) / totpages;
|
|
}
|
|
|
|
return (100.0 * fracmem);
|
|
}
|
|
|
|
double
|
|
pcpu()
|
|
{
|
|
time_t time;
|
|
double p;
|
|
|
|
time = mproc->p_time;
|
|
if (time == 0 || (mproc->p_flag&SLOAD) == 0)
|
|
return (0.0);
|
|
p = (double)mproc->p_pctcpu / FSCALE;
|
|
if (rawcpu)
|
|
return (100.0 * p);
|
|
return (100.0 * p / (1.0 - exp(time * log(ccpu))));
|
|
}
|
|
|
|
char *
|
|
getcmd()
|
|
{
|
|
char **proc_argv = NULL;
|
|
char **proc_environ = NULL;
|
|
register char **argp;
|
|
register char *ap;
|
|
register char *cp, *ep;
|
|
register int c;
|
|
int nbad;
|
|
char tempbuf[sizeof(u->u_comm)+10];
|
|
|
|
bzero(cmdbuf, twidth+1);
|
|
if (mproc->p_stat == SZOMB || mproc->p_flag&(SSYS|SWEXIT))
|
|
return ("");
|
|
if (cflg) {
|
|
(void) strncpy(cmdbuf, u->u_comm, sizeof (u->u_comm));
|
|
return (savestr(cmdbuf));
|
|
}
|
|
if (kvm_getcmd(kvm_des, mproc, u, &proc_argv, eflg ? &proc_environ : NULL) < 0) {
|
|
(void) strcpy(cmdbuf, " (");
|
|
(void) strncat(cmdbuf, u->u_comm, sizeof (u->u_comm));
|
|
(void) strcat(cmdbuf, ")");
|
|
} else {
|
|
cp = cmdbuf;
|
|
ep = cmdbuf + twidth;
|
|
argp = proc_argv;
|
|
nbad = 0;
|
|
while (((ap = *argp++) != NULL) && (cp < ep)) {
|
|
while (((c = (unsigned char)*ap++) != 0) &&
|
|
(cp < ep - 1)) {
|
|
if (!isprint(c)) {
|
|
if (++nbad >= 5)
|
|
break;
|
|
*cp = '?';
|
|
} else
|
|
*cp++ = c;
|
|
}
|
|
*cp++ = ' ';
|
|
}
|
|
if (eflg) {
|
|
argp = proc_environ;
|
|
nbad = 0;
|
|
while (((ap = *argp++) != NULL) && (cp < ep)) {
|
|
while (((c = (unsigned char)*ap++) != 0) &&
|
|
(cp < ep - 1)) {
|
|
if (!isprint(c)) {
|
|
if (++nbad >= 5)
|
|
break;
|
|
*cp = '?';
|
|
} else
|
|
*cp++ = c;
|
|
}
|
|
*cp++ = ' ';
|
|
}
|
|
}
|
|
*cp = 0;
|
|
while (*--cp == ' ')
|
|
*cp = 0;
|
|
if (*proc_argv == NULL || cmdbuf[0] == '-'
|
|
|| cmdbuf[0] == '?' || cmdbuf[0] <= ' ') {
|
|
(void) strcpy(tempbuf, " (");
|
|
(void) strncat(tempbuf, u->u_comm, sizeof(u->u_comm));
|
|
(void) strcat(tempbuf, ")");
|
|
(void) strncat(cmdbuf, tempbuf, ep-cp);
|
|
}
|
|
if (proc_argv != NULL)
|
|
free(proc_argv);
|
|
if (proc_environ != NULL)
|
|
free(proc_environ);
|
|
}
|
|
return (savestr(cmdbuf));
|
|
}
|
|
|
|
char *jhdr =
|
|
" PPID PID PGID SID TT TPGID STAT CPU UID TIME";
|
|
jpr(sp)
|
|
struct savcom *sp;
|
|
{
|
|
register struct asav *ap = sp->ap;
|
|
register struct jsav *jp = sp->s_un.jp;
|
|
char flg[10];
|
|
char *s = flg;
|
|
|
|
strcpy(flg, state(ap));
|
|
for (s=flg; isalpha(*s); s++)
|
|
;
|
|
if (ap->a_flag & SNOCLDSTOP)
|
|
*s++ = 'C';
|
|
if (ap->a_flag & SORPHAN)
|
|
*s++ = 'O';
|
|
if (ap->a_flag & SEXECED)
|
|
*s++ = 'E';
|
|
*s = 0;
|
|
printf("%5u%6u%6u%6d ",
|
|
jp->j_ppid, ap->a_pid, jp->j_pgrp, jp->j_sid);
|
|
ptty(ap->a_tty);
|
|
printf("%6d %5s%6d", jp->j_tpgrp, flg, ap->a_uid);
|
|
ptime(ap);
|
|
}
|
|
|
|
char *lhdr =
|
|
" F UID PID PPID CP PRI NI SZ RSS %*s STAT CPU TT TIME";
|
|
lpr(sp)
|
|
struct savcom *sp;
|
|
{
|
|
register struct asav *ap = sp->ap;
|
|
register struct lsav *lp = sp->s_un.lp;
|
|
|
|
printf("%8x%4d%6u%6u%3d%4d%3d%4d%5d",
|
|
ap->a_flag, ap->a_uid,
|
|
ap->a_pid, lp->l_ppid, lp->l_cpu&0377, ap->a_pri-PZERO,
|
|
ap->a_nice-NZERO, pgtok(ap->a_size), pgtok(ap->a_rss));
|
|
if (lp->l_wchan == 0)
|
|
printf(" %*s", wcwidth, "");
|
|
else if (nflg)
|
|
printf(" %*x", wcwidth, (int)lp->l_wchan&0xffffffff);
|
|
else
|
|
printf(" %*.*s", wcwidth, abs(wcwidth), getchan(lp->l_wchan));
|
|
printf(" %9.9s ", state(ap));
|
|
ptty(ap->a_tty);
|
|
ptime(ap);
|
|
}
|
|
|
|
ptty(tp)
|
|
char *tp;
|
|
{
|
|
|
|
printf("%-2.2s", tp);
|
|
}
|
|
|
|
ptime(ap)
|
|
struct asav *ap;
|
|
{
|
|
|
|
printf("%3ld:%02ld", ap->a_cpu / 60, ap->a_cpu % 60);
|
|
}
|
|
|
|
char *uhdr =
|
|
"%s PID %%CPU %%MEM SZ RSS TT STAT CPU START TIME";
|
|
upr(sp)
|
|
struct savcom *sp;
|
|
{
|
|
register struct asav *ap = sp->ap;
|
|
char *cp;
|
|
int vmsize, rmsize;
|
|
|
|
vmsize = pgtok(ap->a_size);
|
|
rmsize = pgtok(ap->a_rss);
|
|
if (nflg)
|
|
printf("%4d ", ap->a_uid);
|
|
else
|
|
printf("%-8.8s ", getname(ap->a_uid));
|
|
printf("%5d%5.1f%5.1f%5d%5d",
|
|
ap->a_pid, sp->s_un.u_pctcpu, pmem(ap), vmsize, rmsize);
|
|
putchar(' ');
|
|
ptty(ap->a_tty);
|
|
printf(" %9.9s", state(ap));
|
|
if (ap->a_start == 0)
|
|
ap->a_start = boottime.tv_sec;
|
|
cp = ctime(&ap->a_start);
|
|
if ((now - ap->a_start) > 60*60*24)
|
|
printf("%.7s", cp+3);
|
|
else
|
|
printf("%.6s ", cp+10);
|
|
ptime(ap);
|
|
}
|
|
|
|
/*
|
|
* Removed 9 columns by zapping the (meaningless in SunOS 4.0) TSIZ and TRS
|
|
* fields. Consider using this space to widen currently-cramped columns.
|
|
*/
|
|
char *vhdr =
|
|
" PID TT STAT CPU TIME SL RE PAGEIN SIZE RSS LIM %CPU %MEM";
|
|
vpr(sp)
|
|
struct savcom *sp;
|
|
{
|
|
register struct vsav *vp = sp->s_un.vp;
|
|
register struct asav *ap = sp->ap;
|
|
|
|
printf("%5u ", ap->a_pid);
|
|
ptty(ap->a_tty);
|
|
printf(" %9.9s", state(ap));
|
|
ptime(ap);
|
|
printf("%3d%3d%7d%5d%5d",
|
|
ap->a_slptime > 99 ? 99 : ap-> a_slptime,
|
|
ap->a_time > 99 ? 99 : ap->a_time, vp->v_majflt,
|
|
pgtok(ap->a_size), pgtok(ap->a_rss));
|
|
if (ap->a_maxrss == (RLIM_INFINITY/NBPG))
|
|
printf(" xx");
|
|
else
|
|
printf("%6d", pgtok(ap->a_maxrss));
|
|
printf("%5.1f%5.1f", vp->v_pctcpu, pmem(ap));
|
|
}
|
|
|
|
char *shdr =
|
|
" PID TT STAT CPU TIME";
|
|
spr(sp)
|
|
struct savcom *sp;
|
|
{
|
|
register struct asav *ap = sp->ap;
|
|
|
|
printf("%5u", ap->a_pid);
|
|
putchar(' ');
|
|
ptty(ap->a_tty);
|
|
printf(" %9.9s", state(ap));
|
|
ptime(ap);
|
|
}
|
|
|
|
char *
|
|
state(ap)
|
|
register struct asav *ap;
|
|
{
|
|
char stat, load, nice, anom;
|
|
register i;
|
|
static char res[6+NCPU];
|
|
|
|
switch (ap->a_stat) {
|
|
|
|
case SSTOP:
|
|
stat = 'T';
|
|
break;
|
|
|
|
case SSLEEP:
|
|
if (ap->a_pri >= PZERO)
|
|
if (ap->a_slptime >= MAXSLP)
|
|
stat = 'I';
|
|
else
|
|
stat = 'S';
|
|
else if (ap->a_flag & SPAGE)
|
|
stat = 'P';
|
|
else
|
|
stat = 'D';
|
|
break;
|
|
|
|
case SWAIT:
|
|
case SRUN:
|
|
case SIDL:
|
|
stat = 'R';
|
|
break;
|
|
|
|
case SZOMB:
|
|
stat = 'Z';
|
|
break;
|
|
|
|
default:
|
|
stat = '?';
|
|
}
|
|
load = ap->a_flag & SLOAD ? (ap->a_rss>ap->a_maxrss ? '>' : ' ') : 'W';
|
|
if (ap->a_nice < NZERO)
|
|
nice = '<';
|
|
else if (ap->a_nice > NZERO)
|
|
nice = 'N';
|
|
else
|
|
nice = ' ';
|
|
anom = (ap->a_flag&SUANOM) ? 'A' : ((ap->a_flag&SSEQL) ? 'S' : ' ');
|
|
res[0] = stat; res[1] = load; res[2] = nice; res[3] = anom;
|
|
|
|
res[4] = ' ';
|
|
res[5] = '0' + (ap->a_cpuid & 0xff);
|
|
res[6] = 0;
|
|
return (res);
|
|
}
|
|
|
|
|
|
pscomp(s1, s2)
|
|
struct savcom *s1, *s2;
|
|
{
|
|
register int i;
|
|
|
|
if (uflg)
|
|
return (s2->s_un.u_pctcpu > s1->s_un.u_pctcpu ? 1 : -1);
|
|
if (vflg)
|
|
return (vsize(s2) - vsize(s1));
|
|
i = s1->ap->a_ttyd - s2->ap->a_ttyd;
|
|
if (i == 0)
|
|
i = s1->ap->a_pid - s2->ap->a_pid;
|
|
return (i);
|
|
}
|
|
|
|
vsize(sp)
|
|
struct savcom *sp;
|
|
{
|
|
register struct asav *ap = sp->ap;
|
|
register struct vsav *vp = sp->s_un.vp;
|
|
|
|
if (ap->a_flag & SLOAD)
|
|
return (ap->a_rss);
|
|
return (vp->v_swrss);
|
|
}
|
|
|
|
#include <utmp.h>
|
|
|
|
struct utmp utmp;
|
|
#define NMAX (sizeof (utmp.ut_name))
|
|
#define SCPYN(a, b) strncpy(a, b, NMAX)
|
|
|
|
#define NUID 64
|
|
|
|
struct ncache {
|
|
int uid;
|
|
char name[NMAX+1];
|
|
} nc[NUID];
|
|
|
|
/*
|
|
* This function assumes that the password file is hashed
|
|
* (or some such) to allow fast access based on a uid key.
|
|
*/
|
|
char *
|
|
getname(uid)
|
|
{
|
|
register struct passwd *pw;
|
|
struct passwd *getpwent();
|
|
register int cp;
|
|
|
|
#if (((NUID) & ((NUID) - 1)) != 0)
|
|
cp = uid % (NUID);
|
|
#else
|
|
cp = uid & ((NUID) - 1);
|
|
#endif
|
|
if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0])
|
|
return (nc[cp].name);
|
|
pw = getpwuid(uid);
|
|
if (!pw)
|
|
return (0);
|
|
nc[cp].uid = uid;
|
|
SCPYN(nc[cp].name, pw->pw_name);
|
|
return (nc[cp].name);
|
|
}
|
|
|
|
char *
|
|
savestr(cp)
|
|
char *cp;
|
|
{
|
|
register unsigned len;
|
|
register char *dp;
|
|
|
|
len = strlen(cp);
|
|
dp = (char *)calloc(len+1, sizeof (char));
|
|
if (dp == NULL) {
|
|
fprintf(stderr, "ps: savestr: out of memory\n");
|
|
exit(1);
|
|
}
|
|
(void) strcpy(dp, cp);
|
|
return (dp);
|
|
}
|
|
|
|
/*
|
|
* since we can't init unions, the cleanest way to use a.out.h instead
|
|
* of nlist.h (required since nlist() uses some defines) is to do a
|
|
* runtime copy into the nl array -- sigh
|
|
*/
|
|
init_nlist()
|
|
{
|
|
register struct nlist *np;
|
|
register char **namep;
|
|
|
|
nllen = sizeof nl_names / sizeof (char *);
|
|
np = nl = (struct nlist *) malloc(nllen * sizeof (struct nlist));
|
|
if (np == NULL) {
|
|
fprintf(stderr, "ps: out of memory allocating namelist\n");
|
|
exit(1);
|
|
}
|
|
namep = &nl_names[0];
|
|
while (nllen > 0) {
|
|
np->n_un.n_name = *namep;
|
|
if (**namep == '\0')
|
|
break;
|
|
namep++;
|
|
np++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* nlist - retreive attributes from name list (string table version)
|
|
* [The actual work is done in _nlist.c]
|
|
*/
|
|
nlist(name, list)
|
|
char *name;
|
|
struct nlist *list;
|
|
{
|
|
register int fd;
|
|
register int e;
|
|
|
|
fd = open(name, O_RDONLY, 0);
|
|
e = _nlist(fd, list);
|
|
close(fd);
|
|
return (e);
|
|
}
|
|
|
|
/*
|
|
* _nlist - retreive attributes from name list (string table version)
|
|
* modified to add wait channels - Charles R. LaBrec 8/85
|
|
*/
|
|
_nlist(fd, list)
|
|
int fd;
|
|
struct nlist *list;
|
|
{
|
|
register struct nlist *p, *q;
|
|
register int soff;
|
|
register int stroff = 0;
|
|
register n, m;
|
|
int maxlen, nreq;
|
|
off_t sa; /* symbol address */
|
|
off_t ss; /* start of strings */
|
|
int type;
|
|
struct exec buf;
|
|
struct nlist space[BUFSIZ/sizeof (struct nlist)];
|
|
char strs[BUFSIZ];
|
|
|
|
maxlen = 0;
|
|
for (q = list, nreq = 0; q->n_un.n_name && q->n_un.n_name[0]; q++, nreq++) {
|
|
q->n_type = 0;
|
|
q->n_value = 0;
|
|
q->n_desc = 0;
|
|
q->n_other = 0;
|
|
n = strlen(q->n_un.n_name);
|
|
if (n > maxlen)
|
|
maxlen = n;
|
|
}
|
|
if ((fd == -1) || (lseek(fd, 0L, 0) == -1) ||
|
|
(read(fd, (char*)&buf, sizeof buf) != sizeof buf) || N_BADMAG(buf))
|
|
return (-1);
|
|
sa = N_SYMOFF(buf);
|
|
ss = sa + buf.a_syms;
|
|
n = buf.a_syms;
|
|
while (n) {
|
|
m = MIN(n, sizeof (space));
|
|
lseek(fd, sa, 0);
|
|
if (read(fd, (char *)space, m) != m)
|
|
break;
|
|
sa += m;
|
|
n -= m;
|
|
for (q = space; (m -= sizeof(struct nlist)) >= 0; q++) {
|
|
soff = q->n_un.n_strx;
|
|
if (soff == 0 || q->n_type & N_STAB)
|
|
continue;
|
|
/*
|
|
* since we know what type of symbols we will get,
|
|
* we can make a quick check here -- crl
|
|
*/
|
|
type = q->n_type & (N_TYPE | N_EXT);
|
|
if ((q->n_type & N_TYPE) != N_ABS
|
|
&& type != (N_EXT | N_DATA)
|
|
&& type != (N_EXT | N_BSS))
|
|
continue;
|
|
|
|
if ((soff + maxlen + 1) >= stroff) {
|
|
/*
|
|
* Read strings into local cache.
|
|
* Assumes (maxlen < sizeof (strs)).
|
|
*/
|
|
lseek(fd, ss+soff, 0);
|
|
read(fd, strs, sizeof strs);
|
|
stroff = soff + sizeof (strs);
|
|
}
|
|
/* if using wchans, add it to the list of channels */
|
|
if (!nflg && !gotwchans)
|
|
addchan(&strs[soff-(stroff-sizeof (strs))+1],
|
|
(caddr_t) q->n_value);
|
|
for (p = list; p->n_un.n_name && p->n_un.n_name[0]; p++) {
|
|
if (p->n_type == 0 &&
|
|
strcmp(p->n_un.n_name,
|
|
&strs[soff-(stroff-sizeof (strs))]) == 0) {
|
|
p->n_value = q->n_value;
|
|
p->n_type = q->n_type;
|
|
p->n_desc = q->n_desc;
|
|
p->n_other = q->n_other;
|
|
if (--nreq == 0 && (nflg || gotwchans))
|
|
goto alldone;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
alldone:
|
|
return (nreq);
|
|
}
|
|
|
|
/*
|
|
* add the given channel to the channel list
|
|
*/
|
|
addchan(name, caddr)
|
|
char *name;
|
|
caddr_t caddr;
|
|
{
|
|
static int left = 0;
|
|
register struct wchan *wp;
|
|
register char **p;
|
|
register struct wchan_map *mp;
|
|
|
|
for (p = wchan_stop_list; *p; p++) {
|
|
if (**p != *name) /* quick check first */
|
|
continue;
|
|
if (strncmp(name, *p, WNAMESIZ) == 0)
|
|
return; /* if found, don't add */
|
|
}
|
|
for (mp = wchan_map_list; mp->map_from; mp++) {
|
|
if (*(mp->map_from) != *name) /* quick check first */
|
|
continue;
|
|
if (strncmp(name, mp->map_from, WNAMESIZ) == 0)
|
|
name = mp->map_to; /* if found, remap */
|
|
}
|
|
if (left == 0) {
|
|
if (wchanhd) {
|
|
left = 100;
|
|
wchanhd = (struct wchan *) realloc(wchanhd,
|
|
(nchans + left) * sizeof (struct wchan));
|
|
} else {
|
|
left = 600;
|
|
wchanhd = (struct wchan *) malloc(left
|
|
* sizeof (struct wchan));
|
|
}
|
|
if (wchanhd == NULL) {
|
|
fprintf(stderr, "ps: out of memory allocating wait channels\n");
|
|
nflg++;
|
|
return;
|
|
}
|
|
}
|
|
left--;
|
|
wp = &wchanhd[nchans++];
|
|
strncpy(wp->wc_name, name, WNAMESIZ);
|
|
wp->wc_name[WNAMESIZ] = '\0';
|
|
wp->wc_caddr = caddr;
|
|
}
|
|
|
|
/*
|
|
* returns the symbolic wait channel corresponding to chan
|
|
*/
|
|
char *
|
|
getchan(chan)
|
|
register caddr_t chan;
|
|
{
|
|
register i, iend;
|
|
register char *prevsym;
|
|
register struct wchan *wp;
|
|
|
|
prevsym = "???"; /* nothing, to begin with */
|
|
if (chan) {
|
|
for (i = 0; i < NWCINDEX; i++)
|
|
if ((unsigned) chan < (unsigned) wchan_index[i])
|
|
break;
|
|
iend = i--;
|
|
if (i < 0) /* can't be found */
|
|
return prevsym;
|
|
iend *= nchans;
|
|
iend /= NWCINDEX;
|
|
i *= nchans;
|
|
i /= NWCINDEX;
|
|
wp = &wchanhd[i];
|
|
for ( ; i < iend; i++, wp++) {
|
|
if ((unsigned) wp->wc_caddr > (unsigned) chan)
|
|
break;
|
|
prevsym = wp->wc_name;
|
|
}
|
|
}
|
|
return prevsym;
|
|
}
|
|
|
|
/*
|
|
* used in sorting the wait channel array
|
|
*/
|
|
int
|
|
wchancomp (w1, w2)
|
|
struct wchan *w1, *w2;
|
|
{
|
|
register unsigned c1, c2;
|
|
|
|
c1 = (unsigned) w1->wc_caddr;
|
|
c2 = (unsigned) w2->wc_caddr;
|
|
if (c1 > c2)
|
|
return 1;
|
|
else if (c1 == c2)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
usage()
|
|
{
|
|
fprintf(stderr, "ps: usage: ps [-acCegjklnrStuvwxU] [num] [kernel_name] [c_dump_file] [swap_file]\n");
|
|
}
|