]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - bin/ps/print.c
Rework storing files thoroughly. This includes:
[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 static void printval(void *, VAR *);
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 SMTX:
231                 *cp = 'M';
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 void
321 tdev(KINFO *k, VARENT *ve)
322 {
323         VAR *v;
324         dev_t dev;
325         char buff[16];
326
327         v = ve->var;
328         dev = k->ki_p->ki_tdev;
329         if (dev == NODEV)
330                 (void)printf("%*s", v->width, "??");
331         else {
332                 (void)snprintf(buff, sizeof(buff),
333                     "%d/%d", major(dev), minor(dev));
334                 (void)printf("%*s", v->width, buff);
335         }
336 }
337
338 void
339 tname(KINFO *k, VARENT *ve)
340 {
341         VAR *v;
342         dev_t dev;
343         char *ttname;
344
345         v = ve->var;
346         dev = k->ki_p->ki_tdev;
347         if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
348                 (void)printf("%*s ", v->width-1, "??");
349         else {
350                 if (strncmp(ttname, "tty", 3) == 0 ||
351                     strncmp(ttname, "cua", 3) == 0)
352                         ttname += 3;
353                 (void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
354                         k->ki_p->ki_kiflag & KI_CTTY ? ' ' : '-');
355         }
356 }
357
358 void
359 longtname(KINFO *k, VARENT *ve)
360 {
361         VAR *v;
362         dev_t dev;
363         char *ttname;
364
365         v = ve->var;
366         dev = k->ki_p->ki_tdev;
367         if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
368                 (void)printf("%-*s", v->width, "??");
369         else
370                 (void)printf("%-*s", v->width, ttname);
371 }
372
373 void
374 started(KINFO *k, VARENT *ve)
375 {
376         VAR *v;
377         time_t then;
378         struct tm *tp;
379         char buf[100];
380         static int  use_ampm = -1;
381
382         v = ve->var;
383         if (!k->ki_valid) {
384                 (void)printf("%-*s", v->width, "-");
385                 return;
386         }
387
388         if (use_ampm < 0)
389                 use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
390
391         then = k->ki_p->ki_start.tv_sec;
392         tp = localtime(&then);
393         if (now - k->ki_p->ki_start.tv_sec < 24 * 3600) {
394                 (void)strftime(buf, sizeof(buf) - 1,
395                 use_ampm ? "%l:%M%p" : "%k:%M  ", tp);
396         } else if (now - k->ki_p->ki_start.tv_sec < 7 * 86400) {
397                 (void)strftime(buf, sizeof(buf) - 1,
398                 use_ampm ? "%a%I%p" : "%a%H  ", tp);
399         } else
400                 (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp);
401         (void)printf("%-*s", v->width, buf);
402 }
403
404 void
405 lstarted(KINFO *k, VARENT *ve)
406 {
407         VAR *v;
408         time_t then;
409         char buf[100];
410
411         v = ve->var;
412         if (!k->ki_valid) {
413                 (void)printf("%-*s", v->width, "-");
414                 return;
415         }
416         then = k->ki_p->ki_start.tv_sec;
417         (void)strftime(buf, sizeof(buf) -1, "%c", localtime(&then));
418         (void)printf("%-*s", v->width, buf);
419 }
420
421 void
422 mtxname(KINFO *k, VARENT *ve)
423 {
424         VAR *v;
425
426         v = ve->var;
427         if (k->ki_p->ki_kiflag & KI_MTXBLOCK) {
428                 if (k->ki_p->ki_mtxname[0] != 0)
429                         (void)printf("%-*.*s", v->width, v->width,
430                                       k->ki_p->ki_mtxname);
431                 else
432                         (void)printf("%-*s", v->width, "???");
433         } else
434                 (void)printf("%-*s", v->width, "-");
435 }
436
437 void
438 wchan(KINFO *k, VARENT *ve)
439 {
440         VAR *v;
441
442         v = ve->var;
443         if (k->ki_p->ki_wchan) {
444                 if (k->ki_p->ki_wmesg[0] != 0)
445                         (void)printf("%-*.*s", v->width, v->width,
446                                       k->ki_p->ki_wmesg);
447                 else
448                         (void)printf("%-*lx", v->width,
449                             (long)k->ki_p->ki_wchan);
450         } else {
451                 (void)printf("%-*s", v->width, "-");
452         }
453 }
454
455 void
456 mwchan(KINFO *k, VARENT *ve)
457 {
458         VAR *v;
459
460         v = ve->var;
461         if (k->ki_p->ki_wchan) {
462                 if (k->ki_p->ki_wmesg[0] != 0)
463                         (void)printf("%-*.*s", v->width, v->width,
464                                       k->ki_p->ki_wmesg);
465                 else
466                         (void)printf("%-*lx", v->width,
467                             (long)k->ki_p->ki_wchan);
468         } else if (k->ki_p->ki_kiflag & KI_MTXBLOCK) {
469                 if (k->ki_p->ki_mtxname[0]) {
470                         (void)printf("%-*.*s", v->width, v->width,
471                             k->ki_p->ki_mtxname);
472                 } else {
473                         (void)printf("%-*s", v->width, "???");
474                 }
475         } else {
476                 (void)printf("%-*s", v->width, "-");
477         }
478 }
479
480 #ifndef pgtok
481 #define pgtok(a)        (((a)*getpagesize())/1024)
482 #endif
483
484 void
485 vsize(KINFO *k, VARENT *ve)
486 {
487         VAR *v;
488
489         v = ve->var;
490         (void)printf("%*lu", v->width, (u_long)(k->ki_p->ki_size / 1024));
491 }
492
493 void
494 cputime(KINFO *k, VARENT *ve)
495 {
496         VAR *v;
497         long secs;
498         long psecs;     /* "parts" of a second. first micro, then centi */
499         char obuff[128];
500         static char decimal_point = 0;
501
502         if (!decimal_point)
503                 decimal_point = localeconv()->decimal_point[0];
504         v = ve->var;
505         if (k->ki_p->ki_stat == SZOMB || !k->ki_valid) {
506                 secs = 0;
507                 psecs = 0;
508         } else {
509                 /*
510                  * This counts time spent handling interrupts.  We could
511                  * fix this, but it is not 100% trivial (and interrupt
512                  * time fractions only work on the sparc anyway).       XXX
513                  */
514                 secs = k->ki_p->ki_runtime / 1000000;
515                 psecs = k->ki_p->ki_runtime % 1000000;
516                 if (sumrusage) {
517                         secs += k->ki_p->ki_childtime.tv_sec;
518                         psecs += k->ki_p->ki_childtime.tv_usec;
519                 }
520                 /*
521                  * round and scale to 100's
522                  */
523                 psecs = (psecs + 5000) / 10000;
524                 secs += psecs / 100;
525                 psecs = psecs % 100;
526         }
527         (void)snprintf(obuff, sizeof(obuff),
528             "%3ld:%02ld%c%02ld", secs/60, secs%60, decimal_point, psecs);
529         (void)printf("%*s", v->width, obuff);
530 }
531
532 void
533 elapsed(KINFO *k, VARENT *ve)
534 {
535         VAR *v;
536         time_t secs;
537         char obuff[128];
538
539         v = ve->var;
540
541         secs = now - k->ki_p->ki_start.tv_sec;
542         (void)snprintf(obuff, sizeof(obuff), "%3ld:%02ld", (long)secs/60,
543             (long)secs%60);
544         (void)printf("%*s", v->width, obuff);
545 }
546
547 double
548 getpcpu(const KINFO *k)
549 {
550         static int failure;
551
552         if (!nlistread)
553                 failure = donlist();
554         if (failure)
555                 return (0.0);
556
557 #define fxtofl(fixpt)   ((double)(fixpt) / fscale)
558
559         /* XXX - I don't like this */
560         if (k->ki_p->ki_swtime == 0 || (k->ki_p->ki_sflag & PS_INMEM) == 0)
561                 return (0.0);
562         if (rawcpu)
563                 return (100.0 * fxtofl(k->ki_p->ki_pctcpu));
564         return (100.0 * fxtofl(k->ki_p->ki_pctcpu) /
565                 (1.0 - exp(k->ki_p->ki_swtime * log(fxtofl(ccpu)))));
566 }
567
568 void
569 pcpu(KINFO *k, VARENT *ve)
570 {
571         VAR *v;
572
573         v = ve->var;
574         (void)printf("%*.1f", v->width, getpcpu(k));
575 }
576
577 static double
578 getpmem(KINFO *k)
579 {
580         static int failure;
581         double fracmem;
582
583         if (!nlistread)
584                 failure = donlist();
585         if (failure)
586                 return (0.0);
587
588         if ((k->ki_p->ki_sflag & PS_INMEM) == 0)
589                 return (0.0);
590         /* XXX want pmap ptpages, segtab, etc. (per architecture) */
591         /* XXX don't have info about shared */
592         fracmem = ((float)k->ki_p->ki_rssize)/mempages;
593         return (100.0 * fracmem);
594 }
595
596 void
597 pmem(KINFO *k, VARENT *ve)
598 {
599         VAR *v;
600
601         v = ve->var;
602         (void)printf("%*.1f", v->width, getpmem(k));
603 }
604
605 void
606 pagein(KINFO *k, VARENT *ve)
607 {
608         VAR *v;
609
610         v = ve->var;
611         (void)printf("%*ld", v->width,
612             k->ki_valid ? k->ki_p->ki_rusage.ru_majflt : 0);
613 }
614
615 /* ARGSUSED */
616 void
617 maxrss(KINFO *k __unused, VARENT *ve)
618 {
619         VAR *v;
620
621         v = ve->var;
622         /* XXX not yet */
623         (void)printf("%*s", v->width, "-");
624 }
625
626 void
627 tsize(KINFO *k, VARENT *ve)
628 {
629         VAR *v;
630
631         v = ve->var;
632         (void)printf("%*ld", v->width, (long)pgtok(k->ki_p->ki_tsize));
633 }
634
635 void
636 priorityr(KINFO *k, VARENT *ve)
637 {
638         VAR *v;
639         struct priority *lpri;
640         char str[8];
641         unsigned class, level;
642  
643         v = ve->var;
644         lpri = (struct priority *) ((char *)k + v->off);
645         class = lpri->pri_class;
646         level = lpri->pri_level;
647         switch (class) {
648         case PRI_REALTIME:
649                 snprintf(str, sizeof(str), "real:%u", level);
650                 break;
651         case PRI_TIMESHARE:
652                 strncpy(str, "normal", sizeof(str));
653                 break;
654         case PRI_IDLE:
655                 snprintf(str, sizeof(str), "idle:%u", level);
656                 break;
657         default:
658                 snprintf(str, sizeof(str), "%u:%u", class, level);
659                 break;
660         }
661         str[sizeof(str) - 1] = '\0';
662         (void)printf("%*s", v->width, str);
663 }
664
665 /*
666  * Generic output routines.  Print fields from various prototype
667  * structures.
668  */
669 static void
670 printval(void *bp, VAR *v)
671 {
672         static char ofmt[32] = "%";
673         const char *fcp;
674         char *cp;
675
676         cp = ofmt + 1;
677         fcp = v->fmt;
678         if (v->flag & LJUST)
679                 *cp++ = '-';
680         *cp++ = '*';
681         while ((*cp++ = *fcp++));
682
683         switch (v->type) {
684         case CHAR:
685                 (void)printf(ofmt, v->width, *(char *)bp);
686                 break;
687         case UCHAR:
688                 (void)printf(ofmt, v->width, *(u_char *)bp);
689                 break;
690         case SHORT:
691                 (void)printf(ofmt, v->width, *(short *)bp);
692                 break;
693         case USHORT:
694                 (void)printf(ofmt, v->width, *(u_short *)bp);
695                 break;
696         case INT:
697                 (void)printf(ofmt, v->width, *(int *)bp);
698                 break;
699         case UINT:
700                 (void)printf(ofmt, v->width, *(u_int *)bp);
701                 break;
702         case LONG:
703                 (void)printf(ofmt, v->width, *(long *)bp);
704                 break;
705         case ULONG:
706                 (void)printf(ofmt, v->width, *(u_long *)bp);
707                 break;
708         case KPTR:
709                 (void)printf(ofmt, v->width, *(u_long *)bp);
710                 break;
711         default:
712                 errx(1, "unknown type %d", v->type);
713         }
714 }
715
716 void
717 kvar(KINFO *k, VARENT *ve)
718 {
719         VAR *v;
720
721         v = ve->var;
722         printval((char *)((char *)k->ki_p + v->off), v);
723 }
724
725 void
726 rvar(KINFO *k, VARENT *ve)
727 {
728         VAR *v;
729
730         v = ve->var;
731         if (k->ki_valid)
732                 printval((char *)((char *)(&k->ki_p->ki_rusage) + v->off), v);
733         else
734                 (void)printf("%*s", v->width, "-");
735 }
736
737 void
738 lattr(KINFO *k, VARENT *ve)
739 {
740         VAR *v;
741
742         v = ve->var;
743         (void)printf("%-*d", v->width, get_lattr(k->ki_p->ki_pid));
744 }