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