Annotation of src/usr.bin/top/machine.c, Revision 1.105
1.105 ! kn 1: /* $OpenBSD: machine.c,v 1.104 2020/06/24 23:56:01 kn Exp $ */
1.28 tholo 2:
3: /*-
4: * Copyright (c) 1994 Thorsten Lockert <tholo@sigmasoft.com>
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 downsj 28: *
29: * AUTHOR: Thorsten Lockert <tholo@sigmasoft.com>
30: * Adapted from BSD4.4 by Christos Zoulas <christos@ee.cornell.edu>
31: * Patch for process wait display by Jarl F. Greipsland <jarle@idt.unit.no>
1.11 kstailey 32: * Patch for -DORDER by Kenneth Stailey <kstailey@disclosure.com>
1.15 weingart 33: * Patch for new swapctl(2) by Tobias Weingartner <weingart@openbsd.org>
1.1 downsj 34: */
35:
1.81 deraadt 36: #include <sys/param.h> /* DEV_BSIZE MAXCOMLEN PZERO */
1.1 downsj 37: #include <sys/types.h>
1.81 deraadt 38: #include <sys/signal.h>
1.75 millert 39: #include <sys/mount.h>
40: #include <sys/proc.h>
1.79 miod 41: #include <sys/sched.h>
1.75 millert 42: #include <sys/swap.h>
43: #include <sys/sysctl.h>
44:
1.1 downsj 45: #include <stdio.h>
46: #include <stdlib.h>
1.3 downsj 47: #include <string.h>
1.1 downsj 48: #include <unistd.h>
49: #include <err.h>
1.51 millert 50: #include <errno.h>
1.1 downsj 51:
52: #include "top.h"
1.3 downsj 53: #include "display.h"
1.1 downsj 54: #include "machine.h"
55: #include "utils.h"
1.31 deraadt 56:
1.38 deraadt 57: static int swapmode(int *, int *);
1.68 guenther 58: static char *state_abbr(struct kinfo_proc *);
59: static char *format_comm(struct kinfo_proc *);
1.86 edd 60: static int cmd_matches(struct kinfo_proc *, char *);
61: static char **get_proc_args(struct kinfo_proc *);
1.1 downsj 62:
63: /* get_process_info passes back a handle. This is what it looks like: */
64:
1.20 deraadt 65: struct handle {
1.68 guenther 66: struct kinfo_proc **next_proc; /* points to next valid proc pointer */
1.1 downsj 67: };
68:
69: /* what we consider to be process size: */
1.37 millert 70: #define PROCSIZE(pp) ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize)
1.1 downsj 71:
72: /*
73: * These definitions control the format of the per-process area
74: */
1.38 deraadt 75: static char header[] =
1.64 deraadt 76: " PID X PRI NICE SIZE RES STATE WAIT TIME CPU COMMAND";
1.31 deraadt 77:
1.1 downsj 78: /* 0123456 -- field to fill in starts at header+6 */
79: #define UNAME_START 6
80:
81: #define Proc_format \
1.64 deraadt 82: "%5d %-8.8s %3d %4d %5s %5s %-9s %-7.7s %6s %5.2f%% %s"
1.1 downsj 83:
84: /* process state names for the "STATE" column of the display */
1.30 deraadt 85: char *state_abbrev[] = {
1.40 deraadt 86: "", "start", "run", "sleep", "stop", "zomb", "dead", "onproc"
1.1 downsj 87: };
88:
89: /* these are for calculating cpu state percentages */
1.95 cheloha 90: static struct cpustats *cp_time;
91: static struct cpustats *cp_old;
92: static struct cpustats *cp_diff;
1.1 downsj 93:
94: /* these are for detailing the process states */
1.45 markus 95: int process_states[8];
1.30 deraadt 96: char *procstatenames[] = {
97: "", " starting, ", " running, ", " idle, ",
1.47 markus 98: " stopped, ", " zombie, ", " dead, ", " on processor, ",
1.20 deraadt 99: NULL
1.1 downsj 100: };
101:
102: /* these are for detailing the cpu states */
1.48 millert 103: int64_t *cpu_states;
1.30 deraadt 104: char *cpustatenames[] = {
1.90 mpi 105: "user", "nice", "sys", "spin", "intr", "idle", NULL
1.1 downsj 106: };
107:
1.95 cheloha 108: /* this is for tracking which cpus are online */
109: int *cpu_online;
110:
1.1 downsj 111: /* these are for detailing the memory statistics */
1.69 tedu 112: int memory_stats[10];
1.30 deraadt 113: char *memorynames[] = {
1.69 tedu 114: "Real: ", "K/", "K act/tot ", "Free: ", "K ",
115: "Cache: ", "K ",
116: "Swap: ", "K/", "K",
1.20 deraadt 117: NULL
1.1 downsj 118: };
119:
1.11 kstailey 120: /* these are names given to allowed sorting orders -- first is default */
1.31 deraadt 121: char *ordernames[] = {
1.65 tedu 122: "cpu", "size", "res", "time", "pri", "pid", "command", NULL
1.31 deraadt 123: };
1.11 kstailey 124:
1.1 downsj 125: /* these are for keeping track of the proc array */
1.88 deraadt 126: static int nproc;
127: static int onproc = -1;
128: static int pref_len;
1.68 guenther 129: static struct kinfo_proc *pbase;
130: static struct kinfo_proc **pref;
1.1 downsj 131:
132: /* these are for getting the memory statistics */
1.88 deraadt 133: static int pageshift; /* log base 2 of the pagesize */
1.1 downsj 134:
135: /* define pagetok in terms of pageshift */
136: #define pagetok(size) ((size) << pageshift)
137:
1.41 deraadt 138: int ncpu;
1.95 cheloha 139: int ncpuonline;
1.82 deraadt 140: int fscale;
1.41 deraadt 141:
1.33 millert 142: unsigned int maxslp;
1.26 art 143:
1.18 deraadt 144: int
1.82 deraadt 145: getfscale(void)
146: {
147: int mib[] = { CTL_KERN, KERN_FSCALE };
148: size_t size = sizeof(fscale);
149:
150: if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
1.97 deraadt 151: &fscale, &size, NULL, 0) == -1)
1.82 deraadt 152: return (-1);
153: return fscale;
154: }
155:
156: int
1.80 dlg 157: getncpu(void)
158: {
159: int mib[] = { CTL_HW, HW_NCPU };
1.89 tedu 160: int numcpu;
161: size_t size = sizeof(numcpu);
1.80 dlg 162:
163: if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
1.89 tedu 164: &numcpu, &size, NULL, 0) == -1)
1.80 dlg 165: return (-1);
166:
1.89 tedu 167: return (numcpu);
1.80 dlg 168: }
169:
170: int
1.95 cheloha 171: getncpuonline(void)
172: {
173: int mib[] = { CTL_HW, HW_NCPUONLINE };
174: int numcpu;
175: size_t size = sizeof(numcpu);
176:
177: if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
178: &numcpu, &size, NULL, 0) == -1)
179: return (-1);
180:
181: return (numcpu);
182: }
183:
184: int
1.29 pvalchev 185: machine_init(struct statics *statics)
1.1 downsj 186: {
1.95 cheloha 187: int pagesize;
1.41 deraadt 188:
1.80 dlg 189: ncpu = getncpu();
190: if (ncpu == -1)
1.82 deraadt 191: return (-1);
192: if (getfscale() == -1)
1.41 deraadt 193: return (-1);
1.62 deraadt 194: cpu_states = calloc(ncpu, CPUSTATES * sizeof(int64_t));
1.48 millert 195: if (cpu_states == NULL)
196: err(1, NULL);
1.95 cheloha 197: cp_time = calloc(ncpu, sizeof(*cp_time));
198: cp_old = calloc(ncpu, sizeof(*cp_old));
199: cp_diff = calloc(ncpu, sizeof(*cp_diff));
1.48 millert 200: if (cp_time == NULL || cp_old == NULL || cp_diff == NULL)
201: err(1, NULL);
1.95 cheloha 202: cpu_online = calloc(ncpu, sizeof(*cpu_online));
203: if (cpu_online == NULL)
204: err(1, NULL);
1.20 deraadt 205:
206: pbase = NULL;
207: pref = NULL;
208: onproc = -1;
209: nproc = 0;
210:
1.30 deraadt 211: /*
212: * get the page size with "getpagesize" and calculate pageshift from
213: * it
214: */
1.20 deraadt 215: pagesize = getpagesize();
216: pageshift = 0;
217: while (pagesize > 1) {
218: pageshift++;
219: pagesize >>= 1;
220: }
221:
222: /* we only need the amount of log(2)1024 for our conversion */
223: pageshift -= LOG1024;
224:
225: /* fill in the statics information */
226: statics->procstate_names = procstatenames;
227: statics->cpustate_names = cpustatenames;
228: statics->memory_names = memorynames;
229: statics->order_names = ordernames;
230: return (0);
1.1 downsj 231: }
232:
1.20 deraadt 233: char *
1.100 kn 234: format_header(char *second_field)
1.1 downsj 235: {
1.84 mpi 236: char *field_name, *thread_field = " TID";
1.20 deraadt 237: char *ptr;
1.1 downsj 238:
1.100 kn 239: field_name = second_field ? second_field : thread_field;
1.84 mpi 240:
1.20 deraadt 241: ptr = header + UNAME_START;
1.84 mpi 242: while (*field_name != '\0')
243: *ptr++ = *field_name++;
1.20 deraadt 244: return (header);
1.1 downsj 245: }
246:
247: void
1.31 deraadt 248: get_system_info(struct system_info *si)
1.1 downsj 249: {
1.95 cheloha 250: static int cpustats_mib[] = {CTL_KERN, KERN_CPUSTATS, /*fillme*/0};
1.20 deraadt 251: static int sysload_mib[] = {CTL_VM, VM_LOADAVG};
1.77 mpi 252: static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
1.69 tedu 253: static int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT};
1.1 downsj 254: struct loadavg sysload;
1.77 mpi 255: struct uvmexp uvmexp;
1.69 tedu 256: struct bcachestats bcstats;
1.20 deraadt 257: double *infoloadp;
1.30 deraadt 258: size_t size;
1.35 deraadt 259: int i;
1.48 millert 260: int64_t *tmpstate;
1.30 deraadt 261:
1.95 cheloha 262: size = sizeof(*cp_time);
263: for (i = 0; i < ncpu; i++) {
264: cpustats_mib[2] = i;
265: tmpstate = cpu_states + (CPUSTATES * i);
1.97 deraadt 266: if (sysctl(cpustats_mib, 3, &cp_time[i], &size, NULL, 0) == -1)
1.95 cheloha 267: warn("sysctl kern.cpustats failed");
268: /* convert cpustats counts to percentages */
269: (void) percentages(CPUSTATES, tmpstate, cp_time[i].cs_time,
270: cp_old[i].cs_time, cp_diff[i].cs_time);
271: /* note whether the cpu is online */
272: cpu_online[i] = (cp_time[i].cs_flags & CPUSTATS_ONLINE) != 0;
1.48 millert 273: }
1.35 deraadt 274:
1.20 deraadt 275: size = sizeof(sysload);
1.97 deraadt 276: if (sysctl(sysload_mib, 2, &sysload, &size, NULL, 0) == -1)
1.20 deraadt 277: warn("sysctl failed");
1.1 downsj 278: infoloadp = si->load_avg;
279: for (i = 0; i < 3; i++)
1.20 deraadt 280: *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
1.1 downsj 281:
282:
283: /* get total -- systemwide main memory usage structure */
1.77 mpi 284: size = sizeof(uvmexp);
1.97 deraadt 285: if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) == -1) {
1.20 deraadt 286: warn("sysctl failed");
1.77 mpi 287: bzero(&uvmexp, sizeof(uvmexp));
1.1 downsj 288: }
1.69 tedu 289: size = sizeof(bcstats);
1.97 deraadt 290: if (sysctl(bcstats_mib, 3, &bcstats, &size, NULL, 0) == -1) {
1.69 tedu 291: warn("sysctl failed");
292: bzero(&bcstats, sizeof(bcstats));
293: }
1.1 downsj 294: /* convert memory stats to Kbytes */
295: memory_stats[0] = -1;
1.77 mpi 296: memory_stats[1] = pagetok(uvmexp.active);
297: memory_stats[2] = pagetok(uvmexp.npages - uvmexp.free);
1.1 downsj 298: memory_stats[3] = -1;
1.77 mpi 299: memory_stats[4] = pagetok(uvmexp.free);
1.1 downsj 300: memory_stats[5] = -1;
1.69 tedu 301: memory_stats[6] = pagetok(bcstats.numbufpages);
302: memory_stats[7] = -1;
1.31 deraadt 303:
1.69 tedu 304: if (!swapmode(&memory_stats[8], &memory_stats[9])) {
305: memory_stats[8] = 0;
306: memory_stats[9] = 0;
1.1 downsj 307: }
308:
1.20 deraadt 309: /* set arrays and strings */
310: si->cpustates = cpu_states;
1.95 cheloha 311: si->cpuonline = cpu_online;
1.20 deraadt 312: si->memory = memory_stats;
313: si->last_pid = -1;
1.1 downsj 314: }
315:
316: static struct handle handle;
317:
1.68 guenther 318: struct kinfo_proc *
1.29 pvalchev 319: getprocs(int op, int arg, int *cnt)
1.22 deraadt 320: {
1.37 millert 321: size_t size;
1.68 guenther 322: int mib[6] = {CTL_KERN, KERN_PROC, 0, 0, sizeof(struct kinfo_proc), 0};
1.26 art 323: static int maxslp_mib[] = {CTL_VM, VM_MAXSLP};
1.68 guenther 324: static struct kinfo_proc *procbase;
1.24 angelos 325: int st;
1.22 deraadt 326:
1.31 deraadt 327: mib[2] = op;
328: mib[3] = arg;
329:
1.26 art 330: size = sizeof(maxslp);
1.97 deraadt 331: if (sysctl(maxslp_mib, 2, &maxslp, &size, NULL, 0) == -1) {
1.26 art 332: warn("sysctl vm.maxslp failed");
333: return (0);
334: }
1.37 millert 335: retry:
336: free(procbase);
337: st = sysctl(mib, 6, NULL, &size, NULL, 0);
1.22 deraadt 338: if (st == -1) {
1.68 guenther 339: /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
1.22 deraadt 340: return (0);
341: }
1.37 millert 342: size = 5 * size / 4; /* extra slop */
343: if ((procbase = malloc(size)) == NULL)
1.22 deraadt 344: return (0);
1.68 guenther 345: mib[5] = (int)(size / sizeof(struct kinfo_proc));
1.37 millert 346: st = sysctl(mib, 6, procbase, &size, NULL, 0);
1.22 deraadt 347: if (st == -1) {
1.37 millert 348: if (errno == ENOMEM)
349: goto retry;
1.68 guenther 350: /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
1.22 deraadt 351: return (0);
352: }
1.68 guenther 353: *cnt = (int)(size / sizeof(struct kinfo_proc));
1.22 deraadt 354: return (procbase);
355: }
356:
1.86 edd 357: static char **
358: get_proc_args(struct kinfo_proc *kp)
359: {
360: static char **s;
1.87 tedu 361: static size_t siz = 1023;
1.86 edd 362: int mib[4];
363:
1.87 tedu 364: if (!s && !(s = malloc(siz)))
365: err(1, NULL);
366:
367: mib[0] = CTL_KERN;
368: mib[1] = KERN_PROC_ARGS;
369: mib[2] = kp->p_pid;
370: mib[3] = KERN_PROC_ARGV;
371: for (;;) {
372: size_t space = siz;
373: if (sysctl(mib, 4, s, &space, NULL, 0) == 0)
1.86 edd 374: break;
375: if (errno != ENOMEM)
376: return NULL;
1.87 tedu 377: siz *= 2;
378: if ((s = realloc(s, siz)) == NULL)
379: err(1, NULL);
1.86 edd 380: }
381: return s;
382: }
383:
384: static int
385: cmd_matches(struct kinfo_proc *proc, char *term)
386: {
387: extern int show_args;
388: char **args = NULL;
389:
390: if (!term) {
391: /* No command filter set */
392: return 1;
393: } else {
394: /* Filter set, process name needs to contain term */
395: if (strstr(proc->p_comm, term))
396: return 1;
397: /* If showing arguments, search those as well */
398: if (show_args) {
399: args = get_proc_args(proc);
400:
401: if (args == NULL) {
402: /* Failed to get args, so can't search them */
403: return 0;
404: }
405:
406: while (*args != NULL) {
407: if (strstr(*args, term))
408: return 1;
409: args++;
410: }
411: }
412: }
413: return 0;
414: }
415:
1.99 kn 416: struct handle *
1.29 pvalchev 417: get_process_info(struct system_info *si, struct process_select *sel,
1.30 deraadt 418: int (*compare) (const void *, const void *))
1.20 deraadt 419: {
1.56 otto 420: int show_idle, show_system, show_threads, show_uid, show_pid, show_cmd;
1.73 brynet 421: int hide_uid;
1.46 pat 422: int total_procs, active_procs;
1.68 guenther 423: struct kinfo_proc **prefp, *pp;
1.101 guenther 424: int what = KERN_PROC_ALL;
1.20 deraadt 425:
1.101 guenther 426: show_system = sel->system;
427: show_threads = sel->threads;
428:
429: if (show_system)
430: what = KERN_PROC_KTHREAD;
431: if (show_threads)
1.71 pirofti 432: what |= KERN_PROC_SHOW_THREADS;
433:
434: if ((pbase = getprocs(what, 0, &nproc)) == NULL) {
1.22 deraadt 435: /* warnx("%s", kvm_geterr(kd)); */
1.20 deraadt 436: quit(23);
437: }
438: if (nproc > onproc)
1.85 deraadt 439: pref = reallocarray(pref, (onproc = nproc),
440: sizeof(struct kinfo_proc *));
1.20 deraadt 441: if (pref == NULL) {
442: warnx("Out of memory.");
443: quit(23);
444: }
445: /* get a pointer to the states summary array */
446: si->procstates = process_states;
1.1 downsj 447:
1.20 deraadt 448: /* set up flags which define what we are going to select */
449: show_idle = sel->idle;
1.33 millert 450: show_uid = sel->uid != (uid_t)-1;
1.73 brynet 451: hide_uid = sel->huid != (uid_t)-1;
1.44 otto 452: show_pid = sel->pid != (pid_t)-1;
1.56 otto 453: show_cmd = sel->command != NULL;
1.20 deraadt 454:
455: /* count up process states and get pointers to interesting procs */
456: total_procs = 0;
457: active_procs = 0;
458: memset((char *) process_states, 0, sizeof(process_states));
459: prefp = pref;
1.46 pat 460: for (pp = pbase; pp < &pbase[nproc]; pp++) {
1.20 deraadt 461: /*
1.101 guenther 462: * When showing threads, we want to ignore the structure
463: * that represents the entire process, which has TID == -1
1.20 deraadt 464: */
1.70 pirofti 465: if (show_threads && pp->p_tid == -1)
466: continue;
1.101 guenther 467: /*
468: * Place pointers to each valid proc structure in pref[].
469: * Process slots that are actually in use have a non-zero
470: * status field.
471: */
472: if (pp->p_stat != 0) {
1.20 deraadt 473: total_procs++;
1.37 millert 474: process_states[(unsigned char) pp->p_stat]++;
1.78 guenther 475: if ((pp->p_psflags & PS_ZOMBIE) == 0 &&
1.37 millert 476: (show_idle || pp->p_pctcpu != 0 ||
477: pp->p_stat == SRUN) &&
1.73 brynet 478: (!hide_uid || pp->p_ruid != sel->huid) &&
1.44 otto 479: (!show_uid || pp->p_ruid == sel->uid) &&
1.56 otto 480: (!show_pid || pp->p_pid == sel->pid) &&
1.86 edd 481: (!show_cmd || cmd_matches(pp, sel->command))) {
1.20 deraadt 482: *prefp++ = pp;
483: active_procs++;
484: }
485: }
486: }
487:
1.103 kn 488: qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
1.20 deraadt 489: /* remember active and total counts */
490: si->p_total = total_procs;
491: si->p_active = pref_len = active_procs;
492:
493: /* pass back a handle */
494: handle.next_proc = pref;
1.99 kn 495: return &handle;
1.20 deraadt 496: }
497:
1.30 deraadt 498: char fmt[MAX_COLS]; /* static area where result is built */
1.20 deraadt 499:
1.58 otto 500: static char *
1.68 guenther 501: state_abbr(struct kinfo_proc *pp)
1.40 deraadt 502: {
503: static char buf[10];
504:
1.42 deraadt 505: if (ncpu > 1 && pp->p_cpuid != KI_NOCPU)
1.48 millert 506: snprintf(buf, sizeof buf, "%s/%llu",
1.41 deraadt 507: state_abbrev[(unsigned char)pp->p_stat], pp->p_cpuid);
508: else
509: snprintf(buf, sizeof buf, "%s",
510: state_abbrev[(unsigned char)pp->p_stat]);
1.40 deraadt 511: return buf;
512: }
513:
1.58 otto 514: static char *
1.68 guenther 515: format_comm(struct kinfo_proc *kp)
1.49 markus 516: {
1.86 edd 517: static char buf[MAX_COLS];
518: char **p, **s;
519: extern int show_args;
1.49 markus 520:
521: if (!show_args)
522: return (kp->p_comm);
523:
1.86 edd 524: s = get_proc_args(kp);
525: if (s == NULL)
526: return kp->p_comm;
527:
1.49 markus 528: buf[0] = '\0';
529: for (p = s; *p != NULL; p++) {
530: if (p != s)
531: strlcat(buf, " ", sizeof(buf));
532: strlcat(buf, *p, sizeof(buf));
533: }
534: if (buf[0] == '\0')
535: return (kp->p_comm);
536: return (buf);
1.102 zhuk 537: }
538:
539: void
1.105 ! kn 540: skip_processes(struct handle *hndl, int n)
1.102 zhuk 541: {
1.105 ! kn 542: hndl->next_proc += n;
1.49 markus 543: }
544:
545: char *
1.99 kn 546: format_next_process(struct handle *hndl, const char *(*get_userid)(uid_t, int),
1.100 kn 547: pid_t *pid)
1.20 deraadt 548: {
1.76 tedu 549: char *p_wait;
1.68 guenther 550: struct kinfo_proc *pp;
1.20 deraadt 551: int cputime;
552: double pct;
1.84 mpi 553: char buf[16];
1.20 deraadt 554:
555: /* find and remember the next proc structure */
1.99 kn 556: pp = *(hndl->next_proc++);
1.20 deraadt 557:
1.66 lum 558: cputime = pp->p_rtime_sec + ((pp->p_rtime_usec + 500000) / 1000000);
1.20 deraadt 559:
560: /* calculate the base for cpu percentages */
1.83 millert 561: pct = (double)pp->p_pctcpu / fscale;
1.20 deraadt 562:
1.76 tedu 563: if (pp->p_wmesg[0])
564: p_wait = pp->p_wmesg;
565: else
1.20 deraadt 566: p_wait = "-";
567:
1.100 kn 568: if (get_userid == NULL)
1.84 mpi 569: snprintf(buf, sizeof(buf), "%8d", pp->p_tid);
570: else
1.92 millert 571: snprintf(buf, sizeof(buf), "%s", (*get_userid)(pp->p_ruid, 0));
1.84 mpi 572:
1.20 deraadt 573: /* format this entry */
1.84 mpi 574: snprintf(fmt, sizeof(fmt), Proc_format, pp->p_pid, buf,
1.37 millert 575: pp->p_priority - PZERO, pp->p_nice - NZERO,
1.1 downsj 576: format_k(pagetok(PROCSIZE(pp))),
1.37 millert 577: format_k(pagetok(pp->p_vm_rssize)),
578: (pp->p_stat == SSLEEP && pp->p_slptime > maxslp) ?
1.40 deraadt 579: "idle" : state_abbr(pp),
1.30 deraadt 580: p_wait, format_time(cputime), 100.0 * pct,
1.49 markus 581: printable(format_comm(pp)));
1.1 downsj 582:
1.61 otto 583: *pid = pp->p_pid;
1.20 deraadt 584: /* return the result */
585: return (fmt);
1.1 downsj 586: }
587:
588: /* comparison routine for qsort */
1.11 kstailey 589: static unsigned char sorted_state[] =
590: {
1.20 deraadt 591: 0, /* not used */
592: 4, /* start */
593: 5, /* run */
594: 2, /* sleep */
595: 3, /* stop */
596: 1 /* zombie */
1.11 kstailey 597: };
598:
1.96 kn 599: extern int rev_order;
600:
1.11 kstailey 601: /*
602: * proc_compares - comparison functions for "qsort"
603: */
604:
605: /*
606: * First, the possible comparison keys. These are defined in such a way
607: * that they can be merely listed in the source code to define the actual
608: * desired ordering.
609: */
610:
611: #define ORDERKEY_PCTCPU \
1.83 millert 612: if ((result = (int)(p2->p_pctcpu - p1->p_pctcpu)) == 0)
1.11 kstailey 613: #define ORDERKEY_CPUTIME \
1.37 millert 614: if ((result = p2->p_rtime_sec - p1->p_rtime_sec) == 0) \
615: if ((result = p2->p_rtime_usec - p1->p_rtime_usec) == 0)
1.11 kstailey 616: #define ORDERKEY_STATE \
1.37 millert 617: if ((result = sorted_state[(unsigned char)p2->p_stat] - \
618: sorted_state[(unsigned char)p1->p_stat]) == 0)
1.11 kstailey 619: #define ORDERKEY_PRIO \
1.37 millert 620: if ((result = p2->p_priority - p1->p_priority) == 0)
1.11 kstailey 621: #define ORDERKEY_RSSIZE \
1.37 millert 622: if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
1.11 kstailey 623: #define ORDERKEY_MEM \
624: if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0)
1.65 tedu 625: #define ORDERKEY_PID \
626: if ((result = p1->p_pid - p2->p_pid) == 0)
627: #define ORDERKEY_CMD \
628: if ((result = strcmp(p1->p_comm, p2->p_comm)) == 0)
1.11 kstailey 629:
1.96 kn 630: /* remove one level of indirection and set sort order */
631: #define SETORDER do { \
632: if (rev_order) { \
1.98 kn 633: p1 = *(struct kinfo_proc **) v2; \
634: p2 = *(struct kinfo_proc **) v1; \
1.96 kn 635: } else { \
1.98 kn 636: p1 = *(struct kinfo_proc **) v1; \
637: p2 = *(struct kinfo_proc **) v2; \
1.96 kn 638: } \
639: } while (0)
640:
1.11 kstailey 641: /* compare_cpu - the comparison function for sorting by cpu percentage */
1.36 deraadt 642: static int
1.29 pvalchev 643: compare_cpu(const void *v1, const void *v2)
1.11 kstailey 644: {
1.68 guenther 645: struct kinfo_proc *p1, *p2;
1.20 deraadt 646: int result;
647:
1.96 kn 648: SETORDER;
1.20 deraadt 649:
650: ORDERKEY_PCTCPU
1.30 deraadt 651: ORDERKEY_CPUTIME
652: ORDERKEY_STATE
653: ORDERKEY_PRIO
654: ORDERKEY_RSSIZE
655: ORDERKEY_MEM
656: ;
1.20 deraadt 657: return (result);
1.11 kstailey 658: }
659:
660: /* compare_size - the comparison function for sorting by total memory usage */
1.36 deraadt 661: static int
1.29 pvalchev 662: compare_size(const void *v1, const void *v2)
1.11 kstailey 663: {
1.68 guenther 664: struct kinfo_proc *p1, *p2;
1.20 deraadt 665: int result;
666:
1.96 kn 667: SETORDER;
1.20 deraadt 668:
669: ORDERKEY_MEM
1.30 deraadt 670: ORDERKEY_RSSIZE
671: ORDERKEY_PCTCPU
672: ORDERKEY_CPUTIME
673: ORDERKEY_STATE
674: ORDERKEY_PRIO
675: ;
1.20 deraadt 676: return (result);
1.11 kstailey 677: }
678:
679: /* compare_res - the comparison function for sorting by resident set size */
1.36 deraadt 680: static int
1.29 pvalchev 681: compare_res(const void *v1, const void *v2)
1.11 kstailey 682: {
1.68 guenther 683: struct kinfo_proc *p1, *p2;
1.20 deraadt 684: int result;
685:
1.96 kn 686: SETORDER;
1.20 deraadt 687:
688: ORDERKEY_RSSIZE
1.30 deraadt 689: ORDERKEY_MEM
690: ORDERKEY_PCTCPU
691: ORDERKEY_CPUTIME
692: ORDERKEY_STATE
693: ORDERKEY_PRIO
694: ;
1.20 deraadt 695: return (result);
1.11 kstailey 696: }
697:
698: /* compare_time - the comparison function for sorting by CPU time */
1.36 deraadt 699: static int
1.29 pvalchev 700: compare_time(const void *v1, const void *v2)
1.11 kstailey 701: {
1.68 guenther 702: struct kinfo_proc *p1, *p2;
1.20 deraadt 703: int result;
704:
1.96 kn 705: SETORDER;
1.20 deraadt 706:
707: ORDERKEY_CPUTIME
1.30 deraadt 708: ORDERKEY_PCTCPU
709: ORDERKEY_STATE
710: ORDERKEY_PRIO
711: ORDERKEY_MEM
712: ORDERKEY_RSSIZE
713: ;
1.20 deraadt 714: return (result);
1.11 kstailey 715: }
716:
717: /* compare_prio - the comparison function for sorting by CPU time */
1.36 deraadt 718: static int
1.29 pvalchev 719: compare_prio(const void *v1, const void *v2)
1.11 kstailey 720: {
1.68 guenther 721: struct kinfo_proc *p1, *p2;
1.20 deraadt 722: int result;
723:
1.96 kn 724: SETORDER;
1.20 deraadt 725:
726: ORDERKEY_PRIO
1.30 deraadt 727: ORDERKEY_PCTCPU
728: ORDERKEY_CPUTIME
729: ORDERKEY_STATE
730: ORDERKEY_RSSIZE
731: ORDERKEY_MEM
732: ;
1.20 deraadt 733: return (result);
734: }
735:
1.65 tedu 736: static int
737: compare_pid(const void *v1, const void *v2)
738: {
1.68 guenther 739: struct kinfo_proc *p1, *p2;
1.65 tedu 740: int result;
741:
1.96 kn 742: SETORDER;
1.65 tedu 743:
744: ORDERKEY_PID
745: ORDERKEY_PCTCPU
746: ORDERKEY_CPUTIME
747: ORDERKEY_STATE
748: ORDERKEY_PRIO
749: ORDERKEY_RSSIZE
750: ORDERKEY_MEM
751: ;
752: return (result);
753: }
754:
755: static int
756: compare_cmd(const void *v1, const void *v2)
757: {
1.68 guenther 758: struct kinfo_proc *p1, *p2;
1.65 tedu 759: int result;
760:
1.96 kn 761: SETORDER;
1.65 tedu 762:
763: ORDERKEY_CMD
764: ORDERKEY_PCTCPU
765: ORDERKEY_CPUTIME
766: ORDERKEY_STATE
767: ORDERKEY_PRIO
768: ORDERKEY_RSSIZE
769: ORDERKEY_MEM
770: ;
771: return (result);
772: }
773:
774:
1.31 deraadt 775: int (*proc_compares[])(const void *, const void *) = {
1.20 deraadt 776: compare_cpu,
777: compare_size,
778: compare_res,
779: compare_time,
780: compare_prio,
1.65 tedu 781: compare_pid,
782: compare_cmd,
1.20 deraadt 783: NULL
1.11 kstailey 784: };
1.30 deraadt 785:
1.1 downsj 786: /*
787: * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
788: * the process does not exist.
1.43 otto 789: * It is EXTREMELY IMPORTANT that this function work correctly.
1.1 downsj 790: * If top runs setuid root (as in SVR4), then this function
791: * is the only thing that stands in the way of a serious
792: * security problem. It validates requests for the "kill"
793: * and "renice" commands.
794: */
1.33 millert 795: uid_t
1.29 pvalchev 796: proc_owner(pid_t pid)
1.20 deraadt 797: {
1.68 guenther 798: struct kinfo_proc **prefp, *pp;
1.20 deraadt 799: int cnt;
800:
801: prefp = pref;
802: cnt = pref_len;
803: while (--cnt >= 0) {
804: pp = *prefp++;
1.37 millert 805: if (pp->p_pid == pid)
806: return ((uid_t)pp->p_ruid);
1.1 downsj 807: }
1.34 jfb 808: return (uid_t)(-1);
1.1 downsj 809: }
1.30 deraadt 810:
1.1 downsj 811: /*
1.17 todd 812: * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
1.15 weingart 813: * to be based on the new swapctl(2) system call.
1.1 downsj 814: */
815: static int
1.29 pvalchev 816: swapmode(int *used, int *total)
1.1 downsj 817: {
1.15 weingart 818: struct swapent *swdev;
1.30 deraadt 819: int nswap, rnswap, i;
1.1 downsj 820:
1.15 weingart 821: nswap = swapctl(SWAP_NSWAP, 0, 0);
1.20 deraadt 822: if (nswap == 0)
1.15 weingart 823: return 0;
824:
1.62 deraadt 825: swdev = calloc(nswap, sizeof(*swdev));
1.20 deraadt 826: if (swdev == NULL)
1.15 weingart 827: return 0;
828:
829: rnswap = swapctl(SWAP_STATS, swdev, nswap);
1.53 ray 830: if (rnswap == -1) {
831: free(swdev);
1.15 weingart 832: return 0;
1.53 ray 833: }
1.15 weingart 834:
835: /* if rnswap != nswap, then what? */
836:
837: /* Total things up */
838: *total = *used = 0;
839: for (i = 0; i < nswap; i++) {
840: if (swdev[i].se_flags & SWF_ENABLE) {
1.20 deraadt 841: *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
842: *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
1.1 downsj 843: }
844: }
1.20 deraadt 845: free(swdev);
1.1 downsj 846: return 1;
847: }