5ff25cceed396ed49f6d295775fe1092d7974462
[dragonfly.git] / bin / ps / print.c
1 /*-
2  * Copyright (c) 1990, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)print.c  8.6 (Berkeley) 4/16/94
34  * $FreeBSD: src/bin/ps/print.c,v 1.36.2.4 2002/11/30 13:00:14 tjr Exp $
35  * $DragonFly: src/bin/ps/print.c,v 1.8 2003/09/28 14:39:15 hmp Exp $
36  */
37
38 #include <sys/param.h>
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #include <sys/proc.h>
42 #include <sys/stat.h>
43
44 #include <sys/ucred.h>
45 #include <sys/user.h>
46 #include <sys/sysctl.h>
47 #include <sys/rtprio.h>
48 #include <vm/vm.h>
49
50 #include <err.h>
51 #include <langinfo.h>
52 #include <locale.h>
53 #include <math.h>
54 #include <nlist.h>
55 #include <stddef.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <string.h>
60 #include <vis.h>
61
62 #include "ps.h"
63
64 void
65 printheader(void)
66 {
67         VAR *v;
68         struct varent *vent;
69         int allempty;
70
71         allempty = 1;
72         for (vent = vhead; vent; vent = vent->next)
73                 if (*vent->var->header != '\0') {
74                         allempty = 0;
75                         break;
76                 }
77         if (allempty)
78                 return;
79         for (vent = vhead; vent; vent = vent->next) {
80                 v = vent->var;
81                 if (v->flag & LJUST) {
82                         if (vent->next == NULL) /* last one */
83                                 (void)printf("%s", v->header);
84                         else
85                                 (void)printf("%-*s", v->width, v->header);
86                 } else
87                         (void)printf("%*s", v->width, v->header);
88                 if (vent->next != NULL)
89                         (void)putchar(' ');
90         }
91         (void)putchar('\n');
92 }
93
94 void
95 command(KINFO *k, VARENT *ve)
96 {
97         VAR *v;
98         int left;
99         char *cp, *vis_env, *vis_args;
100
101         v = ve->var;
102
103         if (cflag) {
104                 if (ve->next == NULL)   /* last field, don't pad */
105                         (void)printf("%s", KI_THREAD(k)->td_comm);
106                 else
107                         (void)printf("%-*s", v->width, KI_THREAD(k)->td_comm);
108                 return;
109         }
110
111         if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
112                 err(1, NULL);
113         strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
114         if (k->ki_env) {
115                 if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1)) == NULL)
116                         err(1, NULL);
117                 strvis(vis_env, k->ki_env, VIS_TAB | VIS_NL | VIS_NOSLASH);
118         } else
119                 vis_env = NULL;
120
121         if (ve->next == NULL) {
122                 /* last field */
123                 if (termwidth == UNLIMITED) {
124                         if (vis_env)
125                                 (void)printf("%s ", vis_env);
126                         (void)printf("%s", vis_args);
127                 } else {
128                         left = termwidth - (totwidth - v->width);
129                         if (left < 1) /* already wrapped, just use std width */
130                                 left = v->width;
131                         if ((cp = vis_env) != NULL) {
132                                 while (--left >= 0 && *cp)
133                                         (void)putchar(*cp++);
134                                 if (--left >= 0)
135                                         putchar(' ');
136                         }
137                         for (cp = vis_args; --left >= 0 && *cp != '\0';)
138                                 (void)putchar(*cp++);
139                 }
140         } else
141                 /* XXX env? */
142                 (void)printf("%-*.*s", v->width, v->width, vis_args);
143         free(vis_args);
144         if (vis_env != NULL)
145                 free(vis_env);
146 }
147
148 void
149 ucomm(KINFO *k, VARENT *ve)
150 {
151         VAR *v;
152
153         v = ve->var;
154         (void)printf("%-*s", v->width, KI_THREAD(k)->td_comm);
155 }
156
157 void
158 logname(KINFO *k, VARENT *ve)
159 {
160         VAR *v;
161         char *s;
162
163         v = ve->var;
164         (void)printf("%-*s", v->width, (s = KI_EPROC(k)->e_login, *s) ? s : "-");
165 }
166
167 void
168 state(KINFO *k, VARENT *ve)
169 {
170         struct proc *p;
171         int flag;
172         char *cp;
173         VAR *v;
174         char buf[16];
175
176         v = ve->var;
177         p = KI_PROC(k);
178         flag = p->p_flag;
179         cp = buf;
180
181         switch (p->p_stat) {
182
183         case SSTOP:
184                 *cp = 'T';
185                 break;
186
187         case SSLEEP:
188                 if (flag & P_SINTR)     /* interruptable (long) */
189                         *cp = p->p_slptime >= MAXSLP ? 'I' : 'S';
190                 else
191                         *cp = 'D';
192                 break;
193
194         case SRUN:
195         case SIDL:
196                 *cp = 'R';
197                 if (KI_THREAD(k)->td_flags & TDF_RUNNING) {
198                     ++cp;
199                     sprintf(cp, "%d", KI_EPROC(k)->e_cpuid);
200                     while (cp[1])
201                         ++cp;
202                 }
203                 break;
204
205         case SZOMB:
206                 *cp = 'Z';
207                 break;
208
209         default:
210                 *cp = '?';
211         }
212         cp++;
213         if (!(flag & P_INMEM))
214                 *cp++ = 'W';
215         if (p->p_nice < NZERO)
216                 *cp++ = '<';
217         else if (p->p_nice > NZERO)
218                 *cp++ = 'N';
219         if (flag & P_TRACED)
220                 *cp++ = 'X';
221         if (flag & P_WEXIT && p->p_stat != SZOMB)
222                 *cp++ = 'E';
223         if (flag & P_PPWAIT)
224                 *cp++ = 'V';
225         if ((flag & P_SYSTEM) || p->p_lock > 0)
226                 *cp++ = 'L';
227         if (KI_EPROC(k)->e_flag & EPROC_SLEADER)
228                 *cp++ = 's';
229         if ((flag & P_CONTROLT) && KI_EPROC(k)->e_pgid == KI_EPROC(k)->e_tpgid)
230                 *cp++ = '+';
231         if (flag & P_JAILED)
232                 *cp++ = 'J';
233         *cp = '\0';
234         (void)printf("%-*s", v->width, buf);
235 }
236
237 void
238 pri(KINFO *k, VARENT *ve)
239 {
240         VAR *v;
241
242         v = ve->var;
243         (void)printf("%*d", v->width, KI_PROC(k)->p_priority);
244 }
245
246 void
247 uname(KINFO *k, VARENT *ve)
248 {
249         VAR *v;
250
251         v = ve->var;
252         (void)printf("%-*s",
253             (int)v->width, user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0));
254 }
255
256 int
257 s_uname(KINFO *k)
258 {
259             return (strlen(user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0)));
260 }
261
262 void
263 runame(KINFO *k, VARENT *ve)
264 {
265         VAR *v;
266
267         v = ve->var;
268         (void)printf("%-*s",
269             (int)v->width, user_from_uid(KI_EPROC(k)->e_ucred.cr_ruid, 0));
270 }
271
272 int
273 s_runame(KINFO *k)
274 {
275             return (strlen(user_from_uid(KI_EPROC(k)->e_ucred.cr_ruid, 0)));
276 }
277
278 void
279 tdev(KINFO *k, VARENT *ve)
280 {
281         VAR *v;
282         dev_t dev;
283         char buff[16];
284
285         v = ve->var;
286         dev = KI_EPROC(k)->e_tdev;
287         if (dev == NODEV)
288                 (void)printf("%*s", v->width, "??");
289         else {
290                 (void)snprintf(buff, sizeof(buff),
291                     "%d/%d", major(dev), minor(dev));
292                 (void)printf("%*s", v->width, buff);
293         }
294 }
295
296 void
297 tname(KINFO *k, VARENT *ve)
298 {
299         VAR *v;
300         dev_t dev;
301         char *ttname;
302
303         v = ve->var;
304         dev = KI_EPROC(k)->e_tdev;
305         if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
306                 (void)printf("%*s ", v->width-1, "??");
307         else {
308                 if (strncmp(ttname, "tty", 3) == 0 ||
309                     strncmp(ttname, "cua", 3) == 0)
310                         ttname += 3;
311                 (void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
312                         KI_EPROC(k)->e_flag & EPROC_CTTY ? ' ' : '-');
313         }
314 }
315
316 void
317 longtname(KINFO *k, VARENT *ve)
318 {
319         VAR *v;
320         dev_t dev;
321         char *ttname;
322
323         v = ve->var;
324         dev = KI_EPROC(k)->e_tdev;
325         if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
326                 (void)printf("%-*s", v->width, "??");
327         else
328                 (void)printf("%-*s", v->width, ttname);
329 }
330
331 void
332 started(KINFO *k, VARENT *ve)
333 {
334         VAR *v;
335         static time_t now;
336         time_t then;
337         struct tm *tp;
338         char buf[100];
339         static int  use_ampm = -1;
340
341         v = ve->var;
342         if (!k->ki_u.u_valid) {
343                 (void)printf("%-*s", v->width, "-");
344                 return;
345         }
346
347         if (use_ampm < 0)
348                 use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
349
350         then = k->ki_u.u_start.tv_sec;
351         tp = localtime(&then);
352         if (!now)
353                 (void)time(&now);
354         if (now - k->ki_u.u_start.tv_sec < 24 * 3600) {
355                 (void)strftime(buf, sizeof(buf) - 1,
356                 use_ampm ? "%l:%M%p" : "%k:%M  ", tp);
357         } else if (now - k->ki_u.u_start.tv_sec < 7 * 86400) {
358                 (void)strftime(buf, sizeof(buf) - 1,
359                 use_ampm ? "%a%I%p" : "%a%H  ", tp);
360         } else
361                 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
362         (void)printf("%-*s", v->width, buf);
363 }
364
365 void
366 lstarted(KINFO *k, VARENT *ve)
367 {
368         VAR *v;
369         time_t then;
370         char buf[100];
371
372         v = ve->var;
373         if (!k->ki_u.u_valid) {
374                 (void)printf("%-*s", v->width, "-");
375                 return;
376         }
377         then = k->ki_u.u_start.tv_sec;
378         (void)strftime(buf, sizeof(buf) -1, "%c", localtime(&then));
379         (void)printf("%-*s", v->width, buf);
380 }
381
382 void
383 wchan(KINFO *k, VARENT *ve)
384 {
385         VAR *v;
386
387         v = ve->var;
388         if (KI_THREAD(k)->td_wchan) {
389                 if (KI_THREAD(k)->td_wmesg)
390                         (void)printf("%-*.*s", v->width, v->width,
391                                       KI_EPROC(k)->e_wmesg);
392                 else
393                         (void)printf("%-*lx", v->width,
394                             (long)KI_THREAD(k)->td_wchan);
395         } else
396                 (void)printf("%-*s", v->width, "-");
397 }
398
399 #ifndef pgtok
400 #define pgtok(a)        (((a)*getpagesize())/1024)
401 #endif
402
403 void
404 vsize(KINFO *k, VARENT *ve)
405 {
406         VAR *v;
407
408         v = ve->var;
409         (void)printf("%*d", v->width,
410             (KI_EPROC(k)->e_vm.vm_map.size/1024));
411 }
412
413 void
414 rssize(KINFO *k, VARENT *ve)
415 {
416         VAR *v;
417
418         v = ve->var;
419         /* XXX don't have info about shared */
420         (void)printf("%*lu", v->width,
421             (u_long)pgtok(KI_EPROC(k)->e_vm.vm_rssize));
422 }
423
424 void
425 p_rssize(KINFO *k, VARENT *ve)          /* doesn't account for text */
426 {
427         VAR *v;
428
429         v = ve->var;
430         (void)printf("%*ld", v->width, (long)pgtok(KI_EPROC(k)->e_vm.vm_rssize));
431 }
432
433 void
434 cputime(KINFO *k, VARENT *ve)
435 {
436         VAR *v;
437         long secs;
438         long psecs;     /* "parts" of a second. first micro, then centi */
439         char obuff[128];
440         static char decimal_point = 0;
441
442         if (!decimal_point)
443                 decimal_point = localeconv()->decimal_point[0];
444         v = ve->var;
445         if (KI_PROC(k)->p_stat == SZOMB || !k->ki_u.u_valid) {
446                 secs = 0;
447                 psecs = 0;
448         } else {
449                 u_int64_t timeus;
450
451                 /*
452                  * This counts time spent handling interrupts.  We could
453                  * fix this, but it is not 100% trivial (and interrupt
454                  * time fractions only work on the sparc anyway).       XXX
455                  */
456                 timeus = KI_EPROC(k)->e_uticks + KI_EPROC(k)->e_sticks;
457                 secs = timeus / 1000000;
458                 psecs = timeus % 1000000;
459                 if (sumrusage) {
460                         secs += k->ki_u.u_cru.ru_utime.tv_sec +
461                                 k->ki_u.u_cru.ru_stime.tv_sec;
462                         psecs += k->ki_u.u_cru.ru_utime.tv_usec +
463                                 k->ki_u.u_cru.ru_stime.tv_usec;
464                 }
465                 /*
466                  * round and scale to 100's
467                  */
468                 psecs = (psecs + 5000) / 10000;
469                 secs += psecs / 100;
470                 psecs = psecs % 100;
471         }
472         (void)snprintf(obuff, sizeof(obuff),
473             "%3ld:%02ld%c%02ld", secs/60, secs%60, decimal_point, psecs);
474         (void)printf("%*s", v->width, obuff);
475 }
476
477 double
478 getpcpu(KINFO *k)
479 {
480         struct proc *p;
481         static int failure;
482
483         if (!nlistread)
484                 failure = donlist();
485         if (failure)
486                 return (0.0);
487
488         p = KI_PROC(k);
489 #define fxtofl(fixpt)   ((double)(fixpt) / fscale)
490
491         /* XXX - I don't like this */
492         if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0)
493                 return (0.0);
494         if (rawcpu)
495                 return (100.0 * fxtofl(p->p_pctcpu));
496         return (100.0 * fxtofl(p->p_pctcpu) /
497                 (1.0 - exp(p->p_swtime * log(fxtofl(ccpu)))));
498 }
499
500 void
501 pcpu(KINFO *k, VARENT *ve)
502 {
503         VAR *v;
504
505         v = ve->var;
506         (void)printf("%*.1f", v->width, getpcpu(k));
507 }
508
509 void
510 pnice(KINFO *k, VARENT *ve)
511 {
512         VAR *v;
513         int nice;
514
515         switch (KI_PROC(k)->p_rtprio.type) {
516         case RTP_PRIO_REALTIME:
517                 nice = PRIO_MIN - 1 - RTP_PRIO_MAX + KI_PROC(k)->p_rtprio.prio;
518                 break;
519         case RTP_PRIO_IDLE:
520                 nice = PRIO_MAX + 1 + KI_PROC(k)->p_rtprio.prio;
521                 break;
522         case RTP_PRIO_THREAD:
523                 nice = PRIO_MIN - 1 - RTP_PRIO_MAX - KI_PROC(k)->p_rtprio.prio;
524                 break;
525         default:
526                 nice = KI_PROC(k)->p_nice - NZERO;
527                 break;
528         }
529         v = ve->var;
530         (void)printf("%*d", v->width, nice);
531 }
532
533
534 double
535 getpmem(KINFO *k)
536 {
537         static int failure;
538         struct proc *p;
539         struct eproc *e;
540         double fracmem;
541         int szptudot;
542
543         if (!nlistread)
544                 failure = donlist();
545         if (failure)
546                 return (0.0);
547
548         p = KI_PROC(k);
549         e = KI_EPROC(k);
550         if ((p->p_flag & P_INMEM) == 0)
551                 return (0.0);
552         /* XXX want pmap ptpages, segtab, etc. (per architecture) */
553         szptudot = UPAGES;
554         /* XXX don't have info about shared */
555         fracmem = ((float)e->e_vm.vm_rssize + szptudot)/mempages;
556         return (100.0 * fracmem);
557 }
558
559 void
560 pmem(KINFO *k, VARENT *ve)
561 {
562         VAR *v;
563
564         v = ve->var;
565         (void)printf("%*.1f", v->width, getpmem(k));
566 }
567
568 void
569 pagein(KINFO *k, VARENT *ve)
570 {
571         VAR *v;
572
573         v = ve->var;
574         (void)printf("%*ld", v->width,
575             k->ki_u.u_valid ? k->ki_u.u_ru.ru_majflt : 0);
576 }
577
578 void
579 maxrss(KINFO *k, VARENT *ve)
580 {
581         VAR *v;
582
583         v = ve->var;
584         /* XXX not yet */
585         (void)printf("%*s", v->width, "-");
586 }
587
588 void
589 tsize(KINFO *k, VARENT *ve)
590 {
591         VAR *v;
592
593         v = ve->var;
594         (void)printf("%*ld", v->width, (long)pgtok(KI_EPROC(k)->e_vm.vm_tsize));
595 }
596
597 void
598 rtprior(KINFO *k, VARENT *ve)
599 {
600         VAR *v;
601         struct rtprio *prtp;
602         char str[8];
603         unsigned prio, type;
604  
605         v = ve->var;
606         prtp = (struct rtprio *) ((char *)KI_PROC(k) + v->off);
607         prio = prtp->prio;
608         type = prtp->type;
609         switch (type) {
610         case RTP_PRIO_REALTIME:
611                 snprintf(str, sizeof(str), "real:%u", prio);
612                 break;
613         case RTP_PRIO_NORMAL:
614                 strncpy(str, "normal", sizeof(str));
615                 break;
616         case RTP_PRIO_IDLE:
617                 snprintf(str, sizeof(str), "idle:%u", prio);
618                 break;
619         default:
620                 snprintf(str, sizeof(str), "%u:%u", type, prio);
621                 break;
622         }
623         str[sizeof(str) - 1] = '\0';
624         (void)printf("%*s", v->width, str);
625 }
626
627 /*
628  * Generic output routines.  Print fields from various prototype
629  * structures.
630  */
631 static void
632 printval(char *bp, VAR *v)
633 {
634         static char ofmt[32] = "%";
635         char *fcp, *cp;
636
637         cp = ofmt + 1;
638         fcp = v->fmt;
639         if (v->flag & LJUST)
640                 *cp++ = '-';
641         *cp++ = '*';
642         while ((*cp++ = *fcp++));
643
644         switch (v->type) {
645         case CHAR:
646                 (void)printf(ofmt, v->width, *(char *)bp);
647                 break;
648         case UCHAR:
649                 (void)printf(ofmt, v->width, *(u_char *)bp);
650                 break;
651         case SHORT:
652                 (void)printf(ofmt, v->width, *(short *)bp);
653                 break;
654         case USHORT:
655                 (void)printf(ofmt, v->width, *(u_short *)bp);
656                 break;
657         case INT:
658                 (void)printf(ofmt, v->width, *(int *)bp);
659                 break;
660         case UINT:
661                 (void)printf(ofmt, v->width, *(u_int *)bp);
662                 break;
663         case LONG:
664                 (void)printf(ofmt, v->width, *(long *)bp);
665                 break;
666         case ULONG:
667                 (void)printf(ofmt, v->width, *(u_long *)bp);
668                 break;
669         case KPTR:
670                 (void)printf(ofmt, v->width, *(u_long *)bp);
671                 break;
672         default:
673                 errx(1, "unknown type %d", v->type);
674         }
675 }
676
677 void
678 pvar(KINFO *k, VARENT *ve)
679 {
680         VAR *v;
681
682         v = ve->var;
683         printval((char *)((char *)KI_PROC(k) + v->off), v);
684 }
685
686 void
687 tvar(KINFO *k, VARENT *ve)
688 {
689         VAR *v;
690
691         v = ve->var;
692         printval((char *)((char *)KI_THREAD(k) + v->off), v);
693 }
694
695 void
696 evar(KINFO *k, VARENT *ve)
697 {
698         VAR *v;
699
700         v = ve->var;
701         printval((char *)((char *)KI_EPROC(k) + v->off), v);
702 }
703
704 void
705 uvar(KINFO *k, VARENT *ve)
706 {
707         VAR *v;
708
709         v = ve->var;
710         if (k->ki_u.u_valid)
711                 printval((char *)((char *)&k->ki_u + v->off), v);
712         else
713                 (void)printf("%*s", v->width, "-");
714 }
715
716 void
717 rvar(KINFO *k, VARENT *ve)
718 {
719         VAR *v;
720
721         v = ve->var;
722         if (k->ki_u.u_valid)
723                 printval((char *)((char *)(&k->ki_u.u_ru) + v->off), v);
724         else
725                 (void)printf("%*s", v->width, "-");
726 }