1*b89261baSDavid van Moolenbroek /*
2*b89261baSDavid van Moolenbroek * Copyright (c) 1984 through 2008, William LeFebvre
3*b89261baSDavid van Moolenbroek * All rights reserved.
4*b89261baSDavid van Moolenbroek *
5*b89261baSDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
6*b89261baSDavid van Moolenbroek * modification, are permitted provided that the following conditions are met:
7*b89261baSDavid van Moolenbroek *
8*b89261baSDavid van Moolenbroek * * Redistributions of source code must retain the above copyright
9*b89261baSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
10*b89261baSDavid van Moolenbroek *
11*b89261baSDavid van Moolenbroek * * Redistributions in binary form must reproduce the above
12*b89261baSDavid van Moolenbroek * copyright notice, this list of conditions and the following disclaimer
13*b89261baSDavid van Moolenbroek * in the documentation and/or other materials provided with the
14*b89261baSDavid van Moolenbroek * distribution.
15*b89261baSDavid van Moolenbroek *
16*b89261baSDavid van Moolenbroek * * Neither the name of William LeFebvre nor the names of other
17*b89261baSDavid van Moolenbroek * contributors may be used to endorse or promote products derived from
18*b89261baSDavid van Moolenbroek * this software without specific prior written permission.
19*b89261baSDavid van Moolenbroek *
20*b89261baSDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*b89261baSDavid van Moolenbroek * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*b89261baSDavid van Moolenbroek * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*b89261baSDavid van Moolenbroek * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*b89261baSDavid van Moolenbroek * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*b89261baSDavid van Moolenbroek * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*b89261baSDavid van Moolenbroek * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*b89261baSDavid van Moolenbroek * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*b89261baSDavid van Moolenbroek * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*b89261baSDavid van Moolenbroek * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*b89261baSDavid van Moolenbroek * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*b89261baSDavid van Moolenbroek */
32*b89261baSDavid van Moolenbroek
33*b89261baSDavid van Moolenbroek /*
34*b89261baSDavid van Moolenbroek * top - a top users display for Unix
35*b89261baSDavid van Moolenbroek *
36*b89261baSDavid van Moolenbroek * SYNOPSIS: Linux 1.2.x, 1.3.x, 2.x, using the /proc filesystem
37*b89261baSDavid van Moolenbroek *
38*b89261baSDavid van Moolenbroek * DESCRIPTION:
39*b89261baSDavid van Moolenbroek * This is the machine-dependent module for Linux 1.2.x, 1.3.x or 2.x.
40*b89261baSDavid van Moolenbroek *
41*b89261baSDavid van Moolenbroek * LIBS:
42*b89261baSDavid van Moolenbroek *
43*b89261baSDavid van Moolenbroek * CFLAGS: -DHAVE_GETOPT -DHAVE_STRERROR -DORDER
44*b89261baSDavid van Moolenbroek *
45*b89261baSDavid van Moolenbroek * TERMCAP: -lcurses
46*b89261baSDavid van Moolenbroek *
47*b89261baSDavid van Moolenbroek * AUTHOR: Richard Henderson <rth@tamu.edu>
48*b89261baSDavid van Moolenbroek * Order support added by Alexey Klimkin <kad@klon.tme.mcst.ru>
49*b89261baSDavid van Moolenbroek * Ported to 2.4 by William LeFebvre
50*b89261baSDavid van Moolenbroek * Additions for 2.6 by William LeFebvre
51*b89261baSDavid van Moolenbroek */
52*b89261baSDavid van Moolenbroek
53*b89261baSDavid van Moolenbroek #include "config.h"
54*b89261baSDavid van Moolenbroek
55*b89261baSDavid van Moolenbroek #include <sys/types.h>
56*b89261baSDavid van Moolenbroek #include <time.h>
57*b89261baSDavid van Moolenbroek #include <stdio.h>
58*b89261baSDavid van Moolenbroek #include <fcntl.h>
59*b89261baSDavid van Moolenbroek #include <unistd.h>
60*b89261baSDavid van Moolenbroek #include <stdlib.h>
61*b89261baSDavid van Moolenbroek #include <errno.h>
62*b89261baSDavid van Moolenbroek #include <dirent.h>
63*b89261baSDavid van Moolenbroek #include <string.h>
64*b89261baSDavid van Moolenbroek #include <math.h>
65*b89261baSDavid van Moolenbroek #include <ctype.h>
66*b89261baSDavid van Moolenbroek #include <sys/time.h>
67*b89261baSDavid van Moolenbroek #include <sys/stat.h>
68*b89261baSDavid van Moolenbroek #include <sys/vfs.h>
69*b89261baSDavid van Moolenbroek
70*b89261baSDavid van Moolenbroek #include <sys/param.h> /* for HZ */
71*b89261baSDavid van Moolenbroek #include <asm/page.h> /* for PAGE_SHIFT */
72*b89261baSDavid van Moolenbroek
73*b89261baSDavid van Moolenbroek #if 0
74*b89261baSDavid van Moolenbroek #include <linux/proc_fs.h> /* for PROC_SUPER_MAGIC */
75*b89261baSDavid van Moolenbroek #else
76*b89261baSDavid van Moolenbroek #define PROC_SUPER_MAGIC 0x9fa0
77*b89261baSDavid van Moolenbroek #endif
78*b89261baSDavid van Moolenbroek
79*b89261baSDavid van Moolenbroek #include "top.h"
80*b89261baSDavid van Moolenbroek #include "hash.h"
81*b89261baSDavid van Moolenbroek #include "machine.h"
82*b89261baSDavid van Moolenbroek #include "utils.h"
83*b89261baSDavid van Moolenbroek #include "username.h"
84*b89261baSDavid van Moolenbroek
85*b89261baSDavid van Moolenbroek #define PROCFS "/proc"
86*b89261baSDavid van Moolenbroek extern char *myname;
87*b89261baSDavid van Moolenbroek
88*b89261baSDavid van Moolenbroek /*=PROCESS INFORMATION==================================================*/
89*b89261baSDavid van Moolenbroek
90*b89261baSDavid van Moolenbroek struct top_proc
91*b89261baSDavid van Moolenbroek {
92*b89261baSDavid van Moolenbroek pid_t pid;
93*b89261baSDavid van Moolenbroek uid_t uid;
94*b89261baSDavid van Moolenbroek char *name;
95*b89261baSDavid van Moolenbroek int pri, nice, threads;
96*b89261baSDavid van Moolenbroek unsigned long size, rss, shared; /* in k */
97*b89261baSDavid van Moolenbroek int state;
98*b89261baSDavid van Moolenbroek unsigned long time;
99*b89261baSDavid van Moolenbroek unsigned long start_time;
100*b89261baSDavid van Moolenbroek double pcpu;
101*b89261baSDavid van Moolenbroek struct top_proc *next;
102*b89261baSDavid van Moolenbroek };
103*b89261baSDavid van Moolenbroek
104*b89261baSDavid van Moolenbroek
105*b89261baSDavid van Moolenbroek /*=STATE IDENT STRINGS==================================================*/
106*b89261baSDavid van Moolenbroek
107*b89261baSDavid van Moolenbroek #define NPROCSTATES 7
108*b89261baSDavid van Moolenbroek static char *state_abbrev[NPROCSTATES+1] =
109*b89261baSDavid van Moolenbroek {
110*b89261baSDavid van Moolenbroek "", "run", "sleep", "disk", "zomb", "stop", "swap",
111*b89261baSDavid van Moolenbroek NULL
112*b89261baSDavid van Moolenbroek };
113*b89261baSDavid van Moolenbroek
114*b89261baSDavid van Moolenbroek static char *procstatenames[NPROCSTATES+1] =
115*b89261baSDavid van Moolenbroek {
116*b89261baSDavid van Moolenbroek "", " running, ", " sleeping, ", " uninterruptable, ",
117*b89261baSDavid van Moolenbroek " zombie, ", " stopped, ", " swapping, ",
118*b89261baSDavid van Moolenbroek NULL
119*b89261baSDavid van Moolenbroek };
120*b89261baSDavid van Moolenbroek
121*b89261baSDavid van Moolenbroek #define NCPUSTATES 5
122*b89261baSDavid van Moolenbroek static char *cpustatenames[NCPUSTATES+1] =
123*b89261baSDavid van Moolenbroek {
124*b89261baSDavid van Moolenbroek "user", "nice", "system", "idle", "iowait",
125*b89261baSDavid van Moolenbroek NULL
126*b89261baSDavid van Moolenbroek };
127*b89261baSDavid van Moolenbroek static int show_iowait = 0;
128*b89261baSDavid van Moolenbroek
129*b89261baSDavid van Moolenbroek #define KERNELCTXT 0
130*b89261baSDavid van Moolenbroek #define KERNELFLT 1
131*b89261baSDavid van Moolenbroek #define KERNELINTR 2
132*b89261baSDavid van Moolenbroek #define KERNELNEWPROC 3
133*b89261baSDavid van Moolenbroek #define NKERNELSTATS 4
134*b89261baSDavid van Moolenbroek static char *kernelnames[NKERNELSTATS+1] =
135*b89261baSDavid van Moolenbroek {
136*b89261baSDavid van Moolenbroek " ctxsw, ", " flt, ", " intr, ", " newproc",
137*b89261baSDavid van Moolenbroek NULL
138*b89261baSDavid van Moolenbroek };
139*b89261baSDavid van Moolenbroek
140*b89261baSDavid van Moolenbroek #define MEMUSED 0
141*b89261baSDavid van Moolenbroek #define MEMFREE 1
142*b89261baSDavid van Moolenbroek #define MEMSHARED 2
143*b89261baSDavid van Moolenbroek #define MEMBUFFERS 3
144*b89261baSDavid van Moolenbroek #define MEMCACHED 4
145*b89261baSDavid van Moolenbroek #define NMEMSTATS 5
146*b89261baSDavid van Moolenbroek static char *memorynames[NMEMSTATS+1] =
147*b89261baSDavid van Moolenbroek {
148*b89261baSDavid van Moolenbroek "K used, ", "K free, ", "K shared, ", "K buffers, ", "K cached",
149*b89261baSDavid van Moolenbroek NULL
150*b89261baSDavid van Moolenbroek };
151*b89261baSDavid van Moolenbroek
152*b89261baSDavid van Moolenbroek #define SWAPUSED 0
153*b89261baSDavid van Moolenbroek #define SWAPFREE 1
154*b89261baSDavid van Moolenbroek #define SWAPCACHED 2
155*b89261baSDavid van Moolenbroek #define NSWAPSTATS 3
156*b89261baSDavid van Moolenbroek static char *swapnames[NSWAPSTATS+1] =
157*b89261baSDavid van Moolenbroek {
158*b89261baSDavid van Moolenbroek "K used, ", "K free, ", "K cached",
159*b89261baSDavid van Moolenbroek NULL
160*b89261baSDavid van Moolenbroek };
161*b89261baSDavid van Moolenbroek
162*b89261baSDavid van Moolenbroek static char fmt_header[] =
163*b89261baSDavid van Moolenbroek " PID X THR PRI NICE SIZE RES STATE TIME CPU COMMAND";
164*b89261baSDavid van Moolenbroek
165*b89261baSDavid van Moolenbroek static char proc_header_thr[] =
166*b89261baSDavid van Moolenbroek " PID %-9s THR PRI NICE SIZE RES SHR STATE TIME CPU COMMAND";
167*b89261baSDavid van Moolenbroek
168*b89261baSDavid van Moolenbroek static char proc_header_nothr[] =
169*b89261baSDavid van Moolenbroek " PID %-9s PRI NICE SIZE RES SHR STATE TIME CPU COMMAND";
170*b89261baSDavid van Moolenbroek
171*b89261baSDavid van Moolenbroek /* these are names given to allowed sorting orders -- first is default */
172*b89261baSDavid van Moolenbroek char *ordernames[] =
173*b89261baSDavid van Moolenbroek {"cpu", "size", "res", "time", "command", NULL};
174*b89261baSDavid van Moolenbroek
175*b89261baSDavid van Moolenbroek /* forward definitions for comparison functions */
176*b89261baSDavid van Moolenbroek int compare_cpu();
177*b89261baSDavid van Moolenbroek int compare_size();
178*b89261baSDavid van Moolenbroek int compare_res();
179*b89261baSDavid van Moolenbroek int compare_time();
180*b89261baSDavid van Moolenbroek int compare_cmd();
181*b89261baSDavid van Moolenbroek
182*b89261baSDavid van Moolenbroek int (*proc_compares[])() = {
183*b89261baSDavid van Moolenbroek compare_cpu,
184*b89261baSDavid van Moolenbroek compare_size,
185*b89261baSDavid van Moolenbroek compare_res,
186*b89261baSDavid van Moolenbroek compare_time,
187*b89261baSDavid van Moolenbroek compare_cmd,
188*b89261baSDavid van Moolenbroek NULL };
189*b89261baSDavid van Moolenbroek
190*b89261baSDavid van Moolenbroek /*=SYSTEM STATE INFO====================================================*/
191*b89261baSDavid van Moolenbroek
192*b89261baSDavid van Moolenbroek /* these are for calculating cpu state percentages */
193*b89261baSDavid van Moolenbroek
194*b89261baSDavid van Moolenbroek static long cp_time[NCPUSTATES];
195*b89261baSDavid van Moolenbroek static long cp_old[NCPUSTATES];
196*b89261baSDavid van Moolenbroek static long cp_diff[NCPUSTATES];
197*b89261baSDavid van Moolenbroek
198*b89261baSDavid van Moolenbroek /* for calculating the exponential average */
199*b89261baSDavid van Moolenbroek
200*b89261baSDavid van Moolenbroek static struct timeval lasttime = { 0, 0 };
201*b89261baSDavid van Moolenbroek static struct timeval timediff = { 0, 0 };
202*b89261baSDavid van Moolenbroek static long elapsed_msecs;
203*b89261baSDavid van Moolenbroek
204*b89261baSDavid van Moolenbroek /* these are for keeping track of processes and tasks */
205*b89261baSDavid van Moolenbroek
206*b89261baSDavid van Moolenbroek #define HASH_SIZE (1003)
207*b89261baSDavid van Moolenbroek #define INITIAL_ACTIVE_SIZE (256)
208*b89261baSDavid van Moolenbroek #define PROCBLOCK_SIZE (32)
209*b89261baSDavid van Moolenbroek static hash_table *ptable;
210*b89261baSDavid van Moolenbroek static hash_table *tasktable;
211*b89261baSDavid van Moolenbroek static struct top_proc **pactive;
212*b89261baSDavid van Moolenbroek static struct top_proc **nextactive;
213*b89261baSDavid van Moolenbroek static unsigned int activesize = 0;
214*b89261baSDavid van Moolenbroek static time_t boottime = -1;
215*b89261baSDavid van Moolenbroek static int have_task = 0;
216*b89261baSDavid van Moolenbroek
217*b89261baSDavid van Moolenbroek /* these are counters that need to be track */
218*b89261baSDavid van Moolenbroek static unsigned long last_ctxt = 0;
219*b89261baSDavid van Moolenbroek static unsigned long last_intr = 0;
220*b89261baSDavid van Moolenbroek static unsigned long last_newproc = 0;
221*b89261baSDavid van Moolenbroek static unsigned long last_flt = 0;
222*b89261baSDavid van Moolenbroek
223*b89261baSDavid van Moolenbroek /* these are for passing data back to the machine independant portion */
224*b89261baSDavid van Moolenbroek
225*b89261baSDavid van Moolenbroek static int cpu_states[NCPUSTATES];
226*b89261baSDavid van Moolenbroek static int process_states[NPROCSTATES];
227*b89261baSDavid van Moolenbroek static int kernel_stats[NKERNELSTATS];
228*b89261baSDavid van Moolenbroek static long memory_stats[NMEMSTATS];
229*b89261baSDavid van Moolenbroek static long swap_stats[NSWAPSTATS];
230*b89261baSDavid van Moolenbroek
231*b89261baSDavid van Moolenbroek /* useful macros */
232*b89261baSDavid van Moolenbroek #define bytetok(x) (((x) + 512) >> 10)
233*b89261baSDavid van Moolenbroek #define pagetok(x) ((x) << (PAGE_SHIFT - 10))
234*b89261baSDavid van Moolenbroek #define HASH(x) (((x) * 1686629713U) % HASH_SIZE)
235*b89261baSDavid van Moolenbroek
236*b89261baSDavid van Moolenbroek /* calculate a per-second rate using milliseconds */
237*b89261baSDavid van Moolenbroek #define per_second(n, msec) (((n) * 1000) / (msec))
238*b89261baSDavid van Moolenbroek
239*b89261baSDavid van Moolenbroek /*======================================================================*/
240*b89261baSDavid van Moolenbroek
241*b89261baSDavid van Moolenbroek static inline char *
skip_ws(const char * p)242*b89261baSDavid van Moolenbroek skip_ws(const char *p)
243*b89261baSDavid van Moolenbroek {
244*b89261baSDavid van Moolenbroek while (isspace(*p)) p++;
245*b89261baSDavid van Moolenbroek return (char *)p;
246*b89261baSDavid van Moolenbroek }
247*b89261baSDavid van Moolenbroek
248*b89261baSDavid van Moolenbroek static inline char *
skip_token(const char * p)249*b89261baSDavid van Moolenbroek skip_token(const char *p)
250*b89261baSDavid van Moolenbroek {
251*b89261baSDavid van Moolenbroek while (isspace(*p)) p++;
252*b89261baSDavid van Moolenbroek while (*p && !isspace(*p)) p++;
253*b89261baSDavid van Moolenbroek return (char *)p;
254*b89261baSDavid van Moolenbroek }
255*b89261baSDavid van Moolenbroek
256*b89261baSDavid van Moolenbroek static void
xfrm_cmdline(char * p,int len)257*b89261baSDavid van Moolenbroek xfrm_cmdline(char *p, int len)
258*b89261baSDavid van Moolenbroek {
259*b89261baSDavid van Moolenbroek while (--len > 0)
260*b89261baSDavid van Moolenbroek {
261*b89261baSDavid van Moolenbroek if (*p == '\0')
262*b89261baSDavid van Moolenbroek {
263*b89261baSDavid van Moolenbroek *p = ' ';
264*b89261baSDavid van Moolenbroek }
265*b89261baSDavid van Moolenbroek p++;
266*b89261baSDavid van Moolenbroek }
267*b89261baSDavid van Moolenbroek }
268*b89261baSDavid van Moolenbroek
269*b89261baSDavid van Moolenbroek static void
update_procname(struct top_proc * proc,char * cmd)270*b89261baSDavid van Moolenbroek update_procname(struct top_proc *proc, char *cmd)
271*b89261baSDavid van Moolenbroek
272*b89261baSDavid van Moolenbroek {
273*b89261baSDavid van Moolenbroek printable(cmd);
274*b89261baSDavid van Moolenbroek
275*b89261baSDavid van Moolenbroek if (proc->name == NULL)
276*b89261baSDavid van Moolenbroek {
277*b89261baSDavid van Moolenbroek proc->name = strdup(cmd);
278*b89261baSDavid van Moolenbroek }
279*b89261baSDavid van Moolenbroek else if (strcmp(proc->name, cmd) != 0)
280*b89261baSDavid van Moolenbroek {
281*b89261baSDavid van Moolenbroek free(proc->name);
282*b89261baSDavid van Moolenbroek proc->name = strdup(cmd);
283*b89261baSDavid van Moolenbroek }
284*b89261baSDavid van Moolenbroek }
285*b89261baSDavid van Moolenbroek
286*b89261baSDavid van Moolenbroek /*
287*b89261baSDavid van Moolenbroek * Process structures are allocated and freed as needed. Here we
288*b89261baSDavid van Moolenbroek * keep big pools of them, adding more pool as needed. When a
289*b89261baSDavid van Moolenbroek * top_proc structure is freed, it is added to a freelist and reused.
290*b89261baSDavid van Moolenbroek */
291*b89261baSDavid van Moolenbroek
292*b89261baSDavid van Moolenbroek static struct top_proc *freelist = NULL;
293*b89261baSDavid van Moolenbroek static struct top_proc *procblock = NULL;
294*b89261baSDavid van Moolenbroek static struct top_proc *procmax = NULL;
295*b89261baSDavid van Moolenbroek
296*b89261baSDavid van Moolenbroek static struct top_proc *
new_proc()297*b89261baSDavid van Moolenbroek new_proc()
298*b89261baSDavid van Moolenbroek {
299*b89261baSDavid van Moolenbroek struct top_proc *p;
300*b89261baSDavid van Moolenbroek
301*b89261baSDavid van Moolenbroek if (freelist)
302*b89261baSDavid van Moolenbroek {
303*b89261baSDavid van Moolenbroek p = freelist;
304*b89261baSDavid van Moolenbroek freelist = freelist->next;
305*b89261baSDavid van Moolenbroek }
306*b89261baSDavid van Moolenbroek else if (procblock)
307*b89261baSDavid van Moolenbroek {
308*b89261baSDavid van Moolenbroek p = procblock;
309*b89261baSDavid van Moolenbroek if (++procblock >= procmax)
310*b89261baSDavid van Moolenbroek {
311*b89261baSDavid van Moolenbroek procblock = NULL;
312*b89261baSDavid van Moolenbroek }
313*b89261baSDavid van Moolenbroek }
314*b89261baSDavid van Moolenbroek else
315*b89261baSDavid van Moolenbroek {
316*b89261baSDavid van Moolenbroek p = procblock = (struct top_proc *)calloc(PROCBLOCK_SIZE,
317*b89261baSDavid van Moolenbroek sizeof(struct top_proc));
318*b89261baSDavid van Moolenbroek procmax = procblock++ + PROCBLOCK_SIZE;
319*b89261baSDavid van Moolenbroek }
320*b89261baSDavid van Moolenbroek
321*b89261baSDavid van Moolenbroek /* initialization */
322*b89261baSDavid van Moolenbroek if (p->name != NULL)
323*b89261baSDavid van Moolenbroek {
324*b89261baSDavid van Moolenbroek free(p->name);
325*b89261baSDavid van Moolenbroek p->name = NULL;
326*b89261baSDavid van Moolenbroek }
327*b89261baSDavid van Moolenbroek
328*b89261baSDavid van Moolenbroek return p;
329*b89261baSDavid van Moolenbroek }
330*b89261baSDavid van Moolenbroek
331*b89261baSDavid van Moolenbroek static void
free_proc(struct top_proc * proc)332*b89261baSDavid van Moolenbroek free_proc(struct top_proc *proc)
333*b89261baSDavid van Moolenbroek {
334*b89261baSDavid van Moolenbroek proc->next = freelist;
335*b89261baSDavid van Moolenbroek freelist = proc;
336*b89261baSDavid van Moolenbroek }
337*b89261baSDavid van Moolenbroek
338*b89261baSDavid van Moolenbroek
339*b89261baSDavid van Moolenbroek int
machine_init(struct statics * statics)340*b89261baSDavid van Moolenbroek machine_init(struct statics *statics)
341*b89261baSDavid van Moolenbroek
342*b89261baSDavid van Moolenbroek {
343*b89261baSDavid van Moolenbroek /* make sure the proc filesystem is mounted */
344*b89261baSDavid van Moolenbroek {
345*b89261baSDavid van Moolenbroek struct statfs sb;
346*b89261baSDavid van Moolenbroek if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
347*b89261baSDavid van Moolenbroek {
348*b89261baSDavid van Moolenbroek fprintf(stderr, "%s: proc filesystem not mounted on " PROCFS "\n",
349*b89261baSDavid van Moolenbroek myname);
350*b89261baSDavid van Moolenbroek return -1;
351*b89261baSDavid van Moolenbroek }
352*b89261baSDavid van Moolenbroek }
353*b89261baSDavid van Moolenbroek
354*b89261baSDavid van Moolenbroek /* chdir to the proc filesystem to make things easier */
355*b89261baSDavid van Moolenbroek chdir(PROCFS);
356*b89261baSDavid van Moolenbroek
357*b89261baSDavid van Moolenbroek /* a few preliminary checks */
358*b89261baSDavid van Moolenbroek {
359*b89261baSDavid van Moolenbroek int fd;
360*b89261baSDavid van Moolenbroek char buff[128];
361*b89261baSDavid van Moolenbroek char *p;
362*b89261baSDavid van Moolenbroek int cnt = 0;
363*b89261baSDavid van Moolenbroek unsigned long uptime;
364*b89261baSDavid van Moolenbroek struct timeval tv;
365*b89261baSDavid van Moolenbroek struct stat st;
366*b89261baSDavid van Moolenbroek
367*b89261baSDavid van Moolenbroek /* get a boottime */
368*b89261baSDavid van Moolenbroek if ((fd = open("uptime", 0)) != -1)
369*b89261baSDavid van Moolenbroek {
370*b89261baSDavid van Moolenbroek if (read(fd, buff, sizeof(buff)) > 0)
371*b89261baSDavid van Moolenbroek {
372*b89261baSDavid van Moolenbroek uptime = strtoul(buff, &p, 10);
373*b89261baSDavid van Moolenbroek gettimeofday(&tv, 0);
374*b89261baSDavid van Moolenbroek boottime = tv.tv_sec - uptime;
375*b89261baSDavid van Moolenbroek }
376*b89261baSDavid van Moolenbroek close(fd);
377*b89261baSDavid van Moolenbroek }
378*b89261baSDavid van Moolenbroek
379*b89261baSDavid van Moolenbroek /* see how many states we get from stat */
380*b89261baSDavid van Moolenbroek if ((fd = open("stat", 0)) != -1)
381*b89261baSDavid van Moolenbroek {
382*b89261baSDavid van Moolenbroek if (read(fd, buff, sizeof(buff)) > 0)
383*b89261baSDavid van Moolenbroek {
384*b89261baSDavid van Moolenbroek if ((p = strchr(buff, '\n')) != NULL)
385*b89261baSDavid van Moolenbroek {
386*b89261baSDavid van Moolenbroek *p = '\0';
387*b89261baSDavid van Moolenbroek p = buff;
388*b89261baSDavid van Moolenbroek while (*p != '\0')
389*b89261baSDavid van Moolenbroek {
390*b89261baSDavid van Moolenbroek if (*p++ == ' ')
391*b89261baSDavid van Moolenbroek {
392*b89261baSDavid van Moolenbroek cnt++;
393*b89261baSDavid van Moolenbroek }
394*b89261baSDavid van Moolenbroek }
395*b89261baSDavid van Moolenbroek }
396*b89261baSDavid van Moolenbroek }
397*b89261baSDavid van Moolenbroek
398*b89261baSDavid van Moolenbroek close(fd);
399*b89261baSDavid van Moolenbroek }
400*b89261baSDavid van Moolenbroek if (cnt > 5)
401*b89261baSDavid van Moolenbroek {
402*b89261baSDavid van Moolenbroek /* we have iowait */
403*b89261baSDavid van Moolenbroek show_iowait = 1;
404*b89261baSDavid van Moolenbroek }
405*b89261baSDavid van Moolenbroek
406*b89261baSDavid van Moolenbroek /* see if we have task subdirs */
407*b89261baSDavid van Moolenbroek if (stat("self/task", &st) != -1 && S_ISDIR(st.st_mode))
408*b89261baSDavid van Moolenbroek {
409*b89261baSDavid van Moolenbroek dprintf("we have task directories\n");
410*b89261baSDavid van Moolenbroek have_task = 1;
411*b89261baSDavid van Moolenbroek }
412*b89261baSDavid van Moolenbroek }
413*b89261baSDavid van Moolenbroek
414*b89261baSDavid van Moolenbroek /* if we aren't showing iowait, then we have to tweak cpustatenames */
415*b89261baSDavid van Moolenbroek if (!show_iowait)
416*b89261baSDavid van Moolenbroek {
417*b89261baSDavid van Moolenbroek cpustatenames[4] = NULL;
418*b89261baSDavid van Moolenbroek }
419*b89261baSDavid van Moolenbroek
420*b89261baSDavid van Moolenbroek /* fill in the statics information */
421*b89261baSDavid van Moolenbroek statics->procstate_names = procstatenames;
422*b89261baSDavid van Moolenbroek statics->cpustate_names = cpustatenames;
423*b89261baSDavid van Moolenbroek statics->kernel_names = kernelnames;
424*b89261baSDavid van Moolenbroek statics->memory_names = memorynames;
425*b89261baSDavid van Moolenbroek statics->swap_names = swapnames;
426*b89261baSDavid van Moolenbroek statics->order_names = ordernames;
427*b89261baSDavid van Moolenbroek statics->boottime = boottime;
428*b89261baSDavid van Moolenbroek statics->flags.fullcmds = 1;
429*b89261baSDavid van Moolenbroek statics->flags.warmup = 1;
430*b89261baSDavid van Moolenbroek statics->flags.threads = 1;
431*b89261baSDavid van Moolenbroek
432*b89261baSDavid van Moolenbroek /* allocate needed space */
433*b89261baSDavid van Moolenbroek pactive = (struct top_proc **)malloc(sizeof(struct top_proc *) * INITIAL_ACTIVE_SIZE);
434*b89261baSDavid van Moolenbroek activesize = INITIAL_ACTIVE_SIZE;
435*b89261baSDavid van Moolenbroek
436*b89261baSDavid van Moolenbroek /* create process and task hashes */
437*b89261baSDavid van Moolenbroek ptable = hash_create(HASH_SIZE);
438*b89261baSDavid van Moolenbroek tasktable = hash_create(HASH_SIZE);
439*b89261baSDavid van Moolenbroek
440*b89261baSDavid van Moolenbroek /* all done! */
441*b89261baSDavid van Moolenbroek return 0;
442*b89261baSDavid van Moolenbroek }
443*b89261baSDavid van Moolenbroek
444*b89261baSDavid van Moolenbroek
445*b89261baSDavid van Moolenbroek void
get_system_info(struct system_info * info)446*b89261baSDavid van Moolenbroek get_system_info(struct system_info *info)
447*b89261baSDavid van Moolenbroek
448*b89261baSDavid van Moolenbroek {
449*b89261baSDavid van Moolenbroek char buffer[4096+1];
450*b89261baSDavid van Moolenbroek int fd, len;
451*b89261baSDavid van Moolenbroek char *p;
452*b89261baSDavid van Moolenbroek struct timeval thistime;
453*b89261baSDavid van Moolenbroek unsigned long intr = 0;
454*b89261baSDavid van Moolenbroek unsigned long ctxt = 0;
455*b89261baSDavid van Moolenbroek unsigned long newproc = 0;
456*b89261baSDavid van Moolenbroek unsigned long flt = 0;
457*b89261baSDavid van Moolenbroek
458*b89261baSDavid van Moolenbroek /* timestamp and time difference */
459*b89261baSDavid van Moolenbroek gettimeofday(&thistime, 0);
460*b89261baSDavid van Moolenbroek timersub(&thistime, &lasttime, &timediff);
461*b89261baSDavid van Moolenbroek elapsed_msecs = timediff.tv_sec * 1000 + timediff.tv_usec / 1000;
462*b89261baSDavid van Moolenbroek lasttime = thistime;
463*b89261baSDavid van Moolenbroek
464*b89261baSDavid van Moolenbroek /* get load averages */
465*b89261baSDavid van Moolenbroek if ((fd = open("loadavg", O_RDONLY)) != -1)
466*b89261baSDavid van Moolenbroek {
467*b89261baSDavid van Moolenbroek if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
468*b89261baSDavid van Moolenbroek {
469*b89261baSDavid van Moolenbroek buffer[len] = '\0';
470*b89261baSDavid van Moolenbroek info->load_avg[0] = strtod(buffer, &p);
471*b89261baSDavid van Moolenbroek info->load_avg[1] = strtod(p, &p);
472*b89261baSDavid van Moolenbroek info->load_avg[2] = strtod(p, &p);
473*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip running/tasks */
474*b89261baSDavid van Moolenbroek p = skip_ws(p);
475*b89261baSDavid van Moolenbroek if (*p)
476*b89261baSDavid van Moolenbroek {
477*b89261baSDavid van Moolenbroek info->last_pid = atoi(p);
478*b89261baSDavid van Moolenbroek }
479*b89261baSDavid van Moolenbroek else
480*b89261baSDavid van Moolenbroek {
481*b89261baSDavid van Moolenbroek info->last_pid = -1;
482*b89261baSDavid van Moolenbroek }
483*b89261baSDavid van Moolenbroek }
484*b89261baSDavid van Moolenbroek close(fd);
485*b89261baSDavid van Moolenbroek }
486*b89261baSDavid van Moolenbroek
487*b89261baSDavid van Moolenbroek /* get the cpu time info */
488*b89261baSDavid van Moolenbroek if ((fd = open("stat", O_RDONLY)) != -1)
489*b89261baSDavid van Moolenbroek {
490*b89261baSDavid van Moolenbroek if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
491*b89261baSDavid van Moolenbroek {
492*b89261baSDavid van Moolenbroek buffer[len] = '\0';
493*b89261baSDavid van Moolenbroek p = skip_token(buffer); /* "cpu" */
494*b89261baSDavid van Moolenbroek cp_time[0] = strtoul(p, &p, 0);
495*b89261baSDavid van Moolenbroek cp_time[1] = strtoul(p, &p, 0);
496*b89261baSDavid van Moolenbroek cp_time[2] = strtoul(p, &p, 0);
497*b89261baSDavid van Moolenbroek cp_time[3] = strtoul(p, &p, 0);
498*b89261baSDavid van Moolenbroek if (show_iowait)
499*b89261baSDavid van Moolenbroek {
500*b89261baSDavid van Moolenbroek cp_time[4] = strtoul(p, &p, 0);
501*b89261baSDavid van Moolenbroek }
502*b89261baSDavid van Moolenbroek
503*b89261baSDavid van Moolenbroek /* convert cp_time counts to percentages */
504*b89261baSDavid van Moolenbroek percentages(NCPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
505*b89261baSDavid van Moolenbroek
506*b89261baSDavid van Moolenbroek /* get the rest of it */
507*b89261baSDavid van Moolenbroek p = strchr(p, '\n');
508*b89261baSDavid van Moolenbroek while (p != NULL)
509*b89261baSDavid van Moolenbroek {
510*b89261baSDavid van Moolenbroek p++;
511*b89261baSDavid van Moolenbroek if (strncmp(p, "intr ", 5) == 0)
512*b89261baSDavid van Moolenbroek {
513*b89261baSDavid van Moolenbroek p = skip_token(p);
514*b89261baSDavid van Moolenbroek intr = strtoul(p, &p, 10);
515*b89261baSDavid van Moolenbroek }
516*b89261baSDavid van Moolenbroek else if (strncmp(p, "ctxt ", 5) == 0)
517*b89261baSDavid van Moolenbroek {
518*b89261baSDavid van Moolenbroek p = skip_token(p);
519*b89261baSDavid van Moolenbroek ctxt = strtoul(p, &p, 10);
520*b89261baSDavid van Moolenbroek }
521*b89261baSDavid van Moolenbroek else if (strncmp(p, "processes ", 10) == 0)
522*b89261baSDavid van Moolenbroek {
523*b89261baSDavid van Moolenbroek p = skip_token(p);
524*b89261baSDavid van Moolenbroek newproc = strtoul(p, &p, 10);
525*b89261baSDavid van Moolenbroek }
526*b89261baSDavid van Moolenbroek
527*b89261baSDavid van Moolenbroek p = strchr(p, '\n');
528*b89261baSDavid van Moolenbroek }
529*b89261baSDavid van Moolenbroek
530*b89261baSDavid van Moolenbroek kernel_stats[KERNELINTR] = per_second(intr - last_intr, elapsed_msecs);
531*b89261baSDavid van Moolenbroek kernel_stats[KERNELCTXT] = per_second(ctxt - last_ctxt, elapsed_msecs);
532*b89261baSDavid van Moolenbroek kernel_stats[KERNELNEWPROC] = per_second(newproc - last_newproc, elapsed_msecs);
533*b89261baSDavid van Moolenbroek last_intr = intr;
534*b89261baSDavid van Moolenbroek last_ctxt = ctxt;
535*b89261baSDavid van Moolenbroek last_newproc = newproc;
536*b89261baSDavid van Moolenbroek }
537*b89261baSDavid van Moolenbroek close(fd);
538*b89261baSDavid van Moolenbroek }
539*b89261baSDavid van Moolenbroek
540*b89261baSDavid van Moolenbroek /* get system wide memory usage */
541*b89261baSDavid van Moolenbroek if ((fd = open("meminfo", O_RDONLY)) != -1)
542*b89261baSDavid van Moolenbroek {
543*b89261baSDavid van Moolenbroek char *p;
544*b89261baSDavid van Moolenbroek int mem = 0;
545*b89261baSDavid van Moolenbroek int swap = 0;
546*b89261baSDavid van Moolenbroek unsigned long memtotal = 0;
547*b89261baSDavid van Moolenbroek unsigned long memfree = 0;
548*b89261baSDavid van Moolenbroek unsigned long swaptotal = 0;
549*b89261baSDavid van Moolenbroek
550*b89261baSDavid van Moolenbroek if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
551*b89261baSDavid van Moolenbroek {
552*b89261baSDavid van Moolenbroek buffer[len] = '\0';
553*b89261baSDavid van Moolenbroek p = buffer-1;
554*b89261baSDavid van Moolenbroek
555*b89261baSDavid van Moolenbroek /* iterate thru the lines */
556*b89261baSDavid van Moolenbroek while (p != NULL)
557*b89261baSDavid van Moolenbroek {
558*b89261baSDavid van Moolenbroek p++;
559*b89261baSDavid van Moolenbroek if (p[0] == ' ' || p[0] == '\t')
560*b89261baSDavid van Moolenbroek {
561*b89261baSDavid van Moolenbroek /* skip */
562*b89261baSDavid van Moolenbroek }
563*b89261baSDavid van Moolenbroek else if (strncmp(p, "Mem:", 4) == 0)
564*b89261baSDavid van Moolenbroek {
565*b89261baSDavid van Moolenbroek p = skip_token(p); /* "Mem:" */
566*b89261baSDavid van Moolenbroek p = skip_token(p); /* total memory */
567*b89261baSDavid van Moolenbroek memory_stats[MEMUSED] = strtoul(p, &p, 10);
568*b89261baSDavid van Moolenbroek memory_stats[MEMFREE] = strtoul(p, &p, 10);
569*b89261baSDavid van Moolenbroek memory_stats[MEMSHARED] = strtoul(p, &p, 10);
570*b89261baSDavid van Moolenbroek memory_stats[MEMBUFFERS] = strtoul(p, &p, 10);
571*b89261baSDavid van Moolenbroek memory_stats[MEMCACHED] = strtoul(p, &p, 10);
572*b89261baSDavid van Moolenbroek memory_stats[MEMUSED] = bytetok(memory_stats[MEMUSED]);
573*b89261baSDavid van Moolenbroek memory_stats[MEMFREE] = bytetok(memory_stats[MEMFREE]);
574*b89261baSDavid van Moolenbroek memory_stats[MEMSHARED] = bytetok(memory_stats[MEMSHARED]);
575*b89261baSDavid van Moolenbroek memory_stats[MEMBUFFERS] = bytetok(memory_stats[MEMBUFFERS]);
576*b89261baSDavid van Moolenbroek memory_stats[MEMCACHED] = bytetok(memory_stats[MEMCACHED]);
577*b89261baSDavid van Moolenbroek mem = 1;
578*b89261baSDavid van Moolenbroek }
579*b89261baSDavid van Moolenbroek else if (strncmp(p, "Swap:", 5) == 0)
580*b89261baSDavid van Moolenbroek {
581*b89261baSDavid van Moolenbroek p = skip_token(p); /* "Swap:" */
582*b89261baSDavid van Moolenbroek p = skip_token(p); /* total swap */
583*b89261baSDavid van Moolenbroek swap_stats[SWAPUSED] = strtoul(p, &p, 10);
584*b89261baSDavid van Moolenbroek swap_stats[SWAPFREE] = strtoul(p, &p, 10);
585*b89261baSDavid van Moolenbroek swap_stats[SWAPUSED] = bytetok(swap_stats[SWAPUSED]);
586*b89261baSDavid van Moolenbroek swap_stats[SWAPFREE] = bytetok(swap_stats[SWAPFREE]);
587*b89261baSDavid van Moolenbroek swap = 1;
588*b89261baSDavid van Moolenbroek }
589*b89261baSDavid van Moolenbroek else if (!mem && strncmp(p, "MemTotal:", 9) == 0)
590*b89261baSDavid van Moolenbroek {
591*b89261baSDavid van Moolenbroek p = skip_token(p);
592*b89261baSDavid van Moolenbroek memtotal = strtoul(p, &p, 10);
593*b89261baSDavid van Moolenbroek }
594*b89261baSDavid van Moolenbroek else if (!mem && memtotal > 0 && strncmp(p, "MemFree:", 8) == 0)
595*b89261baSDavid van Moolenbroek {
596*b89261baSDavid van Moolenbroek p = skip_token(p);
597*b89261baSDavid van Moolenbroek memfree = strtoul(p, &p, 10);
598*b89261baSDavid van Moolenbroek memory_stats[MEMUSED] = memtotal - memfree;
599*b89261baSDavid van Moolenbroek memory_stats[MEMFREE] = memfree;
600*b89261baSDavid van Moolenbroek }
601*b89261baSDavid van Moolenbroek else if (!mem && strncmp(p, "MemShared:", 10) == 0)
602*b89261baSDavid van Moolenbroek {
603*b89261baSDavid van Moolenbroek p = skip_token(p);
604*b89261baSDavid van Moolenbroek memory_stats[MEMSHARED] = strtoul(p, &p, 10);
605*b89261baSDavid van Moolenbroek }
606*b89261baSDavid van Moolenbroek else if (!mem && strncmp(p, "Buffers:", 8) == 0)
607*b89261baSDavid van Moolenbroek {
608*b89261baSDavid van Moolenbroek p = skip_token(p);
609*b89261baSDavid van Moolenbroek memory_stats[MEMBUFFERS] = strtoul(p, &p, 10);
610*b89261baSDavid van Moolenbroek }
611*b89261baSDavid van Moolenbroek else if (!mem && strncmp(p, "Cached:", 7) == 0)
612*b89261baSDavid van Moolenbroek {
613*b89261baSDavid van Moolenbroek p = skip_token(p);
614*b89261baSDavid van Moolenbroek memory_stats[MEMCACHED] = strtoul(p, &p, 10);
615*b89261baSDavid van Moolenbroek }
616*b89261baSDavid van Moolenbroek else if (!swap && strncmp(p, "SwapTotal:", 10) == 0)
617*b89261baSDavid van Moolenbroek {
618*b89261baSDavid van Moolenbroek p = skip_token(p);
619*b89261baSDavid van Moolenbroek swaptotal = strtoul(p, &p, 10);
620*b89261baSDavid van Moolenbroek }
621*b89261baSDavid van Moolenbroek else if (!swap && swaptotal > 0 && strncmp(p, "SwapFree:", 9) == 0)
622*b89261baSDavid van Moolenbroek {
623*b89261baSDavid van Moolenbroek p = skip_token(p);
624*b89261baSDavid van Moolenbroek memfree = strtoul(p, &p, 10);
625*b89261baSDavid van Moolenbroek swap_stats[SWAPUSED] = swaptotal - memfree;
626*b89261baSDavid van Moolenbroek swap_stats[SWAPFREE] = memfree;
627*b89261baSDavid van Moolenbroek }
628*b89261baSDavid van Moolenbroek else if (!mem && strncmp(p, "SwapCached:", 11) == 0)
629*b89261baSDavid van Moolenbroek {
630*b89261baSDavid van Moolenbroek p = skip_token(p);
631*b89261baSDavid van Moolenbroek swap_stats[SWAPCACHED] = strtoul(p, &p, 10);
632*b89261baSDavid van Moolenbroek }
633*b89261baSDavid van Moolenbroek
634*b89261baSDavid van Moolenbroek /* move to the next line */
635*b89261baSDavid van Moolenbroek p = strchr(p, '\n');
636*b89261baSDavid van Moolenbroek }
637*b89261baSDavid van Moolenbroek }
638*b89261baSDavid van Moolenbroek close(fd);
639*b89261baSDavid van Moolenbroek }
640*b89261baSDavid van Moolenbroek
641*b89261baSDavid van Moolenbroek /* get vm related stuff */
642*b89261baSDavid van Moolenbroek if ((fd = open("vmstat", O_RDONLY)) != -1)
643*b89261baSDavid van Moolenbroek {
644*b89261baSDavid van Moolenbroek char *p;
645*b89261baSDavid van Moolenbroek
646*b89261baSDavid van Moolenbroek if ((len = read(fd, buffer, sizeof(buffer)-1)) > 0)
647*b89261baSDavid van Moolenbroek {
648*b89261baSDavid van Moolenbroek buffer[len] = '\0';
649*b89261baSDavid van Moolenbroek p = buffer;
650*b89261baSDavid van Moolenbroek
651*b89261baSDavid van Moolenbroek /* iterate thru the lines */
652*b89261baSDavid van Moolenbroek while (p != NULL)
653*b89261baSDavid van Moolenbroek {
654*b89261baSDavid van Moolenbroek if (strncmp(p, "pgmajfault ", 11) == 0)
655*b89261baSDavid van Moolenbroek {
656*b89261baSDavid van Moolenbroek p = skip_token(p);
657*b89261baSDavid van Moolenbroek flt = strtoul(p, &p, 10);
658*b89261baSDavid van Moolenbroek kernel_stats[KERNELFLT] = per_second(flt - last_flt, elapsed_msecs);
659*b89261baSDavid van Moolenbroek last_flt = flt;
660*b89261baSDavid van Moolenbroek break;
661*b89261baSDavid van Moolenbroek }
662*b89261baSDavid van Moolenbroek
663*b89261baSDavid van Moolenbroek /* move to the next line */
664*b89261baSDavid van Moolenbroek p = strchr(p, '\n');
665*b89261baSDavid van Moolenbroek p++;
666*b89261baSDavid van Moolenbroek }
667*b89261baSDavid van Moolenbroek }
668*b89261baSDavid van Moolenbroek close(fd);
669*b89261baSDavid van Moolenbroek }
670*b89261baSDavid van Moolenbroek
671*b89261baSDavid van Moolenbroek /* set arrays and strings */
672*b89261baSDavid van Moolenbroek info->cpustates = cpu_states;
673*b89261baSDavid van Moolenbroek info->memory = memory_stats;
674*b89261baSDavid van Moolenbroek info->swap = swap_stats;
675*b89261baSDavid van Moolenbroek info->kernel = kernel_stats;
676*b89261baSDavid van Moolenbroek }
677*b89261baSDavid van Moolenbroek
678*b89261baSDavid van Moolenbroek static void
read_one_proc_stat(pid_t pid,pid_t taskpid,struct top_proc * proc,struct process_select * sel)679*b89261baSDavid van Moolenbroek read_one_proc_stat(pid_t pid, pid_t taskpid, struct top_proc *proc, struct process_select *sel)
680*b89261baSDavid van Moolenbroek {
681*b89261baSDavid van Moolenbroek char buffer[4096], *p, *q;
682*b89261baSDavid van Moolenbroek int fd, len;
683*b89261baSDavid van Moolenbroek int fullcmd;
684*b89261baSDavid van Moolenbroek
685*b89261baSDavid van Moolenbroek dprintf("reading proc %d - %d\n", pid, taskpid);
686*b89261baSDavid van Moolenbroek
687*b89261baSDavid van Moolenbroek /* if anything goes wrong, we return with proc->state == 0 */
688*b89261baSDavid van Moolenbroek proc->state = 0;
689*b89261baSDavid van Moolenbroek
690*b89261baSDavid van Moolenbroek /* full cmd handling */
691*b89261baSDavid van Moolenbroek fullcmd = sel->fullcmd;
692*b89261baSDavid van Moolenbroek if (fullcmd)
693*b89261baSDavid van Moolenbroek {
694*b89261baSDavid van Moolenbroek if (taskpid == -1)
695*b89261baSDavid van Moolenbroek {
696*b89261baSDavid van Moolenbroek sprintf(buffer, "%d/cmdline", pid);
697*b89261baSDavid van Moolenbroek }
698*b89261baSDavid van Moolenbroek else
699*b89261baSDavid van Moolenbroek {
700*b89261baSDavid van Moolenbroek sprintf(buffer, "%d/task/%d/cmdline", pid, taskpid);
701*b89261baSDavid van Moolenbroek }
702*b89261baSDavid van Moolenbroek if ((fd = open(buffer, O_RDONLY)) != -1)
703*b89261baSDavid van Moolenbroek {
704*b89261baSDavid van Moolenbroek /* read command line data */
705*b89261baSDavid van Moolenbroek /* (theres no sense in reading more than we can fit) */
706*b89261baSDavid van Moolenbroek if ((len = read(fd, buffer, MAX_COLS)) > 1)
707*b89261baSDavid van Moolenbroek {
708*b89261baSDavid van Moolenbroek buffer[len] = '\0';
709*b89261baSDavid van Moolenbroek xfrm_cmdline(buffer, len);
710*b89261baSDavid van Moolenbroek update_procname(proc, buffer);
711*b89261baSDavid van Moolenbroek }
712*b89261baSDavid van Moolenbroek else
713*b89261baSDavid van Moolenbroek {
714*b89261baSDavid van Moolenbroek fullcmd = 0;
715*b89261baSDavid van Moolenbroek }
716*b89261baSDavid van Moolenbroek close(fd);
717*b89261baSDavid van Moolenbroek }
718*b89261baSDavid van Moolenbroek else
719*b89261baSDavid van Moolenbroek {
720*b89261baSDavid van Moolenbroek fullcmd = 0;
721*b89261baSDavid van Moolenbroek }
722*b89261baSDavid van Moolenbroek }
723*b89261baSDavid van Moolenbroek
724*b89261baSDavid van Moolenbroek /* grab the shared memory size */
725*b89261baSDavid van Moolenbroek sprintf(buffer, "%d/statm", pid);
726*b89261baSDavid van Moolenbroek fd = open(buffer, O_RDONLY);
727*b89261baSDavid van Moolenbroek len = read(fd, buffer, sizeof(buffer)-1);
728*b89261baSDavid van Moolenbroek close(fd);
729*b89261baSDavid van Moolenbroek buffer[len] = '\0';
730*b89261baSDavid van Moolenbroek p = buffer;
731*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip size */
732*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip resident */
733*b89261baSDavid van Moolenbroek proc->shared = pagetok(strtoul(p, &p, 10));
734*b89261baSDavid van Moolenbroek
735*b89261baSDavid van Moolenbroek /* grab the proc stat info in one go */
736*b89261baSDavid van Moolenbroek if (taskpid == -1)
737*b89261baSDavid van Moolenbroek {
738*b89261baSDavid van Moolenbroek sprintf(buffer, "%d/stat", pid);
739*b89261baSDavid van Moolenbroek }
740*b89261baSDavid van Moolenbroek else
741*b89261baSDavid van Moolenbroek {
742*b89261baSDavid van Moolenbroek sprintf(buffer, "%d/task/%d/stat", pid, taskpid);
743*b89261baSDavid van Moolenbroek }
744*b89261baSDavid van Moolenbroek
745*b89261baSDavid van Moolenbroek fd = open(buffer, O_RDONLY);
746*b89261baSDavid van Moolenbroek len = read(fd, buffer, sizeof(buffer)-1);
747*b89261baSDavid van Moolenbroek close(fd);
748*b89261baSDavid van Moolenbroek
749*b89261baSDavid van Moolenbroek buffer[len] = '\0';
750*b89261baSDavid van Moolenbroek
751*b89261baSDavid van Moolenbroek proc->uid = (uid_t)proc_owner((int)pid);
752*b89261baSDavid van Moolenbroek
753*b89261baSDavid van Moolenbroek /* parse out the status */
754*b89261baSDavid van Moolenbroek
755*b89261baSDavid van Moolenbroek /* skip pid and locate command, which is in parentheses */
756*b89261baSDavid van Moolenbroek if ((p = strchr(buffer, '(')) == NULL)
757*b89261baSDavid van Moolenbroek {
758*b89261baSDavid van Moolenbroek return;
759*b89261baSDavid van Moolenbroek }
760*b89261baSDavid van Moolenbroek if ((q = strrchr(++p, ')')) == NULL)
761*b89261baSDavid van Moolenbroek {
762*b89261baSDavid van Moolenbroek return;
763*b89261baSDavid van Moolenbroek }
764*b89261baSDavid van Moolenbroek
765*b89261baSDavid van Moolenbroek /* set the procname */
766*b89261baSDavid van Moolenbroek *q = '\0';
767*b89261baSDavid van Moolenbroek if (!fullcmd)
768*b89261baSDavid van Moolenbroek {
769*b89261baSDavid van Moolenbroek update_procname(proc, p);
770*b89261baSDavid van Moolenbroek }
771*b89261baSDavid van Moolenbroek
772*b89261baSDavid van Moolenbroek /* scan the rest of the line */
773*b89261baSDavid van Moolenbroek p = q+1;
774*b89261baSDavid van Moolenbroek p = skip_ws(p);
775*b89261baSDavid van Moolenbroek switch (*p++) /* state */
776*b89261baSDavid van Moolenbroek {
777*b89261baSDavid van Moolenbroek case 'R': proc->state = 1; break;
778*b89261baSDavid van Moolenbroek case 'S': proc->state = 2; break;
779*b89261baSDavid van Moolenbroek case 'D': proc->state = 3; break;
780*b89261baSDavid van Moolenbroek case 'Z': proc->state = 4; break;
781*b89261baSDavid van Moolenbroek case 'T': proc->state = 5; break;
782*b89261baSDavid van Moolenbroek case 'W': proc->state = 6; break;
783*b89261baSDavid van Moolenbroek case '\0': return;
784*b89261baSDavid van Moolenbroek }
785*b89261baSDavid van Moolenbroek
786*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip ppid */
787*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip pgrp */
788*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip session */
789*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip tty */
790*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip tty pgrp */
791*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip flags */
792*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip min flt */
793*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip cmin flt */
794*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip maj flt */
795*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip cmaj flt */
796*b89261baSDavid van Moolenbroek
797*b89261baSDavid van Moolenbroek proc->time = strtoul(p, &p, 10); /* utime */
798*b89261baSDavid van Moolenbroek proc->time += strtoul(p, &p, 10); /* stime */
799*b89261baSDavid van Moolenbroek
800*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip cutime */
801*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip cstime */
802*b89261baSDavid van Moolenbroek
803*b89261baSDavid van Moolenbroek proc->pri = strtol(p, &p, 10); /* priority */
804*b89261baSDavid van Moolenbroek proc->nice = strtol(p, &p, 10); /* nice */
805*b89261baSDavid van Moolenbroek proc->threads = strtol(p, &p, 10); /* threads */
806*b89261baSDavid van Moolenbroek
807*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip it_real_val */
808*b89261baSDavid van Moolenbroek proc->start_time = strtoul(p, &p, 10); /* start_time */
809*b89261baSDavid van Moolenbroek
810*b89261baSDavid van Moolenbroek proc->size = bytetok(strtoul(p, &p, 10)); /* vsize */
811*b89261baSDavid van Moolenbroek proc->rss = pagetok(strtoul(p, &p, 10)); /* rss */
812*b89261baSDavid van Moolenbroek
813*b89261baSDavid van Moolenbroek #if 0
814*b89261baSDavid van Moolenbroek /* for the record, here are the rest of the fields */
815*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip rlim */
816*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip start_code */
817*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip end_code */
818*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip start_stack */
819*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip sp */
820*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip pc */
821*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip signal */
822*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip sigblocked */
823*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip sigignore */
824*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip sigcatch */
825*b89261baSDavid van Moolenbroek p = skip_token(p); /* skip wchan */
826*b89261baSDavid van Moolenbroek #endif
827*b89261baSDavid van Moolenbroek
828*b89261baSDavid van Moolenbroek }
829*b89261baSDavid van Moolenbroek
830*b89261baSDavid van Moolenbroek static int show_usernames;
831*b89261baSDavid van Moolenbroek static int show_threads;
832*b89261baSDavid van Moolenbroek
833*b89261baSDavid van Moolenbroek
834*b89261baSDavid van Moolenbroek caddr_t
get_process_info(struct system_info * si,struct process_select * sel,int compare_index)835*b89261baSDavid van Moolenbroek get_process_info(struct system_info *si,
836*b89261baSDavid van Moolenbroek struct process_select *sel,
837*b89261baSDavid van Moolenbroek int compare_index)
838*b89261baSDavid van Moolenbroek {
839*b89261baSDavid van Moolenbroek struct top_proc *proc;
840*b89261baSDavid van Moolenbroek struct top_proc *taskproc;
841*b89261baSDavid van Moolenbroek pid_t pid;
842*b89261baSDavid van Moolenbroek pid_t taskpid;
843*b89261baSDavid van Moolenbroek unsigned long now;
844*b89261baSDavid van Moolenbroek unsigned long elapsed;
845*b89261baSDavid van Moolenbroek hash_item_pid *hi;
846*b89261baSDavid van Moolenbroek hash_pos pos;
847*b89261baSDavid van Moolenbroek
848*b89261baSDavid van Moolenbroek /* round current time to a second */
849*b89261baSDavid van Moolenbroek now = (unsigned long)lasttime.tv_sec;
850*b89261baSDavid van Moolenbroek if (lasttime.tv_usec >= 500000)
851*b89261baSDavid van Moolenbroek {
852*b89261baSDavid van Moolenbroek now++;
853*b89261baSDavid van Moolenbroek }
854*b89261baSDavid van Moolenbroek
855*b89261baSDavid van Moolenbroek /* calculate number of ticks since our last check */
856*b89261baSDavid van Moolenbroek elapsed = timediff.tv_sec * HZ + (timediff.tv_usec * HZ) / 1000000;
857*b89261baSDavid van Moolenbroek if (elapsed <= 0)
858*b89261baSDavid van Moolenbroek {
859*b89261baSDavid van Moolenbroek elapsed = 1;
860*b89261baSDavid van Moolenbroek }
861*b89261baSDavid van Moolenbroek dprintf("get_process_info: elapsed %d ticks\n", elapsed);
862*b89261baSDavid van Moolenbroek
863*b89261baSDavid van Moolenbroek /* mark all hash table entries as not seen */
864*b89261baSDavid van Moolenbroek hi = hash_first_pid(ptable, &pos);
865*b89261baSDavid van Moolenbroek while (hi != NULL)
866*b89261baSDavid van Moolenbroek {
867*b89261baSDavid van Moolenbroek ((struct top_proc *)(hi->value))->state = 0;
868*b89261baSDavid van Moolenbroek hi = hash_next_pid(&pos);
869*b89261baSDavid van Moolenbroek }
870*b89261baSDavid van Moolenbroek /* mark all hash table entries as not seen */
871*b89261baSDavid van Moolenbroek hi = hash_first_pid(tasktable, &pos);
872*b89261baSDavid van Moolenbroek while (hi != NULL)
873*b89261baSDavid van Moolenbroek {
874*b89261baSDavid van Moolenbroek ((struct top_proc *)(hi->value))->state = 0;
875*b89261baSDavid van Moolenbroek hi = hash_next_pid(&pos);
876*b89261baSDavid van Moolenbroek }
877*b89261baSDavid van Moolenbroek
878*b89261baSDavid van Moolenbroek /* read the process information */
879*b89261baSDavid van Moolenbroek {
880*b89261baSDavid van Moolenbroek DIR *dir = opendir(".");
881*b89261baSDavid van Moolenbroek DIR *taskdir;
882*b89261baSDavid van Moolenbroek struct dirent *ent;
883*b89261baSDavid van Moolenbroek struct dirent *taskent;
884*b89261baSDavid van Moolenbroek int total_procs = 0;
885*b89261baSDavid van Moolenbroek struct top_proc **active;
886*b89261baSDavid van Moolenbroek hash_item_pid *hi;
887*b89261baSDavid van Moolenbroek hash_pos pos;
888*b89261baSDavid van Moolenbroek char buffer[64];
889*b89261baSDavid van Moolenbroek
890*b89261baSDavid van Moolenbroek int show_idle = sel->idle;
891*b89261baSDavid van Moolenbroek int show_uid = sel->uid != -1;
892*b89261baSDavid van Moolenbroek char *show_command = sel->command;
893*b89261baSDavid van Moolenbroek
894*b89261baSDavid van Moolenbroek show_usernames = sel->usernames;
895*b89261baSDavid van Moolenbroek show_threads = sel->threads && have_task;
896*b89261baSDavid van Moolenbroek
897*b89261baSDavid van Moolenbroek memset(process_states, 0, sizeof(process_states));
898*b89261baSDavid van Moolenbroek
899*b89261baSDavid van Moolenbroek taskdir = NULL;
900*b89261baSDavid van Moolenbroek taskent = NULL;
901*b89261baSDavid van Moolenbroek taskpid = -1;
902*b89261baSDavid van Moolenbroek
903*b89261baSDavid van Moolenbroek while ((ent = readdir(dir)) != NULL)
904*b89261baSDavid van Moolenbroek {
905*b89261baSDavid van Moolenbroek unsigned long otime;
906*b89261baSDavid van Moolenbroek
907*b89261baSDavid van Moolenbroek if (!isdigit(ent->d_name[0]))
908*b89261baSDavid van Moolenbroek continue;
909*b89261baSDavid van Moolenbroek
910*b89261baSDavid van Moolenbroek pid = atoi(ent->d_name);
911*b89261baSDavid van Moolenbroek
912*b89261baSDavid van Moolenbroek /* look up hash table entry */
913*b89261baSDavid van Moolenbroek proc = hash_lookup_pid(ptable, pid);
914*b89261baSDavid van Moolenbroek
915*b89261baSDavid van Moolenbroek /* if we came up empty, create a new entry */
916*b89261baSDavid van Moolenbroek if (proc == NULL)
917*b89261baSDavid van Moolenbroek {
918*b89261baSDavid van Moolenbroek proc = new_proc();
919*b89261baSDavid van Moolenbroek proc->pid = pid;
920*b89261baSDavid van Moolenbroek proc->time = 0;
921*b89261baSDavid van Moolenbroek hash_add_pid(ptable, pid, (void *)proc);
922*b89261baSDavid van Moolenbroek }
923*b89261baSDavid van Moolenbroek
924*b89261baSDavid van Moolenbroek /* remember the previous cpu time */
925*b89261baSDavid van Moolenbroek otime = proc->time;
926*b89261baSDavid van Moolenbroek
927*b89261baSDavid van Moolenbroek /* get current data */
928*b89261baSDavid van Moolenbroek read_one_proc_stat(pid, -1, proc, sel);
929*b89261baSDavid van Moolenbroek
930*b89261baSDavid van Moolenbroek /* continue on if this isn't really a process */
931*b89261baSDavid van Moolenbroek if (proc->state == 0)
932*b89261baSDavid van Moolenbroek continue;
933*b89261baSDavid van Moolenbroek
934*b89261baSDavid van Moolenbroek /* reset linked list (for threads) */
935*b89261baSDavid van Moolenbroek proc->next = NULL;
936*b89261baSDavid van Moolenbroek
937*b89261baSDavid van Moolenbroek /* accumulate process state data */
938*b89261baSDavid van Moolenbroek total_procs++;
939*b89261baSDavid van Moolenbroek process_states[proc->state]++;
940*b89261baSDavid van Moolenbroek
941*b89261baSDavid van Moolenbroek /* calculate pcpu */
942*b89261baSDavid van Moolenbroek if ((proc->pcpu = (proc->time - otime) / (double)elapsed) < 0.0001)
943*b89261baSDavid van Moolenbroek {
944*b89261baSDavid van Moolenbroek proc->pcpu = 0;
945*b89261baSDavid van Moolenbroek }
946*b89261baSDavid van Moolenbroek
947*b89261baSDavid van Moolenbroek /* if we have task subdirs and this process has more than
948*b89261baSDavid van Moolenbroek one thread, collect data on each thread */
949*b89261baSDavid van Moolenbroek if (have_task && proc->threads > 1)
950*b89261baSDavid van Moolenbroek {
951*b89261baSDavid van Moolenbroek snprintf(buffer, sizeof(buffer), "%d/task", pid);
952*b89261baSDavid van Moolenbroek if ((taskdir = opendir(buffer)) != NULL)
953*b89261baSDavid van Moolenbroek {
954*b89261baSDavid van Moolenbroek while ((taskent = readdir(taskdir)) != NULL)
955*b89261baSDavid van Moolenbroek {
956*b89261baSDavid van Moolenbroek if (!isdigit(taskent->d_name[0]))
957*b89261baSDavid van Moolenbroek continue;
958*b89261baSDavid van Moolenbroek
959*b89261baSDavid van Moolenbroek /* lookup entry in tasktable */
960*b89261baSDavid van Moolenbroek taskpid = atoi(taskent->d_name);
961*b89261baSDavid van Moolenbroek taskproc = hash_lookup_pid(tasktable, taskpid);
962*b89261baSDavid van Moolenbroek
963*b89261baSDavid van Moolenbroek /* if we came up empty, create a new entry */
964*b89261baSDavid van Moolenbroek if (taskproc == NULL)
965*b89261baSDavid van Moolenbroek {
966*b89261baSDavid van Moolenbroek taskproc = new_proc();
967*b89261baSDavid van Moolenbroek taskproc->pid = taskpid;
968*b89261baSDavid van Moolenbroek taskproc->time = 0;
969*b89261baSDavid van Moolenbroek hash_add_pid(tasktable, taskpid, (void *)taskproc);
970*b89261baSDavid van Moolenbroek }
971*b89261baSDavid van Moolenbroek
972*b89261baSDavid van Moolenbroek /* remember the previous cpu time */
973*b89261baSDavid van Moolenbroek otime = taskproc->time;
974*b89261baSDavid van Moolenbroek
975*b89261baSDavid van Moolenbroek /* get current data */
976*b89261baSDavid van Moolenbroek read_one_proc_stat(pid, taskpid, taskproc, sel);
977*b89261baSDavid van Moolenbroek
978*b89261baSDavid van Moolenbroek /* ignore if it isnt real */
979*b89261baSDavid van Moolenbroek if (taskproc->state == 0)
980*b89261baSDavid van Moolenbroek continue;
981*b89261baSDavid van Moolenbroek
982*b89261baSDavid van Moolenbroek /* when showing threads, add this to the accumulated
983*b89261baSDavid van Moolenbroek process state data, but remember that the first
984*b89261baSDavid van Moolenbroek thread is already accounted for */
985*b89261baSDavid van Moolenbroek if (show_threads && pid != taskpid)
986*b89261baSDavid van Moolenbroek {
987*b89261baSDavid van Moolenbroek total_procs++;
988*b89261baSDavid van Moolenbroek process_states[taskproc->state]++;
989*b89261baSDavid van Moolenbroek }
990*b89261baSDavid van Moolenbroek
991*b89261baSDavid van Moolenbroek /* calculate pcpu */
992*b89261baSDavid van Moolenbroek if ((taskproc->pcpu = (taskproc->time - otime) /
993*b89261baSDavid van Moolenbroek (double)elapsed) < 0.0)
994*b89261baSDavid van Moolenbroek {
995*b89261baSDavid van Moolenbroek taskproc->pcpu = 0;
996*b89261baSDavid van Moolenbroek }
997*b89261baSDavid van Moolenbroek
998*b89261baSDavid van Moolenbroek /* link this in to the proc's list */
999*b89261baSDavid van Moolenbroek taskproc->next = proc->next;
1000*b89261baSDavid van Moolenbroek proc->next = taskproc;
1001*b89261baSDavid van Moolenbroek }
1002*b89261baSDavid van Moolenbroek closedir(taskdir);
1003*b89261baSDavid van Moolenbroek }
1004*b89261baSDavid van Moolenbroek }
1005*b89261baSDavid van Moolenbroek }
1006*b89261baSDavid van Moolenbroek closedir(dir);
1007*b89261baSDavid van Moolenbroek
1008*b89261baSDavid van Moolenbroek /* make sure we have enough slots for the active procs */
1009*b89261baSDavid van Moolenbroek if (activesize < total_procs)
1010*b89261baSDavid van Moolenbroek {
1011*b89261baSDavid van Moolenbroek pactive = (struct top_proc **)realloc(pactive,
1012*b89261baSDavid van Moolenbroek sizeof(struct top_proc *) * total_procs);
1013*b89261baSDavid van Moolenbroek activesize = total_procs;
1014*b89261baSDavid van Moolenbroek }
1015*b89261baSDavid van Moolenbroek
1016*b89261baSDavid van Moolenbroek /* set up the active procs and flush dead entries */
1017*b89261baSDavid van Moolenbroek active = pactive;
1018*b89261baSDavid van Moolenbroek hi = hash_first_pid(ptable, &pos);
1019*b89261baSDavid van Moolenbroek while (hi != NULL)
1020*b89261baSDavid van Moolenbroek {
1021*b89261baSDavid van Moolenbroek proc = (struct top_proc *)(hi->value);
1022*b89261baSDavid van Moolenbroek if (proc->state == 0)
1023*b89261baSDavid van Moolenbroek {
1024*b89261baSDavid van Moolenbroek /* dead entry */
1025*b89261baSDavid van Moolenbroek hash_remove_pos_pid(&pos);
1026*b89261baSDavid van Moolenbroek free_proc(proc);
1027*b89261baSDavid van Moolenbroek }
1028*b89261baSDavid van Moolenbroek else
1029*b89261baSDavid van Moolenbroek {
1030*b89261baSDavid van Moolenbroek /* check to see if it qualifies as active */
1031*b89261baSDavid van Moolenbroek if ((show_idle || proc->state == 1 || proc->pcpu) &&
1032*b89261baSDavid van Moolenbroek (!show_uid || proc->uid == sel->uid) &&
1033*b89261baSDavid van Moolenbroek (show_command == NULL ||
1034*b89261baSDavid van Moolenbroek strstr(proc->name, show_command) != NULL))
1035*b89261baSDavid van Moolenbroek {
1036*b89261baSDavid van Moolenbroek /* are we showing threads and does this proc have any? */
1037*b89261baSDavid van Moolenbroek if (show_threads && proc->threads > 1 && proc->next != NULL)
1038*b89261baSDavid van Moolenbroek {
1039*b89261baSDavid van Moolenbroek /* then add just the thread info -- the main process
1040*b89261baSDavid van Moolenbroek info is included in the list */
1041*b89261baSDavid van Moolenbroek proc = proc->next;
1042*b89261baSDavid van Moolenbroek while (proc != NULL)
1043*b89261baSDavid van Moolenbroek {
1044*b89261baSDavid van Moolenbroek *active++ = proc;
1045*b89261baSDavid van Moolenbroek proc = proc->next;
1046*b89261baSDavid van Moolenbroek }
1047*b89261baSDavid van Moolenbroek }
1048*b89261baSDavid van Moolenbroek else
1049*b89261baSDavid van Moolenbroek {
1050*b89261baSDavid van Moolenbroek /* add the process */
1051*b89261baSDavid van Moolenbroek *active++ = proc;
1052*b89261baSDavid van Moolenbroek }
1053*b89261baSDavid van Moolenbroek }
1054*b89261baSDavid van Moolenbroek }
1055*b89261baSDavid van Moolenbroek
1056*b89261baSDavid van Moolenbroek hi = hash_next_pid(&pos);
1057*b89261baSDavid van Moolenbroek }
1058*b89261baSDavid van Moolenbroek
1059*b89261baSDavid van Moolenbroek si->p_active = active - pactive;
1060*b89261baSDavid van Moolenbroek si->p_total = total_procs;
1061*b89261baSDavid van Moolenbroek si->procstates = process_states;
1062*b89261baSDavid van Moolenbroek }
1063*b89261baSDavid van Moolenbroek
1064*b89261baSDavid van Moolenbroek /* if requested, sort the "active" procs */
1065*b89261baSDavid van Moolenbroek if (si->p_active)
1066*b89261baSDavid van Moolenbroek qsort(pactive, si->p_active, sizeof(struct top_proc *),
1067*b89261baSDavid van Moolenbroek proc_compares[compare_index]);
1068*b89261baSDavid van Moolenbroek
1069*b89261baSDavid van Moolenbroek /* don't even pretend that the return value thing here isn't bogus */
1070*b89261baSDavid van Moolenbroek nextactive = pactive;
1071*b89261baSDavid van Moolenbroek return (caddr_t)0;
1072*b89261baSDavid van Moolenbroek }
1073*b89261baSDavid van Moolenbroek
1074*b89261baSDavid van Moolenbroek
1075*b89261baSDavid van Moolenbroek char *
format_header(char * uname_field)1076*b89261baSDavid van Moolenbroek format_header(char *uname_field)
1077*b89261baSDavid van Moolenbroek
1078*b89261baSDavid van Moolenbroek {
1079*b89261baSDavid van Moolenbroek int uname_len = strlen(uname_field);
1080*b89261baSDavid van Moolenbroek if (uname_len > 8)
1081*b89261baSDavid van Moolenbroek uname_len = 8;
1082*b89261baSDavid van Moolenbroek
1083*b89261baSDavid van Moolenbroek memcpy(strchr(fmt_header, 'X'), uname_field, uname_len);
1084*b89261baSDavid van Moolenbroek
1085*b89261baSDavid van Moolenbroek return fmt_header;
1086*b89261baSDavid van Moolenbroek }
1087*b89261baSDavid van Moolenbroek
1088*b89261baSDavid van Moolenbroek static char p_header[MAX_COLS];
1089*b89261baSDavid van Moolenbroek
1090*b89261baSDavid van Moolenbroek char *
format_process_header(struct process_select * sel,caddr_t handle,int count)1091*b89261baSDavid van Moolenbroek format_process_header(struct process_select *sel, caddr_t handle, int count)
1092*b89261baSDavid van Moolenbroek
1093*b89261baSDavid van Moolenbroek {
1094*b89261baSDavid van Moolenbroek char *h;
1095*b89261baSDavid van Moolenbroek
1096*b89261baSDavid van Moolenbroek h = sel->threads ? proc_header_nothr : proc_header_thr;
1097*b89261baSDavid van Moolenbroek
1098*b89261baSDavid van Moolenbroek snprintf(p_header, MAX_COLS, h, sel->usernames ? "USERNAME" : "UID");
1099*b89261baSDavid van Moolenbroek
1100*b89261baSDavid van Moolenbroek return p_header;
1101*b89261baSDavid van Moolenbroek }
1102*b89261baSDavid van Moolenbroek
1103*b89261baSDavid van Moolenbroek
1104*b89261baSDavid van Moolenbroek char *
format_next_process(caddr_t handle,char * (* get_userid)(int))1105*b89261baSDavid van Moolenbroek format_next_process(caddr_t handle, char *(*get_userid)(int))
1106*b89261baSDavid van Moolenbroek
1107*b89261baSDavid van Moolenbroek {
1108*b89261baSDavid van Moolenbroek static char fmt[MAX_COLS]; /* static area where result is built */
1109*b89261baSDavid van Moolenbroek struct top_proc *p = *nextactive++;
1110*b89261baSDavid van Moolenbroek char *userbuf;
1111*b89261baSDavid van Moolenbroek
1112*b89261baSDavid van Moolenbroek userbuf = show_usernames ? username(p->uid) : itoa_w(p->uid, 7);
1113*b89261baSDavid van Moolenbroek
1114*b89261baSDavid van Moolenbroek if (show_threads)
1115*b89261baSDavid van Moolenbroek {
1116*b89261baSDavid van Moolenbroek snprintf(fmt, sizeof(fmt),
1117*b89261baSDavid van Moolenbroek "%5d %-8.8s %3d %4d %5s %5s %5s %-5s %6s %5s%% %s",
1118*b89261baSDavid van Moolenbroek p->pid,
1119*b89261baSDavid van Moolenbroek userbuf,
1120*b89261baSDavid van Moolenbroek p->pri < -99 ? -99 : p->pri,
1121*b89261baSDavid van Moolenbroek p->nice,
1122*b89261baSDavid van Moolenbroek format_k(p->size),
1123*b89261baSDavid van Moolenbroek format_k(p->rss),
1124*b89261baSDavid van Moolenbroek format_k(p->shared),
1125*b89261baSDavid van Moolenbroek state_abbrev[p->state],
1126*b89261baSDavid van Moolenbroek format_time(p->time / HZ),
1127*b89261baSDavid van Moolenbroek format_percent(p->pcpu * 100.0),
1128*b89261baSDavid van Moolenbroek p->name);
1129*b89261baSDavid van Moolenbroek }
1130*b89261baSDavid van Moolenbroek else
1131*b89261baSDavid van Moolenbroek {
1132*b89261baSDavid van Moolenbroek snprintf(fmt, sizeof(fmt),
1133*b89261baSDavid van Moolenbroek "%5d %-8.8s %4d %3d %4d %5s %5s %5s %-5s %6s %5s%% %s",
1134*b89261baSDavid van Moolenbroek p->pid,
1135*b89261baSDavid van Moolenbroek userbuf,
1136*b89261baSDavid van Moolenbroek p->threads <= 9999 ? p->threads : 9999,
1137*b89261baSDavid van Moolenbroek p->pri < -99 ? -99 : p->pri,
1138*b89261baSDavid van Moolenbroek p->nice,
1139*b89261baSDavid van Moolenbroek format_k(p->size),
1140*b89261baSDavid van Moolenbroek format_k(p->rss),
1141*b89261baSDavid van Moolenbroek format_k(p->shared),
1142*b89261baSDavid van Moolenbroek state_abbrev[p->state],
1143*b89261baSDavid van Moolenbroek format_time(p->time / HZ),
1144*b89261baSDavid van Moolenbroek format_percent(p->pcpu * 100.0),
1145*b89261baSDavid van Moolenbroek p->name);
1146*b89261baSDavid van Moolenbroek }
1147*b89261baSDavid van Moolenbroek
1148*b89261baSDavid van Moolenbroek /* return the result */
1149*b89261baSDavid van Moolenbroek return (fmt);
1150*b89261baSDavid van Moolenbroek }
1151*b89261baSDavid van Moolenbroek
1152*b89261baSDavid van Moolenbroek /* comparison routines for qsort */
1153*b89261baSDavid van Moolenbroek
1154*b89261baSDavid van Moolenbroek /*
1155*b89261baSDavid van Moolenbroek * There are currently four possible comparison routines. main selects
1156*b89261baSDavid van Moolenbroek * one of these by indexing in to the array proc_compares.
1157*b89261baSDavid van Moolenbroek *
1158*b89261baSDavid van Moolenbroek * Possible keys are defined as macros below. Currently these keys are
1159*b89261baSDavid van Moolenbroek * defined: percent cpu, cpu ticks, process state, resident set size,
1160*b89261baSDavid van Moolenbroek * total virtual memory usage. The process states are ordered as follows
1161*b89261baSDavid van Moolenbroek * (from least to most important): WAIT, zombie, sleep, stop, start, run.
1162*b89261baSDavid van Moolenbroek * The array declaration below maps a process state index into a number
1163*b89261baSDavid van Moolenbroek * that reflects this ordering.
1164*b89261baSDavid van Moolenbroek */
1165*b89261baSDavid van Moolenbroek
1166*b89261baSDavid van Moolenbroek /* First, the possible comparison keys. These are defined in such a way
1167*b89261baSDavid van Moolenbroek that they can be merely listed in the source code to define the actual
1168*b89261baSDavid van Moolenbroek desired ordering.
1169*b89261baSDavid van Moolenbroek */
1170*b89261baSDavid van Moolenbroek
1171*b89261baSDavid van Moolenbroek #define ORDERKEY_PCTCPU if (dresult = p2->pcpu - p1->pcpu,\
1172*b89261baSDavid van Moolenbroek (result = dresult > 0.0 ? 1 : dresult < 0.0 ? -1 : 0) == 0)
1173*b89261baSDavid van Moolenbroek #define ORDERKEY_CPTICKS if ((result = (long)p2->time - (long)p1->time) == 0)
1174*b89261baSDavid van Moolenbroek #define ORDERKEY_STATE if ((result = (sort_state[p2->state] - \
1175*b89261baSDavid van Moolenbroek sort_state[p1->state])) == 0)
1176*b89261baSDavid van Moolenbroek #define ORDERKEY_PRIO if ((result = p2->pri - p1->pri) == 0)
1177*b89261baSDavid van Moolenbroek #define ORDERKEY_RSSIZE if ((result = p2->rss - p1->rss) == 0)
1178*b89261baSDavid van Moolenbroek #define ORDERKEY_MEM if ((result = p2->size - p1->size) == 0)
1179*b89261baSDavid van Moolenbroek #define ORDERKEY_NAME if ((result = strcmp(p1->name, p2->name)) == 0)
1180*b89261baSDavid van Moolenbroek
1181*b89261baSDavid van Moolenbroek /* Now the array that maps process state to a weight */
1182*b89261baSDavid van Moolenbroek
1183*b89261baSDavid van Moolenbroek unsigned char sort_state[] =
1184*b89261baSDavid van Moolenbroek {
1185*b89261baSDavid van Moolenbroek 0, /* empty */
1186*b89261baSDavid van Moolenbroek 6, /* run */
1187*b89261baSDavid van Moolenbroek 3, /* sleep */
1188*b89261baSDavid van Moolenbroek 5, /* disk wait */
1189*b89261baSDavid van Moolenbroek 1, /* zombie */
1190*b89261baSDavid van Moolenbroek 2, /* stop */
1191*b89261baSDavid van Moolenbroek 4 /* swap */
1192*b89261baSDavid van Moolenbroek };
1193*b89261baSDavid van Moolenbroek
1194*b89261baSDavid van Moolenbroek
1195*b89261baSDavid van Moolenbroek /* compare_cpu - the comparison function for sorting by cpu percentage */
1196*b89261baSDavid van Moolenbroek
1197*b89261baSDavid van Moolenbroek int
compare_cpu(struct top_proc ** pp1,struct top_proc ** pp2)1198*b89261baSDavid van Moolenbroek compare_cpu (
1199*b89261baSDavid van Moolenbroek struct top_proc **pp1,
1200*b89261baSDavid van Moolenbroek struct top_proc **pp2)
1201*b89261baSDavid van Moolenbroek {
1202*b89261baSDavid van Moolenbroek register struct top_proc *p1;
1203*b89261baSDavid van Moolenbroek register struct top_proc *p2;
1204*b89261baSDavid van Moolenbroek register long result;
1205*b89261baSDavid van Moolenbroek double dresult;
1206*b89261baSDavid van Moolenbroek
1207*b89261baSDavid van Moolenbroek /* remove one level of indirection */
1208*b89261baSDavid van Moolenbroek p1 = *pp1;
1209*b89261baSDavid van Moolenbroek p2 = *pp2;
1210*b89261baSDavid van Moolenbroek
1211*b89261baSDavid van Moolenbroek ORDERKEY_PCTCPU
1212*b89261baSDavid van Moolenbroek ORDERKEY_CPTICKS
1213*b89261baSDavid van Moolenbroek ORDERKEY_STATE
1214*b89261baSDavid van Moolenbroek ORDERKEY_PRIO
1215*b89261baSDavid van Moolenbroek ORDERKEY_RSSIZE
1216*b89261baSDavid van Moolenbroek ORDERKEY_MEM
1217*b89261baSDavid van Moolenbroek ;
1218*b89261baSDavid van Moolenbroek
1219*b89261baSDavid van Moolenbroek return result == 0 ? 0 : result < 0 ? -1 : 1;
1220*b89261baSDavid van Moolenbroek }
1221*b89261baSDavid van Moolenbroek
1222*b89261baSDavid van Moolenbroek /* compare_size - the comparison function for sorting by total memory usage */
1223*b89261baSDavid van Moolenbroek
1224*b89261baSDavid van Moolenbroek int
compare_size(struct top_proc ** pp1,struct top_proc ** pp2)1225*b89261baSDavid van Moolenbroek compare_size (
1226*b89261baSDavid van Moolenbroek struct top_proc **pp1,
1227*b89261baSDavid van Moolenbroek struct top_proc **pp2)
1228*b89261baSDavid van Moolenbroek {
1229*b89261baSDavid van Moolenbroek register struct top_proc *p1;
1230*b89261baSDavid van Moolenbroek register struct top_proc *p2;
1231*b89261baSDavid van Moolenbroek register long result;
1232*b89261baSDavid van Moolenbroek double dresult;
1233*b89261baSDavid van Moolenbroek
1234*b89261baSDavid van Moolenbroek /* remove one level of indirection */
1235*b89261baSDavid van Moolenbroek p1 = *pp1;
1236*b89261baSDavid van Moolenbroek p2 = *pp2;
1237*b89261baSDavid van Moolenbroek
1238*b89261baSDavid van Moolenbroek ORDERKEY_MEM
1239*b89261baSDavid van Moolenbroek ORDERKEY_RSSIZE
1240*b89261baSDavid van Moolenbroek ORDERKEY_PCTCPU
1241*b89261baSDavid van Moolenbroek ORDERKEY_CPTICKS
1242*b89261baSDavid van Moolenbroek ORDERKEY_STATE
1243*b89261baSDavid van Moolenbroek ORDERKEY_PRIO
1244*b89261baSDavid van Moolenbroek ;
1245*b89261baSDavid van Moolenbroek
1246*b89261baSDavid van Moolenbroek return result == 0 ? 0 : result < 0 ? -1 : 1;
1247*b89261baSDavid van Moolenbroek }
1248*b89261baSDavid van Moolenbroek
1249*b89261baSDavid van Moolenbroek /* compare_res - the comparison function for sorting by resident set size */
1250*b89261baSDavid van Moolenbroek
1251*b89261baSDavid van Moolenbroek int
compare_res(struct top_proc ** pp1,struct top_proc ** pp2)1252*b89261baSDavid van Moolenbroek compare_res (
1253*b89261baSDavid van Moolenbroek struct top_proc **pp1,
1254*b89261baSDavid van Moolenbroek struct top_proc **pp2)
1255*b89261baSDavid van Moolenbroek {
1256*b89261baSDavid van Moolenbroek register struct top_proc *p1;
1257*b89261baSDavid van Moolenbroek register struct top_proc *p2;
1258*b89261baSDavid van Moolenbroek register long result;
1259*b89261baSDavid van Moolenbroek double dresult;
1260*b89261baSDavid van Moolenbroek
1261*b89261baSDavid van Moolenbroek /* remove one level of indirection */
1262*b89261baSDavid van Moolenbroek p1 = *pp1;
1263*b89261baSDavid van Moolenbroek p2 = *pp2;
1264*b89261baSDavid van Moolenbroek
1265*b89261baSDavid van Moolenbroek ORDERKEY_RSSIZE
1266*b89261baSDavid van Moolenbroek ORDERKEY_MEM
1267*b89261baSDavid van Moolenbroek ORDERKEY_PCTCPU
1268*b89261baSDavid van Moolenbroek ORDERKEY_CPTICKS
1269*b89261baSDavid van Moolenbroek ORDERKEY_STATE
1270*b89261baSDavid van Moolenbroek ORDERKEY_PRIO
1271*b89261baSDavid van Moolenbroek ;
1272*b89261baSDavid van Moolenbroek
1273*b89261baSDavid van Moolenbroek return result == 0 ? 0 : result < 0 ? -1 : 1;
1274*b89261baSDavid van Moolenbroek }
1275*b89261baSDavid van Moolenbroek
1276*b89261baSDavid van Moolenbroek /* compare_time - the comparison function for sorting by total cpu time */
1277*b89261baSDavid van Moolenbroek
1278*b89261baSDavid van Moolenbroek int
compare_time(struct top_proc ** pp1,struct top_proc ** pp2)1279*b89261baSDavid van Moolenbroek compare_time (
1280*b89261baSDavid van Moolenbroek struct top_proc **pp1,
1281*b89261baSDavid van Moolenbroek struct top_proc **pp2)
1282*b89261baSDavid van Moolenbroek {
1283*b89261baSDavid van Moolenbroek register struct top_proc *p1;
1284*b89261baSDavid van Moolenbroek register struct top_proc *p2;
1285*b89261baSDavid van Moolenbroek register long result;
1286*b89261baSDavid van Moolenbroek double dresult;
1287*b89261baSDavid van Moolenbroek
1288*b89261baSDavid van Moolenbroek /* remove one level of indirection */
1289*b89261baSDavid van Moolenbroek p1 = *pp1;
1290*b89261baSDavid van Moolenbroek p2 = *pp2;
1291*b89261baSDavid van Moolenbroek
1292*b89261baSDavid van Moolenbroek ORDERKEY_CPTICKS
1293*b89261baSDavid van Moolenbroek ORDERKEY_PCTCPU
1294*b89261baSDavid van Moolenbroek ORDERKEY_STATE
1295*b89261baSDavid van Moolenbroek ORDERKEY_PRIO
1296*b89261baSDavid van Moolenbroek ORDERKEY_MEM
1297*b89261baSDavid van Moolenbroek ORDERKEY_RSSIZE
1298*b89261baSDavid van Moolenbroek ;
1299*b89261baSDavid van Moolenbroek
1300*b89261baSDavid van Moolenbroek return result == 0 ? 0 : result < 0 ? -1 : 1;
1301*b89261baSDavid van Moolenbroek }
1302*b89261baSDavid van Moolenbroek
1303*b89261baSDavid van Moolenbroek
1304*b89261baSDavid van Moolenbroek /* compare_cmd - the comparison function for sorting by command name */
1305*b89261baSDavid van Moolenbroek
1306*b89261baSDavid van Moolenbroek int
compare_cmd(struct top_proc ** pp1,struct top_proc ** pp2)1307*b89261baSDavid van Moolenbroek compare_cmd (
1308*b89261baSDavid van Moolenbroek struct top_proc **pp1,
1309*b89261baSDavid van Moolenbroek struct top_proc **pp2)
1310*b89261baSDavid van Moolenbroek {
1311*b89261baSDavid van Moolenbroek register struct top_proc *p1;
1312*b89261baSDavid van Moolenbroek register struct top_proc *p2;
1313*b89261baSDavid van Moolenbroek register long result;
1314*b89261baSDavid van Moolenbroek double dresult;
1315*b89261baSDavid van Moolenbroek
1316*b89261baSDavid van Moolenbroek /* remove one level of indirection */
1317*b89261baSDavid van Moolenbroek p1 = *pp1;
1318*b89261baSDavid van Moolenbroek p2 = *pp2;
1319*b89261baSDavid van Moolenbroek
1320*b89261baSDavid van Moolenbroek ORDERKEY_NAME
1321*b89261baSDavid van Moolenbroek ORDERKEY_PCTCPU
1322*b89261baSDavid van Moolenbroek ORDERKEY_CPTICKS
1323*b89261baSDavid van Moolenbroek ORDERKEY_STATE
1324*b89261baSDavid van Moolenbroek ORDERKEY_PRIO
1325*b89261baSDavid van Moolenbroek ORDERKEY_RSSIZE
1326*b89261baSDavid van Moolenbroek ORDERKEY_MEM
1327*b89261baSDavid van Moolenbroek ;
1328*b89261baSDavid van Moolenbroek
1329*b89261baSDavid van Moolenbroek return result == 0 ? 0 : result < 0 ? -1 : 1;
1330*b89261baSDavid van Moolenbroek }
1331*b89261baSDavid van Moolenbroek
1332*b89261baSDavid van Moolenbroek
1333*b89261baSDavid van Moolenbroek /*
1334*b89261baSDavid van Moolenbroek * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
1335*b89261baSDavid van Moolenbroek * the process does not exist.
1336*b89261baSDavid van Moolenbroek * It is EXTREMLY IMPORTANT that this function work correctly.
1337*b89261baSDavid van Moolenbroek * If top runs setuid root (as in SVR4), then this function
1338*b89261baSDavid van Moolenbroek * is the only thing that stands in the way of a serious
1339*b89261baSDavid van Moolenbroek * security problem. It validates requests for the "kill"
1340*b89261baSDavid van Moolenbroek * and "renice" commands.
1341*b89261baSDavid van Moolenbroek */
1342*b89261baSDavid van Moolenbroek
1343*b89261baSDavid van Moolenbroek int
proc_owner(int pid)1344*b89261baSDavid van Moolenbroek proc_owner(int pid)
1345*b89261baSDavid van Moolenbroek
1346*b89261baSDavid van Moolenbroek {
1347*b89261baSDavid van Moolenbroek struct stat sb;
1348*b89261baSDavid van Moolenbroek char buffer[32];
1349*b89261baSDavid van Moolenbroek sprintf(buffer, "%d", pid);
1350*b89261baSDavid van Moolenbroek
1351*b89261baSDavid van Moolenbroek if (stat(buffer, &sb) < 0)
1352*b89261baSDavid van Moolenbroek return -1;
1353*b89261baSDavid van Moolenbroek else
1354*b89261baSDavid van Moolenbroek return (int)sb.st_uid;
1355*b89261baSDavid van Moolenbroek }
1356