1 /*-
2 * Copyright (c) 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 04/16/94";
10 #endif /* not lint */
11
12 #include <sys/param.h>
13 #include <sys/time.h>
14 #include <sys/resource.h>
15 #include <sys/proc.h>
16 #include <sys/stat.h>
17
18 #ifdef P_PPWAIT
19 #define NEWVM
20 #endif
21
22 #ifdef NEWVM
23 #include <sys/ucred.h>
24 #include <sys/sysctl.h>
25 #include <vm/vm.h>
26 #else
27 #include <machine/pte.h>
28 #include <sys/vmparam.h>
29 #include <sys/vm.h>
30 #endif
31
32 #include <err.h>
33 #include <math.h>
34 #include <nlist.h>
35 #include <stddef.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <vis.h>
40 #include <tzfile.h>
41
42 #include "ps.h"
43
44 void
printheader()45 printheader()
46 {
47 VAR *v;
48 struct varent *vent;
49
50 for (vent = vhead; vent; vent = vent->next) {
51 v = vent->var;
52 if (v->flag & LJUST) {
53 if (vent->next == NULL) /* last one */
54 (void)printf("%s", v->header);
55 else
56 (void)printf("%-*s", v->width, v->header);
57 } else
58 (void)printf("%*s", v->width, v->header);
59 if (vent->next != NULL)
60 (void)putchar(' ');
61 }
62 (void)putchar('\n');
63 }
64
65 void
command(k,ve)66 command(k, ve)
67 KINFO *k;
68 VARENT *ve;
69 {
70 VAR *v;
71 int left;
72 char *cp, *vis_env, *vis_args;
73
74 if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
75 err(1, NULL);
76 strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
77 if (k->ki_env) {
78 if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1)) == NULL)
79 err(1, NULL);
80 strvis(vis_env, k->ki_env, VIS_TAB | VIS_NL | VIS_NOSLASH);
81 } else
82 vis_env = NULL;
83
84 v = ve->var;
85 if (ve->next == NULL) {
86 /* last field */
87 if (termwidth == UNLIMITED) {
88 if (vis_env)
89 (void)printf("%s ", vis_env);
90 (void)printf("%s", vis_args);
91 } else {
92 left = termwidth - (totwidth - v->width);
93 if (left < 1) /* already wrapped, just use std width */
94 left = v->width;
95 if ((cp = vis_env) != NULL) {
96 while (--left >= 0 && *cp)
97 (void)putchar(*cp++);
98 if (--left >= 0)
99 putchar(' ');
100 }
101 for (cp = vis_args; --left >= 0 && *cp != '\0';)
102 (void)putchar(*cp++);
103 }
104 } else
105 /* XXX env? */
106 (void)printf("%-*.*s", v->width, v->width, vis_args);
107 free(vis_args);
108 if (vis_env != NULL)
109 free(vis_env);
110 }
111
112 void
ucomm(k,ve)113 ucomm(k, ve)
114 KINFO *k;
115 VARENT *ve;
116 {
117 VAR *v;
118
119 v = ve->var;
120 (void)printf("%-*s", v->width, KI_PROC(k)->p_comm);
121 }
122
123 void
logname(k,ve)124 logname(k, ve)
125 KINFO *k;
126 VARENT *ve;
127 {
128 VAR *v;
129
130 v = ve->var;
131 #ifndef NEWVM
132 (void)printf("%-*s", v->width, KI_PROC(k)->p_logname);
133 #else
134 (void)printf("%-*s", v->width, KI_EPROC(k)->e_login);
135 #endif
136 }
137
138 void
state(k,ve)139 state(k, ve)
140 KINFO *k;
141 VARENT *ve;
142 {
143 struct proc *p;
144 int flag;
145 char *cp;
146 VAR *v;
147 char buf[16];
148
149 v = ve->var;
150 p = KI_PROC(k);
151 flag = p->p_flag;
152 cp = buf;
153
154 switch (p->p_stat) {
155
156 case SSTOP:
157 *cp = 'T';
158 break;
159
160 case SSLEEP:
161 if (flag & P_SINTR) /* interuptable (long) */
162 *cp = p->p_slptime >= MAXSLP ? 'I' : 'S';
163 else
164 *cp = 'D';
165 break;
166
167 case SRUN:
168 case SIDL:
169 *cp = 'R';
170 break;
171
172 case SZOMB:
173 *cp = 'Z';
174 break;
175
176 default:
177 *cp = '?';
178 }
179 cp++;
180 if (flag & P_INMEM) {
181 #ifndef NEWVM
182 if (p->p_rssize > p->p_maxrss)
183 *cp++ = '>';
184 #endif
185 } else
186 *cp++ = 'W';
187 if (p->p_nice < NZERO)
188 *cp++ = '<';
189 else if (p->p_nice > NZERO)
190 *cp++ = 'N';
191 #ifndef NEWVM
192 if (flag & SUANOM)
193 *cp++ = 'A';
194 else if (flag & SSEQL)
195 *cp++ = 'S';
196 #endif
197 if (flag & P_TRACED)
198 *cp++ = 'X';
199 if (flag & P_WEXIT && p->p_stat != SZOMB)
200 *cp++ = 'E';
201 #ifdef NEWVM
202 if (flag & P_PPWAIT)
203 #else
204 if (flag & SVFORK)
205 #endif
206 *cp++ = 'V';
207 #ifdef NEWVM
208 if (flag & (P_SYSTEM | P_NOSWAP | P_PHYSIO))
209 #else
210 if (flag & (SSYS|SLOCK|SULOCK|SKEEP|SPHYSIO))
211 #endif
212 *cp++ = 'L';
213 if (KI_EPROC(k)->e_flag & EPROC_SLEADER)
214 *cp++ = 's';
215 if ((flag & P_CONTROLT) && KI_EPROC(k)->e_pgid == KI_EPROC(k)->e_tpgid)
216 *cp++ = '+';
217 *cp = '\0';
218 (void)printf("%-*s", v->width, buf);
219 }
220
221 void
pri(k,ve)222 pri(k, ve)
223 KINFO *k;
224 VARENT *ve;
225 {
226 VAR *v;
227
228 v = ve->var;
229 (void)printf("%*d", v->width, KI_PROC(k)->p_priority - PZERO);
230 }
231
232 void
uname(k,ve)233 uname(k, ve)
234 KINFO *k;
235 VARENT *ve;
236 {
237 VAR *v;
238
239 v = ve->var;
240 #ifndef NEWVM
241 (void)printf("%-*s",
242 (int)v->width, user_from_uid(KI_PROC(k)->p_uid, 0));
243 #else
244 (void)printf("%-*s",
245 (int)v->width, user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0));
246 #endif
247 }
248
249 void
runame(k,ve)250 runame(k, ve)
251 KINFO *k;
252 VARENT *ve;
253 {
254 VAR *v;
255
256 v = ve->var;
257 #ifndef NEWVM
258 (void)printf("%-*s",
259 (int)v->width, user_from_uid(KI_PROC(k)->p_ruid, 0));
260 #else
261 (void)printf("%-*s",
262 (int)v->width, user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0));
263 #endif
264 }
265
266 void
tdev(k,ve)267 tdev(k, ve)
268 KINFO *k;
269 VARENT *ve;
270 {
271 VAR *v;
272 dev_t dev;
273 char buff[16];
274
275 v = ve->var;
276 dev = KI_EPROC(k)->e_tdev;
277 if (dev == NODEV)
278 (void)printf("%*s", v->width, "??");
279 else {
280 (void)snprintf(buff, sizeof(buff),
281 "%d/%d", major(dev), minor(dev));
282 (void)printf("%*s", v->width, buff);
283 }
284 }
285
286 void
tname(k,ve)287 tname(k, ve)
288 KINFO *k;
289 VARENT *ve;
290 {
291 VAR *v;
292 dev_t dev;
293 char *ttname;
294
295 v = ve->var;
296 dev = KI_EPROC(k)->e_tdev;
297 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
298 (void)printf("%-*s", v->width, "??");
299 else {
300 if (strncmp(ttname, "tty", 3) == 0)
301 ttname += 3;
302 (void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
303 KI_EPROC(k)->e_flag & EPROC_CTTY ? ' ' : '-');
304 }
305 }
306
307 void
longtname(k,ve)308 longtname(k, ve)
309 KINFO *k;
310 VARENT *ve;
311 {
312 VAR *v;
313 dev_t dev;
314 char *ttname;
315
316 v = ve->var;
317 dev = KI_EPROC(k)->e_tdev;
318 if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
319 (void)printf("%-*s", v->width, "??");
320 else
321 (void)printf("%-*s", v->width, ttname);
322 }
323
324 void
started(k,ve)325 started(k, ve)
326 KINFO *k;
327 VARENT *ve;
328 {
329 VAR *v;
330 static time_t now;
331 struct tm *tp;
332 char buf[100];
333
334 v = ve->var;
335 if (!k->ki_u.u_valid) {
336 (void)printf("%-*s", v->width, "-");
337 return;
338 }
339
340 tp = localtime(&k->ki_u.u_start.tv_sec);
341 if (!now)
342 (void)time(&now);
343 if (now - k->ki_u.u_start.tv_sec < 24 * SECSPERHOUR) {
344 /* I *hate* SCCS... */
345 static char fmt[] = __CONCAT("%l:%", "M%p");
346 (void)strftime(buf, sizeof(buf) - 1, fmt, tp);
347 } else if (now - k->ki_u.u_start.tv_sec < 7 * SECSPERDAY) {
348 /* I *hate* SCCS... */
349 static char fmt[] = __CONCAT("%a%", "I%p");
350 (void)strftime(buf, sizeof(buf) - 1, fmt, tp);
351 } else
352 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
353 (void)printf("%-*s", v->width, buf);
354 }
355
356 void
lstarted(k,ve)357 lstarted(k, ve)
358 KINFO *k;
359 VARENT *ve;
360 {
361 VAR *v;
362 char buf[100];
363
364 v = ve->var;
365 if (!k->ki_u.u_valid) {
366 (void)printf("%-*s", v->width, "-");
367 return;
368 }
369 (void)strftime(buf, sizeof(buf) -1, "%C",
370 localtime(&k->ki_u.u_start.tv_sec));
371 (void)printf("%-*s", v->width, buf);
372 }
373
374 void
wchan(k,ve)375 wchan(k, ve)
376 KINFO *k;
377 VARENT *ve;
378 {
379 VAR *v;
380
381 v = ve->var;
382 if (KI_PROC(k)->p_wchan) {
383 if (KI_PROC(k)->p_wmesg)
384 (void)printf("%-*.*s", v->width, v->width,
385 KI_EPROC(k)->e_wmesg);
386 else
387 (void)printf("%-*x", v->width,
388 (int)KI_PROC(k)->p_wchan &~ KERNBASE);
389 } else
390 (void)printf("%-*s", v->width, "-");
391 }
392
393 #define pgtok(a) (((a)*NBPG)/1024)
394
395 void
vsize(k,ve)396 vsize(k, ve)
397 KINFO *k;
398 VARENT *ve;
399 {
400 VAR *v;
401
402 v = ve->var;
403 (void)printf("%*d", v->width,
404 #ifndef NEWVM
405 pgtok(KI_PROC(k)->p_dsize +
406 KI_PROC(k)->p_ssize + KI_EPROC(k)->e_xsize));
407 #else
408 pgtok(KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize +
409 KI_EPROC(k)->e_vm.vm_tsize));
410 #endif
411 }
412
413 void
rssize(k,ve)414 rssize(k, ve)
415 KINFO *k;
416 VARENT *ve;
417 {
418 VAR *v;
419
420 v = ve->var;
421 #ifndef NEWVM
422 (void)printf("%*d", v->width,
423 pgtok(KI_PROC(k)->p_rssize + (KI_EPROC(k)->e_xccount ?
424 (KI_EPROC(k)->e_xrssize / KI_EPROC(k)->e_xccount) : 0)));
425 #else
426 /* XXX don't have info about shared */
427 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_rssize));
428 #endif
429 }
430
431 void
p_rssize(k,ve)432 p_rssize(k, ve) /* doesn't account for text */
433 KINFO *k;
434 VARENT *ve;
435 {
436 VAR *v;
437
438 v = ve->var;
439 #ifndef NEWVM
440 (void)printf("%*d", v->width, pgtok(KI_PROC(k)->p_rssize));
441 #else
442 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_rssize));
443 #endif
444 }
445
446 void
cputime(k,ve)447 cputime(k, ve)
448 KINFO *k;
449 VARENT *ve;
450 {
451 VAR *v;
452 long secs;
453 long psecs; /* "parts" of a second. first micro, then centi */
454 char obuff[128];
455
456 v = ve->var;
457 if (KI_PROC(k)->p_stat == SZOMB || !k->ki_u.u_valid) {
458 secs = 0;
459 psecs = 0;
460 } else {
461 /*
462 * This counts time spent handling interrupts. We could
463 * fix this, but it is not 100% trivial (and interrupt
464 * time fractions only work on the sparc anyway). XXX
465 */
466 secs = KI_PROC(k)->p_rtime.tv_sec;
467 psecs = KI_PROC(k)->p_rtime.tv_usec;
468 if (sumrusage) {
469 secs += k->ki_u.u_cru.ru_utime.tv_sec +
470 k->ki_u.u_cru.ru_stime.tv_sec;
471 psecs += k->ki_u.u_cru.ru_utime.tv_usec +
472 k->ki_u.u_cru.ru_stime.tv_usec;
473 }
474 /*
475 * round and scale to 100's
476 */
477 psecs = (psecs + 5000) / 10000;
478 secs += psecs / 100;
479 psecs = psecs % 100;
480 }
481 (void)snprintf(obuff, sizeof(obuff),
482 "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
483 (void)printf("%*s", v->width, obuff);
484 }
485
486 double
getpcpu(k)487 getpcpu(k)
488 KINFO *k;
489 {
490 struct proc *p;
491 static int failure;
492
493 if (!nlistread)
494 failure = donlist();
495 if (failure)
496 return (0.0);
497
498 p = KI_PROC(k);
499 #define fxtofl(fixpt) ((double)(fixpt) / fscale)
500
501 /* XXX - I don't like this */
502 if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0)
503 return (0.0);
504 if (rawcpu)
505 return (100.0 * fxtofl(p->p_pctcpu));
506 return (100.0 * fxtofl(p->p_pctcpu) /
507 (1.0 - exp(p->p_swtime * log(fxtofl(ccpu)))));
508 }
509
510 void
pcpu(k,ve)511 pcpu(k, ve)
512 KINFO *k;
513 VARENT *ve;
514 {
515 VAR *v;
516
517 v = ve->var;
518 (void)printf("%*.1f", v->width, getpcpu(k));
519 }
520
521 double
getpmem(k)522 getpmem(k)
523 KINFO *k;
524 {
525 static int failure;
526 struct proc *p;
527 struct eproc *e;
528 double fracmem;
529 int szptudot;
530
531 if (!nlistread)
532 failure = donlist();
533 if (failure)
534 return (0.0);
535
536 p = KI_PROC(k);
537 e = KI_EPROC(k);
538 if ((p->p_flag & P_INMEM) == 0)
539 return (0.0);
540 #ifndef NEWVM
541 szptudot = UPAGES + clrnd(ctopt(p->p_dsize + p->p_ssize + e->e_xsize));
542 fracmem = ((float)p->p_rssize + szptudot)/CLSIZE/mempages;
543 if (p->p_textp && e->e_xccount)
544 fracmem += ((float)e->e_xrssize)/CLSIZE/e->e_xccount/mempages;
545 #else
546 /* XXX want pmap ptpages, segtab, etc. (per architecture) */
547 szptudot = UPAGES;
548 /* XXX don't have info about shared */
549 fracmem = ((float)e->e_vm.vm_rssize + szptudot)/CLSIZE/mempages;
550 #endif
551 return (100.0 * fracmem);
552 }
553
554 void
pmem(k,ve)555 pmem(k, ve)
556 KINFO *k;
557 VARENT *ve;
558 {
559 VAR *v;
560
561 v = ve->var;
562 (void)printf("%*.1f", v->width, getpmem(k));
563 }
564
565 void
pagein(k,ve)566 pagein(k, ve)
567 KINFO *k;
568 VARENT *ve;
569 {
570 VAR *v;
571
572 v = ve->var;
573 (void)printf("%*d", v->width,
574 k->ki_u.u_valid ? k->ki_u.u_ru.ru_majflt : 0);
575 }
576
577 void
maxrss(k,ve)578 maxrss(k, ve)
579 KINFO *k;
580 VARENT *ve;
581 {
582 VAR *v;
583
584 v = ve->var;
585 #ifndef NEWVM /* not yet */
586 if (KI_PROC(k)->p_maxrss != (RLIM_INFINITY/NBPG))
587 (void)printf("%*d", v->width, pgtok(KI_PROC(k)->p_maxrss));
588 else
589 #endif
590 (void)printf("%*s", v->width, "-");
591 }
592
593 void
tsize(k,ve)594 tsize(k, ve)
595 KINFO *k;
596 VARENT *ve;
597 {
598 VAR *v;
599
600 v = ve->var;
601 #ifndef NEWVM
602 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_xsize));
603 #else
604 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_vm.vm_tsize));
605 #endif
606 }
607
608 #ifndef NEWVM
609 void
trss(k,ve)610 trss(k, ve)
611 KINFO *k;
612 VARENT *ve;
613 {
614 VAR *v;
615
616 v = ve->var;
617 (void)printf("%*d", v->width, pgtok(KI_EPROC(k)->e_xrssize));
618 }
619 #endif
620
621 /*
622 * Generic output routines. Print fields from various prototype
623 * structures.
624 */
625 static void
printval(bp,v)626 printval(bp, v)
627 char *bp;
628 VAR *v;
629 {
630 static char ofmt[32] = "%";
631 char *fcp, *cp;
632
633 cp = ofmt + 1;
634 fcp = v->fmt;
635 if (v->flag & LJUST)
636 *cp++ = '-';
637 *cp++ = '*';
638 while (*cp++ = *fcp++);
639
640 switch (v->type) {
641 case CHAR:
642 (void)printf(ofmt, v->width, *(char *)bp);
643 break;
644 case UCHAR:
645 (void)printf(ofmt, v->width, *(u_char *)bp);
646 break;
647 case SHORT:
648 (void)printf(ofmt, v->width, *(short *)bp);
649 break;
650 case USHORT:
651 (void)printf(ofmt, v->width, *(u_short *)bp);
652 break;
653 case LONG:
654 (void)printf(ofmt, v->width, *(long *)bp);
655 break;
656 case ULONG:
657 (void)printf(ofmt, v->width, *(u_long *)bp);
658 break;
659 case KPTR:
660 (void)printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE);
661 break;
662 default:
663 errx(1, "unknown type %d", v->type);
664 }
665 }
666
667 void
pvar(k,ve)668 pvar(k, ve)
669 KINFO *k;
670 VARENT *ve;
671 {
672 VAR *v;
673
674 v = ve->var;
675 printval((char *)((char *)KI_PROC(k) + v->off), v);
676 }
677
678 void
evar(k,ve)679 evar(k, ve)
680 KINFO *k;
681 VARENT *ve;
682 {
683 VAR *v;
684
685 v = ve->var;
686 printval((char *)((char *)KI_EPROC(k) + v->off), v);
687 }
688
689 void
uvar(k,ve)690 uvar(k, ve)
691 KINFO *k;
692 VARENT *ve;
693 {
694 VAR *v;
695
696 v = ve->var;
697 if (k->ki_u.u_valid)
698 printval((char *)((char *)&k->ki_u + v->off), v);
699 else
700 (void)printf("%*s", v->width, "-");
701 }
702
703 void
rvar(k,ve)704 rvar(k, ve)
705 KINFO *k;
706 VARENT *ve;
707 {
708 VAR *v;
709
710 v = ve->var;
711 if (k->ki_u.u_valid)
712 printval((char *)((char *)(&k->ki_u.u_ru) + v->off), v);
713 else
714 (void)printf("%*s", v->width, "-");
715 }
716