]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - bin/ps/print.c
This commit was generated by cvs2svn to compensate for changes in r104862,
[FreeBSD/FreeBSD.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
34 #if 0
35 #ifndef lint
36 static char sccsid[] = "@(#)print.c     8.6 (Berkeley) 4/16/94";
37 #endif /* not lint */
38 #endif
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include <sys/param.h>
43 #include <sys/time.h>
44 #include <sys/resource.h>
45 #include <sys/proc.h>
46 #include <sys/stat.h>
47
48 #include <sys/user.h>
49 #include <sys/sysctl.h>
50
51 #include <err.h>
52 #include <grp.h>
53 #include <langinfo.h>
54 #include <locale.h>
55 #include <math.h>
56 #include <nlist.h>
57 #include <pwd.h>
58 #include <stddef.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <vis.h>
64
65 #include "lomac.h"
66 #include "ps.h"
67
68 #define ps_pgtok(a)     (((a) * getpagesize()) / 1024)
69
70 void
71 printheader(void)
72 {
73         VAR *v;
74         struct varent *vent;
75
76         for (vent = vhead; vent; vent = vent->next) {
77                 v = vent->var;
78                 if (v->flag & LJUST) {
79                         if (vent->next == NULL) /* last one */
80                                 (void)printf("%s", v->header);
81                         else
82                                 (void)printf("%-*s", v->width, v->header);
83                 } else
84                         (void)printf("%*s", v->width, v->header);
85                 if (vent->next != NULL)
86                         (void)putchar(' ');
87         }
88         (void)putchar('\n');
89 }
90
91 void
92 arguments(KINFO *k, VARENT *ve)
93 {
94         VAR *v;
95         int left;
96         char *cp, *vis_args;
97
98         v = ve->var;
99
100         if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
101                 errx(1, "malloc failed");
102         strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
103
104         if (ve->next == NULL) {
105                 /* last field */
106                 if (termwidth == UNLIMITED) {
107                         (void)printf("%s", vis_args);
108                 } else {
109                         left = termwidth - (totwidth - v->width);
110                         if (left < 1) /* already wrapped, just use std width */
111                                 left = v->width;
112                         for (cp = vis_args; --left >= 0 && *cp != '\0';)
113                                 (void)putchar(*cp++);
114                 }
115         } else {
116                 (void)printf("%-*.*s", v->width, v->width, vis_args);
117         }
118         free(vis_args);
119 }
120
121 void
122 command(KINFO *k, VARENT *ve)
123 {
124         VAR *v;
125         int left;
126         char *cp, *vis_env, *vis_args;
127
128         v = ve->var;
129
130         if (cflag) {
131                 if (ve->next == NULL)   /* last field, don't pad */
132                         (void)printf("%s", k->ki_p->ki_comm);
133                 else
134                         (void)printf("%-*s", v->width, k->ki_p->ki_comm);
135                 return;
136         }
137
138         if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
139                 errx(1, "malloc failed");
140         strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
141         if (k->ki_env) {
142                 if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1)) == NULL)
143                         errx(1, "malloc failed");
144                 strvis(vis_env, k->ki_env, VIS_TAB | VIS_NL | VIS_NOSLASH);
145         } else
146                 vis_env = NULL;
147
148         if (ve->next == NULL) {
149                 /* last field */
150                 if (termwidth == UNLIMITED) {
151                         if (vis_env)
152                                 (void)printf("%s ", vis_env);
153                         (void)printf("%s", vis_args);
154                 } else {
155                         left = termwidth - (totwidth - v->width);
156                         if (left < 1) /* already wrapped, just use std width */
157                                 left = v->width;
158                         if ((cp = vis_env) != NULL) {
159                                 while (--left >= 0 && *cp)
160                                         (void)putchar(*cp++);
161                                 if (--left >= 0)
162                                         putchar(' ');
163                         }
164                         for (cp = vis_args; --left >= 0 && *cp != '\0';)
165                                 (void)putchar(*cp++);
166                 }
167         } else
168                 /* XXX env? */
169                 (void)printf("%-*.*s", v->width, v->width, vis_args);
170         free(vis_args);
171         if (vis_env != NULL)
172                 free(vis_env);
173 }
174
175 void
176 ucomm(KINFO *k, VARENT *ve)
177 {
178         VAR *v;
179
180         v = ve->var;
181         (void)printf("%-*s", v->width, k->ki_p->ki_comm);
182 }
183
184 void
185 logname(KINFO *k, VARENT *ve)
186 {
187         VAR *v;
188         char *s;
189
190         v = ve->var;
191         (void)printf("%-*s", v->width, (s = k->ki_p->ki_login, *s) ? s : "-");
192 }
193
194 void
195 state(KINFO *k, VARENT *ve)
196 {
197         int flag, sflag, tdflags;
198         char *cp;
199         VAR *v;
200         char buf[16];
201
202         v = ve->var;
203         flag = k->ki_p->ki_flag;
204         sflag = k->ki_p->ki_sflag;
205         tdflags = k->ki_p->ki_tdflags;  /* XXXKSE */
206         cp = buf;
207
208         switch (k->ki_p->ki_stat) {
209
210         case SSTOP:
211                 *cp = 'T';
212                 break;
213
214         case SSLEEP:
215                 if (tdflags & TDF_SINTR)        /* interruptable (long) */
216                         *cp = k->ki_p->ki_slptime >= MAXSLP ? 'I' : 'S';
217                 else
218                         *cp = 'D';
219                 break;
220
221         case SRUN:
222         case SIDL:
223                 *cp = 'R';
224                 break;
225
226         case SWAIT:
227                 *cp = 'W';
228                 break;
229
230         case SLOCK:
231                 *cp = 'L';
232                 break;
233
234         case SZOMB:
235                 *cp = 'Z';
236                 break;
237
238         default:
239                 *cp = '?';
240         }
241         cp++;
242         if (!(sflag & PS_INMEM))
243                 *cp++ = 'W';
244         if (k->ki_p->ki_nice < NZERO)
245                 *cp++ = '<';
246         else if (k->ki_p->ki_nice > NZERO)
247                 *cp++ = 'N';
248         if (flag & P_TRACED)
249                 *cp++ = 'X';
250         if (flag & P_WEXIT && k->ki_p->ki_stat != SZOMB)
251                 *cp++ = 'E';
252         if (flag & P_PPWAIT)
253                 *cp++ = 'V';
254         if ((flag & P_SYSTEM) || k->ki_p->ki_lock > 0)
255                 *cp++ = 'L';
256         if (k->ki_p->ki_kiflag & KI_SLEADER)
257                 *cp++ = 's';
258         if ((flag & P_CONTROLT) && k->ki_p->ki_pgid == k->ki_p->ki_tpgid)
259                 *cp++ = '+';
260         if (flag & P_JAILED)
261                 *cp++ = 'J';
262         *cp = '\0';
263         (void)printf("%-*s", v->width, buf);
264 }
265
266 void
267 pri(KINFO *k, VARENT *ve)
268 {
269         VAR *v;
270
271         v = ve->var;
272         (void)printf("%*d", v->width, k->ki_p->ki_pri.pri_level - PZERO);
273 }
274
275 void
276 uname(KINFO *k, VARENT *ve)
277 {
278         VAR *v;
279
280         v = ve->var;
281         (void)printf("%-*s", v->width, user_from_uid(k->ki_p->ki_uid, 0));
282 }
283
284 int
285 s_uname(KINFO *k)
286 {
287             return (strlen(user_from_uid(k->ki_p->ki_uid, 0)));
288 }
289
290 void
291 rgroupname(KINFO *k, VARENT *ve)
292 {
293         VAR *v;
294
295         v = ve->var;
296         (void)printf("%-*s", v->width, group_from_gid(k->ki_p->ki_rgid, 0));
297 }
298
299 int
300 s_rgroupname(KINFO *k)
301 {
302         return (strlen(group_from_gid(k->ki_p->ki_rgid, 0)));
303 }
304
305 void
306 runame(KINFO *k, VARENT *ve)
307 {
308         VAR *v;
309
310         v = ve->var;
311         (void)printf("%-*s", v->width, user_from_uid(k->ki_p->ki_ruid, 0));
312 }
313
314 int
315 s_runame(KINFO *k)
316 {
317             return (strlen(user_from_uid(k->ki_p->ki_ruid, 0)));
318 }
319
320
321 void
322 tdev(KINFO *k, VARENT *ve)
323 {
324         VAR *v;
325         dev_t dev;
326         char buff[16];
327
328         v = ve->var;
329         dev = k->ki_p->ki_tdev;
330         if (dev == NODEV)
331                 (void)printf("%*s", v->width, "??");
332         else {
333                 (void)snprintf(buff, sizeof(buff),
334                     "%d/%d", major(dev), minor(dev));
335                 (void)printf("%*s", v->width, buff);
336         }
337 }
338
339 void
340 tname(KINFO *k, VARENT *ve)
341 {
342         VAR *v;
343         dev_t dev;
344         char *ttname;
345
346         v = ve->var;
347         dev = k->ki_p->ki_tdev;
348         if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
349                 (void)printf("%*s ", v->width-1, "??");
350         else {
351                 if (strncmp(ttname, "tty", 3) == 0 ||
352                     strncmp(ttname, "cua", 3) == 0)
353                         ttname += 3;
354                 (void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
355                         k->ki_p->ki_kiflag & KI_CTTY ? ' ' : '-');
356         }
357 }
358
359 void
360 longtname(KINFO *k, VARENT *ve)
361 {
362         VAR *v;
363         dev_t dev;
364         char *ttname;
365
366         v = ve->var;
367         dev = k->ki_p->ki_tdev;
368         if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
369                 (void)printf("%-*s", v->width, "??");
370         else
371                 (void)printf("%-*s", v->width, ttname);
372 }
373
374 void
375 started(KINFO *k, VARENT *ve)
376 {
377         VAR *v;
378         time_t then;
379         struct tm *tp;
380         char buf[100];
381         static int  use_ampm = -1;
382
383         v = ve->var;
384         if (!k->ki_valid) {
385                 (void)printf("%-*s", v->width, "-");
386                 return;
387         }
388
389         if (use_ampm < 0)
390                 use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
391
392         then = k->ki_p->ki_start.tv_sec;
393         tp = localtime(&then);
394         if (now - k->ki_p->ki_start.tv_sec < 24 * 3600) {
395                 (void)strftime(buf, sizeof(buf) - 1,
396                 use_ampm ? "%l:%M%p" : "%k:%M  ", tp);
397         } else if (now - k->ki_p->ki_start.tv_sec < 7 * 86400) {
398                 (void)strftime(buf, sizeof(buf) - 1,
399                 use_ampm ? "%a%I%p" : "%a%H  ", tp);
400         } else
401                 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
402         (void)printf("%-*s", v->width, buf);
403 }
404
405 void
406 lstarted(KINFO *k, VARENT *ve)
407 {
408         VAR *v;
409         time_t then;
410         char buf[100];
411
412         v = ve->var;
413         if (!k->ki_valid) {
414                 (void)printf("%-*s", v->width, "-");
415                 return;
416         }
417         then = k->ki_p->ki_start.tv_sec;
418         (void)strftime(buf, sizeof(buf) -1, "%c", localtime(&then));
419         (void)printf("%-*s", v->width, buf);
420 }
421
422 void
423 lockname(KINFO *k, VARENT *ve)
424 {
425         VAR *v;
426
427         v = ve->var;
428         if (k->ki_p->ki_kiflag & KI_LOCKBLOCK) {
429                 if (k->ki_p->ki_lockname[0] != 0)
430                         (void)printf("%-*.*s", v->width, v->width,
431                                       k->ki_p->ki_lockname);
432                 else
433                         (void)printf("%-*s", v->width, "???");
434         } else
435                 (void)printf("%-*s", v->width, "-");
436 }
437
438 void
439 wchan(KINFO *k, VARENT *ve)
440 {
441         VAR *v;
442
443         v = ve->var;
444         if (k->ki_p->ki_wchan) {
445                 if (k->ki_p->ki_wmesg[0] != 0)
446                         (void)printf("%-*.*s", v->width, v->width,
447                                       k->ki_p->ki_wmesg);
448                 else
449                         (void)printf("%-*lx", v->width,
450                             (long)k->ki_p->ki_wchan);
451         } else {
452                 (void)printf("%-*s", v->width, "-");
453         }
454 }
455
456 void
457 mwchan(KINFO *k, VARENT *ve)
458 {
459         VAR *v;
460
461         v = ve->var;
462         if (k->ki_p->ki_wchan) {
463                 if (k->ki_p->ki_wmesg[0] != 0)
464                         (void)printf("%-*.*s", v->width, v->width,
465                                       k->ki_p->ki_wmesg);
466                 else
467                         (void)printf("%-*lx", v->width,
468                             (long)k->ki_p->ki_wchan);
469         } else if (k->ki_p->ki_kiflag & KI_LOCKBLOCK) {
470                 if (k->ki_p->ki_lockname[0]) {
471                         (void)printf("%-*.*s", v->width, v->width,
472                             k->ki_p->ki_lockname);
473                 } else {
474                         (void)printf("%-*s", v->width, "???");
475                 }
476         } else {
477                 (void)printf("%-*s", v->width, "-");
478         }
479 }
480
481 void
482 vsize(KINFO *k, VARENT *ve)
483 {
484         VAR *v;
485
486         v = ve->var;
487         (void)printf("%*lu", v->width, (u_long)(k->ki_p->ki_size / 1024));
488 }
489
490 void
491 cputime(KINFO *k, VARENT *ve)
492 {
493         VAR *v;
494         long secs;
495         long psecs;     /* "parts" of a second. first micro, then centi */
496         char obuff[128];
497         static char decimal_point = 0;
498
499         if (!decimal_point)
500                 decimal_point = localeconv()->decimal_point[0];
501         v = ve->var;
502         if (k->ki_p->ki_stat == SZOMB || !k->ki_valid) {
503                 secs = 0;
504                 psecs = 0;
505         } else {
506                 /*
507                  * This counts time spent handling interrupts.  We could
508                  * fix this, but it is not 100% trivial (and interrupt
509                  * time fractions only work on the sparc anyway).       XXX
510                  */
511                 secs = k->ki_p->ki_runtime / 1000000;
512                 psecs = k->ki_p->ki_runtime % 1000000;
513                 if (sumrusage) {
514                         secs += k->ki_p->ki_childtime.tv_sec;
515                         psecs += k->ki_p->ki_childtime.tv_usec;
516                 }
517                 /*
518                  * round and scale to 100's
519                  */
520                 psecs = (psecs + 5000) / 10000;
521                 secs += psecs / 100;
522                 psecs = psecs % 100;
523         }
524         (void)snprintf(obuff, sizeof(obuff),
525             "%3ld:%02ld%c%02ld", secs/60, secs%60, decimal_point, psecs);
526         (void)printf("%*s", v->width, obuff);
527 }
528
529 void
530 elapsed(KINFO *k, VARENT *ve)
531 {
532         VAR *v;
533         time_t secs;
534         char obuff[128];
535
536         v = ve->var;
537
538         secs = now - k->ki_p->ki_start.tv_sec;
539         (void)snprintf(obuff, sizeof(obuff), "%3ld:%02ld", (long)secs/60,
540             (long)secs%60);
541         (void)printf("%*s", v->width, obuff);
542 }
543
544 double
545 getpcpu(const KINFO *k)
546 {
547         static int failure;
548
549         if (!nlistread)
550                 failure = donlist();
551         if (failure)
552                 return (0.0);
553
554 #define fxtofl(fixpt)   ((double)(fixpt) / fscale)
555
556         /* XXX - I don't like this */
557         if (k->ki_p->ki_swtime == 0 || (k->ki_p->ki_sflag & PS_INMEM) == 0)
558                 return (0.0);
559         if (rawcpu)
560                 return (100.0 * fxtofl(k->ki_p->ki_pctcpu));
561         return (100.0 * fxtofl(k->ki_p->ki_pctcpu) /
562                 (1.0 - exp(k->ki_p->ki_swtime * log(fxtofl(ccpu)))));
563 }
564
565 void
566 pcpu(KINFO *k, VARENT *ve)
567 {
568         VAR *v;
569
570         v = ve->var;
571         (void)printf("%*.1f", v->width, getpcpu(k));
572 }
573
574 static double
575 getpmem(KINFO *k)
576 {
577         static int failure;
578         double fracmem;
579
580         if (!nlistread)
581                 failure = donlist();
582         if (failure)
583                 return (0.0);
584
585         if ((k->ki_p->ki_sflag & PS_INMEM) == 0)
586                 return (0.0);
587         /* XXX want pmap ptpages, segtab, etc. (per architecture) */
588         /* XXX don't have info about shared */
589         fracmem = ((float)k->ki_p->ki_rssize)/mempages;
590         return (100.0 * fracmem);
591 }
592
593 void
594 pmem(KINFO *k, VARENT *ve)
595 {
596         VAR *v;
597
598         v = ve->var;
599         (void)printf("%*.1f", v->width, getpmem(k));
600 }
601
602 void
603 pagein(KINFO *k, VARENT *ve)
604 {
605         VAR *v;
606
607         v = ve->var;
608         (void)printf("%*ld", v->width,
609             k->ki_valid ? k->ki_p->ki_rusage.ru_majflt : 0);
610 }
611
612 /* ARGSUSED */
613 void
614 maxrss(KINFO *k __unused, VARENT *ve)
615 {
616         VAR *v;
617
618         v = ve->var;
619         /* XXX not yet */
620         (void)printf("%*s", v->width, "-");
621 }
622
623 void
624 priorityr(KINFO *k, VARENT *ve)
625 {
626         VAR *v;
627         struct priority *lpri;
628         char str[8];
629         unsigned class, level;
630  
631         v = ve->var;
632         lpri = (struct priority *) ((char *)k + v->off);
633         class = lpri->pri_class;
634         level = lpri->pri_level;
635         switch (class) {
636         case PRI_REALTIME:
637                 snprintf(str, sizeof(str), "real:%u", level);
638                 break;
639         case PRI_TIMESHARE:
640                 strncpy(str, "normal", sizeof(str));
641                 break;
642         case PRI_IDLE:
643                 snprintf(str, sizeof(str), "idle:%u", level);
644                 break;
645         default:
646                 snprintf(str, sizeof(str), "%u:%u", class, level);
647                 break;
648         }
649         str[sizeof(str) - 1] = '\0';
650         (void)printf("%*s", v->width, str);
651 }
652
653 /*
654  * Generic output routines.  Print fields from various prototype
655  * structures.
656  */
657 static void
658 printval(void *bp, VAR *v)
659 {
660         static char ofmt[32] = "%";
661         const char *fcp;
662         char *cp;
663
664         cp = ofmt + 1;
665         fcp = v->fmt;
666         if (v->flag & LJUST)
667                 *cp++ = '-';
668         *cp++ = '*';
669         while ((*cp++ = *fcp++));
670
671         switch (v->type) {
672         case CHAR:
673                 (void)printf(ofmt, v->width, *(char *)bp);
674                 break;
675         case UCHAR:
676                 (void)printf(ofmt, v->width, *(u_char *)bp);
677                 break;
678         case SHORT:
679                 (void)printf(ofmt, v->width, *(short *)bp);
680                 break;
681         case USHORT:
682                 (void)printf(ofmt, v->width, *(u_short *)bp);
683                 break;
684         case INT:
685                 (void)printf(ofmt, v->width, *(int *)bp);
686                 break;
687         case UINT:
688                 (void)printf(ofmt, v->width, *(u_int *)bp);
689                 break;
690         case LONG:
691                 (void)printf(ofmt, v->width, *(long *)bp);
692                 break;
693         case ULONG:
694                 (void)printf(ofmt, v->width, *(u_long *)bp);
695                 break;
696         case KPTR:
697                 (void)printf(ofmt, v->width, *(u_long *)bp);
698                 break;
699         case PGTOK:
700                 (void)printf(ofmt, v->width, ps_pgtok(*(u_long *)bp));
701                 break;
702         default:
703                 errx(1, "unknown type %d", v->type);
704         }
705 }
706
707 void
708 kvar(KINFO *k, VARENT *ve)
709 {
710         VAR *v;
711
712         v = ve->var;
713         printval((char *)((char *)k->ki_p + v->off), v);
714 }
715
716 void
717 rvar(KINFO *k, VARENT *ve)
718 {
719         VAR *v;
720
721         v = ve->var;
722         if (k->ki_valid)
723                 printval((char *)((char *)(&k->ki_p->ki_rusage) + v->off), v);
724         else
725                 (void)printf("%*s", v->width, "-");
726 }
727
728 void
729 lattr(KINFO *k, VARENT *ve)
730 {
731         VAR *v;
732
733         v = ve->var;
734         (void)printf("%-*d", v->width, get_lattr(k->ki_p->ki_pid));
735 }