xref: /dragonfly/usr.bin/top/m_dragonfly.c (revision 7a491db4d92b7514dfa05b421fc01782304b02a7)
1 /*
2  * top - a top users display for Unix
3  *
4  * SYNOPSIS:  For DragonFly 2.x and later
5  *
6  * DESCRIPTION:
7  * Originally written for BSD4.4 system by Christos Zoulas.
8  * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
9  * Order support hacked in from top-3.5beta6/machine/m_aix41.c
10  *   by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/)
11  *
12  * This is the machine-dependent module for DragonFly 2.5.1
13  * Should work for:
14  *        DragonFly 2.x and above
15  *
16  * LIBS: -lkvm
17  *
18  * AUTHOR: Jan Lentfer <Jan.Lentfer@web.de>
19  * This module has been put together from different sources and is based on the
20  * work of many other people, e.g. Matthew Dillon, Simon Schubert, Jordan Gordeev.
21  *
22  * $FreeBSD: src/usr.bin/top/machine.c,v 1.29.2.2 2001/07/31 20:27:05 tmm Exp $
23  */
24 
25 #include <sys/user.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/signal.h>
29 #include <sys/param.h>
30 
31 #include "os.h"
32 #include <err.h>
33 #include <fcntl.h>
34 #include <kvm.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <math.h>
38 #include <pwd.h>
39 #include <sys/errno.h>
40 #include <sys/sysctl.h>
41 #include <sys/vmmeter.h>
42 #include <sys/resource.h>
43 #include <sys/rtprio.h>
44 
45 /* Swap */
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/conf.h>
49 
50 #include <osreldate.h>                  /* for changes in kernel structures */
51 
52 #include <sys/kinfo.h>
53 #include <kinfo.h>
54 #include "top.h"
55 #include "display.h"
56 #include "machine.h"
57 #include "screen.h"
58 #include "utils.h"
59 
60 int swapmode(int *retavail, int *retfree);
61 static int namelength;
62 static int cmdlength;
63 static int show_fullcmd;
64 
65 int n_cpus, enable_ncpus;
66 
67 /* get_process_info passes back a handle.  This is what it looks like: */
68 
69 struct handle {
70           struct kinfo_proc **next_proc;          /* points to next valid proc pointer */
71           int remaining;                /* number of pointers remaining */
72           int show_threads;
73 };
74 
75 /* declarations for load_avg */
76 #include "loadavg.h"
77 
78 #define PP(pp, field) ((pp)->kp_ ## field)
79 #define LP(pp, field) ((pp)->kp_lwp.kl_ ## field)
80 #define VP(pp, field) ((pp)->kp_vm_ ## field)
81 
82 /* what we consider to be process size: */
83 #define PROCSIZE(pp) (VP((pp), map_size) / 1024)
84 
85 /*
86  * These definitions control the format of the per-process area
87  */
88 
89 static char smp_header[] =
90 "   PID %-*.*s NICE  SIZE    RES    STATE   C   TIME   CTIME    CPU COMMAND";
91 
92 #define smp_Proc_format \
93           "%6d %-*.*s %3d%7s %6s %8.8s %3d %6s %7s %5.2f%% %.*s"
94 
95 
96 static kvm_t *kd;
97 
98 /* values that we stash away in _init and use in later routines */
99 
100 static long lastpid;
101 
102 /* these are for calculating cpu state percentages */
103 
104 static struct kinfo_cputime *cp_time, *cp_old;
105 
106 /* these are for detailing the process states */
107 
108 enum {
109           PS_STARTING = 0,
110           PS_RUNNING,
111           PS_STOPPED,
112           PS_SLEEPING,
113           PS_ZOMBIE,
114           PS_DUMPING,
115           PS_MAX,
116 };
117 
118 int process_states[PS_MAX + 1];
119 char *procstatenames[] = {
120           [PS_STARTING]       = " starting, ",
121           [PS_RUNNING]        = " running, ",
122           [PS_STOPPED]        = " stopped, ",
123           [PS_SLEEPING]       = " sleeping, ",
124           [PS_ZOMBIE]         = " zombie, ",
125           [PS_DUMPING]        = " dumping, ",
126           [PS_MAX]  = NULL,
127 };
128 
129 /* process state names for the "STATE" column of the display */
130 const char *state_abbrev[] = {
131           [PS_STARTING]       = "START",
132           [PS_RUNNING]        = "RUN",
133           [PS_STOPPED]        = "STOP",
134           [PS_SLEEPING]       = "SLEEP",
135           [PS_ZOMBIE]         = "ZOMBIE",
136           [PS_DUMPING]        = "DUMP",
137           [PS_MAX]  = NULL,
138 };
139 
140 /* these are for detailing the cpu states */
141 #define CPU_STATES 5
142 int *cpu_states;
143 int* cpu_averages;
144 char *cpustatenames[CPU_STATES + 1] = {
145           "user", "nice", "system", "interrupt", "idle", NULL
146 };
147 
148 /* these are for detailing the memory statistics */
149 
150 long memory_stats[7];
151 char *memorynames[] = {
152           "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
153           NULL
154 };
155 
156 long swap_stats[7];
157 char *swapnames[] = {
158           /* 0           1            2           3            4       5 */
159           "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
160           NULL
161 };
162 
163 
164 /* these are for keeping track of the proc array */
165 
166 static int nproc;
167 static int onproc = -1;
168 static int pref_len;
169 static struct kinfo_proc *pbase;
170 static struct kinfo_proc **pref;
171 
172 static uint64_t prev_pbase_time;        /* unit: us */
173 static struct kinfo_proc *prev_pbase;
174 static int prev_pbase_alloc;
175 static int prev_nproc;
176 static int fscale;
177 
178 /* these are for getting the memory statistics */
179 
180 static int pageshift;                   /* log base 2 of the pagesize */
181 
182 /* define pagetok in terms of pageshift */
183 
184 #define pagetok(size) ((size) << pageshift)
185 
186 /* sorting orders. first is default */
187 char *ordernames[] = {
188   "cpu", "size", "res", "time", "pri", "thr", "pid", "ctime",  "pres", NULL
189 };
190 
191 /* compare routines */
192 int proc_compare (struct kinfo_proc **, struct kinfo_proc **);
193 int compare_size (struct kinfo_proc **, struct kinfo_proc **);
194 int compare_res (struct kinfo_proc **, struct kinfo_proc **);
195 int compare_time (struct kinfo_proc **, struct kinfo_proc **);
196 int compare_ctime (struct kinfo_proc **, struct kinfo_proc **);
197 int compare_prio(struct kinfo_proc **, struct kinfo_proc **);
198 int compare_thr (struct kinfo_proc **, struct kinfo_proc **);
199 int compare_pid (struct kinfo_proc **, struct kinfo_proc **);
200 int compare_pres(struct kinfo_proc **, struct kinfo_proc **);
201 
202 int (*proc_compares[]) (struct kinfo_proc **,struct kinfo_proc **) = {
203           proc_compare,
204           compare_size,
205           compare_res,
206           compare_time,
207           compare_prio,
208           compare_thr,
209           compare_pid,
210           compare_ctime,
211           compare_pres,
212           NULL
213 };
214 
215 static void
cputime_percentages(int out[CPU_STATES],struct kinfo_cputime * new,struct kinfo_cputime * old)216 cputime_percentages(int out[CPU_STATES], struct kinfo_cputime *new,
217     struct kinfo_cputime *old)
218 {
219           struct kinfo_cputime diffs;
220           uint64_t total_change, half_total;
221 
222           /* initialization */
223           total_change = 0;
224 
225           diffs.cp_user = new->cp_user - old->cp_user;
226           diffs.cp_nice = new->cp_nice - old->cp_nice;
227           diffs.cp_sys = new->cp_sys - old->cp_sys;
228           diffs.cp_intr = new->cp_intr - old->cp_intr;
229           diffs.cp_idle = new->cp_idle - old->cp_idle;
230           total_change = diffs.cp_user + diffs.cp_nice + diffs.cp_sys +
231               diffs.cp_intr + diffs.cp_idle;
232           old->cp_user = new->cp_user;
233           old->cp_nice = new->cp_nice;
234           old->cp_sys = new->cp_sys;
235           old->cp_intr = new->cp_intr;
236           old->cp_idle = new->cp_idle;
237 
238           /* avoid divide by zero potential */
239           if (total_change == 0)
240                     total_change = 1;
241 
242           /* calculate percentages based on overall change, rounding up */
243           half_total = total_change >> 1;
244 
245           out[0] = ((diffs.cp_user * 1000LL + half_total) / total_change);
246           out[1] = ((diffs.cp_nice * 1000LL + half_total) / total_change);
247           out[2] = ((diffs.cp_sys * 1000LL + half_total) / total_change);
248           out[3] = ((diffs.cp_intr * 1000LL + half_total) / total_change);
249           out[4] = ((diffs.cp_idle * 1000LL + half_total) / total_change);
250 }
251 
252 int
machine_init(struct statics * statics)253 machine_init(struct statics *statics)
254 {
255           int pagesize;
256           size_t prmlen;
257           struct passwd *pw;
258 
259           if (n_cpus < 1) {
260                     if (kinfo_get_cpus(&n_cpus))
261                               err(1, "kinfo_get_cpus failed");
262           }
263           /* get boot time */
264 
265           prmlen = sizeof(fscale);
266           if (sysctlbyname("kern.fscale", &fscale, &prmlen, NULL, 0) == -1)
267                     err(1, "sysctl kern.fscale failed");
268 
269           while ((pw = getpwent()) != NULL) {
270                     if ((int)strlen(pw->pw_name) > namelength)
271                               namelength = strlen(pw->pw_name);
272           }
273           if (namelength < 8)
274                     namelength = 8;
275           if (namelength > 13)
276                     namelength = 13;
277 
278           if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL)
279                     return -1;
280 
281           pbase = NULL;
282           pref = NULL;
283           nproc = 0;
284           onproc = -1;
285           prev_pbase = NULL;
286           prev_pbase_alloc = 0;
287           prev_pbase_time = 0;
288           prev_nproc = 0;
289           /*
290            * get the page size with "getpagesize" and calculate pageshift from
291            * it
292            */
293           pagesize = getpagesize();
294           pageshift = 0;
295           while (pagesize > 1) {
296                     pageshift++;
297                     pagesize >>= 1;
298           }
299 
300           /* we only need the amount of log(2)1024 for our conversion */
301           pageshift -= LOG1024;
302 
303           /* fill in the statics information */
304           statics->procstate_names = procstatenames;
305           statics->cpustate_names = cpustatenames;
306           statics->memory_names = memorynames;
307           statics->unused01 = 0;
308           statics->swap_names = swapnames;
309           statics->order_names = ordernames;
310           /* we need kvm descriptor in order to show full commands */
311           statics->flags.fullcmds = kd != NULL;
312           statics->flags.threads = 1;
313 
314           /* all done! */
315           return (0);
316 }
317 
318 char *
format_header(char * uname_field)319 format_header(char *uname_field)
320 {
321           static char Header[128];
322 
323           snprintf(Header, sizeof(Header), smp_header,
324               namelength, namelength, uname_field);
325 
326           if (screen_width <= 79)
327                     cmdlength = 80;
328           else
329                     cmdlength = screen_width;
330 
331           cmdlength = cmdlength - strlen(Header) + 6;
332 
333           return Header;
334 }
335 
336 static int swappgsin = -1;
337 static int swappgsout = -1;
338 extern struct timeval timeout;
339 
340 void
get_system_info(struct system_info * si)341 get_system_info(struct system_info *si)
342 {
343           size_t len;
344           int cpu;
345 
346           if (cpu_states == NULL) {
347                     cpu_states = malloc(sizeof(*cpu_states) * CPU_STATES * n_cpus);
348                     if (cpu_states == NULL)
349                               err(1, "malloc");
350                     bzero(cpu_states, sizeof(*cpu_states) * CPU_STATES * n_cpus);
351           }
352           if (cp_time == NULL) {
353                     cp_time = malloc(2 * n_cpus * sizeof(cp_time[0]));
354                     if (cp_time == NULL)
355                               err(1, "cp_time");
356                     cp_old = cp_time + n_cpus;
357                     len = n_cpus * sizeof(cp_old[0]);
358                     bzero(cp_time, len);
359                     if (sysctlbyname("kern.cputime", cp_old, &len, NULL, 0))
360                               err(1, "kern.cputime");
361           }
362           len = n_cpus * sizeof(cp_time[0]);
363           bzero(cp_time, len);
364           if (sysctlbyname("kern.cputime", cp_time, &len, NULL, 0))
365                     err(1, "kern.cputime");
366 
367           getloadavg(si->load_avg, 3);
368 
369           lastpid = 0;
370 
371           /* convert cp_time counts to percentages */
372           int combine_cpus = (enable_ncpus == 0 && n_cpus > 1);
373           for (cpu = 0; cpu < n_cpus; ++cpu) {
374                     cputime_percentages(cpu_states + cpu * CPU_STATES,
375                         &cp_time[cpu], &cp_old[cpu]);
376           }
377           if (combine_cpus) {
378                     if (cpu_averages == NULL) {
379                               cpu_averages = malloc(sizeof(*cpu_averages) * CPU_STATES);
380                               if (cpu_averages == NULL)
381                                         err(1, "cpu_averages");
382                     }
383                     bzero(cpu_averages, sizeof(*cpu_averages) * CPU_STATES);
384                     for (cpu = 0; cpu < n_cpus; ++cpu) {
385                               int j = 0;
386                               cpu_averages[0] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
387                               cpu_averages[1] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
388                               cpu_averages[2] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
389                               cpu_averages[3] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
390                               cpu_averages[4] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
391                     }
392                     for (int i = 0; i < CPU_STATES; ++i)
393                               cpu_averages[i] /= n_cpus;
394           }
395 
396           /* sum memory & swap statistics */
397           {
398                     struct vmmeter vmm;
399                     struct vmstats vms;
400                     size_t vms_size = sizeof(vms);
401                     size_t vmm_size = sizeof(vmm);
402                     static unsigned int swap_delay = 0;
403                     static int swapavail = 0;
404                     static int swapfree = 0;
405                     static long bufspace = 0;
406 
407                     if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0))
408                               err(1, "sysctlbyname: vm.vmstats");
409 
410                     if (sysctlbyname("vm.vmmeter", &vmm, &vmm_size, NULL, 0))
411                               err(1, "sysctlbyname: vm.vmmeter");
412 
413                     if (kinfo_get_vfs_bufspace(&bufspace))
414                               err(1, "kinfo_get_vfs_bufspace");
415 
416                     /* convert memory stats to Kbytes */
417                     memory_stats[0] = pagetok(vms.v_active_count);
418                     memory_stats[1] = pagetok(vms.v_inactive_count);
419                     memory_stats[2] = pagetok(vms.v_wire_count);
420                     memory_stats[3] = pagetok(vms.v_cache_count);
421                     memory_stats[4] = bufspace / 1024;
422                     memory_stats[5] = pagetok(vms.v_free_count);
423                     memory_stats[6] = -1;
424 
425                     /* first interval */
426                     if (swappgsin < 0) {
427                               swap_stats[4] = 0;
428                               swap_stats[5] = 0;
429                     }
430                     /* compute differences between old and new swap statistic */
431                     else {
432                               swap_stats[4] = pagetok(((vmm.v_swappgsin - swappgsin)));
433                               swap_stats[5] = pagetok(((vmm.v_swappgsout - swappgsout)));
434                     }
435 
436                     swappgsin = vmm.v_swappgsin;
437                     swappgsout = vmm.v_swappgsout;
438 
439                     /* call CPU heavy swapmode() only for changes */
440                     if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
441                               swap_stats[3] = swapmode(&swapavail, &swapfree);
442                               swap_stats[0] = swapavail;
443                               swap_stats[1] = swapavail - swapfree;
444                               swap_stats[2] = swapfree;
445                     }
446                     swap_delay = 1;
447                     swap_stats[6] = -1;
448           }
449 
450           /* set arrays and strings */
451           si->cpustates = combine_cpus == 1 ?
452               cpu_averages : cpu_states;
453           si->memory = memory_stats;
454           si->swap = swap_stats;
455 
456 
457           if (lastpid > 0) {
458                     si->last_pid = lastpid;
459           } else {
460                     si->last_pid = -1;
461           }
462 }
463 
464 
465 static struct handle handle;
466 
467 static void
fixup_pctcpu(struct kinfo_proc * fixit,uint64_t d)468 fixup_pctcpu(struct kinfo_proc *fixit, uint64_t d)
469 {
470           struct kinfo_proc *pp;
471           uint64_t ticks;
472           int i;
473 
474           if (prev_nproc == 0 || d == 0)
475                     return;
476 
477           if (LP(fixit, pid) == -1) {
478                     /* Skip kernel "idle" threads */
479                     if (PP(fixit, stat) == SIDL)
480                               return;
481                     for (pp = prev_pbase, i = 0; i < prev_nproc; pp++, i++) {
482                               if (LP(pp, pid) == -1 &&
483                                   PP(pp, ktaddr) == PP(fixit, ktaddr))
484                                         break;
485                     }
486           } else {
487                     for (pp = prev_pbase, i = 0; i < prev_nproc; pp++, i++) {
488                               if (LP(pp, pid) == LP(fixit, pid) &&
489                                   LP(pp, tid) == LP(fixit, tid)) {
490                                         if (PP(pp, paddr) != PP(fixit, paddr)) {
491                                                   /* pid/tid are reused */
492                                                   pp = NULL;
493                                         }
494                                         break;
495                               }
496                     }
497           }
498           if (i == prev_nproc || pp == NULL)
499                     return;
500 
501           ticks = LP(fixit, iticks) - LP(pp, iticks);
502           ticks += LP(fixit, sticks) - LP(pp, sticks);
503           ticks += LP(fixit, uticks) - LP(pp, uticks);
504           if (ticks > d * 1000)
505                     ticks = d * 1000;
506           LP(fixit, pctcpu) = (ticks * (uint64_t)fscale) / d;
507 }
508 
509 caddr_t
get_process_info(struct system_info * si,struct process_select * sel,int compare_index)510 get_process_info(struct system_info *si, struct process_select *sel,
511     int compare_index)
512 {
513           struct timespec tv;
514           uint64_t t, d = 0;
515 
516           int i;
517           int total_procs;
518           int active_procs;
519           struct kinfo_proc **prefp;
520           struct kinfo_proc *pp;
521 
522           /* these are copied out of sel for speed */
523           int show_idle;
524           int show_system;
525           int show_uid;
526           int show_threads;
527           int kvmflags;
528           char *match_command;
529 
530           show_threads = sel->threads;
531           show_system = sel->system;
532 
533           kvmflags = 0;
534           if (show_threads)
535                     kvmflags |= KERN_PROC_FLAG_LWP;
536 #ifdef KERN_PROC_FLAG_LWKT
537           if (show_system)
538                     kvmflags |= KERN_PROC_FLAG_LWKT;
539 #endif
540           pbase = kvm_getprocs(kd, KERN_PROC_ALL | kvmflags, 0, &nproc);
541           if (nproc > onproc)
542                     pref = (struct kinfo_proc **)realloc(pref, sizeof(struct kinfo_proc *)
543                         * (onproc = nproc));
544           if (pref == NULL || pbase == NULL) {
545                     (void)fprintf(stderr, "top: Out of memory.\n");
546                     quit(23);
547           }
548 
549           clock_gettime(CLOCK_MONOTONIC_PRECISE, &tv);
550           t = (tv.tv_sec * 1000000ULL) + (tv.tv_nsec / 1000ULL);
551           if (prev_pbase_time > 0 && t > prev_pbase_time)
552                     d = t - prev_pbase_time;
553 
554           /* get a pointer to the states summary array */
555           si->procstates = process_states;
556 
557           /* set up flags which define what we are going to select */
558           show_idle = sel->idle;
559           show_uid = sel->uid != -1;
560           show_fullcmd = sel->fullcmd;
561           match_command = sel->command;
562 
563           /* count up process states and get pointers to interesting procs */
564           total_procs = 0;
565           active_procs = 0;
566           memset((char *)process_states, 0, sizeof(process_states));
567           prefp = pref;
568           for (pp = pbase, i = 0; i < nproc; pp++, i++) {
569                     /*
570                      * Place pointers to each valid proc structure in pref[].
571                      * Process slots that are actually in use have a non-zero
572                      * status field.  Processes with P_SYSTEM set are system
573                      * processes---these get ignored unless show_sysprocs is set.
574                      */
575                     if ((show_system && (LP(pp, pid) == -1)) ||
576                         (show_system || ((PP(pp, flags) & P_SYSTEM) == 0))) {
577                               int lpstate = LP(pp, stat);
578                               int pstate = PP(pp, stat);
579                               int state;
580 
581                               total_procs++;
582 
583                               switch (pstate) {
584                               case SIDL:
585                                         state = PS_STARTING;
586                                         break;
587                               case SACTIVE:
588                                         switch (lpstate) {
589                                         case LSRUN:
590                                                   state = PS_RUNNING;
591                                                   break;
592                                         case LSSTOP:
593                                                   state = PS_STOPPED;
594                                                   break;
595                                         case LSSLEEP:
596                                                   state = PS_SLEEPING;
597                                                   break;
598                                         default:
599                                                   fprintf(stderr, "top: unknown LWP "
600                                                             "state: %d\n", lpstate);
601                                                   break;
602                                         }
603                                         break;
604                               case SSTOP:
605                                         state = PS_STOPPED;
606                                         break;
607                               case SZOMB:
608                                         state = PS_ZOMBIE;
609                                         break;
610                               case SCORE:
611                                         state = PS_DUMPING;
612                                         break;
613                               default:
614                                         fprintf(stderr, "top: unknown process "
615                                                   "state: %d\n", pstate);
616                                         break;
617                               }
618                               if (state < PS_MAX)
619                                         process_states[state]++;
620 
621                               if (match_command != NULL &&
622                                   strstr(PP(pp, comm), match_command) == NULL) {
623                                         /* Command does not match */
624                                         continue;
625                               }
626 
627                               if (show_uid && PP(pp, ruid) != (uid_t)sel->uid) {
628                                         /* UID does not match */
629                                         continue;
630                               }
631 
632                               if (!show_system && LP(pp, pid) == -1) {
633                                         /* Don't show system processes */
634                                         continue;
635                               }
636 
637                               /* Fix up pctcpu before show_idle test */
638                               fixup_pctcpu(pp, d);
639 
640                               if (!show_idle && LP(pp, pctcpu) == 0 &&
641                                   lpstate != LSRUN) {
642                                         /* Don't show idle processes */
643                                         continue;
644                               }
645 
646                               *prefp++ = pp;
647                               active_procs++;
648                     }
649           }
650 
651           /*
652            * Save kinfo_procs for later pctcpu fixup.
653            */
654           if (prev_pbase_alloc < nproc) {
655                     prev_pbase_alloc = nproc;
656                     prev_pbase = realloc(prev_pbase,
657                         prev_pbase_alloc * sizeof(struct kinfo_proc));
658                     if (prev_pbase == NULL) {
659                               fprintf(stderr, "top: Out of memory.\n");
660                               quit(23);
661                     }
662           }
663           prev_nproc = nproc;
664           prev_pbase_time = t;
665           memcpy(prev_pbase, pbase, nproc * sizeof(struct kinfo_proc));
666 
667           qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *),
668               (int (*)(const void *, const void *))proc_compares[compare_index]);
669 
670           /* remember active and total counts */
671           si->p_total = total_procs;
672           si->p_active = pref_len = active_procs;
673 
674           /* pass back a handle */
675           handle.next_proc = pref;
676           handle.remaining = active_procs;
677           handle.show_threads = show_threads;
678           return ((caddr_t) & handle);
679 }
680 
681 char fmt[MAX_COLS];           /* static area where result is built */
682 
683 char *
format_next_process(caddr_t xhandle,char * (* get_userid)(int))684 format_next_process(caddr_t xhandle, char *(*get_userid) (int))
685 {
686           struct kinfo_proc *pp;
687           long cputime;
688           long ccputime;
689           double pct;
690           struct handle *hp;
691           char status[16];
692           int state;
693           int xnice;
694           char *wmesg, *comm;
695           char cputime_fmt[10], ccputime_fmt[10];
696 
697           /* find and remember the next proc structure */
698           hp = (struct handle *)xhandle;
699           pp = *(hp->next_proc++);
700           hp->remaining--;
701 
702           /* get the process's command name */
703           if (show_fullcmd) {
704                     char **comm_full = kvm_getargv(kd, pp, 0);
705                     if (comm_full != NULL)
706                               comm = *comm_full;
707                     else
708                               comm = PP(pp, comm);
709           }
710           else {
711                     comm = PP(pp, comm);
712           }
713 
714           /* the actual field to display */
715           char cmdfield[MAX_COLS];
716 
717           if (PP(pp, flags) & P_SYSTEM) {
718                     /* system process */
719                     snprintf(cmdfield, sizeof cmdfield, "[%s]", comm);
720           } else if (hp->show_threads && PP(pp, nthreads) > 1) {
721                     /* display it as a thread */
722                     if (strcmp(PP(pp, comm), LP(pp, comm)) == 0) {
723                               snprintf(cmdfield, sizeof cmdfield, "%s{%d}", comm,
724                                   LP(pp, tid));
725                     } else {
726                               /* show thread name in addition to tid */
727                               snprintf(cmdfield, sizeof cmdfield, "%s{%d/%s}", comm,
728                                   LP(pp, tid), LP(pp, comm));
729                     }
730           } else {
731                     snprintf(cmdfield, sizeof cmdfield, "%s", comm);
732           }
733 
734           /*
735            * Convert the process's runtime from microseconds to seconds.  This
736            * time includes the interrupt time to be in compliance with ps output.
737            */
738           cputime = (LP(pp, uticks) + LP(pp, sticks) + LP(pp, iticks)) / 1000000;
739           ccputime = cputime + PP(pp, cru).ru_stime.tv_sec + PP(pp, cru).ru_utime.tv_sec;
740           format_time(cputime, cputime_fmt, sizeof(cputime_fmt));
741           format_time(ccputime, ccputime_fmt, sizeof(ccputime_fmt));
742 
743           /* calculate the base for cpu percentages */
744           pct = pctdouble(LP(pp, pctcpu));
745 
746           /* generate "STATE" field */
747           state = PS_MAX;
748           switch (PP(pp, stat)) {
749           case SIDL:
750                     state = PS_STARTING;
751                     break;
752           case SACTIVE:
753                     switch (LP(pp, stat)) {
754                     case LSRUN:
755                               if (LP(pp, tdflags) & TDF_RUNNING)
756                                         sprintf(status, "CPU%d", LP(pp, cpuid));
757                               else
758                                         state = PS_RUNNING;
759                               break;
760                     case LSSTOP:
761                               state = PS_STOPPED;
762                               break;
763                     case LSSLEEP:
764                               wmesg = LP(pp, wmesg);
765                               if (wmesg[0] != '\0')
766                                         sprintf(status, "%.8s", wmesg); /* WMESGLEN */
767                               else
768                                         state = PS_SLEEPING;
769                               break;
770                     default:
771                               sprintf(status, "?LP/%d", LP(pp, stat));
772                               break;
773                     }
774                     break;
775           case SSTOP:
776                     state = PS_STOPPED;
777                     break;
778           case SZOMB:
779                     state = PS_ZOMBIE;
780                     break;
781           case SCORE:
782                     state = PS_DUMPING;
783                     break;
784           default:
785                     sprintf(status, "?P/%d", PP(pp, stat));
786                     break;
787           }
788           if (state < PS_MAX)
789                     sprintf(status, "%.8s", state_abbrev[state]);
790 
791           /*
792            * idle time 0 - 31 -> nice value +21 - +52 normal time      -> nice
793            * value -20 - +20 real time 0 - 31 -> nice value -52 - -21 thread
794            * 0 - 31 -> nice value -53 -
795            */
796           switch (LP(pp, rtprio.type)) {
797           case RTP_PRIO_REALTIME:
798                     xnice = PRIO_MIN - 1 - RTP_PRIO_MAX + LP(pp, rtprio.prio);
799                     break;
800           case RTP_PRIO_IDLE:
801                     xnice = PRIO_MAX + 1 + LP(pp, rtprio.prio);
802                     break;
803           case RTP_PRIO_THREAD:
804                     xnice = PRIO_MIN - 1 - RTP_PRIO_MAX - LP(pp, rtprio.prio);
805                     break;
806           default:
807                     xnice = PP(pp, nice);
808                     break;
809           }
810 
811           /* format this entry */
812           snprintf(fmt, sizeof(fmt),
813               smp_Proc_format,
814               (int)PP(pp, pid),
815               namelength, namelength,
816               get_userid(PP(pp, ruid)),
817               (int)xnice,
818               format_k(PROCSIZE(pp)),
819               format_k(pagetok(VP(pp, rssize))),
820               status,
821               LP(pp, cpuid),
822               cputime_fmt,
823               ccputime_fmt,
824               100.0 * pct,
825               cmdlength,
826               cmdfield);
827 
828           /* return the result */
829           return (fmt);
830 }
831 
832 /* comparison routines for qsort */
833 
834 /*
835  *  proc_compare - comparison function for "qsort"
836  *        Compares the resource consumption of two processes using five
837  *        distinct keys.  The keys (in descending order of importance) are:
838  *        percent cpu, cpu ticks, state, resident set size, total virtual
839  *        memory usage.  The process states are ordered as follows (from least
840  *        to most important):  WAIT, zombie, sleep, stop, start, run.  The
841  *        array declaration below maps a process state index into a number
842  *        that reflects this ordering.
843  */
844 
845 static unsigned char sorted_state[] =
846 {
847           0,                            /* not used                    */
848           3,                            /* sleep             */
849           1,                            /* ABANDONED (WAIT)  */
850           6,                            /* run                         */
851           5,                            /* start             */
852           2,                            /* zombie            */
853           4                             /* stop                        */
854 };
855 
856 
857 #define ORDERKEY_PCTCPU \
858   if (lresult = (long) LP(p2, pctcpu) - (long) LP(p1, pctcpu), \
859      (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
860 
861 #define CPTICKS(p)  (LP(p, uticks) + LP(p, sticks) + LP(p, iticks))
862 
863 #define ORDERKEY_CPTICKS \
864   if ((result = CPTICKS(p2) > CPTICKS(p1) ? 1 : \
865                     CPTICKS(p2) < CPTICKS(p1) ? -1 : 0) == 0)
866 
867 #define CTIME(p)    (((LP(p, uticks) + LP(p, sticks) + LP(p, iticks))/1000000) + \
868   PP(p, cru).ru_stime.tv_sec + PP(p, cru).ru_utime.tv_sec)
869 
870 #define ORDERKEY_CTIME \
871    if ((result = CTIME(p2) > CTIME(p1) ? 1 : \
872                     CTIME(p2) < CTIME(p1) ? -1 : 0) == 0)
873 
874 #define ORDERKEY_STATE \
875   if ((result = sorted_state[(unsigned char) PP(p2, stat)] - \
876                 sorted_state[(unsigned char) PP(p1, stat)]) == 0)
877 
878 #define ORDERKEY_PRIO \
879   if ((result = LP(p2, prio) - LP(p1, prio)) == 0)
880 
881 #define ORDERKEY_KTHREADS \
882   if ((result = (LP(p1, pid) == 0) - (LP(p2, pid) == 0)) == 0)
883 
884 #define ORDERKEY_KTHREADS_PRIO \
885   if ((result = LP(p2, tdprio) - LP(p1, tdprio)) == 0)
886 
887 #define ORDERKEY_RSSIZE \
888   if ((result = VP(p2, rssize) - VP(p1, rssize)) == 0)
889 
890 #define ORDERKEY_MEM \
891   if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 )
892 
893 #define ORDERKEY_PID \
894   if ( (result = PP(p1, pid) - PP(p2, pid)) == 0)
895 
896 #define ORDERKEY_PRSSIZE \
897   if((result = VP(p2, prssize) - VP(p1, prssize)) == 0)
898 
899 static __inline int
orderkey_kernidle(const struct kinfo_proc * p1,const struct kinfo_proc * p2)900 orderkey_kernidle(const struct kinfo_proc *p1, const struct kinfo_proc *p2)
901 {
902           int p1_kidle = 0, p2_kidle = 0;
903 
904           if (LP(p1, pid) == -1 && PP(p1, stat) == SIDL)
905                     p1_kidle = 1;
906           if (LP(p2, pid) == -1 && PP(p2, stat) == SIDL)
907                     p2_kidle = 1;
908 
909           if (!p2_kidle && p1_kidle)
910                     return 1;
911           if (p2_kidle && !p1_kidle)
912                     return -1;
913           return 0;
914 }
915 
916 #define ORDERKEY_KIDLE        if ((result = orderkey_kernidle(p1, p2)) == 0)
917 
918 /* compare_cpu - the comparison function for sorting by cpu percentage */
919 
920 int
proc_compare(struct kinfo_proc ** pp1,struct kinfo_proc ** pp2)921 proc_compare(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
922 {
923           struct kinfo_proc *p1;
924           struct kinfo_proc *p2;
925           int result;
926           pctcpu lresult;
927 
928           /* remove one level of indirection */
929           p1 = *(struct kinfo_proc **) pp1;
930           p2 = *(struct kinfo_proc **) pp2;
931 
932           ORDERKEY_KIDLE
933           ORDERKEY_PCTCPU
934           ORDERKEY_CPTICKS
935           ORDERKEY_STATE
936           ORDERKEY_PRIO
937           ORDERKEY_RSSIZE
938           ORDERKEY_MEM
939           {}
940 
941           return (result);
942 }
943 
944 /* compare_size - the comparison function for sorting by total memory usage */
945 
946 int
compare_size(struct kinfo_proc ** pp1,struct kinfo_proc ** pp2)947 compare_size(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
948 {
949           struct kinfo_proc *p1;
950           struct kinfo_proc *p2;
951           int result;
952           pctcpu lresult;
953 
954           /* remove one level of indirection */
955           p1 = *(struct kinfo_proc **) pp1;
956           p2 = *(struct kinfo_proc **) pp2;
957 
958           ORDERKEY_MEM
959           ORDERKEY_RSSIZE
960           ORDERKEY_KIDLE
961           ORDERKEY_PCTCPU
962           ORDERKEY_CPTICKS
963           ORDERKEY_STATE
964           ORDERKEY_PRIO
965           {}
966 
967           return (result);
968 }
969 
970 /* compare_res - the comparison function for sorting by resident set size */
971 
972 int
compare_res(struct kinfo_proc ** pp1,struct kinfo_proc ** pp2)973 compare_res(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
974 {
975           struct kinfo_proc *p1;
976           struct kinfo_proc *p2;
977           int result;
978           pctcpu lresult;
979 
980           /* remove one level of indirection */
981           p1 = *(struct kinfo_proc **) pp1;
982           p2 = *(struct kinfo_proc **) pp2;
983 
984           ORDERKEY_RSSIZE
985           ORDERKEY_MEM
986           ORDERKEY_KIDLE
987           ORDERKEY_PCTCPU
988           ORDERKEY_CPTICKS
989           ORDERKEY_STATE
990           ORDERKEY_PRIO
991           {}
992 
993           return (result);
994 }
995 
996 /* compare_pres - the comparison function for sorting by proportional resident set size */
997 
998 int
compare_pres(struct kinfo_proc ** pp1,struct kinfo_proc ** pp2)999 compare_pres(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1000 {
1001           struct kinfo_proc *p1;
1002           struct kinfo_proc *p2;
1003           int result;
1004           pctcpu lresult;
1005 
1006           /* remove one level of indirection */
1007           p1 = *(struct kinfo_proc **) pp1;
1008           p2 = *(struct kinfo_proc **) pp2;
1009 
1010           ORDERKEY_PRSSIZE
1011           ORDERKEY_RSSIZE
1012           ORDERKEY_MEM
1013           ORDERKEY_KIDLE
1014           ORDERKEY_PCTCPU
1015           ORDERKEY_CPTICKS
1016           ORDERKEY_STATE
1017           ORDERKEY_PRIO
1018           {}
1019 
1020           return (result);
1021 }
1022 
1023 /* compare_time - the comparison function for sorting by total cpu time */
1024 
1025 int
compare_time(struct kinfo_proc ** pp1,struct kinfo_proc ** pp2)1026 compare_time(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1027 {
1028           struct kinfo_proc *p1;
1029           struct kinfo_proc *p2;
1030           int result;
1031           pctcpu lresult;
1032 
1033           /* remove one level of indirection */
1034           p1 = *(struct kinfo_proc **) pp1;
1035           p2 = *(struct kinfo_proc **) pp2;
1036 
1037           ORDERKEY_KIDLE
1038           ORDERKEY_CPTICKS
1039           ORDERKEY_PCTCPU
1040           ORDERKEY_KTHREADS
1041           ORDERKEY_KTHREADS_PRIO
1042           ORDERKEY_STATE
1043           ORDERKEY_PRIO
1044           ORDERKEY_RSSIZE
1045           ORDERKEY_MEM
1046           {}
1047 
1048           return (result);
1049 }
1050 
1051 int
compare_ctime(struct kinfo_proc ** pp1,struct kinfo_proc ** pp2)1052 compare_ctime(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1053 {
1054           struct kinfo_proc *p1;
1055           struct kinfo_proc *p2;
1056           int result;
1057           pctcpu lresult;
1058 
1059           /* remove one level of indirection */
1060           p1 = *(struct kinfo_proc **) pp1;
1061           p2 = *(struct kinfo_proc **) pp2;
1062 
1063           ORDERKEY_KIDLE
1064           ORDERKEY_CTIME
1065           ORDERKEY_PCTCPU
1066           ORDERKEY_KTHREADS
1067           ORDERKEY_KTHREADS_PRIO
1068           ORDERKEY_STATE
1069           ORDERKEY_PRIO
1070           ORDERKEY_RSSIZE
1071           ORDERKEY_MEM
1072           {}
1073 
1074           return (result);
1075 }
1076 
1077 /* compare_prio - the comparison function for sorting by cpu percentage */
1078 
1079 int
compare_prio(struct kinfo_proc ** pp1,struct kinfo_proc ** pp2)1080 compare_prio(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1081 {
1082           struct kinfo_proc *p1;
1083           struct kinfo_proc *p2;
1084           int result;
1085           pctcpu lresult;
1086 
1087           /* remove one level of indirection */
1088           p1 = *(struct kinfo_proc **) pp1;
1089           p2 = *(struct kinfo_proc **) pp2;
1090 
1091           ORDERKEY_KTHREADS
1092           ORDERKEY_KTHREADS_PRIO
1093           ORDERKEY_PRIO
1094           ORDERKEY_KIDLE
1095           ORDERKEY_CPTICKS
1096           ORDERKEY_PCTCPU
1097           ORDERKEY_STATE
1098           ORDERKEY_RSSIZE
1099           ORDERKEY_MEM
1100           {}
1101 
1102           return (result);
1103 }
1104 
1105 int
compare_thr(struct kinfo_proc ** pp1,struct kinfo_proc ** pp2)1106 compare_thr(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1107 {
1108           struct kinfo_proc *p1;
1109           struct kinfo_proc *p2;
1110           int result;
1111           pctcpu lresult;
1112 
1113           /* remove one level of indirection */
1114           p1 = *(struct kinfo_proc **)pp1;
1115           p2 = *(struct kinfo_proc **)pp2;
1116 
1117           ORDERKEY_KTHREADS
1118           ORDERKEY_KTHREADS_PRIO
1119           ORDERKEY_KIDLE
1120           ORDERKEY_CPTICKS
1121           ORDERKEY_PCTCPU
1122           ORDERKEY_STATE
1123           ORDERKEY_RSSIZE
1124           ORDERKEY_MEM
1125           {}
1126 
1127           return (result);
1128 }
1129 
1130 /* compare_pid - the comparison function for sorting by process id */
1131 
1132 int
compare_pid(struct kinfo_proc ** pp1,struct kinfo_proc ** pp2)1133 compare_pid(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1134 {
1135           struct kinfo_proc *p1;
1136           struct kinfo_proc *p2;
1137           int result;
1138 
1139           /* remove one level of indirection */
1140           p1 = *(struct kinfo_proc **) pp1;
1141           p2 = *(struct kinfo_proc **) pp2;
1142 
1143           ORDERKEY_PID
1144           ;
1145 
1146           return(result);
1147 }
1148 
1149 /*
1150  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
1151  *                  the process does not exist.
1152  *                  It is EXTREMLY IMPORTANT that this function work correctly.
1153  *                  If top runs setuid root (as in SVR4), then this function
1154  *                  is the only thing that stands in the way of a serious
1155  *                  security problem.  It validates requests for the "kill"
1156  *                  and "renice" commands.
1157  */
1158 
1159 int
proc_owner(int pid)1160 proc_owner(int pid)
1161 {
1162           int xcnt;
1163           struct kinfo_proc **prefp;
1164           struct kinfo_proc *pp;
1165 
1166           prefp = pref;
1167           xcnt = pref_len;
1168           while (--xcnt >= 0) {
1169                     pp = *prefp++;
1170                     if (PP(pp, pid) == (pid_t) pid) {
1171                               return ((int)PP(pp, ruid));
1172                     }
1173           }
1174           return (-1);
1175 }
1176 
1177 
1178 /*
1179  * swapmode is based on a program called swapinfo written
1180  * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
1181  */
1182 int
swapmode(int * retavail,int * retfree)1183 swapmode(int *retavail, int *retfree)
1184 {
1185           int n;
1186           int pagesize = getpagesize();
1187           struct kvm_swap swapary[1];
1188 
1189           *retavail = 0;
1190           *retfree = 0;
1191 
1192 #define CONVERT(v)  ((quad_t)(v) * pagesize / 1024)
1193 
1194           n = kvm_getswapinfo(kd, swapary, 1, 0);
1195           if (n < 0 || swapary[0].ksw_total == 0)
1196                     return (0);
1197 
1198           *retavail = CONVERT(swapary[0].ksw_total);
1199           *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used);
1200 
1201           n = (int)((double)swapary[0].ksw_used * 100.0 /
1202               (double)swapary[0].ksw_total);
1203           return (n);
1204 }
1205