Annotation of src/usr.bin/top/machine.c, Revision 1.106
1.106 ! kn 1: /* $OpenBSD: machine.c,v 1.105 2020/06/25 20:38:41 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:
1.30 deraadt 206: /*
207: * get the page size with "getpagesize" and calculate pageshift from
208: * it
209: */
1.20 deraadt 210: pagesize = getpagesize();
211: pageshift = 0;
212: while (pagesize > 1) {
213: pageshift++;
214: pagesize >>= 1;
215: }
216:
217: /* we only need the amount of log(2)1024 for our conversion */
218: pageshift -= LOG1024;
219:
220: /* fill in the statics information */
221: statics->procstate_names = procstatenames;
222: statics->cpustate_names = cpustatenames;
223: statics->memory_names = memorynames;
224: statics->order_names = ordernames;
225: return (0);
1.1 downsj 226: }
227:
1.20 deraadt 228: char *
1.100 kn 229: format_header(char *second_field)
1.1 downsj 230: {
1.84 mpi 231: char *field_name, *thread_field = " TID";
1.20 deraadt 232: char *ptr;
1.1 downsj 233:
1.100 kn 234: field_name = second_field ? second_field : thread_field;
1.84 mpi 235:
1.20 deraadt 236: ptr = header + UNAME_START;
1.84 mpi 237: while (*field_name != '\0')
238: *ptr++ = *field_name++;
1.20 deraadt 239: return (header);
1.1 downsj 240: }
241:
242: void
1.31 deraadt 243: get_system_info(struct system_info *si)
1.1 downsj 244: {
1.95 cheloha 245: static int cpustats_mib[] = {CTL_KERN, KERN_CPUSTATS, /*fillme*/0};
1.20 deraadt 246: static int sysload_mib[] = {CTL_VM, VM_LOADAVG};
1.77 mpi 247: static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
1.69 tedu 248: static int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT};
1.1 downsj 249: struct loadavg sysload;
1.77 mpi 250: struct uvmexp uvmexp;
1.69 tedu 251: struct bcachestats bcstats;
1.20 deraadt 252: double *infoloadp;
1.30 deraadt 253: size_t size;
1.35 deraadt 254: int i;
1.48 millert 255: int64_t *tmpstate;
1.30 deraadt 256:
1.95 cheloha 257: size = sizeof(*cp_time);
258: for (i = 0; i < ncpu; i++) {
259: cpustats_mib[2] = i;
260: tmpstate = cpu_states + (CPUSTATES * i);
1.97 deraadt 261: if (sysctl(cpustats_mib, 3, &cp_time[i], &size, NULL, 0) == -1)
1.95 cheloha 262: warn("sysctl kern.cpustats failed");
263: /* convert cpustats counts to percentages */
264: (void) percentages(CPUSTATES, tmpstate, cp_time[i].cs_time,
265: cp_old[i].cs_time, cp_diff[i].cs_time);
266: /* note whether the cpu is online */
267: cpu_online[i] = (cp_time[i].cs_flags & CPUSTATS_ONLINE) != 0;
1.48 millert 268: }
1.35 deraadt 269:
1.20 deraadt 270: size = sizeof(sysload);
1.97 deraadt 271: if (sysctl(sysload_mib, 2, &sysload, &size, NULL, 0) == -1)
1.20 deraadt 272: warn("sysctl failed");
1.1 downsj 273: infoloadp = si->load_avg;
274: for (i = 0; i < 3; i++)
1.20 deraadt 275: *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
1.1 downsj 276:
277:
278: /* get total -- systemwide main memory usage structure */
1.77 mpi 279: size = sizeof(uvmexp);
1.97 deraadt 280: if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) == -1) {
1.20 deraadt 281: warn("sysctl failed");
1.77 mpi 282: bzero(&uvmexp, sizeof(uvmexp));
1.1 downsj 283: }
1.69 tedu 284: size = sizeof(bcstats);
1.97 deraadt 285: if (sysctl(bcstats_mib, 3, &bcstats, &size, NULL, 0) == -1) {
1.69 tedu 286: warn("sysctl failed");
287: bzero(&bcstats, sizeof(bcstats));
288: }
1.1 downsj 289: /* convert memory stats to Kbytes */
290: memory_stats[0] = -1;
1.77 mpi 291: memory_stats[1] = pagetok(uvmexp.active);
292: memory_stats[2] = pagetok(uvmexp.npages - uvmexp.free);
1.1 downsj 293: memory_stats[3] = -1;
1.77 mpi 294: memory_stats[4] = pagetok(uvmexp.free);
1.1 downsj 295: memory_stats[5] = -1;
1.69 tedu 296: memory_stats[6] = pagetok(bcstats.numbufpages);
297: memory_stats[7] = -1;
1.31 deraadt 298:
1.69 tedu 299: if (!swapmode(&memory_stats[8], &memory_stats[9])) {
300: memory_stats[8] = 0;
301: memory_stats[9] = 0;
1.1 downsj 302: }
303:
1.20 deraadt 304: /* set arrays and strings */
305: si->cpustates = cpu_states;
1.95 cheloha 306: si->cpuonline = cpu_online;
1.20 deraadt 307: si->memory = memory_stats;
308: si->last_pid = -1;
1.1 downsj 309: }
310:
311: static struct handle handle;
312:
1.68 guenther 313: struct kinfo_proc *
1.29 pvalchev 314: getprocs(int op, int arg, int *cnt)
1.22 deraadt 315: {
1.37 millert 316: size_t size;
1.68 guenther 317: int mib[6] = {CTL_KERN, KERN_PROC, 0, 0, sizeof(struct kinfo_proc), 0};
1.26 art 318: static int maxslp_mib[] = {CTL_VM, VM_MAXSLP};
1.68 guenther 319: static struct kinfo_proc *procbase;
1.24 angelos 320: int st;
1.22 deraadt 321:
1.31 deraadt 322: mib[2] = op;
323: mib[3] = arg;
324:
1.26 art 325: size = sizeof(maxslp);
1.97 deraadt 326: if (sysctl(maxslp_mib, 2, &maxslp, &size, NULL, 0) == -1) {
1.26 art 327: warn("sysctl vm.maxslp failed");
328: return (0);
329: }
1.37 millert 330: retry:
331: free(procbase);
332: st = sysctl(mib, 6, NULL, &size, NULL, 0);
1.22 deraadt 333: if (st == -1) {
1.68 guenther 334: /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
1.22 deraadt 335: return (0);
336: }
1.37 millert 337: size = 5 * size / 4; /* extra slop */
338: if ((procbase = malloc(size)) == NULL)
1.22 deraadt 339: return (0);
1.68 guenther 340: mib[5] = (int)(size / sizeof(struct kinfo_proc));
1.37 millert 341: st = sysctl(mib, 6, procbase, &size, NULL, 0);
1.22 deraadt 342: if (st == -1) {
1.37 millert 343: if (errno == ENOMEM)
344: goto retry;
1.68 guenther 345: /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
1.22 deraadt 346: return (0);
347: }
1.68 guenther 348: *cnt = (int)(size / sizeof(struct kinfo_proc));
1.22 deraadt 349: return (procbase);
350: }
351:
1.86 edd 352: static char **
353: get_proc_args(struct kinfo_proc *kp)
354: {
355: static char **s;
1.87 tedu 356: static size_t siz = 1023;
1.86 edd 357: int mib[4];
358:
1.87 tedu 359: if (!s && !(s = malloc(siz)))
360: err(1, NULL);
361:
362: mib[0] = CTL_KERN;
363: mib[1] = KERN_PROC_ARGS;
364: mib[2] = kp->p_pid;
365: mib[3] = KERN_PROC_ARGV;
366: for (;;) {
367: size_t space = siz;
368: if (sysctl(mib, 4, s, &space, NULL, 0) == 0)
1.86 edd 369: break;
370: if (errno != ENOMEM)
371: return NULL;
1.87 tedu 372: siz *= 2;
373: if ((s = realloc(s, siz)) == NULL)
374: err(1, NULL);
1.86 edd 375: }
376: return s;
377: }
378:
379: static int
380: cmd_matches(struct kinfo_proc *proc, char *term)
381: {
382: extern int show_args;
383: char **args = NULL;
384:
385: if (!term) {
386: /* No command filter set */
387: return 1;
388: } else {
389: /* Filter set, process name needs to contain term */
390: if (strstr(proc->p_comm, term))
391: return 1;
392: /* If showing arguments, search those as well */
393: if (show_args) {
394: args = get_proc_args(proc);
395:
396: if (args == NULL) {
397: /* Failed to get args, so can't search them */
398: return 0;
399: }
400:
401: while (*args != NULL) {
402: if (strstr(*args, term))
403: return 1;
404: args++;
405: }
406: }
407: }
408: return 0;
409: }
410:
1.99 kn 411: struct handle *
1.29 pvalchev 412: get_process_info(struct system_info *si, struct process_select *sel,
1.30 deraadt 413: int (*compare) (const void *, const void *))
1.20 deraadt 414: {
1.56 otto 415: int show_idle, show_system, show_threads, show_uid, show_pid, show_cmd;
1.73 brynet 416: int hide_uid;
1.46 pat 417: int total_procs, active_procs;
1.68 guenther 418: struct kinfo_proc **prefp, *pp;
1.101 guenther 419: int what = KERN_PROC_ALL;
1.20 deraadt 420:
1.101 guenther 421: show_system = sel->system;
422: show_threads = sel->threads;
423:
424: if (show_system)
425: what = KERN_PROC_KTHREAD;
426: if (show_threads)
1.71 pirofti 427: what |= KERN_PROC_SHOW_THREADS;
428:
429: if ((pbase = getprocs(what, 0, &nproc)) == NULL) {
1.22 deraadt 430: /* warnx("%s", kvm_geterr(kd)); */
1.20 deraadt 431: quit(23);
432: }
433: if (nproc > onproc)
1.85 deraadt 434: pref = reallocarray(pref, (onproc = nproc),
435: sizeof(struct kinfo_proc *));
1.20 deraadt 436: if (pref == NULL) {
437: warnx("Out of memory.");
438: quit(23);
439: }
440: /* get a pointer to the states summary array */
441: si->procstates = process_states;
1.1 downsj 442:
1.20 deraadt 443: /* set up flags which define what we are going to select */
444: show_idle = sel->idle;
1.33 millert 445: show_uid = sel->uid != (uid_t)-1;
1.73 brynet 446: hide_uid = sel->huid != (uid_t)-1;
1.44 otto 447: show_pid = sel->pid != (pid_t)-1;
1.56 otto 448: show_cmd = sel->command != NULL;
1.20 deraadt 449:
450: /* count up process states and get pointers to interesting procs */
451: total_procs = 0;
452: active_procs = 0;
453: memset((char *) process_states, 0, sizeof(process_states));
454: prefp = pref;
1.46 pat 455: for (pp = pbase; pp < &pbase[nproc]; pp++) {
1.20 deraadt 456: /*
1.101 guenther 457: * When showing threads, we want to ignore the structure
458: * that represents the entire process, which has TID == -1
1.20 deraadt 459: */
1.70 pirofti 460: if (show_threads && pp->p_tid == -1)
461: continue;
1.101 guenther 462: /*
463: * Place pointers to each valid proc structure in pref[].
464: * Process slots that are actually in use have a non-zero
465: * status field.
466: */
467: if (pp->p_stat != 0) {
1.20 deraadt 468: total_procs++;
1.37 millert 469: process_states[(unsigned char) pp->p_stat]++;
1.78 guenther 470: if ((pp->p_psflags & PS_ZOMBIE) == 0 &&
1.37 millert 471: (show_idle || pp->p_pctcpu != 0 ||
472: pp->p_stat == SRUN) &&
1.73 brynet 473: (!hide_uid || pp->p_ruid != sel->huid) &&
1.44 otto 474: (!show_uid || pp->p_ruid == sel->uid) &&
1.56 otto 475: (!show_pid || pp->p_pid == sel->pid) &&
1.86 edd 476: (!show_cmd || cmd_matches(pp, sel->command))) {
1.20 deraadt 477: *prefp++ = pp;
478: active_procs++;
479: }
480: }
481: }
482:
1.103 kn 483: qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
1.20 deraadt 484: /* remember active and total counts */
485: si->p_total = total_procs;
486: si->p_active = pref_len = active_procs;
487:
488: /* pass back a handle */
489: handle.next_proc = pref;
1.99 kn 490: return &handle;
1.20 deraadt 491: }
492:
1.30 deraadt 493: char fmt[MAX_COLS]; /* static area where result is built */
1.20 deraadt 494:
1.58 otto 495: static char *
1.68 guenther 496: state_abbr(struct kinfo_proc *pp)
1.40 deraadt 497: {
498: static char buf[10];
499:
1.42 deraadt 500: if (ncpu > 1 && pp->p_cpuid != KI_NOCPU)
1.48 millert 501: snprintf(buf, sizeof buf, "%s/%llu",
1.41 deraadt 502: state_abbrev[(unsigned char)pp->p_stat], pp->p_cpuid);
503: else
504: snprintf(buf, sizeof buf, "%s",
505: state_abbrev[(unsigned char)pp->p_stat]);
1.40 deraadt 506: return buf;
507: }
508:
1.58 otto 509: static char *
1.68 guenther 510: format_comm(struct kinfo_proc *kp)
1.49 markus 511: {
1.86 edd 512: static char buf[MAX_COLS];
513: char **p, **s;
514: extern int show_args;
1.49 markus 515:
516: if (!show_args)
517: return (kp->p_comm);
518:
1.86 edd 519: s = get_proc_args(kp);
520: if (s == NULL)
521: return kp->p_comm;
522:
1.49 markus 523: buf[0] = '\0';
524: for (p = s; *p != NULL; p++) {
525: if (p != s)
526: strlcat(buf, " ", sizeof(buf));
527: strlcat(buf, *p, sizeof(buf));
528: }
529: if (buf[0] == '\0')
530: return (kp->p_comm);
531: return (buf);
1.102 zhuk 532: }
533:
534: void
1.105 kn 535: skip_processes(struct handle *hndl, int n)
1.102 zhuk 536: {
1.105 kn 537: hndl->next_proc += n;
1.49 markus 538: }
539:
540: char *
1.99 kn 541: format_next_process(struct handle *hndl, const char *(*get_userid)(uid_t, int),
1.100 kn 542: pid_t *pid)
1.20 deraadt 543: {
1.76 tedu 544: char *p_wait;
1.68 guenther 545: struct kinfo_proc *pp;
1.20 deraadt 546: int cputime;
547: double pct;
1.84 mpi 548: char buf[16];
1.20 deraadt 549:
550: /* find and remember the next proc structure */
1.99 kn 551: pp = *(hndl->next_proc++);
1.20 deraadt 552:
1.66 lum 553: cputime = pp->p_rtime_sec + ((pp->p_rtime_usec + 500000) / 1000000);
1.20 deraadt 554:
555: /* calculate the base for cpu percentages */
1.83 millert 556: pct = (double)pp->p_pctcpu / fscale;
1.20 deraadt 557:
1.76 tedu 558: if (pp->p_wmesg[0])
559: p_wait = pp->p_wmesg;
560: else
1.20 deraadt 561: p_wait = "-";
562:
1.100 kn 563: if (get_userid == NULL)
1.84 mpi 564: snprintf(buf, sizeof(buf), "%8d", pp->p_tid);
565: else
1.92 millert 566: snprintf(buf, sizeof(buf), "%s", (*get_userid)(pp->p_ruid, 0));
1.84 mpi 567:
1.20 deraadt 568: /* format this entry */
1.84 mpi 569: snprintf(fmt, sizeof(fmt), Proc_format, pp->p_pid, buf,
1.37 millert 570: pp->p_priority - PZERO, pp->p_nice - NZERO,
1.1 downsj 571: format_k(pagetok(PROCSIZE(pp))),
1.37 millert 572: format_k(pagetok(pp->p_vm_rssize)),
573: (pp->p_stat == SSLEEP && pp->p_slptime > maxslp) ?
1.40 deraadt 574: "idle" : state_abbr(pp),
1.30 deraadt 575: p_wait, format_time(cputime), 100.0 * pct,
1.49 markus 576: printable(format_comm(pp)));
1.1 downsj 577:
1.61 otto 578: *pid = pp->p_pid;
1.20 deraadt 579: /* return the result */
580: return (fmt);
1.1 downsj 581: }
582:
583: /* comparison routine for qsort */
1.11 kstailey 584: static unsigned char sorted_state[] =
585: {
1.20 deraadt 586: 0, /* not used */
587: 4, /* start */
588: 5, /* run */
589: 2, /* sleep */
590: 3, /* stop */
591: 1 /* zombie */
1.11 kstailey 592: };
593:
1.96 kn 594: extern int rev_order;
595:
1.11 kstailey 596: /*
597: * proc_compares - comparison functions for "qsort"
598: */
599:
600: /*
601: * First, the possible comparison keys. These are defined in such a way
602: * that they can be merely listed in the source code to define the actual
603: * desired ordering.
604: */
605:
606: #define ORDERKEY_PCTCPU \
1.83 millert 607: if ((result = (int)(p2->p_pctcpu - p1->p_pctcpu)) == 0)
1.11 kstailey 608: #define ORDERKEY_CPUTIME \
1.37 millert 609: if ((result = p2->p_rtime_sec - p1->p_rtime_sec) == 0) \
610: if ((result = p2->p_rtime_usec - p1->p_rtime_usec) == 0)
1.11 kstailey 611: #define ORDERKEY_STATE \
1.37 millert 612: if ((result = sorted_state[(unsigned char)p2->p_stat] - \
613: sorted_state[(unsigned char)p1->p_stat]) == 0)
1.11 kstailey 614: #define ORDERKEY_PRIO \
1.37 millert 615: if ((result = p2->p_priority - p1->p_priority) == 0)
1.11 kstailey 616: #define ORDERKEY_RSSIZE \
1.37 millert 617: if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
1.11 kstailey 618: #define ORDERKEY_MEM \
619: if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0)
1.65 tedu 620: #define ORDERKEY_PID \
621: if ((result = p1->p_pid - p2->p_pid) == 0)
622: #define ORDERKEY_CMD \
623: if ((result = strcmp(p1->p_comm, p2->p_comm)) == 0)
1.11 kstailey 624:
1.96 kn 625: /* remove one level of indirection and set sort order */
626: #define SETORDER do { \
627: if (rev_order) { \
1.98 kn 628: p1 = *(struct kinfo_proc **) v2; \
629: p2 = *(struct kinfo_proc **) v1; \
1.96 kn 630: } else { \
1.98 kn 631: p1 = *(struct kinfo_proc **) v1; \
632: p2 = *(struct kinfo_proc **) v2; \
1.96 kn 633: } \
634: } while (0)
635:
1.11 kstailey 636: /* compare_cpu - the comparison function for sorting by cpu percentage */
1.36 deraadt 637: static int
1.29 pvalchev 638: compare_cpu(const void *v1, const void *v2)
1.11 kstailey 639: {
1.68 guenther 640: struct kinfo_proc *p1, *p2;
1.20 deraadt 641: int result;
642:
1.96 kn 643: SETORDER;
1.20 deraadt 644:
645: ORDERKEY_PCTCPU
1.30 deraadt 646: ORDERKEY_CPUTIME
647: ORDERKEY_STATE
648: ORDERKEY_PRIO
649: ORDERKEY_RSSIZE
650: ORDERKEY_MEM
651: ;
1.20 deraadt 652: return (result);
1.11 kstailey 653: }
654:
655: /* compare_size - the comparison function for sorting by total memory usage */
1.36 deraadt 656: static int
1.29 pvalchev 657: compare_size(const void *v1, const void *v2)
1.11 kstailey 658: {
1.68 guenther 659: struct kinfo_proc *p1, *p2;
1.20 deraadt 660: int result;
661:
1.96 kn 662: SETORDER;
1.20 deraadt 663:
664: ORDERKEY_MEM
1.30 deraadt 665: ORDERKEY_RSSIZE
666: ORDERKEY_PCTCPU
667: ORDERKEY_CPUTIME
668: ORDERKEY_STATE
669: ORDERKEY_PRIO
670: ;
1.20 deraadt 671: return (result);
1.11 kstailey 672: }
673:
674: /* compare_res - the comparison function for sorting by resident set size */
1.36 deraadt 675: static int
1.29 pvalchev 676: compare_res(const void *v1, const void *v2)
1.11 kstailey 677: {
1.68 guenther 678: struct kinfo_proc *p1, *p2;
1.20 deraadt 679: int result;
680:
1.96 kn 681: SETORDER;
1.20 deraadt 682:
683: ORDERKEY_RSSIZE
1.30 deraadt 684: ORDERKEY_MEM
685: ORDERKEY_PCTCPU
686: ORDERKEY_CPUTIME
687: ORDERKEY_STATE
688: ORDERKEY_PRIO
689: ;
1.20 deraadt 690: return (result);
1.11 kstailey 691: }
692:
693: /* compare_time - the comparison function for sorting by CPU time */
1.36 deraadt 694: static int
1.29 pvalchev 695: compare_time(const void *v1, const void *v2)
1.11 kstailey 696: {
1.68 guenther 697: struct kinfo_proc *p1, *p2;
1.20 deraadt 698: int result;
699:
1.96 kn 700: SETORDER;
1.20 deraadt 701:
702: ORDERKEY_CPUTIME
1.30 deraadt 703: ORDERKEY_PCTCPU
704: ORDERKEY_STATE
705: ORDERKEY_PRIO
706: ORDERKEY_MEM
707: ORDERKEY_RSSIZE
708: ;
1.20 deraadt 709: return (result);
1.11 kstailey 710: }
711:
712: /* compare_prio - the comparison function for sorting by CPU time */
1.36 deraadt 713: static int
1.29 pvalchev 714: compare_prio(const void *v1, const void *v2)
1.11 kstailey 715: {
1.68 guenther 716: struct kinfo_proc *p1, *p2;
1.20 deraadt 717: int result;
718:
1.96 kn 719: SETORDER;
1.20 deraadt 720:
721: ORDERKEY_PRIO
1.30 deraadt 722: ORDERKEY_PCTCPU
723: ORDERKEY_CPUTIME
724: ORDERKEY_STATE
725: ORDERKEY_RSSIZE
726: ORDERKEY_MEM
727: ;
1.20 deraadt 728: return (result);
729: }
730:
1.65 tedu 731: static int
732: compare_pid(const void *v1, const void *v2)
733: {
1.68 guenther 734: struct kinfo_proc *p1, *p2;
1.65 tedu 735: int result;
736:
1.96 kn 737: SETORDER;
1.65 tedu 738:
739: ORDERKEY_PID
740: ORDERKEY_PCTCPU
741: ORDERKEY_CPUTIME
742: ORDERKEY_STATE
743: ORDERKEY_PRIO
744: ORDERKEY_RSSIZE
745: ORDERKEY_MEM
746: ;
747: return (result);
748: }
749:
750: static int
751: compare_cmd(const void *v1, const void *v2)
752: {
1.68 guenther 753: struct kinfo_proc *p1, *p2;
1.65 tedu 754: int result;
755:
1.96 kn 756: SETORDER;
1.65 tedu 757:
758: ORDERKEY_CMD
759: ORDERKEY_PCTCPU
760: ORDERKEY_CPUTIME
761: ORDERKEY_STATE
762: ORDERKEY_PRIO
763: ORDERKEY_RSSIZE
764: ORDERKEY_MEM
765: ;
766: return (result);
767: }
768:
769:
1.31 deraadt 770: int (*proc_compares[])(const void *, const void *) = {
1.20 deraadt 771: compare_cpu,
772: compare_size,
773: compare_res,
774: compare_time,
775: compare_prio,
1.65 tedu 776: compare_pid,
777: compare_cmd,
1.20 deraadt 778: NULL
1.11 kstailey 779: };
1.30 deraadt 780:
1.1 downsj 781: /*
782: * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
783: * the process does not exist.
1.43 otto 784: * It is EXTREMELY IMPORTANT that this function work correctly.
1.1 downsj 785: * If top runs setuid root (as in SVR4), then this function
786: * is the only thing that stands in the way of a serious
787: * security problem. It validates requests for the "kill"
788: * and "renice" commands.
789: */
1.33 millert 790: uid_t
1.29 pvalchev 791: proc_owner(pid_t pid)
1.20 deraadt 792: {
1.68 guenther 793: struct kinfo_proc **prefp, *pp;
1.20 deraadt 794: int cnt;
795:
796: prefp = pref;
797: cnt = pref_len;
798: while (--cnt >= 0) {
799: pp = *prefp++;
1.37 millert 800: if (pp->p_pid == pid)
801: return ((uid_t)pp->p_ruid);
1.1 downsj 802: }
1.34 jfb 803: return (uid_t)(-1);
1.1 downsj 804: }
1.30 deraadt 805:
1.1 downsj 806: /*
1.17 todd 807: * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
1.15 weingart 808: * to be based on the new swapctl(2) system call.
1.1 downsj 809: */
810: static int
1.29 pvalchev 811: swapmode(int *used, int *total)
1.1 downsj 812: {
1.15 weingart 813: struct swapent *swdev;
1.30 deraadt 814: int nswap, rnswap, i;
1.1 downsj 815:
1.15 weingart 816: nswap = swapctl(SWAP_NSWAP, 0, 0);
1.20 deraadt 817: if (nswap == 0)
1.15 weingart 818: return 0;
819:
1.62 deraadt 820: swdev = calloc(nswap, sizeof(*swdev));
1.20 deraadt 821: if (swdev == NULL)
1.15 weingart 822: return 0;
823:
824: rnswap = swapctl(SWAP_STATS, swdev, nswap);
1.53 ray 825: if (rnswap == -1) {
826: free(swdev);
1.15 weingart 827: return 0;
1.53 ray 828: }
1.15 weingart 829:
830: /* if rnswap != nswap, then what? */
831:
832: /* Total things up */
833: *total = *used = 0;
834: for (i = 0; i < nswap; i++) {
835: if (swdev[i].se_flags & SWF_ENABLE) {
1.20 deraadt 836: *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
837: *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
1.1 downsj 838: }
839: }
1.20 deraadt 840: free(swdev);
1.1 downsj 841: return 1;
842: }