Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / top / dist / machine / m_linux.c
blob480177209eee4e07da1d0be879cc9d6df0f2e2f5
1 /*
2 * Copyright (c) 1984 through 2008, William LeFebvre
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
16 * * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * top - a top users display for Unix
36 * SYNOPSIS: Linux 1.2.x, 1.3.x, 2.x, using the /proc filesystem
38 * DESCRIPTION:
39 * This is the machine-dependent module for Linux 1.2.x, 1.3.x or 2.x.
41 * LIBS:
43 * CFLAGS: -DHAVE_GETOPT -DHAVE_STRERROR -DORDER
45 * TERMCAP: -lcurses
47 * AUTHOR: Richard Henderson <rth@tamu.edu>
48 * Order support added by Alexey Klimkin <kad@klon.tme.mcst.ru>
49 * Ported to 2.4 by William LeFebvre
50 * Additions for 2.6 by William LeFebvre
53 #include "config.h"
55 #include <sys/types.h>
56 #include <time.h>
57 #include <stdio.h>
58 #include <fcntl.h>
59 #include <unistd.h>
60 #include <stdlib.h>
61 #include <errno.h>
62 #include <dirent.h>
63 #include <string.h>
64 #include <math.h>
65 #include <ctype.h>
66 #include <sys/time.h>
67 #include <sys/stat.h>
68 #include <sys/vfs.h>
70 #include <sys/param.h> /* for HZ */
71 #include <asm/page.h> /* for PAGE_SHIFT */
73 #if 0
74 #include <linux/proc_fs.h> /* for PROC_SUPER_MAGIC */
75 #else
76 #define PROC_SUPER_MAGIC 0x9fa0
77 #endif
79 #include "top.h"
80 #include "hash.h"
81 #include "machine.h"
82 #include "utils.h"
83 #include "username.h"
85 #define PROCFS "/proc"
86 extern char *myname;
88 /*=PROCESS INFORMATION==================================================*/
90 struct top_proc
92 pid_t pid;
93 uid_t uid;
94 char *name;
95 int pri, nice, threads;
96 unsigned long size, rss, shared; /* in k */
97 int state;
98 unsigned long time;
99 unsigned long start_time;
100 double pcpu;
101 struct top_proc *next;
105 /*=STATE IDENT STRINGS==================================================*/
107 #define NPROCSTATES 7
108 static char *state_abbrev[NPROCSTATES+1] =
110 "", "run", "sleep", "disk", "zomb", "stop", "swap",
111 NULL
114 static char *procstatenames[NPROCSTATES+1] =
116 "", " running, ", " sleeping, ", " uninterruptable, ",
117 " zombie, ", " stopped, ", " swapping, ",
118 NULL
121 #define NCPUSTATES 5
122 static char *cpustatenames[NCPUSTATES+1] =
124 "user", "nice", "system", "idle", "iowait",
125 NULL
127 static int show_iowait = 0;
129 #define KERNELCTXT 0
130 #define KERNELFLT 1
131 #define KERNELINTR 2
132 #define KERNELNEWPROC 3
133 #define NKERNELSTATS 4
134 static char *kernelnames[NKERNELSTATS+1] =
136 " ctxsw, ", " flt, ", " intr, ", " newproc",
137 NULL
140 #define MEMUSED 0
141 #define MEMFREE 1
142 #define MEMSHARED 2
143 #define MEMBUFFERS 3
144 #define MEMCACHED 4
145 #define NMEMSTATS 5
146 static char *memorynames[NMEMSTATS+1] =
148 "K used, ", "K free, ", "K shared, ", "K buffers, ", "K cached",
149 NULL
152 #define SWAPUSED 0
153 #define SWAPFREE 1
154 #define SWAPCACHED 2
155 #define NSWAPSTATS 3
156 static char *swapnames[NSWAPSTATS+1] =
158 "K used, ", "K free, ", "K cached",
159 NULL
162 static char fmt_header[] =
163 " PID X THR PRI NICE SIZE RES STATE TIME CPU COMMAND";
165 static char proc_header_thr[] =
166 " PID %-9s THR PRI NICE SIZE RES SHR STATE TIME CPU COMMAND";
168 static char proc_header_nothr[] =
169 " PID %-9s PRI NICE SIZE RES SHR STATE TIME CPU COMMAND";
171 /* these are names given to allowed sorting orders -- first is default */
172 char *ordernames[] =
173 {"cpu", "size", "res", "time", "command", NULL};
175 /* forward definitions for comparison functions */
176 int compare_cpu();
177 int compare_size();
178 int compare_res();
179 int compare_time();
180 int compare_cmd();
182 int (*proc_compares[])() = {
183 compare_cpu,
184 compare_size,
185 compare_res,
186 compare_time,
187 compare_cmd,
188 NULL };
190 /*=SYSTEM STATE INFO====================================================*/
192 /* these are for calculating cpu state percentages */
194 static long cp_time[NCPUSTATES];
195 static long cp_old[NCPUSTATES];
196 static long cp_diff[NCPUSTATES];
198 /* for calculating the exponential average */
200 static struct timeval lasttime = { 0, 0 };
201 static struct timeval timediff = { 0, 0 };
202 static long elapsed_msecs;
204 /* these are for keeping track of processes and tasks */
206 #define HASH_SIZE (1003)
207 #define INITIAL_ACTIVE_SIZE (256)
208 #define PROCBLOCK_SIZE (32)
209 static hash_table *ptable;
210 static hash_table *tasktable;
211 static struct top_proc **pactive;
212 static struct top_proc **nextactive;
213 static unsigned int activesize = 0;
214 static time_t boottime = -1;
215 static int have_task = 0;
217 /* these are counters that need to be track */
218 static unsigned long last_ctxt = 0;
219 static unsigned long last_intr = 0;
220 static unsigned long last_newproc = 0;
221 static unsigned long last_flt = 0;
223 /* these are for passing data back to the machine independant portion */
225 static int cpu_states[NCPUSTATES];
226 static int process_states[NPROCSTATES];
227 static int kernel_stats[NKERNELSTATS];
228 static long memory_stats[NMEMSTATS];
229 static long swap_stats[NSWAPSTATS];
231 /* useful macros */
232 #define bytetok(x) (((x) + 512) >> 10)
233 #define pagetok(x) ((x) << (PAGE_SHIFT - 10))
234 #define HASH(x) (((x) * 1686629713U) % HASH_SIZE)
236 /* calculate a per-second rate using milliseconds */
237 #define per_second(n, msec) (((n) * 1000) / (msec))
239 /*======================================================================*/
241 static inline char *
242 skip_ws(const char *p)
244 while (isspace(*p)) p++;
245 return (char *)p;
248 static inline char *
249 skip_token(const char *p)
251 while (isspace(*p)) p++;
252 while (*p && !isspace(*p)) p++;
253 return (char *)p;
256 static void
257 xfrm_cmdline(char *p, int len)
259 while (--len > 0)
261 if (*p == '\0')
263 *p = ' ';
265 p++;
269 static void
270 update_procname(struct top_proc *proc, char *cmd)
273 printable(cmd);
275 if (proc->name == NULL)
277 proc->name = strdup(cmd);
279 else if (strcmp(proc->name, cmd) != 0)
281 free(proc->name);
282 proc->name = strdup(cmd);
287 * Process structures are allocated and freed as needed. Here we
288 * keep big pools of them, adding more pool as needed. When a
289 * top_proc structure is freed, it is added to a freelist and reused.
292 static struct top_proc *freelist = NULL;
293 static struct top_proc *procblock = NULL;
294 static struct top_proc *procmax = NULL;
296 static struct top_proc *
297 new_proc()
299 struct top_proc *p;
301 if (freelist)
303 p = freelist;
304 freelist = freelist->next;
306 else if (procblock)
308 p = procblock;
309 if (++procblock >= procmax)
311 procblock = NULL;
314 else
316 p = procblock = (struct top_proc *)calloc(PROCBLOCK_SIZE,
317 sizeof(struct top_proc));
318 procmax = procblock++ + PROCBLOCK_SIZE;
321 /* initialization */
322 if (p->name != NULL)
324 free(p->name);
325 p->name = NULL;
328 return p;
331 static void
332 free_proc(struct top_proc *proc)
334 proc->next = freelist;
335 freelist = proc;
340 machine_init(struct statics *statics)
343 /* make sure the proc filesystem is mounted */
345 struct statfs sb;
346 if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
348 fprintf(stderr, "%s: proc filesystem not mounted on " PROCFS "\n",
349 myname);
350 return -1;
354 /* chdir to the proc filesystem to make things easier */
355 chdir(PROCFS);
357 /* a few preliminary checks */
359 int fd;
360 char buff[128];
361 char *p;
362 int cnt = 0;
363 unsigned long uptime;
364 struct timeval tv;
365 struct stat st;
367 /* get a boottime */
368 if ((fd = open("uptime", 0)) != -1)
370 if (read(fd, buff, sizeof(buff)) > 0)
372 uptime = strtoul(buff, &p, 10);
373 gettimeofday(&tv, 0);
374 boottime = tv.tv_sec - uptime;
376 close(fd);
379 /* see how many states we get from stat */
380 if ((fd = open("stat", 0)) != -1)
382 if (read(fd, buff, sizeof(buff)) > 0)
384 if ((p = strchr(buff, '\n')) != NULL)
386 *p = '\0';
387 p = buff;
388 while (*p != '\0')
390 if (*p++ == ' ')
392 cnt++;
398 close(fd);
400 if (cnt > 5)
402 /* we have iowait */
403 show_iowait = 1;
406 /* see if we have task subdirs */
407 if (stat("self/task", &st) != -1 && S_ISDIR(st.st_mode))
409 dprintf("we have task directories\n");
410 have_task = 1;
414 /* if we aren't showing iowait, then we have to tweak cpustatenames */
415 if (!show_iowait)
417 cpustatenames[4] = NULL;
420 /* fill in the statics information */
421 statics->procstate_names = procstatenames;
422 statics->cpustate_names = cpustatenames;
423 statics->kernel_names = kernelnames;
424 statics->memory_names = memorynames;
425 statics->swap_names = swapnames;
426 statics->order_names = ordernames;
427 statics->boottime = boottime;
428 statics->flags.fullcmds = 1;
429 statics->flags.warmup = 1;
430 statics->flags.threads = 1;
432 /* allocate needed space */
433 pactive = (struct top_proc **)malloc(sizeof(struct top_proc *) * INITIAL_ACTIVE_SIZE);
434 activesize = INITIAL_ACTIVE_SIZE;
436 /* create process and task hashes */
437 ptable = hash_create(HASH_SIZE);
438 tasktable = hash_create(HASH_SIZE);
440 /* all done! */
441 return 0;
445 void
446 get_system_info(struct system_info *info)
449 char buffer[4096+1];
450 int fd, len;
451 char *p;
452 struct timeval thistime;
453 unsigned long intr = 0;
454 unsigned long ctxt = 0;
455 unsigned long newproc = 0;
456 unsigned long flt = 0;
458 /* timestamp and time difference */
459 gettimeofday(&thistime, 0);
460 timersub(&thistime, &lasttime, &timediff);
461 elapsed_msecs = timediff.tv_sec * 1000 + timediff.tv_usec / 1000;
462 lasttime = thistime;
464 /* get load averages */
465 if ((fd = open("loadavg", O_RDONLY)) != -1)
467 if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
469 buffer[len] = '\0';
470 info->load_avg[0] = strtod(buffer, &p);
471 info->load_avg[1] = strtod(p, &p);
472 info->load_avg[2] = strtod(p, &p);
473 p = skip_token(p); /* skip running/tasks */
474 p = skip_ws(p);
475 if (*p)
477 info->last_pid = atoi(p);
479 else
481 info->last_pid = -1;
484 close(fd);
487 /* get the cpu time info */
488 if ((fd = open("stat", O_RDONLY)) != -1)
490 if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
492 buffer[len] = '\0';
493 p = skip_token(buffer); /* "cpu" */
494 cp_time[0] = strtoul(p, &p, 0);
495 cp_time[1] = strtoul(p, &p, 0);
496 cp_time[2] = strtoul(p, &p, 0);
497 cp_time[3] = strtoul(p, &p, 0);
498 if (show_iowait)
500 cp_time[4] = strtoul(p, &p, 0);
503 /* convert cp_time counts to percentages */
504 percentages(NCPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
506 /* get the rest of it */
507 p = strchr(p, '\n');
508 while (p != NULL)
510 p++;
511 if (strncmp(p, "intr ", 5) == 0)
513 p = skip_token(p);
514 intr = strtoul(p, &p, 10);
516 else if (strncmp(p, "ctxt ", 5) == 0)
518 p = skip_token(p);
519 ctxt = strtoul(p, &p, 10);
521 else if (strncmp(p, "processes ", 10) == 0)
523 p = skip_token(p);
524 newproc = strtoul(p, &p, 10);
527 p = strchr(p, '\n');
530 kernel_stats[KERNELINTR] = per_second(intr - last_intr, elapsed_msecs);
531 kernel_stats[KERNELCTXT] = per_second(ctxt - last_ctxt, elapsed_msecs);
532 kernel_stats[KERNELNEWPROC] = per_second(newproc - last_newproc, elapsed_msecs);
533 last_intr = intr;
534 last_ctxt = ctxt;
535 last_newproc = newproc;
537 close(fd);
540 /* get system wide memory usage */
541 if ((fd = open("meminfo", O_RDONLY)) != -1)
543 char *p;
544 int mem = 0;
545 int swap = 0;
546 unsigned long memtotal = 0;
547 unsigned long memfree = 0;
548 unsigned long swaptotal = 0;
550 if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
552 buffer[len] = '\0';
553 p = buffer-1;
555 /* iterate thru the lines */
556 while (p != NULL)
558 p++;
559 if (p[0] == ' ' || p[0] == '\t')
561 /* skip */
563 else if (strncmp(p, "Mem:", 4) == 0)
565 p = skip_token(p); /* "Mem:" */
566 p = skip_token(p); /* total memory */
567 memory_stats[MEMUSED] = strtoul(p, &p, 10);
568 memory_stats[MEMFREE] = strtoul(p, &p, 10);
569 memory_stats[MEMSHARED] = strtoul(p, &p, 10);
570 memory_stats[MEMBUFFERS] = strtoul(p, &p, 10);
571 memory_stats[MEMCACHED] = strtoul(p, &p, 10);
572 memory_stats[MEMUSED] = bytetok(memory_stats[MEMUSED]);
573 memory_stats[MEMFREE] = bytetok(memory_stats[MEMFREE]);
574 memory_stats[MEMSHARED] = bytetok(memory_stats[MEMSHARED]);
575 memory_stats[MEMBUFFERS] = bytetok(memory_stats[MEMBUFFERS]);
576 memory_stats[MEMCACHED] = bytetok(memory_stats[MEMCACHED]);
577 mem = 1;
579 else if (strncmp(p, "Swap:", 5) == 0)
581 p = skip_token(p); /* "Swap:" */
582 p = skip_token(p); /* total swap */
583 swap_stats[SWAPUSED] = strtoul(p, &p, 10);
584 swap_stats[SWAPFREE] = strtoul(p, &p, 10);
585 swap_stats[SWAPUSED] = bytetok(swap_stats[SWAPUSED]);
586 swap_stats[SWAPFREE] = bytetok(swap_stats[SWAPFREE]);
587 swap = 1;
589 else if (!mem && strncmp(p, "MemTotal:", 9) == 0)
591 p = skip_token(p);
592 memtotal = strtoul(p, &p, 10);
594 else if (!mem && memtotal > 0 && strncmp(p, "MemFree:", 8) == 0)
596 p = skip_token(p);
597 memfree = strtoul(p, &p, 10);
598 memory_stats[MEMUSED] = memtotal - memfree;
599 memory_stats[MEMFREE] = memfree;
601 else if (!mem && strncmp(p, "MemShared:", 10) == 0)
603 p = skip_token(p);
604 memory_stats[MEMSHARED] = strtoul(p, &p, 10);
606 else if (!mem && strncmp(p, "Buffers:", 8) == 0)
608 p = skip_token(p);
609 memory_stats[MEMBUFFERS] = strtoul(p, &p, 10);
611 else if (!mem && strncmp(p, "Cached:", 7) == 0)
613 p = skip_token(p);
614 memory_stats[MEMCACHED] = strtoul(p, &p, 10);
616 else if (!swap && strncmp(p, "SwapTotal:", 10) == 0)
618 p = skip_token(p);
619 swaptotal = strtoul(p, &p, 10);
621 else if (!swap && swaptotal > 0 && strncmp(p, "SwapFree:", 9) == 0)
623 p = skip_token(p);
624 memfree = strtoul(p, &p, 10);
625 swap_stats[SWAPUSED] = swaptotal - memfree;
626 swap_stats[SWAPFREE] = memfree;
628 else if (!mem && strncmp(p, "SwapCached:", 11) == 0)
630 p = skip_token(p);
631 swap_stats[SWAPCACHED] = strtoul(p, &p, 10);
634 /* move to the next line */
635 p = strchr(p, '\n');
638 close(fd);
641 /* get vm related stuff */
642 if ((fd = open("vmstat", O_RDONLY)) != -1)
644 char *p;
646 if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
648 buffer[len] = '\0';
649 p = buffer;
651 /* iterate thru the lines */
652 while (p != NULL)
654 if (strncmp(p, "pgmajfault ", 11) == 0)
656 p = skip_token(p);
657 flt = strtoul(p, &p, 10);
658 kernel_stats[KERNELFLT] = per_second(flt - last_flt, elapsed_msecs);
659 last_flt = flt;
660 break;
663 /* move to the next line */
664 p = strchr(p, '\n');
665 p++;
668 close(fd);
671 /* set arrays and strings */
672 info->cpustates = cpu_states;
673 info->memory = memory_stats;
674 info->swap = swap_stats;
675 info->kernel = kernel_stats;
678 static void
679 read_one_proc_stat(pid_t pid, pid_t taskpid, struct top_proc *proc, struct process_select *sel)
681 char buffer[4096], *p, *q;
682 int fd, len;
683 int fullcmd;
685 dprintf("reading proc %d - %d\n", pid, taskpid);
687 /* if anything goes wrong, we return with proc->state == 0 */
688 proc->state = 0;
690 /* full cmd handling */
691 fullcmd = sel->fullcmd;
692 if (fullcmd)
694 if (taskpid == -1)
696 sprintf(buffer, "%d/cmdline", pid);
698 else
700 sprintf(buffer, "%d/task/%d/cmdline", pid, taskpid);
702 if ((fd = open(buffer, O_RDONLY)) != -1)
704 /* read command line data */
705 /* (theres no sense in reading more than we can fit) */
706 if ((len = read(fd, buffer, MAX_COLS)) > 1)
708 buffer[len] = '\0';
709 xfrm_cmdline(buffer, len);
710 update_procname(proc, buffer);
712 else
714 fullcmd = 0;
716 close(fd);
718 else
720 fullcmd = 0;
724 /* grab the shared memory size */
725 sprintf(buffer, "%d/statm", pid);
726 fd = open(buffer, O_RDONLY);
727 len = read(fd, buffer, sizeof(buffer)-1);
728 close(fd);
729 buffer[len] = '\0';
730 p = buffer;
731 p = skip_token(p); /* skip size */
732 p = skip_token(p); /* skip resident */
733 proc->shared = pagetok(strtoul(p, &p, 10));
735 /* grab the proc stat info in one go */
736 if (taskpid == -1)
738 sprintf(buffer, "%d/stat", pid);
740 else
742 sprintf(buffer, "%d/task/%d/stat", pid, taskpid);
745 fd = open(buffer, O_RDONLY);
746 len = read(fd, buffer, sizeof(buffer)-1);
747 close(fd);
749 buffer[len] = '\0';
751 proc->uid = (uid_t)proc_owner((int)pid);
753 /* parse out the status */
755 /* skip pid and locate command, which is in parentheses */
756 if ((p = strchr(buffer, '(')) == NULL)
758 return;
760 if ((q = strrchr(++p, ')')) == NULL)
762 return;
765 /* set the procname */
766 *q = '\0';
767 if (!fullcmd)
769 update_procname(proc, p);
772 /* scan the rest of the line */
773 p = q+1;
774 p = skip_ws(p);
775 switch (*p++) /* state */
777 case 'R': proc->state = 1; break;
778 case 'S': proc->state = 2; break;
779 case 'D': proc->state = 3; break;
780 case 'Z': proc->state = 4; break;
781 case 'T': proc->state = 5; break;
782 case 'W': proc->state = 6; break;
783 case '\0': return;
786 p = skip_token(p); /* skip ppid */
787 p = skip_token(p); /* skip pgrp */
788 p = skip_token(p); /* skip session */
789 p = skip_token(p); /* skip tty */
790 p = skip_token(p); /* skip tty pgrp */
791 p = skip_token(p); /* skip flags */
792 p = skip_token(p); /* skip min flt */
793 p = skip_token(p); /* skip cmin flt */
794 p = skip_token(p); /* skip maj flt */
795 p = skip_token(p); /* skip cmaj flt */
797 proc->time = strtoul(p, &p, 10); /* utime */
798 proc->time += strtoul(p, &p, 10); /* stime */
800 p = skip_token(p); /* skip cutime */
801 p = skip_token(p); /* skip cstime */
803 proc->pri = strtol(p, &p, 10); /* priority */
804 proc->nice = strtol(p, &p, 10); /* nice */
805 proc->threads = strtol(p, &p, 10); /* threads */
807 p = skip_token(p); /* skip it_real_val */
808 proc->start_time = strtoul(p, &p, 10); /* start_time */
810 proc->size = bytetok(strtoul(p, &p, 10)); /* vsize */
811 proc->rss = pagetok(strtoul(p, &p, 10)); /* rss */
813 #if 0
814 /* for the record, here are the rest of the fields */
815 p = skip_token(p); /* skip rlim */
816 p = skip_token(p); /* skip start_code */
817 p = skip_token(p); /* skip end_code */
818 p = skip_token(p); /* skip start_stack */
819 p = skip_token(p); /* skip sp */
820 p = skip_token(p); /* skip pc */
821 p = skip_token(p); /* skip signal */
822 p = skip_token(p); /* skip sigblocked */
823 p = skip_token(p); /* skip sigignore */
824 p = skip_token(p); /* skip sigcatch */
825 p = skip_token(p); /* skip wchan */
826 #endif
830 static int show_usernames;
831 static int show_threads;
834 caddr_t
835 get_process_info(struct system_info *si,
836 struct process_select *sel,
837 int compare_index)
839 struct top_proc *proc;
840 struct top_proc *taskproc;
841 pid_t pid;
842 pid_t taskpid;
843 unsigned long now;
844 unsigned long elapsed;
845 hash_item_pid *hi;
846 hash_pos pos;
848 /* round current time to a second */
849 now = (unsigned long)lasttime.tv_sec;
850 if (lasttime.tv_usec >= 500000)
852 now++;
855 /* calculate number of ticks since our last check */
856 elapsed = timediff.tv_sec * HZ + (timediff.tv_usec * HZ) / 1000000;
857 if (elapsed <= 0)
859 elapsed = 1;
861 dprintf("get_process_info: elapsed %d ticks\n", elapsed);
863 /* mark all hash table entries as not seen */
864 hi = hash_first_pid(ptable, &pos);
865 while (hi != NULL)
867 ((struct top_proc *)(hi->value))->state = 0;
868 hi = hash_next_pid(&pos);
870 /* mark all hash table entries as not seen */
871 hi = hash_first_pid(tasktable, &pos);
872 while (hi != NULL)
874 ((struct top_proc *)(hi->value))->state = 0;
875 hi = hash_next_pid(&pos);
878 /* read the process information */
880 DIR *dir = opendir(".");
881 DIR *taskdir;
882 struct dirent *ent;
883 struct dirent *taskent;
884 int total_procs = 0;
885 struct top_proc **active;
886 hash_item_pid *hi;
887 hash_pos pos;
888 char buffer[64];
890 int show_idle = sel->idle;
891 int show_uid = sel->uid != -1;
892 char *show_command = sel->command;
894 show_usernames = sel->usernames;
895 show_threads = sel->threads && have_task;
897 memset(process_states, 0, sizeof(process_states));
899 taskdir = NULL;
900 taskent = NULL;
901 taskpid = -1;
903 while ((ent = readdir(dir)) != NULL)
905 unsigned long otime;
907 if (!isdigit(ent->d_name[0]))
908 continue;
910 pid = atoi(ent->d_name);
912 /* look up hash table entry */
913 proc = hash_lookup_pid(ptable, pid);
915 /* if we came up empty, create a new entry */
916 if (proc == NULL)
918 proc = new_proc();
919 proc->pid = pid;
920 proc->time = 0;
921 hash_add_pid(ptable, pid, (void *)proc);
924 /* remember the previous cpu time */
925 otime = proc->time;
927 /* get current data */
928 read_one_proc_stat(pid, -1, proc, sel);
930 /* continue on if this isn't really a process */
931 if (proc->state == 0)
932 continue;
934 /* reset linked list (for threads) */
935 proc->next = NULL;
937 /* accumulate process state data */
938 total_procs++;
939 process_states[proc->state]++;
941 /* calculate pcpu */
942 if ((proc->pcpu = (proc->time - otime) / (double)elapsed) < 0.0001)
944 proc->pcpu = 0;
947 /* if we have task subdirs and this process has more than
948 one thread, collect data on each thread */
949 if (have_task && proc->threads > 1)
951 snprintf(buffer, sizeof(buffer), "%d/task", pid);
952 if ((taskdir = opendir(buffer)) != NULL)
954 while ((taskent = readdir(taskdir)) != NULL)
956 if (!isdigit(taskent->d_name[0]))
957 continue;
959 /* lookup entry in tasktable */
960 taskpid = atoi(taskent->d_name);
961 taskproc = hash_lookup_pid(tasktable, taskpid);
963 /* if we came up empty, create a new entry */
964 if (taskproc == NULL)
966 taskproc = new_proc();
967 taskproc->pid = taskpid;
968 taskproc->time = 0;
969 hash_add_pid(tasktable, taskpid, (void *)taskproc);
972 /* remember the previous cpu time */
973 otime = taskproc->time;
975 /* get current data */
976 read_one_proc_stat(pid, taskpid, taskproc, sel);
978 /* ignore if it isnt real */
979 if (taskproc->state == 0)
980 continue;
982 /* when showing threads, add this to the accumulated
983 process state data, but remember that the first
984 thread is already accounted for */
985 if (show_threads && pid != taskpid)
987 total_procs++;
988 process_states[taskproc->state]++;
991 /* calculate pcpu */
992 if ((taskproc->pcpu = (taskproc->time - otime) /
993 (double)elapsed) < 0.0)
995 taskproc->pcpu = 0;
998 /* link this in to the proc's list */
999 taskproc->next = proc->next;
1000 proc->next = taskproc;
1002 closedir(taskdir);
1006 closedir(dir);
1008 /* make sure we have enough slots for the active procs */
1009 if (activesize < total_procs)
1011 pactive = (struct top_proc **)realloc(pactive,
1012 sizeof(struct top_proc *) * total_procs);
1013 activesize = total_procs;
1016 /* set up the active procs and flush dead entries */
1017 active = pactive;
1018 hi = hash_first_pid(ptable, &pos);
1019 while (hi != NULL)
1021 proc = (struct top_proc *)(hi->value);
1022 if (proc->state == 0)
1024 /* dead entry */
1025 hash_remove_pos_pid(&pos);
1026 free_proc(proc);
1028 else
1030 /* check to see if it qualifies as active */
1031 if ((show_idle || proc->state == 1 || proc->pcpu) &&
1032 (!show_uid || proc->uid == sel->uid) &&
1033 (show_command == NULL ||
1034 strstr(proc->name, show_command) != NULL))
1036 /* are we showing threads and does this proc have any? */
1037 if (show_threads && proc->threads > 1 && proc->next != NULL)
1039 /* then add just the thread info -- the main process
1040 info is included in the list */
1041 proc = proc->next;
1042 while (proc != NULL)
1044 *active++ = proc;
1045 proc = proc->next;
1048 else
1050 /* add the process */
1051 *active++ = proc;
1056 hi = hash_next_pid(&pos);
1059 si->p_active = active - pactive;
1060 si->p_total = total_procs;
1061 si->procstates = process_states;
1064 /* if requested, sort the "active" procs */
1065 if (si->p_active)
1066 qsort(pactive, si->p_active, sizeof(struct top_proc *),
1067 proc_compares[compare_index]);
1069 /* don't even pretend that the return value thing here isn't bogus */
1070 nextactive = pactive;
1071 return (caddr_t)0;
1075 char *
1076 format_header(char *uname_field)
1079 int uname_len = strlen(uname_field);
1080 if (uname_len > 8)
1081 uname_len = 8;
1083 memcpy(strchr(fmt_header, 'X'), uname_field, uname_len);
1085 return fmt_header;
1088 static char p_header[MAX_COLS];
1090 char *
1091 format_process_header(struct process_select *sel, caddr_t handle, int count)
1094 char *h;
1096 h = sel->threads ? proc_header_nothr : proc_header_thr;
1098 snprintf(p_header, MAX_COLS, h, sel->usernames ? "USERNAME" : "UID");
1100 return p_header;
1104 char *
1105 format_next_process(caddr_t handle, char *(*get_userid)(int))
1108 static char fmt[MAX_COLS]; /* static area where result is built */
1109 struct top_proc *p = *nextactive++;
1110 char *userbuf;
1112 userbuf = show_usernames ? username(p->uid) : itoa_w(p->uid, 7);
1114 if (show_threads)
1116 snprintf(fmt, sizeof(fmt),
1117 "%5d %-8.8s %3d %4d %5s %5s %5s %-5s %6s %5s%% %s",
1118 p->pid,
1119 userbuf,
1120 p->pri < -99 ? -99 : p->pri,
1121 p->nice,
1122 format_k(p->size),
1123 format_k(p->rss),
1124 format_k(p->shared),
1125 state_abbrev[p->state],
1126 format_time(p->time / HZ),
1127 format_percent(p->pcpu * 100.0),
1128 p->name);
1130 else
1132 snprintf(fmt, sizeof(fmt),
1133 "%5d %-8.8s %4d %3d %4d %5s %5s %5s %-5s %6s %5s%% %s",
1134 p->pid,
1135 userbuf,
1136 p->threads <= 9999 ? p->threads : 9999,
1137 p->pri < -99 ? -99 : p->pri,
1138 p->nice,
1139 format_k(p->size),
1140 format_k(p->rss),
1141 format_k(p->shared),
1142 state_abbrev[p->state],
1143 format_time(p->time / HZ),
1144 format_percent(p->pcpu * 100.0),
1145 p->name);
1148 /* return the result */
1149 return (fmt);
1152 /* comparison routines for qsort */
1155 * There are currently four possible comparison routines. main selects
1156 * one of these by indexing in to the array proc_compares.
1158 * Possible keys are defined as macros below. Currently these keys are
1159 * defined: percent cpu, cpu ticks, process state, resident set size,
1160 * total virtual memory usage. The process states are ordered as follows
1161 * (from least to most important): WAIT, zombie, sleep, stop, start, run.
1162 * The array declaration below maps a process state index into a number
1163 * that reflects this ordering.
1166 /* First, the possible comparison keys. These are defined in such a way
1167 that they can be merely listed in the source code to define the actual
1168 desired ordering.
1171 #define ORDERKEY_PCTCPU if (dresult = p2->pcpu - p1->pcpu,\
1172 (result = dresult > 0.0 ? 1 : dresult < 0.0 ? -1 : 0) == 0)
1173 #define ORDERKEY_CPTICKS if ((result = (long)p2->time - (long)p1->time) == 0)
1174 #define ORDERKEY_STATE if ((result = (sort_state[p2->state] - \
1175 sort_state[p1->state])) == 0)
1176 #define ORDERKEY_PRIO if ((result = p2->pri - p1->pri) == 0)
1177 #define ORDERKEY_RSSIZE if ((result = p2->rss - p1->rss) == 0)
1178 #define ORDERKEY_MEM if ((result = p2->size - p1->size) == 0)
1179 #define ORDERKEY_NAME if ((result = strcmp(p1->name, p2->name)) == 0)
1181 /* Now the array that maps process state to a weight */
1183 unsigned char sort_state[] =
1185 0, /* empty */
1186 6, /* run */
1187 3, /* sleep */
1188 5, /* disk wait */
1189 1, /* zombie */
1190 2, /* stop */
1191 4 /* swap */
1195 /* compare_cpu - the comparison function for sorting by cpu percentage */
1198 compare_cpu (
1199 struct top_proc **pp1,
1200 struct top_proc **pp2)
1202 register struct top_proc *p1;
1203 register struct top_proc *p2;
1204 register long result;
1205 double dresult;
1207 /* remove one level of indirection */
1208 p1 = *pp1;
1209 p2 = *pp2;
1211 ORDERKEY_PCTCPU
1212 ORDERKEY_CPTICKS
1213 ORDERKEY_STATE
1214 ORDERKEY_PRIO
1215 ORDERKEY_RSSIZE
1216 ORDERKEY_MEM
1219 return result == 0 ? 0 : result < 0 ? -1 : 1;
1222 /* compare_size - the comparison function for sorting by total memory usage */
1225 compare_size (
1226 struct top_proc **pp1,
1227 struct top_proc **pp2)
1229 register struct top_proc *p1;
1230 register struct top_proc *p2;
1231 register long result;
1232 double dresult;
1234 /* remove one level of indirection */
1235 p1 = *pp1;
1236 p2 = *pp2;
1238 ORDERKEY_MEM
1239 ORDERKEY_RSSIZE
1240 ORDERKEY_PCTCPU
1241 ORDERKEY_CPTICKS
1242 ORDERKEY_STATE
1243 ORDERKEY_PRIO
1246 return result == 0 ? 0 : result < 0 ? -1 : 1;
1249 /* compare_res - the comparison function for sorting by resident set size */
1252 compare_res (
1253 struct top_proc **pp1,
1254 struct top_proc **pp2)
1256 register struct top_proc *p1;
1257 register struct top_proc *p2;
1258 register long result;
1259 double dresult;
1261 /* remove one level of indirection */
1262 p1 = *pp1;
1263 p2 = *pp2;
1265 ORDERKEY_RSSIZE
1266 ORDERKEY_MEM
1267 ORDERKEY_PCTCPU
1268 ORDERKEY_CPTICKS
1269 ORDERKEY_STATE
1270 ORDERKEY_PRIO
1273 return result == 0 ? 0 : result < 0 ? -1 : 1;
1276 /* compare_time - the comparison function for sorting by total cpu time */
1279 compare_time (
1280 struct top_proc **pp1,
1281 struct top_proc **pp2)
1283 register struct top_proc *p1;
1284 register struct top_proc *p2;
1285 register long result;
1286 double dresult;
1288 /* remove one level of indirection */
1289 p1 = *pp1;
1290 p2 = *pp2;
1292 ORDERKEY_CPTICKS
1293 ORDERKEY_PCTCPU
1294 ORDERKEY_STATE
1295 ORDERKEY_PRIO
1296 ORDERKEY_MEM
1297 ORDERKEY_RSSIZE
1300 return result == 0 ? 0 : result < 0 ? -1 : 1;
1304 /* compare_cmd - the comparison function for sorting by command name */
1307 compare_cmd (
1308 struct top_proc **pp1,
1309 struct top_proc **pp2)
1311 register struct top_proc *p1;
1312 register struct top_proc *p2;
1313 register long result;
1314 double dresult;
1316 /* remove one level of indirection */
1317 p1 = *pp1;
1318 p2 = *pp2;
1320 ORDERKEY_NAME
1321 ORDERKEY_PCTCPU
1322 ORDERKEY_CPTICKS
1323 ORDERKEY_STATE
1324 ORDERKEY_PRIO
1325 ORDERKEY_RSSIZE
1326 ORDERKEY_MEM
1329 return result == 0 ? 0 : result < 0 ? -1 : 1;
1334 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
1335 * the process does not exist.
1336 * It is EXTREMLY IMPORTANT that this function work correctly.
1337 * If top runs setuid root (as in SVR4), then this function
1338 * is the only thing that stands in the way of a serious
1339 * security problem. It validates requests for the "kill"
1340 * and "renice" commands.
1344 proc_owner(int pid)
1347 struct stat sb;
1348 char buffer[32];
1349 sprintf(buffer, "%d", pid);
1351 if (stat(buffer, &sb) < 0)
1352 return -1;
1353 else
1354 return (int)sb.st_uid;