|
|
1.1 root 1: /*-
2: * Copyright (c) 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)ps.c 5.28 (Berkeley) 6/26/90";
28: #endif /* not lint */
29:
30: #include <machine/pte.h>
31:
32: #include <sys/param.h>
33: #include <sys/ioctl.h>
34: #include <sys/tty.h>
35: #include <sys/user.h>
36: #include <sys/proc.h>
37: #include <sys/vm.h>
38: #include <sys/text.h>
39: #include <sys/stat.h>
40: #include <sys/mbuf.h>
41: #include <nlist.h>
42: #include <pwd.h>
43: #include <math.h>
44: #include <errno.h>
45: #include <stdio.h>
46: #include <ctype.h>
47: #include <kvm.h>
48:
49: struct usave {
50: struct proc *u_procp;
51: struct timeval u_start;
52: struct rusage u_ru;
53: struct rusage u_cru;
54: short u_cmask;
55: char u_acflag;
56: };
57:
58: /*
59: * to compute offset in common structures
60: */
61: #define POFF(x) ((int)&((struct proc *)0)->x)
62: #define EOFF(x) ((int)&((struct eproc *)0)->x)
63: #define UOFF(x) ((int)&((struct usave *)0)->x)
64: #define ROFF(x) ((int)&((struct rusage *)0)->x)
65:
66: enum type { CHAR, UCHAR, SHORT, USHORT, LONG, ULONG, KPTR };
67:
68: #define UIDFMT "u"
69: #define UIDLEN 5
70: #define PIDFMT "d"
71: #define PIDLEN 5
72: #define USERLEN 8
73:
74: int needuser, needcomm, neednlist;
75:
76: int command(), ucomm(), logname(), pvar(), evar(), uvar(), rvar(), uname(),
77: runame(), state(), pri(), tdev(), tname(), longtname(), started(),
78: lstarted(), wchan(), vsize(), rssize(), p_rssize(), cputime(),
79: pmem(), pcpu(), pagein(), maxrss(), tsize(), trss();
80: /**
81: utime(), stime(), ixrss(), idrss(), isrss();
82: **/
83:
84: struct usave *saveuser();
85: char *saveargs();
86:
87: struct var {
88: char *name[8]; /* name(s) of variable */
89: char *header; /* default header */
90: int flag;
91: #define USER 0x01 /* requires user structure */
92: #define LJUST 0x02 /* right adjust on output */
93: #define COMM 0x04 /* requires exec arguments and environment (XXX) */
94: #define NLIST 0x08 /* requires nlist to get extra variables */
95: int (*oproc)(); /* output routine */
96: short width; /* printing width */
97: /*
98: * The following (optional) elements are hooks for passing information
99: * to the generic output routines: pvar, evar, uvar (those which print
100: * simple elements from well known structures: proc, eproc, usave)
101: */
102: int off; /* offset in structure */
103: enum type type; /* type of element */
104: char *fmt; /* printf format */
105: /*
106: * glue to link selected fields together
107: */
108: struct var *next;
109: } var[] = {
110: {{"command", "comm", "args"}, "COMMAND", USER|LJUST|COMM,
111: command, 16},
112: {{"ucomm"}, "COMMAND", LJUST, ucomm, MAXCOMLEN},
113: {{"logname"}, "LOGNAME", LJUST, logname, MAXLOGNAME},
114: {{"flag", "f"}, "F", 0, pvar, 7, POFF(p_flag), LONG, "x"},
115: {{"uid"}, "UID", 0, pvar, UIDLEN, POFF(p_uid),USHORT, UIDFMT},
116: {{"ruid"}, "RUID", 0, pvar, UIDLEN, POFF(p_ruid), USHORT, UIDFMT},
117: {{"svuid"}, "SVUID", 0, pvar, UIDLEN, POFF(p_svuid), USHORT, UIDFMT},
118: {{"rgid"}, "RGID", 0, pvar, UIDLEN, POFF(p_rgid), USHORT, UIDFMT},
119: {{"svgid"}, "SVGID", 0, pvar, UIDLEN, POFF(p_svgid), USHORT, UIDFMT},
120: {{"pid"}, "PID", 0, pvar, PIDLEN, POFF(p_pid),SHORT, PIDFMT},
121: {{"ppid"}, "PPID", 0, pvar, PIDLEN, POFF(p_ppid), SHORT, PIDFMT},
122: {{"cp", "cpu"}, "CP", 0, pvar, 3, POFF(p_cpu), UCHAR, "d"},
123: {{"xstat"}, "XSTAT", 0, pvar, 4, POFF(p_xstat), USHORT, "x"},
124: {{"poip"}, "POIP", 0, pvar, 4, POFF(p_poip), SHORT, "d"},
125: {{"nwchan"}, "WCHAN", 0, pvar, 6, POFF(p_wchan), KPTR, "x"},
126: {{"wchan"}, "WCHAN", LJUST, wchan, 6},
127: {{"rlink"}, "RLINK", 0, pvar, 8, POFF(p_rlink), KPTR, "x"},
128: {{"ktrace", "traceflag"}, "KTRACE",
129: 0, pvar, 8, POFF(p_traceflag), LONG, "x"},
130: {{"ktracep", "tracep"}, "KTRACEP",
131: 0, pvar, 8, POFF(p_tracep), LONG, "x"},
132: {{"sig", "pending"}, "PENDING",
133: 0, pvar, 8, POFF(p_sig), LONG, "x"},
134: {{"sigmask", "blocked"}, "BLOCKED",
135: 0, pvar, 8, POFF(p_sigmask), LONG, "x"},
136: {{"sigignore", "ignored"}, "IGNORED",
137: 0, pvar, 8, POFF(p_sigignore), LONG, "x"},
138: {{"sigcatch", "caught"}, "CAUGHT",
139: 0, pvar, 8, POFF(p_sigcatch), LONG, "x"},
140: {{"user", "uname"}, "USER", LJUST, uname, USERLEN},
141: {{"ruser", "runame"}, "RUSER", LJUST, runame, USERLEN},
142: {{"pgid"}, "PGID", 0, evar, PIDLEN, EOFF(e_pgid), USHORT, PIDFMT},
143: {{"jobc"}, "JOBC", 0, evar, 4, EOFF(e_jobc), SHORT, "d"},
144: {{"sess", "session"}, "SESS", 0, evar, 6, EOFF(e_sess), KPTR, "x"},
145: {{"tdev", "dev"}, "TDEV", 0, tdev, 4},
146: {{"tname", "tty", "tt"}, "TT", LJUST, tname, 3},
147: {{"longtname", "longtty"}, "TT", LJUST, longtname, 8},
148: {{"tpgid"}, "TPGID", 0, evar, 4, EOFF(e_tpgid), USHORT, PIDFMT},
149: {{"tsession", "tsess"}, "TSESS",
150: 0, evar, 6, EOFF(e_tsess), KPTR, "x"},
151: {{"paddr", "procaddr"}, "PADDR",
152: 0, evar, 6, EOFF(e_paddr), KPTR, "x"},
153: {{"state", "stat"}, "STAT", 0, state, 4},
154: {{"pri"}, "PRI", 0, pri, 3},
155: {{"usrpri"}, "UPR", 0, pvar, 3, POFF(p_usrpri), CHAR, "d"},
156: {{"nice", "ni"}, "NI", 0, pvar, 2, POFF(p_nice), CHAR, "d"},
157: {{"vsize", "vsz"}, "VSZ", 0, vsize, 5},
158: {{"rssize", "rsz"}, "RSZ", 0, rssize, 4},
159: {{"rss", "p_rss"}, "RSS", 0, p_rssize, 4},
160: {{"u_procp", "uprocp"}, "UPROCP",
161: USER, uvar, 6, UOFF(u_procp), KPTR, "x"},
162: {{"umask", "u_cmask"}, "UMASK",
163: USER, uvar, 3, UOFF(u_cmask), CHAR, "#o"},
164: {{"acflag", "acflg"}, "ACFLG",
165: USER, uvar, 3, UOFF(u_acflag), SHORT, "x"},
166: {{"start"}, "STARTED", USER|LJUST, started, 8},
167: {{"lstart"}, "STARTED", USER|LJUST, lstarted, 28},
168: {{"cputime", "time"}, "TIME", USER, cputime, 9},
169: {{"p_ru"}, "P_RU", 0, pvar, 6, POFF(p_ru), KPTR, "x"},
170: {{"pcpu", "%cpu"}, "%CPU", NLIST, pcpu, 4},
171: {{"pmem", "%mem"}, "%MEM", NLIST, pmem, 4},
172: {{"sl", "slp", "slptime"}, "SL",
173: 0, pvar, 3, POFF(p_slptime), CHAR, "d"},
174: {{"re", "resident"}, "RE",
175: 0, pvar, 3, POFF(p_time), CHAR, "d"},
176: {{"pagein", "majflt"}, "PAGEIN", USER, pagein, 6},
177: {{"lim", "maxrss"}, "LIM", 0, maxrss, 5},
178: {{"tsiz"}, "TSIZ", 0, tsize, 4},
179: {{"trs"}, "TRS", 0, trss, 3},
180: /***
181: {{"utime"}, "UTIME", USER, utime, 4},
182: {{"stime"}, "STIME", USER, stime, 4},
183: {{"ixrss"}, "IXRSS", USER, ixrss, 4},
184: {{"idrss"}, "IDRSS", USER, idrss, 4},
185: {{"isrss"}, "ISRSS", USER, isrss, 4},
186: ***/
187: {{"minflt"}, "MINFLT",
188: USER, rvar, 4, ROFF(ru_minflt), LONG, "d"},
189: {{"majflt"}, "MAJFLT",
190: USER, rvar, 4, ROFF(ru_majflt), LONG, "d"},
191: {{"nswap"}, "NSWAP",
192: USER, rvar, 4, ROFF(ru_nswap), LONG, "d"},
193: {{"inblock", "inblk"}, "INBLK",
194: USER, rvar, 4, ROFF(ru_inblock), LONG, "d"},
195: {{"oublock", "oublk"}, "OUBLK",
196: USER, rvar, 4, ROFF(ru_oublock), LONG, "d"},
197: {{"msgsnd"}, "MSGSND",
198: USER, rvar, 4, ROFF(ru_msgsnd), LONG, "d"},
199: {{"msgrcv"}, "MSGRCV",
200: USER, rvar, 4, ROFF(ru_msgrcv), LONG, "d"},
201: {{"nsignals", "nsigs"}, "NSIGS",
202: USER, rvar, 4, ROFF(ru_nsignals), LONG, "d"},
203: {{"nvcsw", "vcsw"}, "VCSW",
204: USER, rvar, 5, ROFF(ru_nvcsw), LONG, "d"},
205: {{"nivcsw", "ivcsw"}, "IVCSW",
206: USER, rvar, 5, ROFF(ru_nivcsw), LONG, "d"},
207: NULL
208: };
209:
210: /*
211: * combination variables
212: */
213: struct combovar {
214: char *name;
215: char *replace;
216: } combovar[] = {
217: "RUSAGE", "minflt majflt nswap inblock oublock \
218: msgsnd msgrcv nsigs nvcsw nivcsw",
219: 0, 0
220: };
221: #define DFMT "pid tname state cputime comm"
222: #define LFMT \
223: "uid pid ppid cp pri nice vsz rss wchan state tname cputime comm"
224: #define JFMT "user pid ppid pgid sess jobc state tname cputime comm"
225: #define SFMT "uid pid sig sigmask sigignore sigcatch stat tname comm"
226: #define VFMT \
227: "pid tt state time sl re pagein vsz rss lim tsiz trs %cpu %mem comm"
228: #define UFMT \
229: "uname pid %cpu %mem vsz rss tt state start time comm"
230:
231: struct kinfo {
232: struct proc *ki_p; /* proc structure */
233: struct eproc *ki_e; /* extra stuff */
234: struct usave *ki_u; /* interesting parts of user */
235: char *ki_args; /* exec args (should be char **) */
236: char *ki_env; /* environment (should be char **) */
237: } *kinfo;
238:
239: struct var *vhead, *vtail;
240: int termwidth; /* width of screen (0 == infinity) */
241: #define UNLIMITED 0
242: int totwidth; /* calculated width of requested variables */
243: int sumrusage;
244: int rawcpu;
245: int sortby;
246: #define SORTMEM 1
247: #define SORTCPU 2
248:
249: int uid = -1;
250: dev_t ttydev = NODEV;
251: int pid = -1;
252: int all;
253: int xflg;
254: int prtheader;
255: int lineno;
256:
257: /*
258: * variables retrieved via nlist
259: */
260: struct nlist psnl[] = {
261: {"_ecmx"},
262: #define X_ECMX 0
263: {"_fscale"},
264: #define X_FSCALE 1
265: {"_ccpu"},
266: #define X_CCPU 2
267: {NULL}
268: };
269: int fscale;
270: int ecmx;
271: fixpt_t ccpu;
272:
273: #define USAGE "ps [ -(o|O) fmt ] [ -wlvujnsaxSCLmcr ] [ -p pid ] [ -t tty ]"
274:
275: main (argc, argv)
276: char *argv[];
277: {
278: extern char *optarg;
279: extern int optind;
280: int ch;
281: register i;
282: register struct var *v;
283: register struct proc *p;
284: struct winsize ws;
285: struct kinfo_proc *kprocs;
286: int nentries;
287: int fmt = 0;
288: int pscomp();
289: int what, flag;
290: char *kludge_oldps_options();
291:
292: if ((ioctl(1, TIOCGWINSZ, &ws) == -1 &&
293: ioctl(2, TIOCGWINSZ, &ws) == -1 &&
294: ioctl(0, TIOCGWINSZ, &ws) == -1) ||
295: ws.ws_col == 0)
296: termwidth = 79;
297: else
298: termwidth = ws.ws_col - 1;
299: if (argc > 1)
300: argv[1] = kludge_oldps_options(argv[1]);
301:
302: while ((ch = getopt(argc, argv, "o:O:wlvujnsaxt:p:SCLmrhTg")) != EOF)
303: switch((char)ch) {
304: case 'o':
305: parsefmt(optarg);
306: fmt++;
307: break;
308: case 'O':
309: parsefmt("pid");
310: parsefmt(optarg);
311: parsefmt("state tt time command");
312: fmt++;
313: break;
314: case 'w':
315: if (termwidth < 131)
316: termwidth = 131;
317: else
318: termwidth = UNLIMITED;
319: break;
320: case 'l':
321: parsefmt(LFMT);
322: fmt++;
323: break;
324: case 'v':
325: parsefmt(VFMT);
326: sortby = SORTMEM;
327: fmt++;
328: break;
329: case 'u':
330: parsefmt(UFMT);
331: sortby = SORTCPU;
332: fmt++;
333: break;
334: case 'j':
335: parsefmt(JFMT);
336: fmt++;
337: break;
338: case 's':
339: parsefmt(SFMT);
340: fmt++;
341: break;
342: case 'T':
343: case 't': {
344: struct stat stbuf;
345: char *tname, *ttyname();
346: char termname[MAXPATHLEN+1];
347:
348: if (ch == 'T') {
349: if ((tname = ttyname(0)) == NULL)
350: error("<stdin>: not a terminal");
351: } else
352: tname = optarg;
353: if (strlen(tname) == 2) {
354: if (strcmp(tname, "co") == 0)
355: strcpy(termname, "/dev/console");
356: else {
357: strcpy(termname, "/dev/tty");
358: strcat(termname, tname);
359: }
360: } else if (*tname != '/') {
361: strcpy(termname, "/dev/");
362: strcat(termname, tname);
363: } else
364: strcpy(termname, tname);
365: if (stat(termname, &stbuf) == -1)
366: syserror(termname);
367: if ((stbuf.st_mode & S_IFMT) != S_IFCHR)
368: error("%s: not a terminal", termname);
369: ttydev = stbuf.st_rdev;
370: break;
371: }
372: case 'p':
373: pid = atoi(optarg);
374: xflg++;
375: break;
376: case 'S':
377: sumrusage++;
378: break;
379: case 'C':
380: rawcpu++;
381: break;
382: case 'L': {
383: int i = 0;
384: struct combovar *cb = &combovar[0];
385: char *cp;
386:
387: v = &var[0];
388: for (;;) {
389: if (v->name[0] != NULL) {
390: cp = v->name[0];
391: v++;
392: } else if (cb->name != NULL) {
393: cp = cb->name;
394: cb++;
395: } else
396: break;
397: if (termwidth &&
398: (i += strlen(cp)+1) > termwidth)
399: i = strlen(cp), printf("\n");
400: printf("%s ", cp);
401: }
402: printf("\n");
403: exit(0);
404: }
405: case 'a':
406: all++;
407: break;
408: case 'x':
409: xflg++;
410: break;
411: case 'm':
412: sortby = SORTMEM;
413: break;
414: case 'r':
415: sortby = SORTCPU;
416: break;
417: case 'h':
418: prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
419: break;
420: case 'g':
421: break; /* no-op */
422: case '?':
423: default:
424: fprintf(stderr, "usage: %s\n", USAGE);
425: exit(1);
426: }
427: argc -= optind;
428: argv += optind;
429:
430: if (*argv) {
431: char *nlistf, *memf = NULL, *swapf = NULL;
432:
433: nlistf = *argv++;
434: if (*argv) {
435: memf = *argv++;
436: if (*argv)
437: swapf = *argv++;
438: }
439: if (kvm_openfiles(nlistf, memf, swapf) == -1)
440: error("kvm_openfiles: %s", kvm_geterr());
441: }
442:
443: if (!fmt)
444: parsefmt(DFMT);
445:
446: if (!all && ttydev == NODEV && pid == -1) /* XXX - should be cleaner */
447: uid = getuid();
448:
449: /*
450: * scan requested variables, noting what structures are needed,
451: * and adjusting header widths as appropiate.
452: */
453: scanvars();
454: #ifdef notdef
455: if (sortby == SORTCPU)
456: neednlist = 1;
457: #endif
458: if (neednlist)
459: donlist();
460: /*
461: * get proc list
462: */
463: if (uid != -1) {
464: what = KINFO_PROC_UID;
465: flag = uid;
466: } else if (ttydev != NODEV) {
467: what = KINFO_PROC_TTY;
468: flag = ttydev;
469: } else if (pid != -1) {
470: what = KINFO_PROC_PID;
471: flag = pid;
472: } else
473: what = KINFO_PROC_ALL;
474: /*
475: * select procs
476: */
477: if ((nentries = kvm_getprocs(what, flag)) == -1) {
478: fprintf(stderr, "ps: %s\n", kvm_geterr());
479: exit(1);
480: }
481: kinfo = (struct kinfo *)malloc(nentries * sizeof (struct kinfo));
482: if (kinfo == NULL)
483: error("out of memory");
484: i = 0;
485: while ((p = kvm_nextproc()) != NULL) {
486: kinfo[i].ki_p = p;
487: kinfo[i].ki_e = kvm_geteproc(p);
488: if (needuser)
489: saveuser(&kinfo[i]);
490: i++;
491: }
492: nentries = i;
493: /*
494: * print header
495: */
496: printheader();
497: if (nentries == 0)
498: exit(0);
499: /*
500: * sort proc list
501: */
502: qsort(kinfo, nentries, sizeof (struct kinfo), pscomp);
503: /*
504: * for each proc, call each variable output function.
505: */
506: for (i = 0; i < nentries; i++) {
507: if (xflg == 0 && (kinfo[i].ki_e->e_tdev == NODEV ||
508: (kinfo[i].ki_p->p_flag & SCTTY ) == 0))
509: continue;
510: for (v = vhead; v != NULL; v = v->next) {
511: (*v->oproc)(&kinfo[i], v);
512: if (v->next != NULL)
513: putchar(' ');
514: }
515: putchar('\n');
516: if (prtheader && lineno++ == prtheader-4) {
517: putchar('\n');
518: printheader();
519: lineno = 0;
520: }
521: }
522:
523: exit(0);
524: }
525:
526: #define FMTSEP " \t,\n"
527:
528: parsefmt(fmt)
529: char *fmt;
530: {
531: register char *f = fmt, *cp, *hp;
532: struct var *v;
533: char *strtok(), *index();
534: char newbuf[1024], *nb = newbuf; /* XXX */
535: char *lookupcombo();
536: struct var *lookupvar();
537:
538: /*
539: * strtok is not &^%^& re-entrant, so we have
540: * only one level of expansion, looking for combo
541: * variables once here, and expanding the string
542: * before really parsing it. With strtok_r,
543: * you would move the expansion to before the
544: * lookupvar inside the 2nd while loop with a
545: * recursive call to parsefmt.
546: */
547: while ((cp = strtok(f, FMTSEP)) != NULL) {
548: if ((hp = lookupcombo(cp)) == NULL);
549: hp = cp;
550: if (((nb + strlen(hp)) - newbuf) >= 1024)
551: error("format too large");
552: strcpy(nb, hp);
553: while (*nb)
554: nb++;
555: *nb++ = ' ';
556: *nb = '\0';
557: f = NULL;
558: }
559: f = newbuf;
560: while ((cp = strtok(f, FMTSEP)) != NULL) {
561: if (hp = index(cp, '='))
562: *hp++ = '\0';
563: v = lookupvar(cp);
564: if (v == NULL)
565: error("unknown variable in format: %s", cp);
566: if (v->next != NULL || vtail == v)
567: error("can't specify a variable twice: %s", cp);
568: if (hp)
569: v->header = hp;
570: if (vhead == NULL)
571: vhead = vtail = v;
572: else {
573: vtail->next = v;
574: vtail = v;
575: }
576: f = NULL; /* for strtok */
577: }
578:
579: }
580:
581: scanvars()
582: {
583: register i;
584: register struct var *v;
585:
586: for (v = vhead; v != NULL; v = v->next) {
587: i = strlen(v->header);
588: if (v->width < i)
589: v->width = i;
590: totwidth += v->width + 1; /* +1 for space */
591: if (v->flag & USER)
592: needuser = 1;
593: if (v->flag & COMM)
594: needcomm = 1;
595: if (v->flag & NLIST)
596: neednlist = 1;
597: }
598: totwidth--;
599: }
600: printheader()
601: {
602: register struct var *v;
603:
604: for (v = vhead; v != NULL; v = v->next) {
605: if (v->flag & LJUST) {
606: if (v->next == NULL) /* last one */
607: printf("%s", v->header);
608: else
609: printf("%-*s",v->width, v->header);
610: } else
611: printf("%*s",v->width, v->header);
612: if (v->next != NULL)
613: putchar(' ');
614: }
615: putchar('\n');
616: }
617:
618: command(k, v)
619: struct kinfo *k;
620: struct var *v;
621: {
622:
623: if (v->next == NULL) {
624: /* last field */
625: if (termwidth == UNLIMITED)
626: printf("%s", k->ki_args);
627: else {
628: register left = termwidth - (totwidth - v->width);
629: register char *cp = k->ki_args;
630:
631: if (left < 1) /* already wrapped, just use std width */
632: left = v->width;
633: while (left-- && *cp)
634: putchar(*cp++);
635: }
636: } else
637: printf("%-*.*s", v->width, v->width, k->ki_args);
638:
639: }
640:
641: ucomm(k, v)
642: struct kinfo *k;
643: struct var *v;
644: {
645:
646: printf("%-*s", v->width, k->ki_p->p_comm);
647: }
648:
649: logname(k, v)
650: struct kinfo *k;
651: struct var *v;
652: {
653:
654: printf("%-*s", v->width, k->ki_p->p_logname);
655: }
656:
657: state(k, v)
658: struct kinfo *k;
659: struct var *v;
660: {
661: char buf[16];
662: register char *cp = buf;
663: register struct proc *p = k->ki_p;
664: register flag = p->p_flag;
665:
666: switch (p->p_stat) {
667:
668: case SSTOP:
669: *cp = 'T';
670: break;
671:
672: case SSLEEP:
673: if (flag & SSINTR) /* interuptable (long) */
674: *cp = p->p_slptime >= MAXSLP ? 'I' : 'S';
675: else
676: *cp = (flag & SPAGE) ? 'P' : 'D';
677: break;
678:
679: case SRUN:
680: case SIDL:
681: *cp = 'R';
682: break;
683:
684: case SZOMB:
685: *cp = 'Z';
686: break;
687:
688: default:
689: *cp = '?';
690: }
691: cp++;
692: if (flag & SLOAD) {
693: if (p->p_rssize > p->p_maxrss)
694: *cp++ = '>';
695: } else
696: *cp++ = 'W';
697: if (p->p_nice < NZERO)
698: *cp++ = '<';
699: else if (p->p_nice > NZERO)
700: *cp++ = 'N';
701: if (flag & SUANOM)
702: *cp++ = 'A';
703: else if (flag & SSEQL)
704: *cp++ = 'S';
705: if (flag & STRC)
706: *cp++ = 'X';
707: if (flag & SWEXIT)
708: *cp++ = 'E';
709: if (flag & SVFORK)
710: *cp++ = 'V';
711: if (flag & (SSYS|SLOCK|SULOCK|SKEEP|SPHYSIO))
712: *cp++ = 'L';
713: if (k->ki_e->e_flag & EPROC_SLEADER)
714: *cp++ = 's';
715: if ((flag & SCTTY) && k->ki_e->e_pgid == k->ki_e->e_tpgid)
716: *cp++ = '+';
717: *cp = '\0';
718: printf("%-*s", v->width, buf);
719: }
720:
721: pri(k, v)
722: struct kinfo *k;
723: struct var *v;
724: {
725:
726: printf("%*d", v->width, k->ki_p->p_pri - PZERO);
727: }
728:
729: uname(k, v)
730: struct kinfo *k;
731: struct var *v;
732: {
733:
734: printf("%-*s", v->width, user_from_uid(k->ki_p->p_uid, 0));
735: }
736:
737: runame(k, v)
738: struct kinfo *k;
739: struct var *v;
740: {
741:
742: printf("%-*s", v->width, user_from_uid(k->ki_p->p_ruid, 0));
743: }
744:
745: tdev(k, v)
746: struct kinfo *k;
747: struct var *v;
748: {
749: dev_t dev = k->ki_e->e_tdev;
750:
751: if (dev == NODEV)
752: printf("%*s", v->width, "??");
753: else {
754: char buff[16];
755:
756: sprintf(buff, "%d/%d", major(dev), minor(dev));
757: printf("%*s", v->width, buff);
758: }
759: }
760:
761: extern char *devname();
762:
763: tname(k, v)
764: struct kinfo *k;
765: struct var *v;
766: {
767: dev_t dev = k->ki_e->e_tdev;
768: char *tname;
769:
770: if (dev == NODEV || (tname = devname(dev, S_IFCHR)) == NULL)
771: printf("%-*s", v->width, "??");
772: else {
773: if (strncmp(tname, "tty", 3) == 0)
774: tname += 3;
775: printf("%*.*s%c", v->width-1, v->width-1, tname,
776: k->ki_e->e_flag & EPROC_CTTY ? ' ' : '-');
777: }
778: }
779:
780: longtname(k, v)
781: struct kinfo *k;
782: struct var *v;
783: {
784: dev_t dev = k->ki_e->e_tdev;
785: char *tname;
786:
787: if (dev == NODEV || (tname = devname(dev, S_IFCHR)) == NULL)
788: printf("%-*s", v->width, "??");
789: else
790: printf("%-*s", v->width, tname);
791: }
792:
793: #include <sys/time.h>
794:
795: started(k, v)
796: struct kinfo *k;
797: struct var *v;
798: {
799: extern char *attime();
800:
801: printf("%-*s", v->width, k->ki_u ?
802: attime(&k->ki_u->u_start.tv_sec) : "-");
803:
804: }
805:
806: lstarted(k, v)
807: struct kinfo *k;
808: struct var *v;
809: {
810: extern char *ctime();
811: char *tp;
812:
813: if (k->ki_u)
814: (tp = ctime(&k->ki_u->u_start.tv_sec))[24] = '\0';
815: else
816: tp = "-";
817: printf("%-*s", v->width, tp);
818: }
819:
820: wchan(k, v)
821: struct kinfo *k;
822: struct var *v;
823: {
824:
825: if (k->ki_p->p_wchan) {
826: if (k->ki_p->p_pri > PZERO)
827: printf("%-*.*s", v->width, v->width, k->ki_e->e_wmesg);
828: else
829: printf("%*x", v->width,
830: (int)k->ki_p->p_wchan &~ KERNBASE);
831: } else
832: printf("%-*s", v->width, "-");
833: }
834:
835: #define pgtok(a) (((a)*NBPG)/1024)
836: #define pgtok(a) (((a)*NBPG)/1024)
837:
838: vsize(k, v)
839: struct kinfo *k;
840: struct var *v;
841: {
842:
843: printf("%*d", v->width,
844: pgtok(k->ki_p->p_dsize + k->ki_p->p_ssize + k->ki_e->e_xsize));
845: }
846:
847: rssize(k, v)
848: struct kinfo *k;
849: struct var *v;
850: {
851:
852: printf("%*d", v->width,
853: pgtok(k->ki_p->p_rssize + (k->ki_e->e_xccount ?
854: (k->ki_e->e_xrssize / k->ki_e->e_xccount) : 0)));
855: }
856:
857: p_rssize(k, v) /* doesn't account for text */
858: struct kinfo *k;
859: struct var *v;
860: {
861:
862: printf("%*d", v->width, pgtok(k->ki_p->p_rssize));
863: }
864:
865: cputime(k, v)
866: struct kinfo *k;
867: struct var *v;
868: {
869: long secs;
870: long psecs; /* "parts" of a second. first micro, then centi */
871: char obuff[128];
872:
873: if (k->ki_p->p_stat == SZOMB || k->ki_u == NULL) {
874: secs = 0;
875: psecs = 0;
876: } else {
877: secs = k->ki_p->p_utime.tv_sec +
878: k->ki_p->p_stime.tv_sec;
879: psecs = k->ki_p->p_utime.tv_usec +
880: k->ki_p->p_stime.tv_usec;
881: if (sumrusage) {
882: secs += k->ki_u->u_cru.ru_utime.tv_sec +
883: k->ki_u->u_cru.ru_stime.tv_sec;
884: psecs += k->ki_u->u_cru.ru_utime.tv_usec +
885: k->ki_u->u_cru.ru_stime.tv_usec;
886: }
887: /*
888: * round and scale to 100's
889: */
890: psecs = (psecs + 5000) / 10000;
891: if (psecs >= 100) {
892: psecs -= 100;
893: secs++;
894: }
895: }
896: sprintf(obuff, "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
897: printf("%*s", v->width, obuff);
898: }
899:
900: double
901: getpcpu(k)
902: struct kinfo *k;
903: {
904: /*
905: * note: this routine requires ccpu and fscale
906: * be initialized. If you call this routine from
907: * somewhere new, insure that the "neednlist" flag
908: * gets set.
909: */
910: struct proc *p = k->ki_p;
911: #define fxtofl(fixpt) ((double)(fixpt) / fscale)
912:
913: if (p->p_time == 0 || (p->p_flag & SLOAD) == 0) /* XXX - I don't like this */
914: return (0.0);
915: if (rawcpu)
916: return (100.0 * fxtofl(p->p_pctcpu));
917: return (100.0 * fxtofl(p->p_pctcpu) /
918: (1.0 - exp(p->p_time * log(fxtofl(ccpu)))));
919: }
920:
921: pcpu(k, v)
922: struct kinfo *k;
923: struct var *v;
924: {
925:
926: printf("%*.1f", v->width, getpcpu(k));
927: }
928:
929: double
930: getpmem(k, v)
931: struct kinfo *k;
932: struct var *v;
933: {
934: struct proc *p = k->ki_p;
935: struct eproc *e = k->ki_e;
936: double fracmem;
937: int szptudot;
938: /*
939: * note: this routine requires that ecmx
940: * be initialized. If you call this routine from
941: * somewhere new, insure that the "neednlist" flag
942: * gets set.
943: */
944:
945: if (p->p_flag & SLOAD == 0)
946: return (0.0);
947: szptudot = UPAGES + clrnd(ctopt(p->p_dsize + p->p_ssize + e->e_xsize));
948: fracmem = ((float)p->p_rssize + szptudot)/CLSIZE/ecmx;
949: if (p->p_textp && e->e_xccount)
950: fracmem += ((float)e->e_xrssize)/CLSIZE/e->e_xccount/ecmx;
951: return (100.0 * fracmem);
952: }
953:
954: pmem(k, v)
955: struct kinfo *k;
956: struct var *v;
957: {
958:
959: printf("%*.1f", v->width, getpmem(k));
960: }
961:
962: pagein(k, v)
963: struct kinfo *k;
964: struct var *v;
965: {
966:
967: printf("%*d", v->width, k->ki_u ? k->ki_u->u_ru.ru_majflt : 0);
968: }
969:
970: maxrss(k, v)
971: struct kinfo *k;
972: struct var *v;
973: {
974:
975: if (k->ki_p->p_maxrss != (RLIM_INFINITY/NBPG))
976: printf("%*d", v->width, pgtok(k->ki_p->p_maxrss));
977: else
978: printf("%*s", v->width, "-");
979: }
980:
981: tsize(k, v)
982: struct kinfo *k;
983: struct var *v;
984: {
985:
986: printf("%*d", v->width, pgtok(k->ki_e->e_xsize));
987: }
988:
989: trss(k, v)
990: struct kinfo *k;
991: struct var *v;
992: {
993:
994: printf("%*d", v->width, pgtok(k->ki_e->e_xrssize));
995: }
996:
997: /*
998: * Generic output routines. Print fields from various prototype
999: * structures.
1000: */
1001: pvar(k, v)
1002: struct kinfo *k;
1003: struct var *v;
1004: {
1005:
1006: printval((char *)((char *)k->ki_p + v->off), v);
1007: }
1008:
1009: evar(k, v)
1010: struct kinfo *k;
1011: struct var *v;
1012: {
1013:
1014: printval((char *)((char *)k->ki_e + v->off), v);
1015: }
1016:
1017: uvar(k, v)
1018: struct kinfo *k;
1019: struct var *v;
1020: {
1021:
1022: if (k->ki_u)
1023: printval((char *)((char *)k->ki_u + v->off), v);
1024: else
1025: printf("%*s", v->width, "-");
1026: }
1027:
1028: rvar(k, v)
1029: struct kinfo *k;
1030: struct var *v;
1031: {
1032:
1033: if (k->ki_u)
1034: printval((char *)((char *)(&k->ki_u->u_ru) + v->off), v);
1035: else
1036: printf("%*s", v->width, "-");
1037: }
1038:
1039: char *
1040: lookupcombo(cp)
1041: char *cp;
1042: {
1043: register struct combovar *cv = &combovar[0];
1044:
1045: for (; cv->name; cv++)
1046: if (strcmp(cp, cv->name) == 0)
1047: return (cv->replace);
1048: return (NULL);
1049: }
1050:
1051: struct var *
1052: lookupvar(cp)
1053: char *cp;
1054: {
1055: register int i, j;
1056:
1057: for (i=0; var[i].name[0] != NULL; i++)
1058: for (j=0; var[i].name[j] != NULL; j++)
1059: if (strcmp(cp, var[i].name[j]) == 0)
1060: return (&var[i]);
1061: return (NULL);
1062: }
1063:
1064: printval(bp, v)
1065: char *bp;
1066: struct var *v;
1067: {
1068: static char ofmt[32] = "%";
1069: register char *cp = ofmt+1, *fcp = v->fmt;
1070:
1071: if (v->flag & LJUST)
1072: *cp++ = '-';
1073: *cp++ = '*';
1074: while (*cp++ = *fcp++)
1075: ;
1076:
1077: switch (v->type) {
1078: case CHAR:
1079: printf(ofmt, v->width, *(char *)bp);
1080: break;
1081:
1082: case UCHAR:
1083: printf(ofmt, v->width, *(u_char *)bp);
1084: break;
1085:
1086: case SHORT:
1087: printf(ofmt, v->width, *(short *)bp);
1088: break;
1089:
1090: case USHORT:
1091: printf(ofmt, v->width, *(u_short *)bp);
1092: break;
1093:
1094: case LONG:
1095: printf(ofmt, v->width, *(long *)bp);
1096: break;
1097:
1098: case ULONG:
1099: printf(ofmt, v->width, *(u_long *)bp);
1100: break;
1101:
1102: case KPTR:
1103: printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE);
1104: break;
1105:
1106: default:
1107: error("unknown type %d", v->type);
1108: }
1109: }
1110:
1111: /* XXX - redo */
1112: struct usave *
1113: saveuser(ki)
1114: struct kinfo *ki;
1115: {
1116: register struct usave *usp;
1117: register struct user *up;
1118:
1119: if ((usp = (struct usave *)calloc(1, sizeof (struct usave))) == NULL) {
1120: fprintf(stderr, "ps: out of memory\n");
1121: exit(1);
1122: }
1123: ki->ki_u = usp;
1124: up = kvm_getu(ki->ki_p);
1125: /*
1126: * save arguments if needed
1127: */
1128: if (needcomm)
1129: ki->ki_args = saveargs(ki->ki_p, up);
1130: else
1131: ki->ki_args = NULL;
1132: if (up != NULL) {
1133: /*
1134: * save important fields
1135: */
1136: usp->u_procp = up->u_procp;
1137: usp->u_start = up->u_start;
1138: usp->u_ru = up->u_ru;
1139: usp->u_cru = up->u_cru;
1140: usp->u_cmask = up->u_cmask;
1141: usp->u_acflag = up->u_acflag;
1142: }
1143: return;
1144: }
1145:
1146: char *
1147: saveargs(p, up)
1148: struct proc *p;
1149: struct user *up;
1150: {
1151: char *savestr();
1152:
1153: return(savestr(kvm_getargs(p, up)));
1154: }
1155:
1156:
1157: pscomp(k1, k2)
1158: struct kinfo *k1, *k2;
1159: {
1160: int i;
1161: #define VSIZE(k) ((k)->ki_p->p_dsize + (k)->ki_p->p_ssize + (k)->ki_e->e_xsize)
1162:
1163: if (sortby == SORTCPU)
1164: return (getpcpu(k2) - getpcpu(k1));
1165: #ifdef notyet
1166: if (sortby == SORTRUN)
1167: return (proc_compare(k1->ki_p, k2->ki_p));
1168: #endif
1169: if (sortby == SORTMEM)
1170: return (VSIZE(k2) - VSIZE(k1));
1171: i = k1->ki_e->e_tdev - k2->ki_e->e_tdev;
1172: if (i == 0)
1173: i = k1->ki_p->p_pid - k2->ki_p->p_pid;
1174: return (i);
1175: }
1176:
1177: donlist()
1178: {
1179: if (kvm_nlist(psnl) != 0)
1180: error("can't get namelist");
1181: if (kvm_read(psnl[X_FSCALE].n_value, &fscale, sizeof(int)) !=
1182: sizeof (int))
1183: error("error reading fscale: %s", kvm_geterr());
1184: if (kvm_read(psnl[X_ECMX].n_value, &ecmx, sizeof(int)) !=
1185: sizeof (int))
1186: error("error reading ecmx: %s", kvm_geterr());
1187: if (kvm_read(psnl[X_CCPU].n_value, &ccpu, sizeof(fixpt_t)) !=
1188: sizeof (fixpt_t))
1189: error("error reading ccpu: %s", kvm_geterr());
1190: }
1191:
1192: char *
1193: savestr(cp)
1194: char *cp;
1195: {
1196: register unsigned len;
1197: register char *dp;
1198:
1199: len = strlen(cp);
1200: dp = (char *)calloc(len+1, sizeof (char));
1201: (void) strcpy(dp, cp);
1202: return (dp);
1203: }
1204:
1205: error(a, b, c, d, e)
1206: char *a, *b, *c, *d, *e;
1207: {
1208: fprintf(stderr, "ps: ");
1209: fprintf(stderr, a, b, c, d, e);
1210: fprintf(stderr, "\n");
1211: exit(1);
1212: }
1213:
1214: syserror(a)
1215: char *a;
1216: {
1217: extern errno;
1218:
1219: error("%s: %s", a, strerror(errno));
1220: }
1221:
1222: /*
1223: * ICK (all for getopt), would rather hide the ugliness
1224: * here than taint the main code.
1225: *
1226: * ps foo -> ps -foo
1227: * ps 34 -> ps -p34
1228: *
1229: * The old convention that 't' with no trailing tty arg means the users
1230: * tty, is only supported if argv[1] doesn't begin with a '-'. This same
1231: * feature is available with the option 'T', which takes no argument.
1232: */
1233: char *
1234: kludge_oldps_options(s)
1235: char *s;
1236: {
1237: int len = strlen(s), numlen = 0;
1238: char *newopts, *ns, *cp;
1239:
1240: if ((newopts = ns = (char *)malloc(len+2)) == NULL)
1241: error("out of memory");
1242: /*
1243: * options begin with '-'
1244: */
1245: if (*s != '-')
1246: *ns++ = '-'; /* add option flag */
1247: /*
1248: * gaze to end of argv[1]
1249: */
1250: cp = s + len - 1;
1251: /*
1252: * if last letter is a 't' flag with no argument (in the context
1253: * of the oldps options -- option string NOT starting with a '-' --
1254: * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0).
1255: */
1256: if (*cp == 't' && *s != '-')
1257: *cp = 'T';
1258: else {
1259: /*
1260: * otherwise check for trailing number, which *may* be a
1261: * pid.
1262: */
1263: while (isdigit(*cp)) {
1264: --cp;
1265: numlen++;
1266: }
1267: }
1268: cp++;
1269: bcopy(s, ns, cp - s); /* copy everything up to trailing number */
1270: while (*ns)
1271: ns++;
1272: /*
1273: * if there's a trailing number, and not a preceding 'p' (pid) or
1274: * 't' (tty) flag, then assume it's a pid and insert a 'p' flag.
1275: */
1276: if (isdigit(*cp) && (cp == s || *(cp-1) != 't' && *(cp-1) != 'p' &&
1277: ((cp-1) == s || *(cp-2) != 't')))
1278: *ns++ = 'p';
1279: strcat(ns, cp); /* and append the number */
1280:
1281: return (newopts);
1282: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.