2.11BSD/src/bin/ps.c
/*
* 1999/8/11 - Remove reference to SDETACH. It was removed from the kernel
* (finally) because it was not needed.
*
* 1997/12/16 - Fix coredump when processing -U.
*
* 1996/11/16 - Move 'psdatabase' in /var/run.
*
* 12/20/94 - Missing casts caused errors in reporting on swapped
* processes - sms
* 1/7/93 - Heavily revised when the symbol table format changed - sms
*
* ps - process status
* Usage: ps [ acgklnrtuwxU# ] [ corefile [ swapfile [ system ] ] ]
*/
#include <sys/param.h>
#include <stdio.h>
#include <pwd.h>
#include <a.out.h>
#include <ctype.h>
#include <string.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <utmp.h>
#include <OLD/psout.h>
#define within(x,y,z) (((unsigned)(x) >= (y)) && ((unsigned)(x) < (z)))
#define round(x,y) ((long) ((((long) (x) + (long) (y) - 1L) / (long) (y)) * (long) (y)))
struct nlist nl[4];
#define X_PROC 0
#define X_NPROC 1
#define X_HZ 2
/*
* This is no longer the size of a symbol's name, symbols can be much
* larger now. This define says how many characters of a symbol's name
* to save in the wait channel name. A new define has been created to
* limit the size of symbol string read from the string table.
*/
#define NNAMESIZ 8
#define MAXSYMLEN 32
struct proc *mproc, proc[8];
struct user u;
int hz;
int chkpid = 0;
char aflg; /* -a: all processes, not just mine */
char cflg; /* -c: not complete listing of args, just comm. */
char gflg; /* -g: complete listing including group headers, etc */
char kflg; /* -k: read from core file instead of real memory */
char lflg; /* -l: long listing form */
char nflg; /* -n: numeric wchans */
char rflg; /* -r: raw output in style <psout.h> */
char uflg; /* -u: user name */
char wflg; /* -w[w]: wide terminal */
char xflg; /* -x: ALL processes, even those without ttys */
char Uflg; /* -U: update the private list */
char *tptr, *mytty;
char *uname;
int file;
int nproc;
int nchans;
int nttys;
char *psdb = "/var/run/psdatabase";
int npr; /* number of processes found so far */
int twidth; /* terminal width */
int cmdstart; /* start position for command field */
char *memf; /* name of kernel memory file */
char *kmemf = "/dev/kmem"; /* name of physical memory file */
char *swapf; /* name of swap file to use */
char *nlistf; /* name of symbol table file to use */
int kmem, mem, swap;
/*
* Structure for the unix wchan table
*/
typedef struct wchan {
char cname[NNAMESIZ];
unsigned caddr;
} WCHAN;
WCHAN *wchand;
extern char *calloc(), *malloc(), *realloc(), *ttyname();
char *gettty(), *getptr(), *getchan();
int pscomp(), wchancomp();
extern off_t lseek();
/*
* 256 terminals was not only wasteful but unrealistic. For one thing
* 2.11BSD uses bit 7 of the minor device (for almost all terminal interfaces)
* to indicate direct/modem status - this means that 128 terminals is
* a better maximum number of terminals, for another thing the system can't
* support 256 terminals - other resources (memory, files, processes) will
* have been exhausted long ago. If 'ps' complains about too many terminals
* it is time to clean up /dev!
*/
#define MAXTTYS 160 /* 128 plus a few extra */
struct ttys {
char name[14]; /* MAXNAMLEN uses too much memory, besides */
/* device names tend to be very short */
dev_t ttyd;
} allttys[MAXTTYS];
struct map {
off_t b1, e1; off_t f1;
off_t b2, e2; off_t f2;
};
struct winsize ws;
struct map datmap;
struct psout *outargs; /* info for first npr processes */
main (argc, argv)
char **argv;
{
int uid, euid, puid, nread;
register int i, j;
char *ap;
register struct proc *procp;
/*
* Can't initialize unions and we need the macros from a.out.h, so the
* namelist is set up at run time.
*/
nl[X_PROC].n_un.n_name = "_proc";
nl[X_NPROC].n_un.n_name = "_nproc";
nl[X_HZ].n_un.n_name = "_hz";
if ((ioctl(fileno(stdout), TIOCGWINSZ, &ws) != -1 &&
ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 &&
ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) ||
ws.ws_col == 0)
twidth = 80;
else
twidth = ws.ws_col;
argc--, argv++;
if (argc > 0) {
ap = argv [0];
while (*ap) switch (*ap++) {
case '-':
break;
case 'a':
aflg++;
break;
case 'c':
cflg++;
break;
case 'g':
gflg++;
break;
case 'k':
kflg++;
break;
case 'l':
lflg = 1;
break;
case 'n':
nflg++;
lflg = 1;
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 = 1;
break;
case 'U':
Uflg++;
break;
case 'w':
if (wflg)
twidth = BUFSIZ;
else if (twidth < 132)
twidth = 132;
wflg++;
break;
case 'x':
xflg++;
break;
default:
if (!isdigit(ap[-1]))
break;
chkpid = atoi(--ap);
*ap = '\0';
aflg++;
xflg++;
break;
}
}
openfiles(argc, argv);
getkvars(argc, argv);
lseek(kmem,(off_t)nl[X_PROC].n_value,0);
uid = getuid();
euid = geteuid();
mytty = ttyname(0);
if (!strncmp(mytty,"/dev/",5)) mytty += 5;
if (!strncmp(mytty,"tty",3)) mytty += 3;
printhdr();
for (i = 0; i < nproc; i += 8) {
j = nproc - i;
if (j > 8)
j = 8;
j *= sizeof (struct proc);
if ((nread = read(kmem, (char *) proc, j)) != j) {
cantread("proc table", kmemf);
if (nread == -1)
break;
}
for (j = nread / sizeof (struct proc) - 1; j >= 0; j--) {
mproc = &proc[j];
procp = mproc;
/* skip processes that don't exist */
if (procp->p_stat == 0)
continue;
/* skip those without a tty unless -x */
if (procp->p_pgrp == 0 && xflg == 0)
continue;
/* skip group leaders on a tty unless -g, -x, or -t.. */
if (!tptr && !gflg && !xflg && procp->p_ppid == 1)
continue;
/* -g also skips those where **argv is "-" - see savcom */
puid = procp->p_uid;
/* skip other peoples processes unless -a or a specific pid */
if ((uid != puid && euid != puid && aflg == 0) ||
(chkpid != 0 && chkpid != procp->p_pid))
continue;
if (savcom(puid))
npr++;
}
}
fixup(npr);
for (i = 0; i < npr; i++) {
register int cmdwidth = twidth - cmdstart - 2;
register struct psout *a = &outargs[i];
if (rflg) {
if (write(1, (char *) a, sizeof (*a)) != sizeof (*a))
perror("write");
continue;
}
else if (lflg)
lpr(a);
else if (uflg)
upr(a);
else
spr(a);
if (cmdwidth < 0)
cmdwidth = 80 - cmdstart - 2;
if (a->o_stat == SZOMB)
printf("%.*s", cmdwidth, " <defunct>");
else if (a->o_pid == 0)
printf("%.*s", cmdwidth, " swapper");
else
printf(" %.*s", twidth - cmdstart - 2, cflg ? a->o_comm : a->o_args);
putchar('\n');
}
exit(!npr);
}
getdev()
{
register DIR *df;
register struct direct *dbuf;
if (chdir("/dev") < 0) {
perror("/dev");
exit(1);
}
if ((df = opendir(".")) == NULL) {
fprintf(stderr, "Can't open . in /dev\n");
exit(1);
}
while (dbuf = readdir(df))
maybetty(dbuf->d_name);
closedir(df);
}
/*
* 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(cp)
register char *cp;
{
register struct ttys *dp;
struct stat stb;
switch (cp[0]) {
case 'c':
if (!strcmp(cp, "console"))
break;
/* 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':
if (!strcmp(cp, "kUmem") || !strcmp(cp, "kmem"))
return;
if (!strcmp(cp, "klog"))
return;
break;
case 'r':
#define is(a,b) cp[1] == 'a' && cp[2] == 'b'
if (is(h,p) || is(r,a) || is(u,p) || is(h,k) || is(x,p)
|| is(r,b) || is(r,l) || is(m,t)) {
if (isdigit(cp[3]))
return;
}
break;
case 'm':
if (!strcmp("mem", cp))
return;
if (cp[1] == 't')
return;
break;
case 'n':
if (!strcmp(cp, "null"))
return;
if (!strncmp(cp, "nrmt", 4))
return;
break;
case 'p':
if (cp[1] == 't' && cp[2] == 'y')
return;
break;
}
if (nttys >= MAXTTYS) {
fprintf(stderr, "ps: tty table overflow\n");
exit(1);
}
dp = &allttys[nttys++];
(void)strcpy(dp->name, cp);
if (Uflg) {
if (stat(dp->name, &stb) == 0 &&
(stb.st_mode&S_IFMT)==S_IFCHR)
dp->ttyd = stb.st_rdev;
else {
nttys--;
return;
}
} else
dp->ttyd = -1;
}
savcom(puid)
{
char *tp;
off_t addr;
off_t daddr, saddr;
register struct psout *a;
register struct proc *procp = mproc;
register struct user *up = &u;
long txtsiz, datsiz, stksiz;
int septxt;
if (procp->p_flag & SLOAD) {
addr = ctob((off_t) procp->p_addr);
daddr = ctob((off_t) procp->p_daddr);
saddr = ctob((off_t) procp->p_saddr);
file = mem;
}
else {
addr = (off_t)procp->p_addr << 9;
daddr = (off_t)procp->p_daddr << 9;
saddr = (off_t)procp->p_saddr << 9;
file = swap;
}
lseek(file, addr, 0);
if (read(file, (char *) up, sizeof (u)) != sizeof (u))
return(0);
txtsiz = ctob(up->u_tsize); /* set up address maps for user pcs */
datsiz = ctob(up->u_dsize);
stksiz = ctob(up->u_ssize);
septxt = up->u_sep;
datmap.b1 = (septxt ? 0 : round(txtsiz, TXTRNDSIZ));
datmap.e1 = datmap.b1 + datsiz;
datmap.f1 = daddr;
datmap.f2 = saddr;
datmap.b2 = stackbas(stksiz);
datmap.e2 = stacktop(stksiz);
tp = gettty();
if ((tptr && strncmp(tptr,tp,2)) || (strncmp(mytty, tp, 2) && !aflg))
return(0);
a = &outargs[npr]; /* saving com starts here */
a->o_uid = puid;
a->o_pid = procp->p_pid;
a->o_flag = procp->p_flag;
a->o_ppid = procp->p_ppid;
a->o_cpu = procp->p_cpu;
a->o_pri = procp->p_pri;
a->o_nice = procp->p_nice;
a->o_addr0 = procp->p_addr;
a->o_size = ctod(procp->p_dsize + procp->p_ssize + USIZE);
a->o_wchan = procp->p_wchan;
a->o_pgrp = procp->p_pgrp;
strncpy(a->o_tty, tp, sizeof (a->o_tty));
a->o_ttyd = tp[0] == '?' ? -1 : up->u_ttyd;
a->o_stat = procp->p_stat;
a->o_flag = procp->p_flag;
if (a->o_stat == SZOMB)
return(1);
a->o_utime = up->u_ru.ru_utime;
a->o_stime = up->u_ru.ru_stime;
a->o_cutime = up->u_cru.ru_utime;
a->o_cstime = up->u_cru.ru_stime;
a->o_sigs = (int)up->u_signal[SIGINT] + (int)up->u_signal[SIGQUIT];
a->o_uname[0] = 0;
strncpy(a->o_comm, up->u_comm, MAXCOMLEN);
if (cflg)
return (1);
else
return(getcmd(a,saddr));
}
char *
gettty()
{
register int tty_step;
register char *p;
if (u.u_ttyp)
for (tty_step = 0;tty_step < nttys;++tty_step)
if (allttys[tty_step].ttyd == u.u_ttyd) {
p = allttys[tty_step].name;
if (!strncmp(p,"tty",3))
p += 3;
return(p);
}
return("?");
}
/*
* fixup figures out everybodys name and sorts into a nice order.
*/
fixup(np)
register int np;
{
register int i;
register struct passwd *pw;
if (uflg) {
/*
* If we want names, traverse the password file. For each
* passwd entry, look for it in the processes.
* In case of multiple entries in the password file we believe
* the first one (same thing ls does).
*/
while ((pw = getpwent()) != (struct passwd *) NULL) {
for (i = 0; i < np; i++)
if (outargs[i].o_uid == pw->pw_uid) {
if (outargs[i].o_uname[0] == 0)
strcpy(outargs[i].o_uname, pw->pw_name);
}
}
}
qsort(outargs, np, sizeof (outargs[0]), pscomp);
}
pscomp(x1, x2)
register struct psout *x1, *x2;
{
register int c;
c = (x1)->o_ttyd - (x2)->o_ttyd;
if (c == 0)
c = (x1)->o_pid - (x2)->o_pid;
return(c);
}
wchancomp(x1, x2)
register WCHAN *x1, *x2;
{
if (x1->caddr > x2->caddr)
return(1);
else if (x1->caddr == x2->caddr)
return(0);
else
return(-1);
}
char *
getptr(adr)
char **adr;
{
char *ptr = 0;
register char *p, *pa;
register int i;
pa = (char *)adr;
p = (char *)&ptr;
for (i = 0; i < sizeof (ptr); i++)
*p++ = getbyte(pa++);
return(ptr);
}
getbyte(adr)
register char *adr;
{
register struct map *amap = &datmap;
char b;
off_t saddr;
if (!within(adr, amap->b1, amap->e1))
if (within(adr, amap->b2, amap->e2))
saddr = (unsigned) adr + amap->f2 - amap->b2;
else return(0);
else saddr = (unsigned) adr + amap->f1 - amap->b1;
if (lseek(file, saddr, 0) == (off_t) -1 || read (file, &b, 1) < 1)
return(0);
return((unsigned) b);
}
addchan(name, caddr)
char *name;
unsigned caddr;
{
static int left = 0;
register WCHAN *wp;
if (left == 0)
{
if (wchand)
{
left = 50;
wchand = (WCHAN *)realloc(wchand, (nchans + left) *
sizeof (struct wchan));
}
else
{
left = 300;
wchand = (WCHAN *)malloc(left * sizeof (struct wchan));
}
if (!wchand)
{
fprintf(stderr, "ps: out of wait channel memory\n");
nflg++;
return;
}
}
wp = &wchand[nchans++];
left--;
strncpy(wp->cname, name, NNAMESIZ - 1);
wp->cname[NNAMESIZ-1] = '\0';
wp->caddr = caddr;
}
char *
getchan(chan)
register unsigned int chan;
{
register int i;
register char *prevsym;
prevsym = "";
if (chan)
for (i = 0; i < nchans; i++) {
if (wchand[i].caddr > chan)
return (prevsym);
prevsym = wchand[i].cname;
}
return(prevsym);
}
nlist()
{
register FILE *nlistf_fp;
FILE *strfp;
register struct nlist *nnn;
int flag, nsyms;
struct nlist nbuf;
struct xexec hbuf;
char name[MAXSYMLEN + 2];
int nllen;
off_t sa, stroff;
bzero(name, sizeof (name));
nllen = sizeof(nl) / sizeof(struct nlist);
if (!(nlistf_fp = fopen(nlistf,"r")))
perrexit(nlistf);
strfp = fopen(nlistf, "r");
if (fread(&hbuf,sizeof(hbuf),1,nlistf_fp) != 1)
{
fputs("Invalid symbol table\n",stderr);
exit(1);
}
if (N_BADMAG(hbuf.e))
{
fprintf(stderr,"%s: bad magic number\n",nlistf);
exit(1);
}
nsyms = hbuf.e.a_syms / sizeof (struct nlist);
if (nsyms == 0)
{
fprintf(stderr,"%s: no symbols\n",nlistf);
exit(1);
}
sa = N_SYMOFF(hbuf);
stroff = N_STROFF(hbuf);
fseek(nlistf_fp, sa, L_SET);
addchan("u", 0140000); /* XXX - see comment below */
while (nsyms--)
{
fread(&nbuf,sizeof(nbuf),1,nlistf_fp);
if ((nbuf.n_type & N_EXT) == 0)
continue;
flag = nbuf.n_type & N_TYPE;
/*
* Now read the symbol string. Can't rely on having enough memory to
* hold the entire string table, so we do a seek+read for each name. Luckily
* this is only done for global symbols, which cuts down the work done.
*/
fseek(strfp, nbuf.n_un.n_strx + stroff, L_SET);
fread(name, MAXSYMLEN, 1, strfp);
/*
* Skip over anything which isn't an external data or bss symbol.
* Advantage was taken of the facts that 1) 'ps' is highly machine
* dependent and 2) _u on a pdp-11 is not likely to change _ever_.
* The reason behind this is to avoid matching on absolute symbols created
* during the unix/netnix cross binding.
*/
if (!(flag == N_DATA || flag == N_BSS))
continue;
if (!nflg)
addchan(name + 1, nbuf.n_value);
if (nllen)
{
for (nnn = nl; nnn->n_un.n_name; nnn++)
{
if (!strcmp(nnn->n_un.n_name, name))
{
nnn->n_value = nbuf.n_value;
nnn->n_type = nbuf.n_type;
nnn->n_ovly = nbuf.n_ovly;
--nllen;
break;
}
}
}
}
fclose(nlistf_fp);
fclose(strfp);
if (!nflg)
qsort(wchand,nchans,sizeof(WCHAN),wchancomp);
}
perrexit(msg)
char *msg;
{
perror(msg);
exit(1);
}
writepsdb()
{
register FILE *fp;
int nllen;
setuid(getuid());
if (!(fp = fopen (psdb, "w")))
perrexit(psdb);
else
fchmod(fileno(fp),0644);
nllen = sizeof(nl) / sizeof(struct nlist);
fwrite(nlistf,strlen(nlistf) + 1,1,fp);
fwrite((char *)&nllen,sizeof(nllen),1,fp);
fwrite((char *)&nttys,sizeof(nttys),1,fp);
fwrite((char *)&nchans,sizeof(nchans),1,fp);
fwrite((char *)nl,sizeof(struct nlist),nllen,fp);
fwrite((char *)allttys,sizeof(struct ttys),nttys,fp);
fwrite((char *)wchand,sizeof(WCHAN),nchans,fp);
fclose(fp);
}
char *
readpsdb()
{
register int i;
register FILE *fp;
register WCHAN *ccc;
static char unamebuf[MAXPATHLEN + 1];
char *p = unamebuf;
int nllen;
if ((fp = fopen(psdb, "r")) == NULL)
perrexit(psdb);
while ((*p= getc(fp)) != '\0')
p++;
fread(&nllen, sizeof nllen, 1, fp);
fread(&nttys, sizeof nttys, 1, fp);
fread(&nchans, sizeof nchans, 1, fp);
fread(nl, sizeof (struct nlist), nllen, fp);
fread(allttys, sizeof (struct ttys), nttys, fp);
if (!nflg)
if (!(wchand = (WCHAN *)calloc(nchans, sizeof(WCHAN)))) {
fputs("Too many symbols\n",stderr);
exit(1);
}
else for (i = 0, ccc = wchand; i < nchans; i++) {
fread((char *) ccc, sizeof(WCHAN), 1, fp);
ccc++;
}
return(unamebuf);
}
openfiles(argc, argv)
char **argv;
{
if (kflg)
kmemf = argc > 1 ? argv[1] : "/usr/sys/core";
kmem = open(kmemf, 0);
if (kmem < 0)
perrexit(kmemf);
if (!kflg)
memf = "/dev/mem";
else
memf = kmemf;
mem = open(memf, 0);
if (mem < 0)
perrexit(memf);
swapf = argc > 2 ? argv[2] : "/dev/swap";
swap = open(swapf, 0);
if (swap < 0)
perrexit(swapf);
}
getkvars(argc,argv)
int argc;
char **argv;
{
struct stat st;
nlistf = argc > 3 ? argv[3] : "/unix";
if (Uflg) {
nlist();
getdev();
writepsdb();
exit(0);
}
else if (stat(psdb, &st) == 0) {
uname = readpsdb();
if (strcmp(uname,nlistf)) {
/*
* Let addchan() do the work.
*/
nchans = 0;
free((char *)wchand);
nlist();
}
}
else {
nlist();
getdev();
}
/* find number of procs */
if (nl[X_NPROC].n_value) {
lseek(kmem,(off_t)nl[X_NPROC].n_value,0);
if (read(kmem,(char *)&nproc,sizeof(nproc)) != sizeof(nproc)) {
perror(kmemf);
exit(1);
}
}
else {
fputs("nproc not in namelist\n",stderr);
exit(1);
}
outargs = (struct psout *)calloc(nproc, sizeof(struct psout));
if (!outargs) {
fputs("ps: not enough memory for saving info\n",stderr);
exit(1);
}
/* find value of hz */
lseek(kmem,(off_t)nl[X_HZ].n_value,0);
read(kmem,(char *)&hz,sizeof(hz));
}
char *uhdr = "USER PID NICE SZ TTY TIME";
upr(a)
register struct psout *a;
{
printf("%-8.8s%6u%4d%4d %-2.2s",a->o_uname,a->o_pid,a->o_nice,a->o_size,a->o_tty);
ptime(a);
}
char *shdr = " PID TTY TIME";
spr (a)
register struct psout *a;
{
printf("%6u %-2.2s",a->o_pid,a->o_tty);
ptime(a);
}
char *lhdr = " F S UID PID PPID CPU PRI NICE ADDR SZ WCHAN TTY TIME";
lpr(a)
register struct psout *a;
{
static char clist[] = "0SWRIZT";
printf("%3o %c%6u%6u%6u%4d%4d%4d%7o%4d",
0377 & a->o_flag,clist[a->o_stat],a->o_uid,a->o_pid,
a->o_ppid,a->o_cpu & 0377,a->o_pri,a->o_nice,a->o_addr0,a->o_size);
if (nflg)
if (a->o_wchan)
printf("%*.*o",NNAMESIZ, NNAMESIZ, a->o_wchan);
else
fputs(" ",stdout);
else
printf(" %-*.*s",NNAMESIZ, NNAMESIZ, getchan(a->o_wchan));
printf(" %-2.2s",a->o_tty);
ptime(a);
}
ptime(a)
struct psout *a;
{
time_t tm;
tm = (a->o_utime + a->o_stime + 30) / hz;
printf("%3ld:",tm / 60);
tm %= 60;
printf(tm < 10 ? "0%ld" : "%ld",tm);
}
getcmd(a,addr)
off_t addr;
register struct psout *a;
{
/* amount of top of stack to examine for args */
#define ARGLIST (1024/sizeof(int))
register int *ip;
register char *cp, *cp1;
char c, **ap;
int cc, nbad, abuf [ARGLIST];
a->o_args[0] = 0; /* in case of early return */
addr += ctob((off_t) mproc->p_ssize) - ARGLIST*sizeof(int);
/* look for sh special */
lseek(file, addr + ARGLIST*sizeof(int) - sizeof (char **), 0);
if (read(file, (char *) &ap, sizeof (char *)) != sizeof (char *))
return (1);
if (ap) {
char b[82];
char *bp = b;
while ((cp = getptr(ap++)) && cp && (bp < b+sizeof (a->o_args)) ) {
nbad = 0;
while ((c = getbyte(cp++)) && (bp < b+sizeof (a->o_args))) {
if (c<' ' || c > '~') {
if (nbad++ > 3)
break;
continue;
}
*bp++ = c;
}
*bp++ = ' ';
}
*bp++ = 0;
(void)strcpy(a->o_args, b);
return(1);
}
lseek(file, addr, 0);
if (read(file, (char *) abuf, sizeof (abuf)) != sizeof (abuf))
return (1);
abuf[ARGLIST-1] = 0;
for (ip = &abuf[ARGLIST-2]; ip > abuf;) {
if (*--ip == -1 || *ip == 0) {
cp = (char *) (ip + 1);
if (*cp == '\0')
cp++;
nbad = 0;
for (cp1 = cp; cp1 < (char *) &abuf[ARGLIST]; cp1++) {
cc = *cp1 & 0177;
if (cc == 0)
*cp1 = ' ';
else if (cc < ' ' || cc > 0176) {
if (++nbad >= 5) {
*cp1++ = ' ';
break;
}
*cp1 = '?';
} else if (cc == '=') {
*cp1 = '\0';
while (cp1 > cp && *--cp1 != ' ')
*cp1 = '\0';
break;
}
}
while (*--cp1 == ' ')
*cp1 = 0;
(void)strcpy(a->o_args, cp);
garbage:
cp = a->o_args;
if (cp[0] == '-' && cp[1] <= ' ' || cp[0] == '?' || cp[0] <= ' ') {
strcat(cp, " (");
strcat(cp, u.u_comm);
strcat(cp, ")");
}
cp[63] = 0; /* max room in psout is 64 chars */
if (xflg || gflg || tptr || cp[0] != '-')
return(1);
return(0);
}
}
goto garbage;
}
printhdr()
{
register char *hdr, *cmdstr = " COMMAND";
if (rflg)
return;
if (lflg && uflg) {
fputs("ps: specify only one of l and u.\n",stderr);
exit(1);
}
hdr = lflg ? lhdr : (uflg ? uhdr : shdr);
fputs(hdr,stdout);
cmdstart = strlen(hdr);
if (cmdstart + strlen(cmdstr) >= twidth)
cmdstr = " CMD";
printf("%s\n", cmdstr);
fflush(stdout);
}
cantread(what, fromwhat)
char *what, *fromwhat;
{
fprintf(stderr, "ps: error reading %s from %s\n", what, fromwhat);
}