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