Annotation of src/usr.bin/top/machine.c, Revision 1.112
1.112 ! cheloha 1: /* $OpenBSD: machine.c,v 1.111 2022/02/22 17:35:01 deraadt 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.111 deraadt 36: #include <sys/param.h> /* DEV_BSIZE 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.110 kn 78: /* offsets in the header line to start alternative columns */
1.1 downsj 79: #define UNAME_START 6
1.110 kn 80: #define RTABLE_START 46
1.1 downsj 81:
82: #define Proc_format \
1.64 deraadt 83: "%5d %-8.8s %3d %4d %5s %5s %-9s %-7.7s %6s %5.2f%% %s"
1.1 downsj 84:
85: /* process state names for the "STATE" column of the display */
1.30 deraadt 86: char *state_abbrev[] = {
1.40 deraadt 87: "", "start", "run", "sleep", "stop", "zomb", "dead", "onproc"
1.1 downsj 88: };
89:
90: /* these are for calculating cpu state percentages */
1.95 cheloha 91: static struct cpustats *cp_time;
92: static struct cpustats *cp_old;
93: static struct cpustats *cp_diff;
1.1 downsj 94:
95: /* these are for detailing the process states */
1.45 markus 96: int process_states[8];
1.30 deraadt 97: char *procstatenames[] = {
98: "", " starting, ", " running, ", " idle, ",
1.47 markus 99: " stopped, ", " zombie, ", " dead, ", " on processor, ",
1.20 deraadt 100: NULL
1.1 downsj 101: };
102:
103: /* these are for detailing the cpu states */
1.48 millert 104: int64_t *cpu_states;
1.30 deraadt 105: char *cpustatenames[] = {
1.90 mpi 106: "user", "nice", "sys", "spin", "intr", "idle", NULL
1.1 downsj 107: };
108:
1.95 cheloha 109: /* this is for tracking which cpus are online */
110: int *cpu_online;
111:
1.1 downsj 112: /* these are for detailing the memory statistics */
1.69 tedu 113: int memory_stats[10];
1.30 deraadt 114: char *memorynames[] = {
1.69 tedu 115: "Real: ", "K/", "K act/tot ", "Free: ", "K ",
116: "Cache: ", "K ",
117: "Swap: ", "K/", "K",
1.20 deraadt 118: NULL
1.1 downsj 119: };
120:
1.11 kstailey 121: /* these are names given to allowed sorting orders -- first is default */
1.31 deraadt 122: char *ordernames[] = {
1.65 tedu 123: "cpu", "size", "res", "time", "pri", "pid", "command", NULL
1.31 deraadt 124: };
1.11 kstailey 125:
1.1 downsj 126: /* these are for keeping track of the proc array */
1.88 deraadt 127: static int nproc;
128: static int onproc = -1;
129: static int pref_len;
1.68 guenther 130: static struct kinfo_proc *pbase;
131: static struct kinfo_proc **pref;
1.1 downsj 132:
133: /* these are for getting the memory statistics */
1.88 deraadt 134: static int pageshift; /* log base 2 of the pagesize */
1.1 downsj 135:
136: /* define pagetok in terms of pageshift */
137: #define pagetok(size) ((size) << pageshift)
138:
1.41 deraadt 139: int ncpu;
1.95 cheloha 140: int ncpuonline;
1.82 deraadt 141: int fscale;
1.41 deraadt 142:
1.33 millert 143: unsigned int maxslp;
1.26 art 144:
1.18 deraadt 145: int
1.82 deraadt 146: getfscale(void)
147: {
148: int mib[] = { CTL_KERN, KERN_FSCALE };
149: size_t size = sizeof(fscale);
150:
151: if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
1.97 deraadt 152: &fscale, &size, NULL, 0) == -1)
1.82 deraadt 153: return (-1);
154: return fscale;
155: }
156:
157: int
1.80 dlg 158: getncpu(void)
159: {
160: int mib[] = { CTL_HW, HW_NCPU };
1.89 tedu 161: int numcpu;
162: size_t size = sizeof(numcpu);
1.80 dlg 163:
164: if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
1.89 tedu 165: &numcpu, &size, NULL, 0) == -1)
1.80 dlg 166: return (-1);
167:
1.89 tedu 168: return (numcpu);
1.80 dlg 169: }
170:
171: int
1.95 cheloha 172: getncpuonline(void)
173: {
174: int mib[] = { CTL_HW, HW_NCPUONLINE };
175: int numcpu;
176: size_t size = sizeof(numcpu);
177:
178: if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
179: &numcpu, &size, NULL, 0) == -1)
180: return (-1);
181:
182: return (numcpu);
183: }
184:
185: int
1.29 pvalchev 186: machine_init(struct statics *statics)
1.1 downsj 187: {
1.95 cheloha 188: int pagesize;
1.41 deraadt 189:
1.80 dlg 190: ncpu = getncpu();
191: if (ncpu == -1)
1.82 deraadt 192: return (-1);
193: if (getfscale() == -1)
1.41 deraadt 194: return (-1);
1.62 deraadt 195: cpu_states = calloc(ncpu, CPUSTATES * sizeof(int64_t));
1.48 millert 196: if (cpu_states == NULL)
197: err(1, NULL);
1.95 cheloha 198: cp_time = calloc(ncpu, sizeof(*cp_time));
199: cp_old = calloc(ncpu, sizeof(*cp_old));
200: cp_diff = calloc(ncpu, sizeof(*cp_diff));
1.48 millert 201: if (cp_time == NULL || cp_old == NULL || cp_diff == NULL)
202: err(1, NULL);
1.95 cheloha 203: cpu_online = calloc(ncpu, sizeof(*cpu_online));
204: if (cpu_online == NULL)
205: err(1, NULL);
1.20 deraadt 206:
1.30 deraadt 207: /*
208: * get the page size with "getpagesize" and calculate pageshift from
209: * it
210: */
1.20 deraadt 211: pagesize = getpagesize();
212: pageshift = 0;
213: while (pagesize > 1) {
214: pageshift++;
215: pagesize >>= 1;
216: }
217:
218: /* we only need the amount of log(2)1024 for our conversion */
219: pageshift -= LOG1024;
220:
221: /* fill in the statics information */
222: statics->procstate_names = procstatenames;
223: statics->cpustate_names = cpustatenames;
224: statics->memory_names = memorynames;
225: statics->order_names = ordernames;
226: return (0);
1.1 downsj 227: }
228:
1.20 deraadt 229: char *
1.110 kn 230: format_header(char *second_field, char *eighth_field)
1.1 downsj 231: {
1.110 kn 232: char *second_fieldp = second_field, *eighth_fieldp = eighth_field, *ptr;
1.84 mpi 233:
1.20 deraadt 234: ptr = header + UNAME_START;
1.110 kn 235: while (*second_fieldp != '\0')
236: *ptr++ = *second_fieldp++;
237: ptr = header + RTABLE_START;
238: while (*eighth_fieldp != '\0')
239: *ptr++ = *eighth_fieldp++;
1.20 deraadt 240: return (header);
1.1 downsj 241: }
242:
243: void
1.31 deraadt 244: get_system_info(struct system_info *si)
1.1 downsj 245: {
1.95 cheloha 246: static int cpustats_mib[] = {CTL_KERN, KERN_CPUSTATS, /*fillme*/0};
1.20 deraadt 247: static int sysload_mib[] = {CTL_VM, VM_LOADAVG};
1.77 mpi 248: static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
1.69 tedu 249: static int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT};
1.1 downsj 250: struct loadavg sysload;
1.77 mpi 251: struct uvmexp uvmexp;
1.69 tedu 252: struct bcachestats bcstats;
1.20 deraadt 253: double *infoloadp;
1.30 deraadt 254: size_t size;
1.35 deraadt 255: int i;
1.48 millert 256: int64_t *tmpstate;
1.30 deraadt 257:
1.95 cheloha 258: size = sizeof(*cp_time);
259: for (i = 0; i < ncpu; i++) {
260: cpustats_mib[2] = i;
261: tmpstate = cpu_states + (CPUSTATES * i);
1.97 deraadt 262: if (sysctl(cpustats_mib, 3, &cp_time[i], &size, NULL, 0) == -1)
1.95 cheloha 263: warn("sysctl kern.cpustats failed");
264: /* convert cpustats counts to percentages */
265: (void) percentages(CPUSTATES, tmpstate, cp_time[i].cs_time,
266: cp_old[i].cs_time, cp_diff[i].cs_time);
267: /* note whether the cpu is online */
268: cpu_online[i] = (cp_time[i].cs_flags & CPUSTATS_ONLINE) != 0;
1.48 millert 269: }
1.35 deraadt 270:
1.20 deraadt 271: size = sizeof(sysload);
1.97 deraadt 272: if (sysctl(sysload_mib, 2, &sysload, &size, NULL, 0) == -1)
1.20 deraadt 273: warn("sysctl failed");
1.1 downsj 274: infoloadp = si->load_avg;
275: for (i = 0; i < 3; i++)
1.20 deraadt 276: *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
1.1 downsj 277:
278:
279: /* get total -- systemwide main memory usage structure */
1.77 mpi 280: size = sizeof(uvmexp);
1.97 deraadt 281: if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) == -1) {
1.20 deraadt 282: warn("sysctl failed");
1.77 mpi 283: bzero(&uvmexp, sizeof(uvmexp));
1.1 downsj 284: }
1.69 tedu 285: size = sizeof(bcstats);
1.97 deraadt 286: if (sysctl(bcstats_mib, 3, &bcstats, &size, NULL, 0) == -1) {
1.69 tedu 287: warn("sysctl failed");
288: bzero(&bcstats, sizeof(bcstats));
289: }
1.1 downsj 290: /* convert memory stats to Kbytes */
291: memory_stats[0] = -1;
1.77 mpi 292: memory_stats[1] = pagetok(uvmexp.active);
293: memory_stats[2] = pagetok(uvmexp.npages - uvmexp.free);
1.1 downsj 294: memory_stats[3] = -1;
1.77 mpi 295: memory_stats[4] = pagetok(uvmexp.free);
1.1 downsj 296: memory_stats[5] = -1;
1.69 tedu 297: memory_stats[6] = pagetok(bcstats.numbufpages);
298: memory_stats[7] = -1;
1.31 deraadt 299:
1.69 tedu 300: if (!swapmode(&memory_stats[8], &memory_stats[9])) {
301: memory_stats[8] = 0;
302: memory_stats[9] = 0;
1.1 downsj 303: }
304:
1.20 deraadt 305: /* set arrays and strings */
306: si->cpustates = cpu_states;
1.95 cheloha 307: si->cpuonline = cpu_online;
1.20 deraadt 308: si->memory = memory_stats;
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.107 kn 317: int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0,
318: sizeof(struct kinfo_proc), 0};
1.26 art 319: static int maxslp_mib[] = {CTL_VM, VM_MAXSLP};
1.68 guenther 320: static struct kinfo_proc *procbase;
1.24 angelos 321: int st;
1.22 deraadt 322:
1.31 deraadt 323: mib[2] = op;
324: mib[3] = arg;
325:
1.26 art 326: size = sizeof(maxslp);
1.97 deraadt 327: if (sysctl(maxslp_mib, 2, &maxslp, &size, NULL, 0) == -1) {
1.26 art 328: warn("sysctl vm.maxslp failed");
329: return (0);
330: }
1.37 millert 331: retry:
332: free(procbase);
333: st = sysctl(mib, 6, NULL, &size, NULL, 0);
1.22 deraadt 334: if (st == -1) {
1.68 guenther 335: /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
1.22 deraadt 336: return (0);
337: }
1.37 millert 338: size = 5 * size / 4; /* extra slop */
339: if ((procbase = malloc(size)) == NULL)
1.22 deraadt 340: return (0);
1.68 guenther 341: mib[5] = (int)(size / sizeof(struct kinfo_proc));
1.37 millert 342: st = sysctl(mib, 6, procbase, &size, NULL, 0);
1.22 deraadt 343: if (st == -1) {
1.37 millert 344: if (errno == ENOMEM)
345: goto retry;
1.68 guenther 346: /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
1.22 deraadt 347: return (0);
348: }
1.68 guenther 349: *cnt = (int)(size / sizeof(struct kinfo_proc));
1.22 deraadt 350: return (procbase);
351: }
352:
1.86 edd 353: static char **
354: get_proc_args(struct kinfo_proc *kp)
355: {
356: static char **s;
1.87 tedu 357: static size_t siz = 1023;
1.86 edd 358: int mib[4];
359:
1.87 tedu 360: if (!s && !(s = malloc(siz)))
361: err(1, NULL);
362:
363: mib[0] = CTL_KERN;
364: mib[1] = KERN_PROC_ARGS;
365: mib[2] = kp->p_pid;
366: mib[3] = KERN_PROC_ARGV;
367: for (;;) {
368: size_t space = siz;
369: if (sysctl(mib, 4, s, &space, NULL, 0) == 0)
1.86 edd 370: break;
371: if (errno != ENOMEM)
372: return NULL;
1.87 tedu 373: siz *= 2;
374: if ((s = realloc(s, siz)) == NULL)
375: err(1, NULL);
1.86 edd 376: }
377: return s;
378: }
379:
380: static int
381: cmd_matches(struct kinfo_proc *proc, char *term)
382: {
383: extern int show_args;
384: char **args = NULL;
385:
386: if (!term) {
387: /* No command filter set */
388: return 1;
389: } else {
390: /* Filter set, process name needs to contain term */
391: if (strstr(proc->p_comm, term))
392: return 1;
393: /* If showing arguments, search those as well */
394: if (show_args) {
395: args = get_proc_args(proc);
396:
397: if (args == NULL) {
398: /* Failed to get args, so can't search them */
399: return 0;
400: }
401:
402: while (*args != NULL) {
403: if (strstr(*args, term))
404: return 1;
405: args++;
406: }
407: }
408: }
409: return 0;
410: }
411:
1.99 kn 412: struct handle *
1.29 pvalchev 413: get_process_info(struct system_info *si, struct process_select *sel,
1.30 deraadt 414: int (*compare) (const void *, const void *))
1.20 deraadt 415: {
1.56 otto 416: int show_idle, show_system, show_threads, show_uid, show_pid, show_cmd;
1.109 kn 417: int show_rtableid, hide_rtableid, hide_uid;
1.46 pat 418: int total_procs, active_procs;
1.68 guenther 419: struct kinfo_proc **prefp, *pp;
1.101 guenther 420: int what = KERN_PROC_ALL;
1.20 deraadt 421:
1.101 guenther 422: show_system = sel->system;
423: show_threads = sel->threads;
424:
425: if (show_system)
426: what = KERN_PROC_KTHREAD;
427: if (show_threads)
1.71 pirofti 428: what |= KERN_PROC_SHOW_THREADS;
429:
430: if ((pbase = getprocs(what, 0, &nproc)) == NULL) {
1.22 deraadt 431: /* warnx("%s", kvm_geterr(kd)); */
1.20 deraadt 432: quit(23);
433: }
434: if (nproc > onproc)
1.85 deraadt 435: pref = reallocarray(pref, (onproc = nproc),
436: sizeof(struct kinfo_proc *));
1.20 deraadt 437: if (pref == NULL) {
438: warnx("Out of memory.");
439: quit(23);
440: }
441: /* get a pointer to the states summary array */
442: si->procstates = process_states;
1.1 downsj 443:
1.20 deraadt 444: /* set up flags which define what we are going to select */
445: show_idle = sel->idle;
1.33 millert 446: show_uid = sel->uid != (uid_t)-1;
1.73 brynet 447: hide_uid = sel->huid != (uid_t)-1;
1.44 otto 448: show_pid = sel->pid != (pid_t)-1;
1.109 kn 449: show_rtableid = sel->rtableid != -1;
450: hide_rtableid = sel->hrtableid != -1;
1.56 otto 451: show_cmd = sel->command != NULL;
1.20 deraadt 452:
453: /* count up process states and get pointers to interesting procs */
454: total_procs = 0;
455: active_procs = 0;
456: memset((char *) process_states, 0, sizeof(process_states));
457: prefp = pref;
1.46 pat 458: for (pp = pbase; pp < &pbase[nproc]; pp++) {
1.20 deraadt 459: /*
1.101 guenther 460: * When showing threads, we want to ignore the structure
461: * that represents the entire process, which has TID == -1
1.20 deraadt 462: */
1.70 pirofti 463: if (show_threads && pp->p_tid == -1)
464: continue;
1.101 guenther 465: /*
466: * Place pointers to each valid proc structure in pref[].
467: * Process slots that are actually in use have a non-zero
468: * status field.
469: */
470: if (pp->p_stat != 0) {
1.20 deraadt 471: total_procs++;
1.37 millert 472: process_states[(unsigned char) pp->p_stat]++;
1.78 guenther 473: if ((pp->p_psflags & PS_ZOMBIE) == 0 &&
1.37 millert 474: (show_idle || pp->p_pctcpu != 0 ||
475: pp->p_stat == SRUN) &&
1.73 brynet 476: (!hide_uid || pp->p_ruid != sel->huid) &&
1.44 otto 477: (!show_uid || pp->p_ruid == sel->uid) &&
1.56 otto 478: (!show_pid || pp->p_pid == sel->pid) &&
1.109 kn 479: (!hide_rtableid || pp->p_rtableid != sel->hrtableid) &&
480: (!show_rtableid || pp->p_rtableid == sel->rtableid) &&
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.110 kn 547: int rtable, pid_t *pid)
1.20 deraadt 548: {
1.68 guenther 549: struct kinfo_proc *pp;
1.20 deraadt 550: int cputime;
551: double pct;
1.110 kn 552: char second_buf[16], eighth_buf[8];
1.20 deraadt 553:
554: /* find and remember the next proc structure */
1.99 kn 555: pp = *(hndl->next_proc++);
1.20 deraadt 556:
1.66 lum 557: cputime = pp->p_rtime_sec + ((pp->p_rtime_usec + 500000) / 1000000);
1.20 deraadt 558:
559: /* calculate the base for cpu percentages */
1.83 millert 560: pct = (double)pp->p_pctcpu / fscale;
1.20 deraadt 561:
1.109 kn 562: if (get_userid == NULL)
563: snprintf(second_buf, sizeof(second_buf), "%8d", pp->p_tid);
1.76 tedu 564: else
1.109 kn 565: strlcpy(second_buf, (*get_userid)(pp->p_ruid, 0),
566: sizeof(second_buf));
1.20 deraadt 567:
1.110 kn 568: if (rtable)
569: snprintf(eighth_buf, sizeof(eighth_buf), "%7d", pp->p_rtableid);
570: else
571: strlcpy(eighth_buf, pp->p_wmesg[0] ? pp->p_wmesg : "-",
572: sizeof(eighth_buf));
1.84 mpi 573:
1.20 deraadt 574: /* format this entry */
1.109 kn 575: snprintf(fmt, sizeof(fmt), Proc_format, pp->p_pid, second_buf,
1.37 millert 576: pp->p_priority - PZERO, pp->p_nice - NZERO,
1.1 downsj 577: format_k(pagetok(PROCSIZE(pp))),
1.37 millert 578: format_k(pagetok(pp->p_vm_rssize)),
579: (pp->p_stat == SSLEEP && pp->p_slptime > maxslp) ?
1.40 deraadt 580: "idle" : state_abbr(pp),
1.110 kn 581: eighth_buf, format_time(cputime), 100.0 * pct,
1.49 markus 582: printable(format_comm(pp)));
1.1 downsj 583:
1.61 otto 584: *pid = pp->p_pid;
1.20 deraadt 585: /* return the result */
586: return (fmt);
1.1 downsj 587: }
588:
589: /* comparison routine for qsort */
1.11 kstailey 590: static unsigned char sorted_state[] =
591: {
1.20 deraadt 592: 0, /* not used */
593: 4, /* start */
594: 5, /* run */
595: 2, /* sleep */
596: 3, /* stop */
597: 1 /* zombie */
1.11 kstailey 598: };
599:
1.96 kn 600: extern int rev_order;
601:
1.11 kstailey 602: /*
603: * proc_compares - comparison functions for "qsort"
604: */
605:
606: /*
607: * First, the possible comparison keys. These are defined in such a way
608: * that they can be merely listed in the source code to define the actual
609: * desired ordering.
610: */
611:
612: #define ORDERKEY_PCTCPU \
1.83 millert 613: if ((result = (int)(p2->p_pctcpu - p1->p_pctcpu)) == 0)
1.11 kstailey 614: #define ORDERKEY_CPUTIME \
1.37 millert 615: if ((result = p2->p_rtime_sec - p1->p_rtime_sec) == 0) \
616: if ((result = p2->p_rtime_usec - p1->p_rtime_usec) == 0)
1.11 kstailey 617: #define ORDERKEY_STATE \
1.37 millert 618: if ((result = sorted_state[(unsigned char)p2->p_stat] - \
619: sorted_state[(unsigned char)p1->p_stat]) == 0)
1.11 kstailey 620: #define ORDERKEY_PRIO \
1.37 millert 621: if ((result = p2->p_priority - p1->p_priority) == 0)
1.11 kstailey 622: #define ORDERKEY_RSSIZE \
1.37 millert 623: if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
1.11 kstailey 624: #define ORDERKEY_MEM \
625: if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0)
1.65 tedu 626: #define ORDERKEY_PID \
627: if ((result = p1->p_pid - p2->p_pid) == 0)
628: #define ORDERKEY_CMD \
629: if ((result = strcmp(p1->p_comm, p2->p_comm)) == 0)
1.11 kstailey 630:
1.96 kn 631: /* remove one level of indirection and set sort order */
632: #define SETORDER do { \
633: if (rev_order) { \
1.98 kn 634: p1 = *(struct kinfo_proc **) v2; \
635: p2 = *(struct kinfo_proc **) v1; \
1.96 kn 636: } else { \
1.98 kn 637: p1 = *(struct kinfo_proc **) v1; \
638: p2 = *(struct kinfo_proc **) v2; \
1.96 kn 639: } \
640: } while (0)
641:
1.11 kstailey 642: /* compare_cpu - the comparison function for sorting by cpu percentage */
1.36 deraadt 643: static int
1.29 pvalchev 644: compare_cpu(const void *v1, const void *v2)
1.11 kstailey 645: {
1.68 guenther 646: struct kinfo_proc *p1, *p2;
1.20 deraadt 647: int result;
648:
1.96 kn 649: SETORDER;
1.20 deraadt 650:
651: ORDERKEY_PCTCPU
1.30 deraadt 652: ORDERKEY_CPUTIME
653: ORDERKEY_STATE
654: ORDERKEY_PRIO
655: ORDERKEY_RSSIZE
656: ORDERKEY_MEM
657: ;
1.20 deraadt 658: return (result);
1.11 kstailey 659: }
660:
661: /* compare_size - the comparison function for sorting by total memory usage */
1.36 deraadt 662: static int
1.29 pvalchev 663: compare_size(const void *v1, const void *v2)
1.11 kstailey 664: {
1.68 guenther 665: struct kinfo_proc *p1, *p2;
1.20 deraadt 666: int result;
667:
1.96 kn 668: SETORDER;
1.20 deraadt 669:
670: ORDERKEY_MEM
1.30 deraadt 671: ORDERKEY_RSSIZE
672: ORDERKEY_PCTCPU
673: ORDERKEY_CPUTIME
674: ORDERKEY_STATE
675: ORDERKEY_PRIO
676: ;
1.20 deraadt 677: return (result);
1.11 kstailey 678: }
679:
680: /* compare_res - the comparison function for sorting by resident set size */
1.36 deraadt 681: static int
1.29 pvalchev 682: compare_res(const void *v1, const void *v2)
1.11 kstailey 683: {
1.68 guenther 684: struct kinfo_proc *p1, *p2;
1.20 deraadt 685: int result;
686:
1.96 kn 687: SETORDER;
1.20 deraadt 688:
689: ORDERKEY_RSSIZE
1.30 deraadt 690: ORDERKEY_MEM
691: ORDERKEY_PCTCPU
692: ORDERKEY_CPUTIME
693: ORDERKEY_STATE
694: ORDERKEY_PRIO
695: ;
1.20 deraadt 696: return (result);
1.11 kstailey 697: }
698:
699: /* compare_time - the comparison function for sorting by CPU time */
1.36 deraadt 700: static int
1.29 pvalchev 701: compare_time(const void *v1, const void *v2)
1.11 kstailey 702: {
1.68 guenther 703: struct kinfo_proc *p1, *p2;
1.20 deraadt 704: int result;
705:
1.96 kn 706: SETORDER;
1.20 deraadt 707:
708: ORDERKEY_CPUTIME
1.30 deraadt 709: ORDERKEY_PCTCPU
710: ORDERKEY_STATE
711: ORDERKEY_PRIO
712: ORDERKEY_MEM
713: ORDERKEY_RSSIZE
714: ;
1.20 deraadt 715: return (result);
1.11 kstailey 716: }
717:
718: /* compare_prio - the comparison function for sorting by CPU time */
1.36 deraadt 719: static int
1.29 pvalchev 720: compare_prio(const void *v1, const void *v2)
1.11 kstailey 721: {
1.68 guenther 722: struct kinfo_proc *p1, *p2;
1.20 deraadt 723: int result;
724:
1.96 kn 725: SETORDER;
1.20 deraadt 726:
727: ORDERKEY_PRIO
1.30 deraadt 728: ORDERKEY_PCTCPU
729: ORDERKEY_CPUTIME
730: ORDERKEY_STATE
731: ORDERKEY_RSSIZE
732: ORDERKEY_MEM
733: ;
1.20 deraadt 734: return (result);
735: }
736:
1.65 tedu 737: static int
738: compare_pid(const void *v1, const void *v2)
739: {
1.68 guenther 740: struct kinfo_proc *p1, *p2;
1.65 tedu 741: int result;
742:
1.96 kn 743: SETORDER;
1.65 tedu 744:
745: ORDERKEY_PID
746: ORDERKEY_PCTCPU
747: ORDERKEY_CPUTIME
748: ORDERKEY_STATE
749: ORDERKEY_PRIO
750: ORDERKEY_RSSIZE
751: ORDERKEY_MEM
752: ;
753: return (result);
754: }
755:
756: static int
757: compare_cmd(const void *v1, const void *v2)
758: {
1.68 guenther 759: struct kinfo_proc *p1, *p2;
1.65 tedu 760: int result;
761:
1.96 kn 762: SETORDER;
1.65 tedu 763:
764: ORDERKEY_CMD
765: ORDERKEY_PCTCPU
766: ORDERKEY_CPUTIME
767: ORDERKEY_STATE
768: ORDERKEY_PRIO
769: ORDERKEY_RSSIZE
770: ORDERKEY_MEM
771: ;
772: return (result);
773: }
774:
775:
1.31 deraadt 776: int (*proc_compares[])(const void *, const void *) = {
1.20 deraadt 777: compare_cpu,
778: compare_size,
779: compare_res,
780: compare_time,
781: compare_prio,
1.65 tedu 782: compare_pid,
783: compare_cmd,
1.20 deraadt 784: NULL
1.11 kstailey 785: };
1.30 deraadt 786:
1.1 downsj 787: /*
788: * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
789: * the process does not exist.
1.43 otto 790: * It is EXTREMELY IMPORTANT that this function work correctly.
1.1 downsj 791: * If top runs setuid root (as in SVR4), then this function
792: * is the only thing that stands in the way of a serious
793: * security problem. It validates requests for the "kill"
794: * and "renice" commands.
795: */
1.33 millert 796: uid_t
1.29 pvalchev 797: proc_owner(pid_t pid)
1.20 deraadt 798: {
1.68 guenther 799: struct kinfo_proc **prefp, *pp;
1.20 deraadt 800: int cnt;
801:
802: prefp = pref;
803: cnt = pref_len;
804: while (--cnt >= 0) {
805: pp = *prefp++;
1.37 millert 806: if (pp->p_pid == pid)
807: return ((uid_t)pp->p_ruid);
1.1 downsj 808: }
1.34 jfb 809: return (uid_t)(-1);
1.1 downsj 810: }
1.30 deraadt 811:
1.1 downsj 812: /*
1.17 todd 813: * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
1.15 weingart 814: * to be based on the new swapctl(2) system call.
1.1 downsj 815: */
816: static int
1.29 pvalchev 817: swapmode(int *used, int *total)
1.1 downsj 818: {
1.15 weingart 819: struct swapent *swdev;
1.30 deraadt 820: int nswap, rnswap, i;
1.1 downsj 821:
1.15 weingart 822: nswap = swapctl(SWAP_NSWAP, 0, 0);
1.20 deraadt 823: if (nswap == 0)
1.15 weingart 824: return 0;
825:
1.62 deraadt 826: swdev = calloc(nswap, sizeof(*swdev));
1.20 deraadt 827: if (swdev == NULL)
1.15 weingart 828: return 0;
829:
830: rnswap = swapctl(SWAP_STATS, swdev, nswap);
1.53 ray 831: if (rnswap == -1) {
832: free(swdev);
1.15 weingart 833: return 0;
1.53 ray 834: }
1.15 weingart 835:
836: /* if rnswap != nswap, then what? */
837:
838: /* Total things up */
839: *total = *used = 0;
840: for (i = 0; i < nswap; i++) {
841: if (swdev[i].se_flags & SWF_ENABLE) {
1.20 deraadt 842: *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
843: *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
1.1 downsj 844: }
845: }
1.20 deraadt 846: free(swdev);
1.1 downsj 847: return 1;
848: }