BSD 3 development
[unix-history] / usr / src / cmd / ps.c
CommitLineData
1ee1e8e9
BJ
1/*
2 * ps - process status
3 * This is the augmented UCB ps for UCB/VM Unix (9/79)
4 * examine and print certain things about processes
5 * usage: ps [acgklrt#uvwx] [corefile] [swapfile] [system]
6 */
7
8#include <stdio.h>
9#include <a.out.h>
10#include <pwd.h>
11#include <sys/param.h>
12#include <sys/proc.h>
13#include <sys/tty.h>
14#include <sys/dir.h>
15#include <sys/user.h>
16#include <sys/pte.h>
17#include <sys/vm.h>
18#include <sys/text.h>
19#include <psout.h>
20
21struct nlist nl[] = {
22 { "_proc" },
23#define X_PROC 0
24 { "_swapdev" },
25#define X_SWAPDEV 1
26 { "_swplo" },
27#define X_SWPLO 2
28 { "_Usrptma" },
29#define X_USRPTMA 3
30 { "_usrpt" },
31#define X_USRPT 4
32 { "_text" },
33#define X_TEXT 5
34 { "_nswap" },
35#define X_NSWAP 6
36 { 0 },
37};
38
39struct proc mproc;
40struct text text[NTEXT];
41
42#define INTPPG (NBPG/sizeof(int)) /* ints per page */
43union {
44 struct user yy;
45 int xx[INTPPG][UPAGES];
46 } zz;
47#define clear(x) ((int)x & 0x7fffffff)
48#define u zz.yy
49int chkpid = 0;
50int aflg; /* -a: all processes, not just mine */
51int cflg; /* -c: complete listing of args, not just comm. */
52int gflg; /* -g: complete listing including group headers, etc */
53int kflg; /* -k: read from core file instead of real memory */
54int lflg; /* -l: long listing form */
55int rflg; /* -r: raw output in style <psout.h> */
56int sflg; /* -s: stack depth */
57int uflg; /* -u: user name */
58int vflg; /* -v: virtual memory statistics */
59int wflg; /* -w[w]: wide terminal */
60int xflg; /* -x: ALL processes, even those without ttys */
61int login; /* -: this is a login shell */
62char *tptr;
63char *gettty();
64int pscomp();
65struct pte pagetbl[NPTEPG];
66int kmem;
67int mem;
68int swap;
69daddr_t swplo;
70int nswap;
71int Usrptma;
72int usrpt;
73
74int ndev;
75struct devl {
76 char dname[DIRSIZ];
77 dev_t dev;
78} devl[256];
79
80struct psout outargs[NPROC]; /* info for first npr processes */
81int npr; /* number of processes found so far */
82int argwidth; /* number of chars of args to print */
83
84char *coref;
85
86main(argc, argv)
87char **argv;
88{
89 int i;
90 char *ap;
91 int uid, puid;
92 char obuf[BUFSIZ];
93 register struct nlist *nlp;
94
95 setbuf(stdout, obuf);
96 argc--, argv++;
97 if (argc>0) {
98 ap = argv[0];
99 while (*ap) switch (*ap++) {
100 case '-':
101 break;
102
103 case 'a':
104 aflg++;
105 break;
106
107 case 'c':
108 cflg++;
109 break;
110
111 case 'g':
112 gflg++;
113 break;
114
115 case 'k':
116 kflg++;
117 break;
118
119 case 'l':
120 lflg++;
121 break;
122
123 case 'r':
124 rflg++;
125 break;
126
127 case 's':
128 sflg++;
129 break;
130
131 case 't':
132 if(*ap)
133 tptr = ap;
134 aflg++;
135 gflg++;
136 if (*tptr == '?')
137 xflg++;
138 while (*ap)
139 ap++;
140 break;
141
142 case 'u':
143 uflg++;
144 break;
145
146 case 'v':
147 vflg++;
148 break;
149
150 case 'w':
151 wflg++;
152 break;
153
154 case 'x':
155 xflg++;
156 break;
157
158 default:
159 chkpid=atoi(--ap);
160 *ap = '\0';
161 aflg++;
162 xflg++;
163 break;
164 }
165 }
166 coref = "/dev/kmem";
167 if(kflg)
168 coref = argc > 1 ? argv[1] : "/vmcore";
169
170 if ((kmem = open(coref, 0)) < 0) {
171 perror(coref);
172 done(1);
173 }
174 if ((mem = open("/dev/mem", 0)) < 0) {
175 fprintf(stderr, "No mem\n");
176 done(1);
177 }
178 if (kflg)
179 mem = kmem;
180
181 if ((swap = open(argc>2 ? argv[2]: "/dev/drum", 0)) < 0) {
182 fprintf(stderr, "Can't open /dev/drum\n");
183 done(1);
184 }
185
186 nlist(argc>3 ? argv[3] : "/vmunix", nl);
187 if (nl[0].n_type==0) {
188 fprintf(stderr, "No namelist\n");
189 done(1);
190 }
191
192 if(chdir("/dev") < 0) {
193 fprintf(stderr, "Can't change to /dev\n");
194 done(1);
195 }
196 if (kflg)
197 for (nlp= nl; nlp < &nl[sizeof (nl)/sizeof (nl[0])]; nlp++)
198 nlp->n_value &= 0x7ffffffff;
199 Usrptma = nl[X_USRPTMA].n_value;
200 usrpt = nl[X_USRPT].n_value;
201 /*
202 * read kmem to find swap dev.
203 */
204 lseek(kmem, (long)nl[X_SWAPDEV].n_value, 0);
205 read(kmem, &nl[X_SWAPDEV].n_value, sizeof(nl[X_SWAPDEV].n_value));
206 /*
207 * Find base and size of swap
208 */
209 lseek(kmem, (long)nl[X_SWPLO].n_value, 0);
210 read(kmem, &swplo, sizeof(swplo));
211 lseek(kmem, (long)nl[X_NSWAP].n_value, 0);
212 read(kmem, &nswap, sizeof (nswap));
213 /*
214 * If v flag get text table
215 */
216 if (vflg) {
217 lseek(kmem, (long)nl[X_TEXT].n_value, 0);
218 read(kmem, text, sizeof (text));
219 }
220 if (kflg)
221 swplo = 0;
222 getdev();
223 uid = getuid();
224 if (sflg + lflg + vflg + uflg > 1) {
225 printf("Cannot combine s, l, v, and/or u.\n");
226 exit(1);
227 }
228 /* different psout widths depending on how much printed & w flag */
229 if (wflg <= 1) {
230 argwidth = 63;
231 if (wflg) argwidth += 52; /* 132 col term */
232 if (lflg) argwidth -= 49; /* extra junk printed */
233 if (vflg) argwidth -= 48; /* extra junk for -v */
234 if (sflg) argwidth -= 4; /* 4 cols of stack size */
235 if (uflg) argwidth -= 27; /* user name */
236 } else argwidth = 127;
237 if (rflg)
238 ; /* No heading for raw output */
239 else if (lflg)
240 printf(" F S UID PID PPID CPU PRI NICE ADDR SZ RSS WCHAN TTY TIME COMMAND\n");
241 else if (vflg)
242 printf("F PID TT TIME TIM SL MINFLT MAJFLT SIZE RSS SRS TSIZ TRS PF COMMAND\n");
243 else if (uflg)
244 printf("USER PID %%CPU NICE SZ RSS TTY TIME COMMAND\n");
245 else if (chkpid==0) {
246 if (sflg)
247 printf(" SSIZ");
248 printf(" PID TTY TIME COMMAND\n");
249 }
250 fflush(stdout);
251 for (i=0; i<NPROC; i++) {
252 lseek(kmem, (long)(nl[X_PROC].n_value+i*(sizeof mproc)), 0);
253 read(kmem, &mproc, sizeof mproc);
254 /* skip processes that don't exist */
255 if (mproc.p_stat==0)
256 continue;
257 /* skip those without a tty unless -x */
258 if (mproc.p_pgrp==0 && xflg==0)
259 continue;
260 /* skip group leaders on a tty unless -g, -x, or -t.. */
261 if (!gflg && !xflg && !tptr && mproc.p_pid == mproc.p_pgrp)
262 continue;
263 /* -g also skips those where **argv is "-" - see savcom */
264 puid = mproc.p_uid;
265 /* skip other peoples processes unless -a or a specific pid */
266 if ((uid != puid && aflg==0) ||
267 (chkpid!=0 && chkpid!=mproc.p_pid))
268 continue;
269 if (savcom(puid))
270 npr++;
271 }
272 fixup(npr);
273 for (i=0; i<npr; i++)
274 if (prcom(&outargs[i])) {
275 putchar('\n');
276 fflush(stdout);
277 }
278 done(!npr);
279}
280
281getdev()
282{
283#include <sys/stat.h>
284 register FILE *df;
285 struct stat sbuf;
286 struct direct dbuf;
287
288 if ((df = fopen("/dev", "r")) == NULL) {
289 fprintf(stderr, "Can't open /dev\n");
290 done(1);
291 }
292 ndev = 0;
293 while (fread(&dbuf, sizeof(dbuf), 1, df) == 1) {
294 if(dbuf.d_ino == 0)
295 continue;
296 if(stat(dbuf.d_name, &sbuf) < 0)
297 continue;
298 if ((sbuf.st_mode&S_IFMT) != S_IFCHR)
299 continue;
300 strcpy(devl[ndev].dname, dbuf.d_name);
301 devl[ndev].dev = sbuf.st_rdev;
302 ndev++;
303 }
304 fclose(df);
305}
306
307savcom(puid)
308{
309 int abuf[INTPPG];
310 long addr;
311 register int *ip;
312 register struct psout *a;
313 register char *cp, *cp1;
314 long tm;
315 int cc, nbad;
316 int szpt, p0br;
317 register char *tp;
318 struct dblock db;
319 struct pte apte;
320
321 /* skip long sleeping or dead processes if -v unless -g or -x */
322 if (!gflg && vflg && !xflg) {
323 switch (mproc.p_stat) {
324
325 case SSLEEP:
326 case SSTOP:
327 if (mproc.p_slptime > MAXSLP)
328 return (0);
329 break;
330
331 case SRUN:
332 case SIDL:
333 break;
334
335 case SZOMB:
336 return (0);
337 }
338 }
339 /* read in the user structure */
340 if ((mproc.p_flag& SLOAD ) == 0) {
341 /* not loaded - get from swap */
342 addr = (mproc.p_swaddr+swplo)<<9;
343 lseek(swap, addr, 0);
344 if (read(swap, &u, sizeof(u)) != sizeof(u))
345 return(0);
346 } else {
347 /* loaded, get each page from memory separately */
348 for(cc=0; cc<UPAGES; cc++) { /* get u area */
349 int upage = ctob(mproc.p_addr[cc]);
350 lseek(mem,upage,0);
351 if (read(mem,((int *)&u)+INTPPG*cc,NBPG) != NBPG)
352 return(0);
353 }
354 }
355 tp = gettty();
356 if (tptr && strcmpn(tptr, tp, 2))
357 return(0);
358 a = &outargs[npr];
359 /* saving com starts here */
360 a->o_uid = puid;
361 a->o_pid = mproc.p_pid;
362 a->o_flag = mproc.p_flag;
363 a->o_ppid = mproc.p_ppid;
364 a->o_cpu = mproc.p_cpu;
365 a->o_pctcpu = 0.0; /* This needs to be fixed later */
366 a->o_pri = mproc.p_pri;
367 a->o_nice = mproc.p_nice;
368 a->o_addr0 = mproc.p_addr[0];
369 a->o_dsize = mproc.p_dsize;
370 a->o_ssize = mproc.p_ssize;
371 a->o_rssize = mproc.p_rssize;
372 a->o_swrss = mproc.p_swrss;
373 a->o_wchan = mproc.p_wchan;
374 a->o_pgrp = mproc.p_pgrp;
375 a->o_tty[0] = tp[0];
376 a->o_tty[1] = tp[1] ? tp[1] : ' ';
377 a->o_ttyd = u.u_ttyd;
378 a->o_stat = mproc.p_stat;
379 a->o_flag = mproc.p_flag;
380 if (a->o_stat==SZOMB) return(1);
381 a->o_utime = u.u_utime;
382 a->o_stime = u.u_stime;
383 a->o_cutime = u.u_cutime;
384 a->o_cstime = u.u_cstime;
385 a->o_sigs = u.u_signal[SIGINT] + u.u_signal[SIGQUIT];
386 a->o_time = mproc.p_time;
387 a->o_slptime = mproc.p_slptime;
388 a->o_uname[0] = 0;
389 if (sflg) {
390 for (cp = (char *)u.u_stack; cp < (char *)&u + ctob(UPAGES); cp++)
391 if (*cp)
392 break;
393 a->o_stksize = (int) ((char *)&u + ctob(UPAGES) - cp);
394 }
395 if (mproc.p_stat==SZOMB) return(1);
396 if (vflg) {
397 register struct text *xp;
398
399 if (mproc.p_textp) {
400 xp = &text[mproc.p_textp - (struct text *)nl[5].n_value];
401 a->o_xsize = xp->x_size;
402 a->o_xrssize = xp->x_rssize;
403 } else {
404 a->o_xsize = 0;
405 a->o_xrssize = 0;
406 }
407 a->o_aveflt = mproc.p_aveflt;
408 a->o_minorflt = u.u_minorflt;
409 a->o_majorflt = u.u_majorflt;
410 }
411 strcpy(a->o_comm, u.u_comm);
412 if (cflg)
413 return (1);
414 a->o_args[0] = 0; /* in case of early return */
415 if ((mproc.p_flag & SLOAD) == 0) {
416 vstodb(0, 1, &u.u_smap, &db, 1);
417 addr = ctob(swplo + db.db_base);
418 lseek(swap, addr, 0);
419 if (read(swap, abuf, sizeof(abuf)) != sizeof(abuf))
420 goto garbage;
421 } else {
422 szpt = u.u_pcb.pcb_szpt;
423 p0br = kflg ? clear((int)mproc.p_p0br) : (int)mproc.p_p0br;
424 cc = Usrptma + (p0br + NBPG*(szpt-1) - usrpt)/NPTEPG;
425 lseek(kmem, cc, 0);
426 if (read(kmem, &apte, sizeof(apte)) != sizeof(apte))
427 goto garbage;
428 lseek(mem, ctob(apte.pg_pfnum), 0);
429 if (read(mem,pagetbl,sizeof(pagetbl)) != sizeof(pagetbl))
430 goto garbage;
431 if (pagetbl[NPTEPG-1].pg_fod == 0 && pagetbl[NPTEPG-1].pg_pfnum) {
432 lseek(mem,ctob((pagetbl[NPTEPG-1].pg_pfnum)),0);
433 if (read(mem,abuf,sizeof(abuf)) != sizeof(abuf))
434 goto garbage;
435 } else {
436 vstodb(0, 1, &u.u_smap, &db, 1);
437 addr = ctob(swplo + db.db_base);
438 lseek(swap, addr, 0);
439 if (read(swap, abuf, sizeof(abuf)) != sizeof(abuf))
440 goto garbage;
441 }
442 }
443 abuf[INTPPG] = 0;
444 for (ip = &abuf[INTPPG-2]; ip > abuf;) {
445 if (*--ip == -1 || *ip == 0) {
446 cp = (char *)(ip+1);
447 if (*cp==0)
448 cp++;
449 nbad = 0;
450 for (cp1 = cp; cp1 < (char *)&abuf[INTPPG]; cp1++) {
451 cc = *cp1&0177;
452 if (cc==0)
453 *cp1 = ' ';
454 else if (cc < ' ' || cc > 0176) {
455 if (++nbad >= 5) {
456 *cp1++ = ' ';
457 break;
458 }
459 *cp1 = '?';
460 } else if (cc=='=') {
461 *cp1 = 0;
462 while (cp1>cp && *--cp1!=' ')
463 *cp1 = 0;
464 break;
465 }
466 }
467 while (*--cp1==' ')
468 *cp1 = 0;
469 strcpy(a->o_args, cp);
470garbage:
471 cp = a->o_args;
472 if (cp[0]=='-'&&cp[1]<=' ' || cp[0]=='?' || cp[0]<=' ') {
473 strcat(cp, " (");
474 strcat(cp, u.u_comm);
475 strcat(cp, ")");
476 }
477 cp[127] = 0; /* max room in psout is 128 chars */
478 if (xflg || gflg || tptr || cp[0]!='-')
479 return(1);
480 return(0);
481 }
482 }
483 goto garbage;
484}
485
486prcom(a)
487 register struct psout *a;
488{
489 long tm;
490
491 if (rflg) {
492 write(1, a, sizeof (*a));
493 return(0);
494 }
495 if (lflg) {
496 printf("%4x %c", 0xffff & a->o_flag,
497 "0SWRIZT"[a->o_stat]);
498 printf("%4d", a->o_uid);
499 } else if (vflg) {
500 switch (a->o_stat) {
501
502 case SSLEEP:
503 case SSTOP:
504 if ((a->o_flag & SLOAD) == 0)
505 printf("W");
506 else if (a->o_pri >= PZERO)
507 printf("S");
508 else if (a->o_flag & SPAGE)
509 printf("P");
510 else
511 printf("D");
512 break;
513
514 case SRUN:
515 case SIDL:
516 if (a->o_flag & SLOAD)
517 printf("R");
518 else
519 printf("W");
520 break;
521 }
522 if (a->o_nice > NZERO)
523 printf("N");
524 else
525 printf(" ");
526 } else if (uflg) {
527 printf("%-8.8s", a->o_uname);
528 }
529 if (sflg) {
530 printf("%5d", a->o_stksize);
531 }
532 printf("%6u", a->o_pid);
533 if (lflg)
534 printf("%6u%4d%4d%4d%6x", a->o_ppid, a->o_cpu&0377,
535 a->o_pri, a->o_nice, a->o_addr0);
536 else if (uflg)
537 printf("%5.1f%4d ", a->o_pctcpu, a->o_nice);
538 if (lflg || uflg)
539 printf("%4d%5d", a->o_dsize+a->o_ssize, a->o_rssize);
540 if (lflg)
541 if (a->o_wchan)
542 printf("%6x", clear(a->o_wchan));
543 else
544 printf(" ");
545 printf(" %-2.2s", a->o_tty);
546 if (a->o_stat==SZOMB) {
547 printf(" <defunct>");
548 return(1);
549 }
550 tm = (a->o_utime + a->o_stime + 30)/60;
551 printf("%3ld:", tm/60);
552 tm %= 60;
553 printf(tm<10?"0%ld":"%ld", tm);
554 if (vflg) {
555/*
556 tm = (a->o_stime + 30) / 60;
557 printf(" %2ld:", tm/60);
558 tm %= 60;
559 printf(tm<10?"0%ld":"%ld", tm);
560*/
561 printf("%4d%3d", a->o_time, a->o_slptime);
562 }
563#ifdef notdef
564 if (0 && lflg==0) { /* 0 == old tflg (print long times) */
565 tm = (a->o_cstime + 30)/60;
566 printf(" %2ld:", tm/60);
567 tm %= 60;
568 printf(tm<10?"0%ld":"%ld", tm);
569 tm = (a->o_cutime + 30)/60;
570 printf(" %2ld:", tm/60);
571 tm %= 60;
572 printf(tm<10?"0%ld":"%ld", tm);
573 }
574#endif
575 if (vflg) {
576 printf("%7d%7d",a->o_minorflt,a->o_majorflt);
577 printf("%5d%4d%4d", a->o_dsize+a->o_ssize, a->o_rssize, a->o_swrss);
578 printf("%5d%4d", a->o_xsize, a->o_xrssize);
579 printf("%3d", a->o_aveflt);
580 }
581 if (a->o_pid == 0) {
582 printf(" swapper");
583 return(1);
584 }
585 if (a->o_pid == 2) {
586 printf(" pagedaemon");
587 return(1);
588 }
589 if (cflg) {
590 printf(" %s", a->o_comm);
591 return(1);
592 }
593 a -> o_args[argwidth] = 0; /* force it to quit early */
594 printf(" %s", a->o_args);
595 return (1);
596}
597
598char *
599gettty()
600{
601 register i;
602 register char *p;
603
604 if (u.u_ttyp==0)
605 return("?");
606 for (i=0; i<ndev; i++) {
607 if (devl[i].dev == u.u_ttyd) {
608 p = devl[i].dname;
609 if (p[0]=='t' && p[1]=='t' && p[2]=='y')
610 p += 3;
611 return(p);
612 }
613 }
614 return("?");
615}
616
617/*
618 * Given a base/size pair in virtual swap area,
619 * return a physical base/size pair which is the
620 * (largest) initial, physically contiguous block.
621 */
622vstodb(vsbase, vssize, dmp, dbp, rev)
623 register int vsbase;
624 int vssize;
625 struct dmap *dmp;
626 register struct dblock *dbp;
627{
628 register int blk = DMMIN;
629 register swblk_t *ip = dmp->dm_map;
630
631 if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
632 panic("vstodb");
633 while (vsbase >= blk) {
634 vsbase -= blk;
635 if (blk < DMMAX)
636 blk *= 2;
637 ip++;
638 }
639 if (*ip <= 0 || *ip + blk > nswap)
640 panic("vstodb *ip");
641 dbp->db_size = min(vssize, blk - vsbase);
642 dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
643}
644
645panic(cp)
646 char *cp;
647{
648
649#ifdef DEBUG
650 printf("%s\n", cp);
651#endif
652}
653
654min(a, b)
655{
656
657 return (a < b ? a : b);
658}
659
660done(exitno)
661{
662 if (login) {
663 printf("Press return when done: ");
664 getchar();
665 }
666 exit(exitno);
667}
668
669/*
670 * fixup figures out everybodys name and sorts into a nice order.
671 */
672fixup(np) int np; {
673 register int i;
674 register struct passwd *pw;
675 struct passwd *getpwent();
676
677 if (uflg) {
678 /*
679 * If we want names, traverse the password file. For each
680 * passwd entry, look for it in the processes.
681 * In case of multiple entries in /etc/passwd, we believe
682 * the first one (same thing ls does).
683 */
684 while ((pw=getpwent()) != NULL) {
685 for (i=0; i<np; i++)
686 if (outargs[i].o_uid == pw -> pw_uid) {
687 if (outargs[i].o_uname[0] == 0)
688 strcpy(outargs[i].o_uname, pw -> pw_name);
689 }
690 }
691 }
692
693 qsort(outargs, np, sizeof(outargs[0]), pscomp);
694}
695
696pscomp(x1, x2) struct psout *x1, *x2; {
697 register int c;
698
699 c = (x1)->o_ttyd - (x2)->o_ttyd;
700 if (c==0) c = (x1)->o_pid - (x2)->o_pid;
701 return(c);
702}