Index: head/bin/ps/extern.h =================================================================== --- head/bin/ps/extern.h (revision 72376) +++ head/bin/ps/extern.h (revision 72377) @@ -1,85 +1,85 @@ /*- * Copyright (c) 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)extern.h 8.3 (Berkeley) 4/2/94 * $FreeBSD$ */ struct kinfo; struct nlist; struct var; struct varent; extern fixpt_t ccpu; extern int eval, fscale, mempages, nlistread, rawcpu, cflag; extern int sumrusage, termwidth, totwidth; extern VAR var[]; extern VARENT *vhead; __BEGIN_DECLS void command __P((KINFO *, VARENT *)); void cputime __P((KINFO *, VARENT *)); int donlist __P((void)); char *fmt_argv __P((char **, char *, int)); double getpcpu __P((KINFO *)); double getpmem __P((KINFO *)); void kvar __P((KINFO *, VARENT *)); void logname __P((KINFO *, VARENT *)); void longtname __P((KINFO *, VARENT *)); void lstarted __P((KINFO *, VARENT *)); void maxrss __P((KINFO *, VARENT *)); void mtxname __P((KINFO *, VARENT *)); void nlisterr __P((struct nlist *)); void p_rssize __P((KINFO *, VARENT *)); void pagein __P((KINFO *, VARENT *)); void parsefmt __P((char *)); void pcpu __P((KINFO *, VARENT *)); void pmem __P((KINFO *, VARENT *)); void pri __P((KINFO *, VARENT *)); -void rtprior __P((KINFO *, VARENT *)); +void priorityr __P((KINFO *, VARENT *)); void printheader __P((void)); void rssize __P((KINFO *, VARENT *)); void runame __P((KINFO *, VARENT *)); int s_runame __P((KINFO *)); void rvar __P((KINFO *, VARENT *)); void showkey __P((void)); void started __P((KINFO *, VARENT *)); void state __P((KINFO *, VARENT *)); void tdev __P((KINFO *, VARENT *)); void tname __P((KINFO *, VARENT *)); void tsize __P((KINFO *, VARENT *)); void ucomm __P((KINFO *, VARENT *)); void uname __P((KINFO *, VARENT *)); int s_uname __P((KINFO *)); void vsize __P((KINFO *, VARENT *)); void wchan __P((KINFO *, VARENT *)); __END_DECLS Index: head/bin/ps/keyword.c =================================================================== --- head/bin/ps/keyword.c (revision 72376) +++ head/bin/ps/keyword.c (revision 72377) @@ -1,274 +1,275 @@ /*- * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)keyword.c 8.5 (Berkeley) 4/2/94"; #else static const char rcsid[] = "$FreeBSD$"; #endif #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ps.h" static VAR *findvar __P((char *)); static int vcmp __P((const void *, const void *)); #ifdef NOTINUSE int utime(), stime(), ixrss(), idrss(), isrss(); {{"utime"}, "UTIME", USER, utime, NULL, 4}, {{"stime"}, "STIME", USER, stime, NULL, 4}, {{"ixrss"}, "IXRSS", USER, ixrss, NULL, 4}, {{"idrss"}, "IDRSS", USER, idrss, NULL, 4}, {{"isrss"}, "ISRSS", USER, isrss, NULL, 4}, #endif /* Compute offset in common structures. */ #define KOFF(x) offsetof(struct kinfo_proc, x) #define UOFF(x) offsetof(struct usave, x) #define ROFF(x) offsetof(struct rusage, x) #define UIDFMT "u" #define UIDLEN 5 #define PIDFMT "d" #define PIDLEN 5 #define USERLEN UT_NAMESIZE VAR var[] = { {"%cpu", "%CPU", NULL, 0, pcpu, NULL, 4}, {"%mem", "%MEM", NULL, 0, pmem, NULL, 4}, {"acflag", "ACFLG", NULL, 0, kvar, NULL, 3, KOFF(ki_acflag), USHORT, "x"}, {"acflg", "", "acflag"}, {"blocked", "", "sigmask"}, {"caught", "", "sigcatch"}, {"command", "COMMAND", NULL, COMM|LJUST|USER, command, NULL, 16}, {"cpu", "CPU", NULL, 0, kvar, NULL, 3, KOFF(ki_estcpu), UINT, "d"}, {"cputime", "", "time"}, {"f", "F", NULL, 0, kvar, NULL, 7, KOFF(ki_flag), INT, "x"}, {"flags", "", "f"}, {"ignored", "", "sigignore"}, {"inblk", "INBLK", NULL, USER, rvar, NULL, 4, ROFF(ru_inblock), LONG, "ld"}, {"inblock", "", "inblk"}, {"jobc", "JOBC", NULL, 0, kvar, NULL, 4, KOFF(ki_jobc), SHORT, "d"}, {"ktrace", "KTRACE", NULL, 0, kvar, NULL, 8, KOFF(ki_traceflag), INT, "x"}, {"lim", "LIM", NULL, 0, maxrss, NULL, 5}, {"login", "LOGIN", NULL, LJUST, logname, NULL, MAXLOGNAME-1}, {"logname", "", "login"}, {"lstart", "STARTED", NULL, LJUST|USER, lstarted, NULL, 28}, {"majflt", "MAJFLT", NULL, USER, rvar, NULL, 4, ROFF(ru_majflt), LONG, "ld"}, {"minflt", "MINFLT", NULL, USER, rvar, NULL, 4, ROFF(ru_minflt), LONG, "ld"}, {"mtxname", "MUTEX", NULL, LJUST, mtxname, NULL, 6}, {"msgrcv", "MSGRCV", NULL, USER, rvar, NULL, 4, ROFF(ru_msgrcv), LONG, "ld"}, {"msgsnd", "MSGSND", NULL, USER, rvar, NULL, 4, ROFF(ru_msgsnd), LONG, "ld"}, {"ni", "", "nice"}, {"nice", "NI", NULL, 0, kvar, NULL, 2, KOFF(ki_nice), CHAR, "d"}, {"nivcsw", "NIVCSW", NULL, USER, rvar, NULL, 5, ROFF(ru_nivcsw), LONG, "ld"}, {"nsignals", "", "nsigs"}, {"nsigs", "NSIGS", NULL, USER, rvar, NULL, 4, ROFF(ru_nsignals), LONG, "ld"}, {"nswap", "NSWAP", NULL, USER, rvar, NULL, 4, ROFF(ru_nswap), LONG, "ld"}, {"nvcsw", "NVCSW", NULL, USER, rvar, NULL, 5, ROFF(ru_nvcsw), LONG, "ld"}, {"nwchan", "WCHAN", NULL, 0, kvar, NULL, 6, KOFF(ki_wchan), KPTR, "lx"}, {"oublk", "OUBLK", NULL, USER, rvar, NULL, 4, ROFF(ru_oublock), LONG, "ld"}, {"oublock", "", "oublk"}, {"paddr", "PADDR", NULL, 0, kvar, NULL, 6, KOFF(ki_paddr), KPTR, "lx"}, {"pagein", "PAGEIN", NULL, USER, pagein, NULL, 6}, {"pcpu", "", "%cpu"}, {"pending", "", "sig"}, {"pgid", "PGID", NULL, 0, kvar, NULL, PIDLEN, KOFF(ki_pgid), UINT, PIDFMT}, {"pid", "PID", NULL, 0, kvar, NULL, PIDLEN, KOFF(ki_pid), UINT, PIDFMT}, {"pmem", "", "%mem"}, {"ppid", "PPID", NULL, 0, kvar, NULL, PIDLEN, KOFF(ki_ppid), UINT, PIDFMT}, {"pri", "PRI", NULL, 0, pri, NULL, 3}, {"re", "RE", NULL, 0, kvar, NULL, 3, KOFF(ki_swtime), UINT, "d"}, {"rgid", "RGID", NULL, 0, kvar, NULL, UIDLEN, KOFF(ki_rgid), UINT, UIDFMT}, {"rss", "RSS", NULL, 0, kvar, NULL, 4, KOFF(ki_rssize), UINT, "d"}, - {"rtprio", "RTPRIO", NULL, 0, rtprior, NULL, 7, KOFF(ki_rtprio)}, + {"rtprio", "RTPRIO", NULL, 0, priorityr, NULL, 7, KOFF(ki_pri)}, {"ruid", "RUID", NULL, 0, kvar, NULL, UIDLEN, KOFF(ki_ruid), UINT, UIDFMT}, {"ruser", "RUSER", NULL, LJUST|DSIZ, runame, s_runame, USERLEN}, {"sig", "PENDING", NULL, 0, kvar, NULL, 8, KOFF(ki_siglist), INT, "x"}, {"sigcatch", "CAUGHT", NULL, 0, kvar, NULL, 8, KOFF(ki_sigcatch), UINT, "x"}, {"sigignore", "IGNORED", NULL, 0, kvar, NULL, 8, KOFF(ki_sigignore), UINT, "x"}, {"sigmask", "BLOCKED", NULL, 0, kvar, NULL, 8, KOFF(ki_sigmask), UINT, "x"}, {"sl", "SL", NULL, 0, kvar, NULL, 3, KOFF(ki_slptime), UINT, "d"}, {"start", "STARTED", NULL, LJUST|USER, started, NULL, 7}, {"stat", "", "state"}, {"state", "STAT", NULL, 0, state, NULL, 4}, {"svgid", "SVGID", NULL, 0, kvar, NULL, UIDLEN, KOFF(ki_svgid), UINT, UIDFMT}, {"svuid", "SVUID", NULL, 0, kvar, NULL, UIDLEN, KOFF(ki_svuid), UINT, UIDFMT}, {"tdev", "TDEV", NULL, 0, tdev, NULL, 4}, {"time", "TIME", NULL, USER, cputime, NULL, 9}, {"tpgid", "TPGID", NULL, 0, kvar, NULL, 4, KOFF(ki_tpgid), UINT, PIDFMT}, {"tsiz", "TSIZ", NULL, 0, tsize, NULL, 4}, {"tt", "TT ", NULL, 0, tname, NULL, 4}, {"tty", "TTY", NULL, LJUST, longtname, NULL, 8}, {"ucomm", "UCOMM", NULL, LJUST, ucomm, NULL, MAXCOMLEN}, {"uid", "UID", NULL, 0, kvar, NULL, UIDLEN, KOFF(ki_uid), UINT, UIDFMT}, - {"upr", "UPR", NULL, 0, kvar, NULL, 3, KOFF(ki_usrpri), CHAR, "d"}, + {"upr", "UPR", NULL, 0, kvar, NULL, 3, KOFF(ki_pri.pri_user), + UCHAR, "d"}, {"user", "USER", NULL, LJUST|DSIZ, uname, s_uname, USERLEN}, {"usrpri", "", "upr"}, {"vsize", "", "vsz"}, {"vsz", "VSZ", NULL, 0, vsize, NULL, 5}, {"wchan", "WCHAN", NULL, LJUST, wchan, NULL, 6}, {"xstat", "XSTAT", NULL, 0, kvar, NULL, 4, KOFF(ki_xstat), USHORT, "x"}, {""}, }; void showkey() { VAR *v; int i; char *p, *sep; i = 0; sep = ""; for (v = var; *(p = v->name); ++v) { int len = strlen(p); if (termwidth && (i += len + 1) > termwidth) { i = len; sep = "\n"; } (void) printf("%s%s", sep, p); sep = " "; } (void) printf("\n"); } void parsefmt(p) char *p; { static struct varent *vtail; #define FMTSEP " \t,\n" while (p && *p) { char *cp; VAR *v; struct varent *vent; while ((cp = strsep(&p, FMTSEP)) != NULL && *cp == '\0') /* void */; if (!(v = findvar(cp))) continue; if ((vent = malloc(sizeof(struct varent))) == NULL) err(1, NULL); vent->var = v; vent->next = NULL; if (vhead == NULL) vhead = vtail = vent; else { vtail->next = vent; vtail = vent; } } if (!vhead) errx(1, "no valid keywords"); } static VAR * findvar(p) char *p; { VAR *v, key; char *hp; int vcmp(); hp = strchr(p, '='); if (hp) *hp++ = '\0'; key.name = p; v = bsearch(&key, var, sizeof(var)/sizeof(VAR) - 1, sizeof(VAR), vcmp); if (v && v->alias) { if (hp) { warnx("%s: illegal keyword specification", p); eval = 1; } parsefmt(v->alias); return ((VAR *)NULL); } if (!v) { warnx("%s: keyword not found", p); eval = 1; } else if (hp) v->header = hp; return (v); } static int vcmp(a, b) const void *a, *b; { return (strcmp(((VAR *)a)->name, ((VAR *)b)->name)); } Index: head/bin/ps/print.c =================================================================== --- head/bin/ps/print.c (revision 72376) +++ head/bin/ps/print.c (revision 72377) @@ -1,722 +1,722 @@ /*- * Copyright (c) 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ps.h" void printheader() { VAR *v; struct varent *vent; for (vent = vhead; vent; vent = vent->next) { v = vent->var; if (v->flag & LJUST) { if (vent->next == NULL) /* last one */ (void)printf("%s", v->header); else (void)printf("%-*s", v->width, v->header); } else (void)printf("%*s", v->width, v->header); if (vent->next != NULL) (void)putchar(' '); } (void)putchar('\n'); } void command(k, ve) KINFO *k; VARENT *ve; { VAR *v; int left; char *cp, *vis_env, *vis_args; v = ve->var; if (cflag) { if (ve->next == NULL) /* last field, don't pad */ (void)printf("%s", k->ki_p->ki_comm); else (void)printf("%-*s", v->width, k->ki_p->ki_comm); return; } if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL) err(1, NULL); strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH); if (k->ki_env) { if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1)) == NULL) err(1, NULL); strvis(vis_env, k->ki_env, VIS_TAB | VIS_NL | VIS_NOSLASH); } else vis_env = NULL; if (ve->next == NULL) { /* last field */ if (termwidth == UNLIMITED) { if (vis_env) (void)printf("%s ", vis_env); (void)printf("%s", vis_args); } else { left = termwidth - (totwidth - v->width); if (left < 1) /* already wrapped, just use std width */ left = v->width; if ((cp = vis_env) != NULL) { while (--left >= 0 && *cp) (void)putchar(*cp++); if (--left >= 0) putchar(' '); } for (cp = vis_args; --left >= 0 && *cp != '\0';) (void)putchar(*cp++); } } else /* XXX env? */ (void)printf("%-*.*s", v->width, v->width, vis_args); free(vis_args); if (vis_env != NULL) free(vis_env); } void ucomm(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; (void)printf("%-*s", v->width, k->ki_p->ki_comm); } void logname(k, ve) KINFO *k; VARENT *ve; { VAR *v; char *s; v = ve->var; (void)printf("%-*s", v->width, (s = k->ki_p->ki_login, *s) ? s : "-"); } void state(k, ve) KINFO *k; VARENT *ve; { int flag, sflag; char *cp; VAR *v; char buf[16]; v = ve->var; flag = k->ki_p->ki_flag; sflag = k->ki_p->ki_flag; cp = buf; switch (k->ki_p->ki_stat) { case SSTOP: *cp = 'T'; break; case SSLEEP: if (sflag & PS_SINTR) /* interruptable (long) */ *cp = k->ki_p->ki_slptime >= MAXSLP ? 'I' : 'S'; else *cp = 'D'; break; case SRUN: case SIDL: *cp = 'R'; break; case SWAIT: *cp = 'W'; break; case SMTX: *cp = 'M'; break; case SZOMB: *cp = 'Z'; break; default: *cp = '?'; } cp++; if (!(sflag & PS_INMEM)) *cp++ = 'W'; if (k->ki_p->ki_nice < NZERO) *cp++ = '<'; else if (k->ki_p->ki_nice > NZERO) *cp++ = 'N'; if (flag & P_TRACED) *cp++ = 'X'; if (flag & P_WEXIT && k->ki_p->ki_stat != SZOMB) *cp++ = 'E'; if (flag & P_PPWAIT) *cp++ = 'V'; if ((flag & P_SYSTEM) || k->ki_p->ki_lock > 0) *cp++ = 'L'; if (k->ki_p->ki_kiflag & KI_SLEADER) *cp++ = 's'; if ((flag & P_CONTROLT) && k->ki_p->ki_pgid == k->ki_p->ki_tpgid) *cp++ = '+'; if (flag & P_JAILED) *cp++ = 'J'; *cp = '\0'; (void)printf("%-*s", v->width, buf); } void pri(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; - (void)printf("%*d", v->width, k->ki_p->ki_priority - PZERO); + (void)printf("%*d", v->width, k->ki_p->ki_pri.pri_level - PZERO); } void uname(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; (void)printf("%-*s", (int)v->width, user_from_uid(k->ki_p->ki_uid, 0)); } int s_uname(k) KINFO *k; { return (strlen(user_from_uid(k->ki_p->ki_uid, 0))); } void runame(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; (void)printf("%-*s", (int)v->width, user_from_uid(k->ki_p->ki_ruid, 0)); } int s_runame(k) KINFO *k; { return (strlen(user_from_uid(k->ki_p->ki_ruid, 0))); } void tdev(k, ve) KINFO *k; VARENT *ve; { VAR *v; dev_t dev; char buff[16]; v = ve->var; dev = k->ki_p->ki_tdev; if (dev == NODEV) (void)printf("%*s", v->width, "??"); else { (void)snprintf(buff, sizeof(buff), "%d/%d", major(dev), minor(dev)); (void)printf("%*s", v->width, buff); } } void tname(k, ve) KINFO *k; VARENT *ve; { VAR *v; dev_t dev; char *ttname; v = ve->var; dev = k->ki_p->ki_tdev; if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) (void)printf("%*s ", v->width-1, "??"); else { if (strncmp(ttname, "tty", 3) == 0 || strncmp(ttname, "cua", 3) == 0) ttname += 3; (void)printf("%*.*s%c", v->width-1, v->width-1, ttname, k->ki_p->ki_kiflag & KI_CTTY ? ' ' : '-'); } } void longtname(k, ve) KINFO *k; VARENT *ve; { VAR *v; dev_t dev; char *ttname; v = ve->var; dev = k->ki_p->ki_tdev; if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) (void)printf("%-*s", v->width, "??"); else (void)printf("%-*s", v->width, ttname); } void started(k, ve) KINFO *k; VARENT *ve; { VAR *v; static time_t now; time_t then; struct tm *tp; char buf[100]; v = ve->var; if (!k->ki_valid) { (void)printf("%-*s", v->width, "-"); return; } then = k->ki_p->ki_start.tv_sec; tp = localtime(&then); if (!now) (void)time(&now); if (now - k->ki_p->ki_start.tv_sec < 24 * 3600) { (void)strftime(buf, sizeof(buf) - 1, "%l:%M%p", tp); } else if (now - k->ki_p->ki_start.tv_sec < 7 * 86400) { (void)strftime(buf, sizeof(buf) - 1, "%a%I%p", tp); } else (void)strftime(buf, sizeof(buf) - 1, "%e%b%y", tp); (void)printf("%-*s", v->width, buf); } void lstarted(k, ve) KINFO *k; VARENT *ve; { VAR *v; time_t then; char buf[100]; v = ve->var; if (!k->ki_valid) { (void)printf("%-*s", v->width, "-"); return; } then = k->ki_p->ki_start.tv_sec; (void)strftime(buf, sizeof(buf) -1, "%c", localtime(&then)); (void)printf("%-*s", v->width, buf); } void mtxname(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; if (k->ki_p->ki_kiflag & KI_MTXBLOCK) { if (k->ki_p->ki_mtxname[0] != 0) (void)printf("%-*.*s", v->width, v->width, k->ki_p->ki_mtxname); else (void)printf("%-*s", v->width, "???"); } else (void)printf("%-*s", v->width, "-"); } void wchan(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; if (k->ki_p->ki_wchan) { if (k->ki_p->ki_wmesg[0] != 0) (void)printf("%-*.*s", v->width, v->width, k->ki_p->ki_wmesg); else (void)printf("%-*lx", v->width, (long)k->ki_p->ki_wchan &~ KERNBASE); } else (void)printf("%-*s", v->width, "-"); } #ifndef pgtok #define pgtok(a) (((a)*getpagesize())/1024) #endif void vsize(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; (void)printf("%*d", v->width, (k->ki_p->ki_size/1024)); } void rssize(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; /* XXX don't have info about shared */ (void)printf("%*lu", v->width, (u_long)pgtok(k->ki_p->ki_rssize)); } void p_rssize(k, ve) /* doesn't account for text */ KINFO *k; VARENT *ve; { VAR *v; v = ve->var; (void)printf("%*ld", v->width, (long)pgtok(k->ki_p->ki_rssize)); } void cputime(k, ve) KINFO *k; VARENT *ve; { VAR *v; long secs; long psecs; /* "parts" of a second. first micro, then centi */ char obuff[128]; static char decimal_point = 0; if (!decimal_point) decimal_point = localeconv()->decimal_point[0]; v = ve->var; if (k->ki_p->ki_stat == SZOMB || !k->ki_valid) { secs = 0; psecs = 0; } else { /* * This counts time spent handling interrupts. We could * fix this, but it is not 100% trivial (and interrupt * time fractions only work on the sparc anyway). XXX */ secs = k->ki_p->ki_runtime / 1000000; psecs = k->ki_p->ki_runtime % 1000000; if (sumrusage) { secs += k->ki_p->ki_childtime.tv_sec; psecs += k->ki_p->ki_childtime.tv_usec; } /* * round and scale to 100's */ psecs = (psecs + 5000) / 10000; secs += psecs / 100; psecs = psecs % 100; } (void)snprintf(obuff, sizeof(obuff), "%3ld:%02ld%c%02ld", secs/60, secs%60, decimal_point, psecs); (void)printf("%*s", v->width, obuff); } double getpcpu(k) KINFO *k; { static int failure; if (!nlistread) failure = donlist(); if (failure) return (0.0); #define fxtofl(fixpt) ((double)(fixpt) / fscale) /* XXX - I don't like this */ if (k->ki_p->ki_swtime == 0 || (k->ki_p->ki_sflag & PS_INMEM) == 0) return (0.0); if (rawcpu) return (100.0 * fxtofl(k->ki_p->ki_pctcpu)); return (100.0 * fxtofl(k->ki_p->ki_pctcpu) / (1.0 - exp(k->ki_p->ki_swtime * log(fxtofl(ccpu))))); } void pcpu(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; (void)printf("%*.1f", v->width, getpcpu(k)); } double getpmem(k) KINFO *k; { static int failure; double fracmem; int szptudot; if (!nlistread) failure = donlist(); if (failure) return (0.0); if ((k->ki_p->ki_sflag & PS_INMEM) == 0) return (0.0); /* XXX want pmap ptpages, segtab, etc. (per architecture) */ szptudot = UPAGES; /* XXX don't have info about shared */ fracmem = ((float)k->ki_p->ki_rssize + szptudot)/mempages; return (100.0 * fracmem); } void pmem(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; (void)printf("%*.1f", v->width, getpmem(k)); } void pagein(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; (void)printf("%*ld", v->width, k->ki_valid ? k->ki_p->ki_rusage.ru_majflt : 0); } void maxrss(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; /* XXX not yet */ (void)printf("%*s", v->width, "-"); } void tsize(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; (void)printf("%*ld", v->width, (long)pgtok(k->ki_p->ki_tsize)); } void -rtprior(k, ve) +priorityr(k, ve) KINFO *k; VARENT *ve; { VAR *v; - struct rtprio *prtp; + struct priority *pri; char str[8]; - unsigned prio, type; + unsigned class, level; v = ve->var; - prtp = (struct rtprio *) ((char *)k + v->off); - prio = prtp->prio; - type = prtp->type; - switch (type) { - case RTP_PRIO_REALTIME: - snprintf(str, sizeof(str), "real:%u", prio); + pri = (struct priority *) ((char *)k + v->off); + class = pri->pri_class; + level = pri->pri_level; + switch (class) { + case PRI_REALTIME: + snprintf(str, sizeof(str), "real:%u", level); break; - case RTP_PRIO_NORMAL: + case PRI_TIMESHARE: strncpy(str, "normal", sizeof(str)); break; - case RTP_PRIO_IDLE: - snprintf(str, sizeof(str), "idle:%u", prio); + case PRI_IDLE: + snprintf(str, sizeof(str), "idle:%u", level); break; default: - snprintf(str, sizeof(str), "%u:%u", type, prio); + snprintf(str, sizeof(str), "%u:%u", class, level); break; } str[sizeof(str) - 1] = '\0'; (void)printf("%*s", v->width, str); } /* * Generic output routines. Print fields from various prototype * structures. */ static void printval(bp, v) char *bp; VAR *v; { static char ofmt[32] = "%"; char *fcp, *cp; cp = ofmt + 1; fcp = v->fmt; if (v->flag & LJUST) *cp++ = '-'; *cp++ = '*'; while ((*cp++ = *fcp++)); switch (v->type) { case CHAR: (void)printf(ofmt, v->width, *(char *)bp); break; case UCHAR: (void)printf(ofmt, v->width, *(u_char *)bp); break; case SHORT: (void)printf(ofmt, v->width, *(short *)bp); break; case USHORT: (void)printf(ofmt, v->width, *(u_short *)bp); break; case INT: (void)printf(ofmt, v->width, *(int *)bp); break; case UINT: (void)printf(ofmt, v->width, *(u_int *)bp); break; case LONG: (void)printf(ofmt, v->width, *(long *)bp); break; case ULONG: (void)printf(ofmt, v->width, *(u_long *)bp); break; case KPTR: (void)printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE); break; default: errx(1, "unknown type %d", v->type); } } void kvar(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; printval((char *)((char *)k->ki_p + v->off), v); } void rvar(k, ve) KINFO *k; VARENT *ve; { VAR *v; v = ve->var; if (k->ki_valid) printval((char *)((char *)(&k->ki_p->ki_rusage) + v->off), v); else (void)printf("%*s", v->width, "-"); } Index: head/lib/libkvm/kvm_proc.c =================================================================== --- head/lib/libkvm/kvm_proc.c (revision 72376) +++ head/lib/libkvm/kvm_proc.c (revision 72377) @@ -1,877 +1,874 @@ /*- * Copyright (c) 1989, 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software developed by the Computer Systems * Engineering group at Lawrence Berkeley Laboratory under DARPA contract * BG 91-66 and contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)kvm_proc.c 8.3 (Berkeley) 9/23/93"; #endif /* LIBC_SCCS and not lint */ /* * Proc traversal interface for kvm. ps and w are (probably) the exclusive * users of this code, so we've factored it out into a separate module. * Thus, we keep this grunge out of the other kvm applications (i.e., * most other applications are interested only in open/close/read/nlist). */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kvm_private.h" #if used static char * kvm_readswap(kd, p, va, cnt) kvm_t *kd; const struct proc *p; u_long va; u_long *cnt; { #ifdef __FreeBSD__ /* XXX Stubbed out, our vm system is differnet */ _kvm_err(kd, kd->program, "kvm_readswap not implemented"); return(0); #endif /* __FreeBSD__ */ } #endif #define KREAD(kd, addr, obj) \ (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj)) /* * Read proc's from memory file into buffer bp, which has space to hold * at most maxcnt procs. */ static int kvm_proclist(kd, what, arg, p, bp, maxcnt) kvm_t *kd; int what, arg; struct proc *p; struct kinfo_proc *bp; int maxcnt; { register int cnt = 0; struct kinfo_proc kinfo_proc, *kp; struct pgrp pgrp; struct session sess; struct tty tty; struct vmspace vmspace; struct procsig procsig; struct pcred pcred; struct pstats pstats; struct ucred ucred; struct proc proc; struct proc pproc; kp = &kinfo_proc; kp->ki_structsize = sizeof(kinfo_proc); for (; cnt < maxcnt && p != NULL; p = LIST_NEXT(&proc, p_list)) { if (KREAD(kd, (u_long)p, &proc)) { _kvm_err(kd, kd->program, "can't read proc at %x", p); return (-1); } if (KREAD(kd, (u_long)proc.p_cred, &pcred) == 0) { kp->ki_ruid = pcred.p_ruid; kp->ki_svuid = pcred.p_svuid; kp->ki_rgid = pcred.p_rgid; kp->ki_svgid = pcred.p_svgid; (void)(KREAD(kd, (u_long)pcred.pc_ucred, &ucred)); kp->ki_ngroups = ucred.cr_ngroups; bcopy(ucred.cr_groups, kp->ki_groups, NGROUPS * sizeof(gid_t)); kp->ki_uid = ucred.cr_uid; } switch(what) { case KERN_PROC_PID: if (proc.p_pid != (pid_t)arg) continue; break; case KERN_PROC_UID: if (kp->ki_uid != (uid_t)arg) continue; break; case KERN_PROC_RUID: if (kp->ki_ruid != (uid_t)arg) continue; break; } /* * We're going to add another proc to the set. If this * will overflow the buffer, assume the reason is because * nprocs (or the proc list) is corrupt and declare an error. */ if (cnt >= maxcnt) { _kvm_err(kd, kd->program, "nprocs corrupt"); return (-1); } /* * gather kinfo_proc */ kp->ki_paddr = p; kp->ki_addr = proc.p_addr; kp->ki_args = proc.p_args; kp->ki_tracep = proc.p_tracep; kp->ki_textvp = proc.p_textvp; kp->ki_fd = proc.p_fd; kp->ki_vmspace = proc.p_vmspace; if (proc.p_procsig != NULL) { if (KREAD(kd, (u_long)proc.p_procsig, &procsig)) { _kvm_err(kd, kd->program, "can't read procsig at %x", proc.p_procsig); return (-1); } kp->ki_sigignore = procsig.ps_sigignore; kp->ki_sigcatch = procsig.ps_sigcatch; } if ((proc.p_sflag & PS_INMEM) && proc.p_stats != NULL) { if (KREAD(kd, (u_long)proc.p_stats, &pstats)) { _kvm_err(kd, kd->program, "can't read stats at %x", proc.p_stats); return (-1); } kp->ki_start = pstats.p_start; kp->ki_rusage = pstats.p_ru; kp->ki_childtime.tv_sec = pstats.p_cru.ru_utime.tv_sec + pstats.p_cru.ru_stime.tv_sec; kp->ki_childtime.tv_usec = pstats.p_cru.ru_utime.tv_usec + pstats.p_cru.ru_stime.tv_usec; } if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) { _kvm_err(kd, kd->program, "can't read pgrp at %x", proc.p_pgrp); return (-1); } if (proc.p_oppid) kp->ki_ppid = proc.p_oppid; else if (proc.p_pptr) { if (KREAD(kd, (u_long)proc.p_pptr, &pproc)) { _kvm_err(kd, kd->program, "can't read pproc at %x", proc.p_pptr); return (-1); } kp->ki_ppid = pproc.p_pid; } else kp->ki_ppid = 0; kp->ki_pgid = pgrp.pg_id; kp->ki_jobc = pgrp.pg_jobc; if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) { _kvm_err(kd, kd->program, "can't read session at %x", pgrp.pg_session); return (-1); } kp->ki_sid = sess.s_sid; (void)memcpy(kp->ki_login, sess.s_login, sizeof(kp->ki_login)); kp->ki_kiflag = sess.s_ttyvp ? KI_CTTY : 0; if (sess.s_leader == p) kp->ki_kiflag |= KI_SLEADER; if ((proc.p_flag & P_CONTROLT) && sess.s_ttyp != NULL) { if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) { _kvm_err(kd, kd->program, "can't read tty at %x", sess.s_ttyp); return (-1); } kp->ki_tdev = tty.t_dev; if (tty.t_pgrp != NULL) { if (KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) { _kvm_err(kd, kd->program, "can't read tpgrp at &x", tty.t_pgrp); return (-1); } kp->ki_tpgid = pgrp.pg_id; } else kp->ki_tpgid = -1; if (tty.t_session != NULL) { if (KREAD(kd, (u_long)tty.t_session, &sess)) { _kvm_err(kd, kd->program, "can't read session at %x", tty.t_session); return (-1); } kp->ki_tsid = sess.s_sid; } } else kp->ki_tdev = NODEV; if (proc.p_wmesg) (void)kvm_read(kd, (u_long)proc.p_wmesg, kp->ki_wmesg, WMESGLEN); #ifdef sparc (void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_rssize, (char *)&kp->ki_rssize, sizeof(kp->ki_rssize)); (void)kvm_read(kd, (u_long)&proc.p_vmspace->vm_tsize, (char *)&kp->ki_tsize, 3 * sizeof(kp->ki_rssize)); /* XXX */ #else (void)kvm_read(kd, (u_long)proc.p_vmspace, (char *)&vmspace, sizeof(vmspace)); kp->ki_size = vmspace.vm_map.size; kp->ki_rssize = vmspace.vm_swrss; /* XXX */ kp->ki_swrss = vmspace.vm_swrss; kp->ki_tsize = vmspace.vm_tsize; kp->ki_dsize = vmspace.vm_dsize; kp->ki_ssize = vmspace.vm_ssize; #endif switch (what) { case KERN_PROC_PGRP: if (kp->ki_pgid != (pid_t)arg) continue; break; case KERN_PROC_TTY: if ((proc.p_flag & P_CONTROLT) == 0 || kp->ki_tdev != (dev_t)arg) continue; break; } if (proc.p_comm[0] != 0) { strncpy(kp->ki_comm, proc.p_comm, MAXCOMLEN); kp->ki_comm[MAXCOMLEN] = 0; } if (proc.p_blocked != 0) { kp->ki_kiflag |= KI_MTXBLOCK; if (proc.p_mtxname) (void)kvm_read(kd, (u_long)proc.p_mtxname, kp->ki_mtxname, MTXNAMELEN); kp->ki_mtxname[MTXNAMELEN] = 0; } - kp->ki_rtprio = proc.p_rtprio; kp->ki_runtime = proc.p_runtime; kp->ki_pid = proc.p_pid; kp->ki_siglist = proc.p_siglist; kp->ki_sigmask = proc.p_sigmask; kp->ki_xstat = proc.p_xstat; kp->ki_acflag = proc.p_acflag; kp->ki_pctcpu = proc.p_pctcpu; kp->ki_estcpu = proc.p_estcpu; kp->ki_slptime = proc.p_slptime; kp->ki_swtime = proc.p_swtime; kp->ki_flag = proc.p_flag; kp->ki_sflag = proc.p_sflag; kp->ki_wchan = proc.p_wchan; kp->ki_traceflag = proc.p_traceflag; - kp->ki_priority = proc.p_priority; - kp->ki_usrpri = proc.p_usrpri; - kp->ki_nativepri = proc.p_nativepri; kp->ki_stat = proc.p_stat; + kp->ki_pri = proc.p_pri; kp->ki_nice = proc.p_nice; kp->ki_lock = proc.p_lock; kp->ki_rqindex = proc.p_rqindex; kp->ki_oncpu = proc.p_oncpu; kp->ki_lastcpu = proc.p_lastcpu; bcopy(&kinfo_proc, bp, sizeof(kinfo_proc)); ++bp; ++cnt; } return (cnt); } /* * Build proc info array by reading in proc list from a crash dump. * Return number of procs read. maxcnt is the max we will read. */ static int kvm_deadprocs(kd, what, arg, a_allproc, a_zombproc, maxcnt) kvm_t *kd; int what, arg; u_long a_allproc; u_long a_zombproc; int maxcnt; { register struct kinfo_proc *bp = kd->procbase; register int acnt, zcnt; struct proc *p; if (KREAD(kd, a_allproc, &p)) { _kvm_err(kd, kd->program, "cannot read allproc"); return (-1); } acnt = kvm_proclist(kd, what, arg, p, bp, maxcnt); if (acnt < 0) return (acnt); if (KREAD(kd, a_zombproc, &p)) { _kvm_err(kd, kd->program, "cannot read zombproc"); return (-1); } zcnt = kvm_proclist(kd, what, arg, p, bp + acnt, maxcnt - acnt); if (zcnt < 0) zcnt = 0; return (acnt + zcnt); } struct kinfo_proc * kvm_getprocs(kd, op, arg, cnt) kvm_t *kd; int op, arg; int *cnt; { int mib[4], st, nprocs; size_t size; if (kd->procbase != 0) { free((void *)kd->procbase); /* * Clear this pointer in case this call fails. Otherwise, * kvm_close() will free it again. */ kd->procbase = 0; } if (ISALIVE(kd)) { size = 0; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = op; mib[3] = arg; st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4, NULL, &size, NULL, 0); if (st == -1) { _kvm_syserr(kd, kd->program, "kvm_getprocs"); return (0); } do { size += size / 10; kd->procbase = (struct kinfo_proc *) _kvm_realloc(kd, kd->procbase, size); if (kd->procbase == 0) return (0); st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4, kd->procbase, &size, NULL, 0); } while (st == -1 && errno == ENOMEM); if (st == -1) { _kvm_syserr(kd, kd->program, "kvm_getprocs"); return (0); } if (kd->procbase->ki_structsize != sizeof(struct kinfo_proc)) { _kvm_err(kd, kd->program, "kinfo_proc size mismatch (expected %d, got %d)", sizeof(struct kinfo_proc), kd->procbase->ki_structsize); return (0); } nprocs = size / kd->procbase->ki_structsize; } else { struct nlist nl[4], *p; nl[0].n_name = "_nprocs"; nl[1].n_name = "_allproc"; nl[2].n_name = "_zombproc"; nl[3].n_name = 0; if (kvm_nlist(kd, nl) != 0) { for (p = nl; p->n_type != 0; ++p) ; _kvm_err(kd, kd->program, "%s: no such symbol", p->n_name); return (0); } if (KREAD(kd, nl[0].n_value, &nprocs)) { _kvm_err(kd, kd->program, "can't read nprocs"); return (0); } size = nprocs * sizeof(struct kinfo_proc); kd->procbase = (struct kinfo_proc *)_kvm_malloc(kd, size); if (kd->procbase == 0) return (0); nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value, nl[2].n_value, nprocs); #ifdef notdef size = nprocs * sizeof(struct kinfo_proc); (void)realloc(kd->procbase, size); #endif } *cnt = nprocs; return (kd->procbase); } void _kvm_freeprocs(kd) kvm_t *kd; { if (kd->procbase) { free(kd->procbase); kd->procbase = 0; } } void * _kvm_realloc(kd, p, n) kvm_t *kd; void *p; size_t n; { void *np = (void *)realloc(p, n); if (np == 0) { free(p); _kvm_err(kd, kd->program, "out of memory"); } return (np); } #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif /* * Read in an argument vector from the user address space of process kp. * addr if the user-space base address of narg null-terminated contiguous * strings. This is used to read in both the command arguments and * environment strings. Read at most maxcnt characters of strings. */ static char ** kvm_argv(kd, kp, addr, narg, maxcnt) kvm_t *kd; struct kinfo_proc *kp; register u_long addr; register int narg; register int maxcnt; { register char *np, *cp, *ep, *ap; register u_long oaddr = -1; register int len, cc; register char **argv; /* * Check that there aren't an unreasonable number of agruments, * and that the address is in user space. */ if (narg > 512 || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS) return (0); /* * kd->argv : work space for fetching the strings from the target * process's space, and is converted for returning to caller */ if (kd->argv == 0) { /* * Try to avoid reallocs. */ kd->argc = MAX(narg + 1, 32); kd->argv = (char **)_kvm_malloc(kd, kd->argc * sizeof(*kd->argv)); if (kd->argv == 0) return (0); } else if (narg + 1 > kd->argc) { kd->argc = MAX(2 * kd->argc, narg + 1); kd->argv = (char **)_kvm_realloc(kd, kd->argv, kd->argc * sizeof(*kd->argv)); if (kd->argv == 0) return (0); } /* * kd->argspc : returned to user, this is where the kd->argv * arrays are left pointing to the collected strings. */ if (kd->argspc == 0) { kd->argspc = (char *)_kvm_malloc(kd, PAGE_SIZE); if (kd->argspc == 0) return (0); kd->arglen = PAGE_SIZE; } /* * kd->argbuf : used to pull in pages from the target process. * the strings are copied out of here. */ if (kd->argbuf == 0) { kd->argbuf = (char *)_kvm_malloc(kd, PAGE_SIZE); if (kd->argbuf == 0) return (0); } /* Pull in the target process'es argv vector */ cc = sizeof(char *) * narg; if (kvm_uread(kd, kp, addr, (char *)kd->argv, cc) != cc) return (0); /* * ap : saved start address of string we're working on in kd->argspc * np : pointer to next place to write in kd->argspc * len: length of data in kd->argspc * argv: pointer to the argv vector that we are hunting around the * target process space for, and converting to addresses in * our address space (kd->argspc). */ ap = np = kd->argspc; argv = kd->argv; len = 0; /* * Loop over pages, filling in the argument vector. * Note that the argv strings could be pointing *anywhere* in * the user address space and are no longer contiguous. * Note that *argv is modified when we are going to fetch a string * that crosses a page boundary. We copy the next part of the string * into to "np" and eventually convert the pointer. */ while (argv < kd->argv + narg && *argv != 0) { /* get the address that the current argv string is on */ addr = (u_long)*argv & ~(PAGE_SIZE - 1); /* is it the same page as the last one? */ if (addr != oaddr) { if (kvm_uread(kd, kp, addr, kd->argbuf, PAGE_SIZE) != PAGE_SIZE) return (0); oaddr = addr; } /* offset within the page... kd->argbuf */ addr = (u_long)*argv & (PAGE_SIZE - 1); /* cp = start of string, cc = count of chars in this chunk */ cp = kd->argbuf + addr; cc = PAGE_SIZE - addr; /* dont get more than asked for by user process */ if (maxcnt > 0 && cc > maxcnt - len) cc = maxcnt - len; /* pointer to end of string if we found it in this page */ ep = memchr(cp, '\0', cc); if (ep != 0) cc = ep - cp + 1; /* * at this point, cc is the count of the chars that we are * going to retrieve this time. we may or may not have found * the end of it. (ep points to the null if the end is known) */ /* will we exceed the malloc/realloced buffer? */ if (len + cc > kd->arglen) { register int off; register char **pp; register char *op = kd->argspc; kd->arglen *= 2; kd->argspc = (char *)_kvm_realloc(kd, kd->argspc, kd->arglen); if (kd->argspc == 0) return (0); /* * Adjust argv pointers in case realloc moved * the string space. */ off = kd->argspc - op; for (pp = kd->argv; pp < argv; pp++) *pp += off; ap += off; np += off; } /* np = where to put the next part of the string in kd->argspc*/ /* np is kinda redundant.. could use "kd->argspc + len" */ memcpy(np, cp, cc); np += cc; /* inc counters */ len += cc; /* * if end of string found, set the *argv pointer to the * saved beginning of string, and advance. argv points to * somewhere in kd->argv.. This is initially relative * to the target process, but when we close it off, we set * it to point in our address space. */ if (ep != 0) { *argv++ = ap; ap = np; } else { /* update the address relative to the target process */ *argv += cc; } if (maxcnt > 0 && len >= maxcnt) { /* * We're stopping prematurely. Terminate the * current string. */ if (ep == 0) { *np = '\0'; *argv++ = ap; } break; } } /* Make sure argv is terminated. */ *argv = 0; return (kd->argv); } static void ps_str_a(p, addr, n) struct ps_strings *p; u_long *addr; int *n; { *addr = (u_long)p->ps_argvstr; *n = p->ps_nargvstr; } static void ps_str_e(p, addr, n) struct ps_strings *p; u_long *addr; int *n; { *addr = (u_long)p->ps_envstr; *n = p->ps_nenvstr; } /* * Determine if the proc indicated by p is still active. * This test is not 100% foolproof in theory, but chances of * being wrong are very low. */ static int proc_verify(curkp) struct kinfo_proc *curkp; { struct kinfo_proc newkp; int mib[4]; size_t len; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = curkp->ki_pid; len = sizeof(newkp); if (sysctl(mib, 4, &newkp, &len, NULL, 0) == -1) return (0); return (curkp->ki_pid == newkp.ki_pid && (newkp.ki_stat != SZOMB || curkp->ki_stat == SZOMB)); } static char ** kvm_doargv(kd, kp, nchr, info) kvm_t *kd; struct kinfo_proc *kp; int nchr; void (*info)(struct ps_strings *, u_long *, int *); { char **ap; u_long addr; int cnt; static struct ps_strings arginfo; static u_long ps_strings; size_t len; if (ps_strings == NULL) { len = sizeof(ps_strings); if (sysctlbyname("kern.ps_strings", &ps_strings, &len, NULL, 0) == -1) ps_strings = PS_STRINGS; } /* * Pointers are stored at the top of the user stack. */ if (kp->ki_stat == SZOMB || kvm_uread(kd, kp, ps_strings, (char *)&arginfo, sizeof(arginfo)) != sizeof(arginfo)) return (0); (*info)(&arginfo, &addr, &cnt); if (cnt == 0) return (0); ap = kvm_argv(kd, kp, addr, cnt, nchr); /* * For live kernels, make sure this process didn't go away. */ if (ap != 0 && ISALIVE(kd) && !proc_verify(kp)) ap = 0; return (ap); } /* * Get the command args. This code is now machine independent. */ char ** kvm_getargv(kd, kp, nchr) kvm_t *kd; const struct kinfo_proc *kp; int nchr; { int oid[4]; int i; size_t bufsz; static int buflen; static char *buf, *p; static char **bufp; static int argc; if (!ISALIVE(kd)) { _kvm_err(kd, kd->program, "cannot read user space from dead kernel"); return (0); } if (!buflen) { bufsz = sizeof(buflen); i = sysctlbyname("kern.ps_arg_cache_limit", &buflen, &bufsz, NULL, 0); if (i == -1) { buflen = 0; } else { buf = malloc(buflen); if (buf == NULL) buflen = 0; argc = 32; bufp = malloc(sizeof(char *) * argc); } } if (buf != NULL) { oid[0] = CTL_KERN; oid[1] = KERN_PROC; oid[2] = KERN_PROC_ARGS; oid[3] = kp->ki_pid; bufsz = buflen; i = sysctl(oid, 4, buf, &bufsz, 0, 0); if (i == 0 && bufsz > 0) { i = 0; p = buf; do { bufp[i++] = p; p += strlen(p) + 1; if (i >= argc) { argc += argc; bufp = realloc(bufp, sizeof(char *) * argc); } } while (p < buf + bufsz); bufp[i++] = 0; return (bufp); } } if (kp->ki_flag & P_SYSTEM) return (NULL); return (kvm_doargv(kd, kp, nchr, ps_str_a)); } char ** kvm_getenvv(kd, kp, nchr) kvm_t *kd; const struct kinfo_proc *kp; int nchr; { return (kvm_doargv(kd, kp, nchr, ps_str_e)); } /* * Read from user space. The user context is given by p. */ ssize_t kvm_uread(kd, kp, uva, buf, len) kvm_t *kd; struct kinfo_proc *kp; register u_long uva; register char *buf; register size_t len; { register char *cp; char procfile[MAXPATHLEN]; ssize_t amount; int fd; if (!ISALIVE(kd)) { _kvm_err(kd, kd->program, "cannot read user space from dead kernel"); return (0); } sprintf(procfile, "/proc/%d/mem", kp->ki_pid); fd = open(procfile, O_RDONLY, 0); if (fd < 0) { _kvm_err(kd, kd->program, "cannot open %s", procfile); close(fd); return (0); } cp = buf; while (len > 0) { errno = 0; if (lseek(fd, (off_t)uva, 0) == -1 && errno != 0) { _kvm_err(kd, kd->program, "invalid address (%x) in %s", uva, procfile); break; } amount = read(fd, cp, len); if (amount < 0) { _kvm_syserr(kd, kd->program, "error reading %s", procfile); break; } if (amount == 0) { _kvm_err(kd, kd->program, "EOF reading %s", procfile); break; } cp += amount; uva += amount; len -= amount; } close(fd); return ((ssize_t)(cp - buf)); } Index: head/usr.bin/top/machine.c =================================================================== --- head/usr.bin/top/machine.c (revision 72376) +++ head/usr.bin/top/machine.c (revision 72377) @@ -1,1003 +1,1003 @@ /* * top - a top users display for Unix * * SYNOPSIS: For FreeBSD-2.x and later * * DESCRIPTION: * Originally written for BSD4.4 system by Christos Zoulas. * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider * Order support hacked in from top-3.5beta6/machine/m_aix41.c * by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/) * * This is the machine-dependent module for FreeBSD 2.2 * Works for: * FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x * * LIBS: -lkvm * * AUTHOR: Christos Zoulas * Steven Wallace * Wolfram Schneider * * $FreeBSD$ */ #include #include #include #include #include "os.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Swap */ #include #include #include /* for changes in kernel structures */ #include "top.h" #include "machine.h" #include "screen.h" static int check_nlist __P((struct nlist *)); static int getkval __P((unsigned long, int *, int, char *)); extern char* printable __P((char *)); int swapmode __P((int *retavail, int *retfree)); static int smpmode; static int namelength; static int cmdlengthdelta; /* get_process_info passes back a handle. This is what it looks like: */ struct handle { struct kinfo_proc **next_proc; /* points to next valid proc pointer */ int remaining; /* number of pointers remaining */ }; /* declarations for load_avg */ #include "loadavg.h" /* define what weighted cpu is. */ #define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \ ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu)))) /* what we consider to be process size: */ #define PROCSIZE(pp) ((pp)->ki_size / 1024) /* definitions for indices in the nlist array */ static struct nlist nlst[] = { #define X_CCPU 0 { "_ccpu" }, #define X_CP_TIME 1 { "_cp_time" }, #define X_AVENRUN 2 { "_averunnable" }, #define X_BUFSPACE 3 { "_bufspace" }, /* K in buffer cache */ #define X_CNT 4 { "_cnt" }, /* struct vmmeter cnt */ /* Last pid */ #define X_LASTPID 5 { "_nextpid" }, { 0 } }; /* * These definitions control the format of the per-process area */ static char smp_header[] = " PID %-*.*s PRI NICE SIZE RES STATE C TIME WCPU CPU COMMAND"; #define smp_Proc_format \ "%5d %-*.*s %3d %3d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %.*s" static char up_header[] = " PID %-*.*s PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; #define up_Proc_format \ "%5d %-*.*s %3d %3d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s" /* process state names for the "STATE" column of the display */ /* the extra nulls in the string "run" are for adding a slash and the processor number when needed */ char *state_abbrev[] = { "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "MUTEX" }; static kvm_t *kd; /* values that we stash away in _init and use in later routines */ static double logcpu; /* these are retrieved from the kernel in _init */ static load_avg ccpu; /* these are offsets obtained via nlist and used in the get_ functions */ static unsigned long cp_time_offset; static unsigned long avenrun_offset; static unsigned long lastpid_offset; static long lastpid; static unsigned long cnt_offset; static unsigned long bufspace_offset; static long cnt; /* these are for calculating cpu state percentages */ static long cp_time[CPUSTATES]; static long cp_old[CPUSTATES]; static long cp_diff[CPUSTATES]; /* these are for detailing the process states */ int process_states[8]; char *procstatenames[] = { "", " starting, ", " running, ", " sleeping, ", " stopped, ", " zombie, ", " waiting, ", " mutex, ", NULL }; /* these are for detailing the cpu states */ int cpu_states[CPUSTATES]; char *cpustatenames[] = { "user", "nice", "system", "interrupt", "idle", NULL }; /* these are for detailing the memory statistics */ int memory_stats[7]; char *memorynames[] = { "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free", NULL }; int swap_stats[7]; char *swapnames[] = { /* 0 1 2 3 4 5 */ "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", NULL }; /* these are for keeping track of the proc array */ static int nproc; static int onproc = -1; static int pref_len; static struct kinfo_proc *pbase; static struct kinfo_proc **pref; /* these are for getting the memory statistics */ static int pageshift; /* log base 2 of the pagesize */ /* define pagetok in terms of pageshift */ #define pagetok(size) ((size) << pageshift) /* useful externals */ long percentages(); #ifdef ORDER /* sorting orders. first is default */ char *ordernames[] = { "cpu", "size", "res", "time", "pri", NULL }; #endif int machine_init(statics) struct statics *statics; { register int i = 0; register int pagesize; int modelen; struct passwd *pw; modelen = sizeof(smpmode); if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 && sysctlbyname("smp.smp_active", &smpmode, &modelen, NULL, 0) < 0) || modelen != sizeof(smpmode)) smpmode = 0; while ((pw = getpwent()) != NULL) { if (strlen(pw->pw_name) > namelength) namelength = strlen(pw->pw_name); } if (namelength < 8) namelength = 8; if (namelength > 15) namelength = 15; if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL) return -1; /* get the list of symbols we want to access in the kernel */ (void) kvm_nlist(kd, nlst); if (nlst[0].n_type == 0) { fprintf(stderr, "top: nlist failed\n"); return(-1); } /* make sure they were all found */ if (i > 0 && check_nlist(nlst) > 0) { return(-1); } (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu), nlst[X_CCPU].n_name); /* stash away certain offsets for later use */ cp_time_offset = nlst[X_CP_TIME].n_value; avenrun_offset = nlst[X_AVENRUN].n_value; lastpid_offset = nlst[X_LASTPID].n_value; cnt_offset = nlst[X_CNT].n_value; bufspace_offset = nlst[X_BUFSPACE].n_value; /* this is used in calculating WCPU -- calculate it ahead of time */ logcpu = log(loaddouble(ccpu)); pbase = NULL; pref = NULL; nproc = 0; onproc = -1; /* get the page size with "getpagesize" and calculate pageshift from it */ pagesize = getpagesize(); pageshift = 0; while (pagesize > 1) { pageshift++; pagesize >>= 1; } /* we only need the amount of log(2)1024 for our conversion */ pageshift -= LOG1024; /* fill in the statics information */ statics->procstate_names = procstatenames; statics->cpustate_names = cpustatenames; statics->memory_names = memorynames; statics->swap_names = swapnames; #ifdef ORDER statics->order_names = ordernames; #endif /* all done! */ return(0); } char *format_header(uname_field) register char *uname_field; { register char *ptr; static char Header[128]; snprintf(Header, sizeof(Header), smpmode ? smp_header : up_header, namelength, namelength, uname_field); cmdlengthdelta = strlen(Header) - 7; return Header; } static int swappgsin = -1; static int swappgsout = -1; extern struct timeval timeout; void get_system_info(si) struct system_info *si; { long total; load_avg avenrun[3]; int mib[2]; struct timeval boottime; size_t bt_size; /* get the cp_time array */ (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time), nlst[X_CP_TIME].n_name); (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun), nlst[X_AVENRUN].n_name); (void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid), "!"); /* convert load averages to doubles */ { register int i; register double *infoloadp; load_avg *avenrunp; #ifdef notyet struct loadavg sysload; int size; getkerninfo(KINFO_LOADAVG, &sysload, &size, 0); #endif infoloadp = si->load_avg; avenrunp = avenrun; for (i = 0; i < 3; i++) { #ifdef notyet *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale; #endif *infoloadp++ = loaddouble(*avenrunp++); } } /* convert cp_time counts to percentages */ total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); /* sum memory & swap statistics */ { struct vmmeter sum; static unsigned int swap_delay = 0; static int swapavail = 0; static int swapfree = 0; static int bufspace = 0; (void) getkval(cnt_offset, (int *)(&sum), sizeof(sum), "_cnt"); (void) getkval(bufspace_offset, (int *)(&bufspace), sizeof(bufspace), "_bufspace"); /* convert memory stats to Kbytes */ memory_stats[0] = pagetok(sum.v_active_count); memory_stats[1] = pagetok(sum.v_inactive_count); memory_stats[2] = pagetok(sum.v_wire_count); memory_stats[3] = pagetok(sum.v_cache_count); memory_stats[4] = bufspace / 1024; memory_stats[5] = pagetok(sum.v_free_count); memory_stats[6] = -1; /* first interval */ if (swappgsin < 0) { swap_stats[4] = 0; swap_stats[5] = 0; } /* compute differences between old and new swap statistic */ else { swap_stats[4] = pagetok(((sum.v_swappgsin - swappgsin))); swap_stats[5] = pagetok(((sum.v_swappgsout - swappgsout))); } swappgsin = sum.v_swappgsin; swappgsout = sum.v_swappgsout; /* call CPU heavy swapmode() only for changes */ if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) { swap_stats[3] = swapmode(&swapavail, &swapfree); swap_stats[0] = swapavail; swap_stats[1] = swapavail - swapfree; swap_stats[2] = swapfree; } swap_delay = 1; swap_stats[6] = -1; } /* set arrays and strings */ si->cpustates = cpu_states; si->memory = memory_stats; si->swap = swap_stats; if(lastpid > 0) { si->last_pid = lastpid; } else { si->last_pid = -1; } /* * Print how long system has been up. * (Found by looking getting "boottime" from the kernel) */ mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; bt_size = sizeof(boottime); if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 && boottime.tv_sec != 0) { si->boottime = boottime; } else { si->boottime.tv_sec = -1; } } static struct handle handle; caddr_t get_process_info(si, sel, compare) struct system_info *si; struct process_select *sel; int (*compare)(); { register int i; register int total_procs; register int active_procs; register struct kinfo_proc **prefp; register struct kinfo_proc *pp; /* these are copied out of sel for speed */ int show_idle; int show_self; int show_system; int show_uid; int show_command; pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc); if (nproc > onproc) pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *) * (onproc = nproc)); if (pref == NULL || pbase == NULL) { (void) fprintf(stderr, "top: Out of memory.\n"); quit(23); } /* get a pointer to the states summary array */ si->procstates = process_states; /* set up flags which define what we are going to select */ show_idle = sel->idle; show_self = sel->self; show_system = sel->system; show_uid = sel->uid != -1; show_command = sel->command != NULL; /* count up process states and get pointers to interesting procs */ total_procs = 0; active_procs = 0; memset((char *)process_states, 0, sizeof(process_states)); prefp = pref; for (pp = pbase, i = 0; i < nproc; pp++, i++) { /* * Place pointers to each valid proc structure in pref[]. * Process slots that are actually in use have a non-zero * status field. Processes with P_SYSTEM set are system * processes---these get ignored unless show_sysprocs is set. */ if (pp->ki_stat != 0 && (show_self != pp->ki_pid) && (show_system || ((pp->ki_flag & P_SYSTEM) == 0))) { total_procs++; process_states[(unsigned char) pp->ki_stat]++; if ((pp->ki_stat != SZOMB) && (show_idle || (pp->ki_pctcpu != 0) || (pp->ki_stat == SRUN)) && (!show_uid || pp->ki_ruid == (uid_t)sel->uid)) { *prefp++ = pp; active_procs++; } } } /* if requested, sort the "interesting" processes */ if (compare != NULL) { qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare); } /* remember active and total counts */ si->p_total = total_procs; si->p_active = pref_len = active_procs; /* pass back a handle */ handle.next_proc = pref; handle.remaining = active_procs; return((caddr_t)&handle); } char fmt[128]; /* static area where result is built */ char *format_next_process(handle, get_userid) caddr_t handle; char *(*get_userid)(); { register struct kinfo_proc *pp; register long cputime; register double pct; struct handle *hp; char status[16]; int state; /* find and remember the next proc structure */ hp = (struct handle *)handle; pp = *(hp->next_proc++); hp->remaining--; /* get the process's command name */ if ((pp->ki_sflag & PS_INMEM) == 0) { /* * Print swapped processes as */ char *comm = pp->ki_comm; #define COMSIZ sizeof(pp->ki_comm) char buf[COMSIZ]; (void) strncpy(buf, comm, COMSIZ); comm[0] = '<'; (void) strncpy(&comm[1], buf, COMSIZ - 2); comm[COMSIZ - 2] = '\0'; (void) strncat(comm, ">", COMSIZ - 1); comm[COMSIZ - 1] = '\0'; } /* * Convert the process's runtime from microseconds to seconds. This * time includes the interrupt time although that is not wanted here. * ps(1) is similarly sloppy. */ cputime = (pp->ki_runtime + 500000) / 1000000; /* calculate the base for cpu percentages */ pct = pctdouble(pp->ki_pctcpu); /* generate "STATE" field */ switch (state = pp->ki_stat) { case SRUN: if (smpmode && pp->ki_oncpu != 0xff) sprintf(status, "CPU%d", pp->ki_oncpu); else strcpy(status, "RUN"); break; case SMTX: if (pp->ki_kiflag & KI_MTXBLOCK) { sprintf(status, "*%.6s", pp->ki_mtxname); break; } /* fall through */ case SSLEEP: if (pp->ki_wmesg != NULL) { sprintf(status, "%.6s", pp->ki_wmesg); break; } /* fall through */ default: if (state >= 0 && state < sizeof(state_abbrev) / sizeof(*state_abbrev)) sprintf(status, "%.6s", state_abbrev[(unsigned char) state]); else sprintf(status, "?%5d", state); break; } /* format this entry */ sprintf(fmt, smpmode ? smp_Proc_format : up_Proc_format, pp->ki_pid, namelength, namelength, (*get_userid)(pp->ki_ruid), - pp->ki_priority - PZERO, + pp->ki_pri.pri_level - PZERO, /* * normal time -> nice value -20 - +20 * real time 0 - 31 -> nice value -52 - -21 * idle time 0 - 31 -> nice value +21 - +52 */ - (pp->ki_rtprio.type == RTP_PRIO_NORMAL ? + (pp->ki_pri.pri_class == PRI_TIMESHARE ? pp->ki_nice - NZERO : - (RTP_PRIO_IS_REALTIME(pp->ki_rtprio.type) ? - (PRIO_MIN - 1 - RTP_PRIO_MAX + pp->ki_rtprio.prio) : - (PRIO_MAX + 1 + pp->ki_rtprio.prio))), + (PRI_IS_REALTIME(pp->ki_pri.pri_class) ? + (PRIO_MIN - 1 - (PRI_MAX_REALTIME - pp->ki_pri.pri_level)) : + (PRIO_MAX + 1 + pp->ki_pri.pri_level - PRI_MIN_IDLE))), format_k2(PROCSIZE(pp)), format_k2(pagetok(pp->ki_rssize)), status, smpmode ? pp->ki_lastcpu : 0, format_time(cputime), 100.0 * weighted_cpu(pct, pp), 100.0 * pct, screen_width > cmdlengthdelta ? screen_width - cmdlengthdelta : 0, printable(pp->ki_comm)); /* return the result */ return(fmt); } /* * check_nlist(nlst) - checks the nlist to see if any symbols were not * found. For every symbol that was not found, a one-line * message is printed to stderr. The routine returns the * number of symbols NOT found. */ static int check_nlist(nlst) register struct nlist *nlst; { register int i; /* check to see if we got ALL the symbols we requested */ /* this will write one line to stderr for every symbol not found */ i = 0; while (nlst->n_name != NULL) { if (nlst->n_type == 0) { /* this one wasn't found */ (void) fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name); i = 1; } nlst++; } return(i); } /* * getkval(offset, ptr, size, refstr) - get a value out of the kernel. * "offset" is the byte offset into the kernel for the desired value, * "ptr" points to a buffer into which the value is retrieved, * "size" is the size of the buffer (and the object to retrieve), * "refstr" is a reference string used when printing error meessages, * if "refstr" starts with a '!', then a failure on read will not * be fatal (this may seem like a silly way to do things, but I * really didn't want the overhead of another argument). * */ static int getkval(offset, ptr, size, refstr) unsigned long offset; int *ptr; int size; char *refstr; { if (kvm_read(kd, offset, (char *) ptr, size) != size) { if (*refstr == '!') { return(0); } else { fprintf(stderr, "top: kvm_read for %s: %s\n", refstr, strerror(errno)); quit(23); } } return(1); } /* comparison routines for qsort */ /* * proc_compare - comparison function for "qsort" * Compares the resource consumption of two processes using five * distinct keys. The keys (in descending order of importance) are: * percent cpu, cpu ticks, state, resident set size, total virtual * memory usage. The process states are ordered as follows (from least * to most important): WAIT, zombie, sleep, stop, start, run. The * array declaration below maps a process state index into a number * that reflects this ordering. */ static unsigned char sorted_state[] = { 0, /* not used */ 3, /* sleep */ 1, /* ABANDONED (WAIT) */ 6, /* run */ 5, /* start */ 2, /* zombie */ 4 /* stop */ }; #define ORDERKEY_PCTCPU \ if (lresult = (long) p2->ki_pctcpu - (long) p1->ki_pctcpu, \ (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) #define ORDERKEY_CPTICKS \ if ((result = p2->ki_runtime > p1->ki_runtime ? 1 : \ p2->ki_runtime < p1->ki_runtime ? -1 : 0) == 0) #define ORDERKEY_STATE \ if ((result = sorted_state[(unsigned char) p2->ki_stat] - \ sorted_state[(unsigned char) p1->ki_stat]) == 0) #define ORDERKEY_PRIO \ - if ((result = p2->ki_priority - p1->ki_priority) == 0) + if ((result = p2->ki_pri.pri_level - p1->ki_pri.pri_level) == 0) #define ORDERKEY_RSSIZE \ if ((result = p2->ki_rssize - p1->ki_rssize) == 0) #define ORDERKEY_MEM \ if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 ) /* compare_cpu - the comparison function for sorting by cpu percentage */ int #ifdef ORDER compare_cpu(pp1, pp2) #else proc_compare(pp1, pp2) #endif struct proc **pp1; struct proc **pp2; { register struct kinfo_proc *p1; register struct kinfo_proc *p2; register int result; register pctcpu lresult; /* remove one level of indirection */ p1 = *(struct kinfo_proc **) pp1; p2 = *(struct kinfo_proc **) pp2; ORDERKEY_PCTCPU ORDERKEY_CPTICKS ORDERKEY_STATE ORDERKEY_PRIO ORDERKEY_RSSIZE ORDERKEY_MEM ; return(result); } #ifdef ORDER /* compare routines */ int compare_size(), compare_res(), compare_time(), compare_prio(); int (*proc_compares[])() = { compare_cpu, compare_size, compare_res, compare_time, compare_prio, NULL }; /* compare_size - the comparison function for sorting by total memory usage */ int compare_size(pp1, pp2) struct proc **pp1; struct proc **pp2; { register struct kinfo_proc *p1; register struct kinfo_proc *p2; register int result; register pctcpu lresult; /* remove one level of indirection */ p1 = *(struct kinfo_proc **) pp1; p2 = *(struct kinfo_proc **) pp2; ORDERKEY_MEM ORDERKEY_RSSIZE ORDERKEY_PCTCPU ORDERKEY_CPTICKS ORDERKEY_STATE ORDERKEY_PRIO ; return(result); } /* compare_res - the comparison function for sorting by resident set size */ int compare_res(pp1, pp2) struct proc **pp1; struct proc **pp2; { register struct kinfo_proc *p1; register struct kinfo_proc *p2; register int result; register pctcpu lresult; /* remove one level of indirection */ p1 = *(struct kinfo_proc **) pp1; p2 = *(struct kinfo_proc **) pp2; ORDERKEY_RSSIZE ORDERKEY_MEM ORDERKEY_PCTCPU ORDERKEY_CPTICKS ORDERKEY_STATE ORDERKEY_PRIO ; return(result); } /* compare_time - the comparison function for sorting by total cpu time */ int compare_time(pp1, pp2) struct proc **pp1; struct proc **pp2; { register struct kinfo_proc *p1; register struct kinfo_proc *p2; register int result; register pctcpu lresult; /* remove one level of indirection */ p1 = *(struct kinfo_proc **) pp1; p2 = *(struct kinfo_proc **) pp2; ORDERKEY_CPTICKS ORDERKEY_PCTCPU ORDERKEY_STATE ORDERKEY_PRIO ORDERKEY_RSSIZE ORDERKEY_MEM ; return(result); } /* compare_prio - the comparison function for sorting by cpu percentage */ int compare_prio(pp1, pp2) struct proc **pp1; struct proc **pp2; { register struct kinfo_proc *p1; register struct kinfo_proc *p2; register int result; register pctcpu lresult; /* remove one level of indirection */ p1 = *(struct kinfo_proc **) pp1; p2 = *(struct kinfo_proc **) pp2; ORDERKEY_PRIO ORDERKEY_CPTICKS ORDERKEY_PCTCPU ORDERKEY_STATE ORDERKEY_RSSIZE ORDERKEY_MEM ; return(result); } #endif /* * proc_owner(pid) - returns the uid that owns process "pid", or -1 if * the process does not exist. * It is EXTREMLY IMPORTANT that this function work correctly. * If top runs setuid root (as in SVR4), then this function * is the only thing that stands in the way of a serious * security problem. It validates requests for the "kill" * and "renice" commands. */ int proc_owner(pid) int pid; { register int cnt; register struct kinfo_proc **prefp; register struct kinfo_proc *pp; prefp = pref; cnt = pref_len; while (--cnt >= 0) { pp = *prefp++; if (pp->ki_pid == (pid_t)pid) { return((int)pp->ki_ruid); } } return(-1); } /* * swapmode is based on a program called swapinfo written * by Kevin Lahey . */ #define SVAR(var) __STRING(var) /* to force expansion */ #define KGET(idx, var) \ KGET1(idx, &var, sizeof(var), SVAR(var)) #define KGET1(idx, p, s, msg) \ KGET2(nlst[idx].n_value, p, s, msg) #define KGET2(addr, p, s, msg) \ if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ return (0); \ } #define KGETRET(addr, p, s, msg) \ if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ return (0); \ } int swapmode(retavail, retfree) int *retavail; int *retfree; { int n; int pagesize = getpagesize(); struct kvm_swap swapary[1]; *retavail = 0; *retfree = 0; #define CONVERT(v) ((quad_t)(v) * pagesize / 1024) n = kvm_getswapinfo(kd, swapary, 1, 0); if (n < 0 || swapary[0].ksw_total == 0) return(0); *retavail = CONVERT(swapary[0].ksw_total); *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); n = (int)((double)swapary[0].ksw_used * 100.0 / (double)swapary[0].ksw_total); return(n); }