2 * Copyright (c) 1984 through 2008, William LeFebvre
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
16 * * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * top - a top users display for Unix
36 * SYNOPSIS: any hp9000 running hpux version 10.x
39 * This is the machine-dependent module for HPUX 10/11 that uses pstat.
40 * It has been tested on HP/UX 10.01, 10.20, and 11.00. It is presumed
41 * to work also on 10.10.
42 * Idle processes are marked by being either runnable or having a %CPU
43 * of at least 0.1%. This fraction is defined by CPU_IDLE_THRESH and
44 * can be adjusted at compile time.
46 * CFLAGS: -DHAVE_GETOPT
50 * AUTHOR: John Haxby <john_haxby@hp.com>
51 * AUTHOR: adapted from Rich Holland <holland@synopsys.com>
52 * AUTHOR: adapted from Kevin Schmidt <kevin@mcl.ucsb.edu>
65 #include <sys/types.h>
66 #include <sys/param.h>
67 #include <sys/pstat.h>
70 #include <sys/dirent.h>
77 * The idle threshold (CPU_IDLE_THRESH) is an extension to the normal
78 * idle process check. Basically, we regard a process as idle if it is
79 * both asleep and using less that CPU_IDLE_THRESH percent cpu time. I
80 * believe this makes the "i" option more useful, but if you don't, add
81 * "-DCPU_IDLE_THRESH=0.0" to the CFLAGS.
83 #ifndef CPU_IDLE_THRESH
84 #define CPU_IDLE_THRESH 0.1
87 # define P_RSSIZE(p) (p)->pst_rssize
88 # define P_TSIZE(p) (p)->pst_tsize
89 # define P_DSIZE(p) (p)->pst_dsize
90 # define P_SSIZE(p) (p)->pst_ssize
92 #define VMUNIX "/stand/vmunix"
93 #define KMEM "/dev/kmem"
94 #define MEM "/dev/mem"
96 #define SWAP "/dev/dmem"
99 /* what we consider to be process size: */
100 #define PROCSIZE(pp) (P_TSIZE(pp) + P_DSIZE(pp) + P_SSIZE(pp))
102 /* definitions for indices in the nlist array */
105 static struct nlist nlst
[] = {
111 * These definitions control the format of the per-process area
114 static char header
[] =
115 " TTY PID X PRI NICE SIZE RES STATE TIME CPU COMMAND";
116 /* 0123456789.12345 -- field to fill in starts at header+6 */
117 #define UNAME_START 15
119 #define Proc_format \
120 "%8.8s %5d %-8.8s %4d %4d %5s %5s %-5s %6s %5.2f%% %s"
122 /* process state names for the "STATE" column of the display */
124 char *state_abbrev
[] =
126 "", "sleep", "run", "stop", "zomb", "trans", "start"
130 /* values that we stash away in _init and use in later routines */
132 static struct pst_status
*pst
;
134 /* these are retrieved from the OS in _init */
138 /* these are offsets obtained via nlist and used in the get_ functions */
139 static unsigned long mpid_offset
;
141 /* these are for calculating cpu state percentages */
142 static long cp_time
[PST_MAX_CPUSTATES
];
143 static long cp_old
[PST_MAX_CPUSTATES
];
144 static long cp_diff
[PST_MAX_CPUSTATES
];
146 /* these are for detailing the process states */
147 int process_states
[7];
148 char *procstatenames
[] = {
149 "", " sleeping, ", " running, ", " stopped, ", " zombie, ",
150 " trans, ", " starting, ",
154 /* these are for detailing the cpu states */
155 int cpu_states
[PST_MAX_CPUSTATES
];
156 char *cpustatenames
[] = {
157 /* roll "swait" into "block" and "ssys" into "sys" */
158 "usr", "nice", "sys", "idle", "", "block", "\0swait", "intr", "\0ssys",
162 /* these are for detailing the memory statistics */
163 long memory_stats
[8];
164 char *memorynames
[] = {
165 "Real: ", "K act, ", "K tot ", "Virtual: ", "K act, ",
166 "K tot, ", "K free", NULL
169 /* these are for getting the memory statistics */
170 static int pageshift
; /* log base 2 of the pagesize */
172 /* define pagetok in terms of pageshift */
173 #define pagetok(size) ((size) << pageshift)
175 /* Mapping TTY major/minor numbers is done through this structure */
180 static struct ttymap
*ttynames
= NULL
;
181 static int nttys
= 0;
182 static get_tty_names ();
184 /* comparison routine for qsort */
187 * proc_compare - comparison function for "qsort"
188 * Compares the resource consumption of two processes using five
189 * distinct keys. The keys (in descending order of importance) are:
190 * percent cpu, cpu ticks, state, resident set size, total virtual
191 * memory usage. The process states are ordered as follows (from least
192 * to most important): WAIT, zombie, sleep, stop, start, run. The
193 * array declaration below maps a process state index into a number
194 * that reflects this ordering.
197 static unsigned char sorted_state
[] =
209 struct pst_status
*p1
;
210 struct pst_status
*p2
;
216 /* compare percent cpu (pctcpu) */
217 if ((lresult
= p2
->pst_pctcpu
- p1
->pst_pctcpu
) == 0)
219 /* use cpticks to break the tie */
220 if ((result
= p2
->pst_cpticks
- p1
->pst_cpticks
) == 0)
222 /* use process state to break the tie */
223 if ((result
= sorted_state
[p2
->pst_stat
] -
224 sorted_state
[p1
->pst_stat
]) == 0)
226 /* use priority to break the tie */
227 if ((result
= p2
->pst_pri
- p1
->pst_pri
) == 0)
229 /* use resident set size (rssize) to break the tie */
230 if ((result
= P_RSSIZE(p2
) - P_RSSIZE(p1
)) == 0)
232 /* use total memory to break the tie */
233 result
= PROCSIZE(p2
) - PROCSIZE(p1
);
241 result
= lresult
< 0 ? -1 : 1;
247 machine_init(statics
)
249 struct statics
*statics
;
252 struct pst_static info
;
256 /* If we can get mpid from the kernel, we'll use it, otherwise */
257 /* we'll guess from the most recently started proces */
258 if ((kmem
= open (KMEM
, O_RDONLY
)) < 0 ||
259 (nlist (VMUNIX
, nlst
)) < 0 ||
260 (nlst
[X_MPID
].n_type
) == 0)
263 mpid_offset
= nlst
[X_MPID
].n_value
;
265 if (pstat_getstatic (&info
, sizeof (info
), 1, 0) < 0)
267 perror ("pstat_getstatic");
272 * Allocate space for the per-process structures (pst_status). To
273 * make life easier, simply allocate enough storage to hold all the
274 * process information at once. This won't normally be a problem
275 * since machines with lots of processes configured will also have
278 nproc
= info
.max_proc
;
279 pst
= (struct pst_status
*) malloc (nproc
* sizeof (struct pst_status
));
282 fprintf (stderr
, "out of memory\n");
287 * Calculate pageshift -- the value needed to convert pages to Kbytes.
288 * This will usually be 2.
291 for (pagesize
= info
.page_size
; pagesize
> 1; pagesize
>>= 1)
293 pageshift
-= LOG1024
;
295 /* get tty name information */
297 get_tty_names ("/dev", &i
);
299 /* fill in the statics information */
300 statics
->procstate_names
= procstatenames
;
301 statics
->cpustate_names
= cpustatenames
;
302 statics
->memory_names
= memorynames
;
308 char *format_header(uname_field
)
311 char *ptr
= header
+ UNAME_START
;
312 while (*uname_field
!= '\0')
313 *ptr
++ = *uname_field
++;
321 struct system_info
*si
;
324 static struct pst_dynamic dynamic
;
328 pstat_getdynamic (&dynamic
, sizeof (dynamic
), 1, 0);
329 ncpu
= dynamic
.psd_proc_cnt
; /* need this later */
332 si
->load_avg
[0] = dynamic
.psd_avg_1_min
;
333 si
->load_avg
[1] = dynamic
.psd_avg_5_min
;
334 si
->load_avg
[2] = dynamic
.psd_avg_15_min
;
338 * to avoid space problems, we roll SWAIT (kernel semaphore block)
339 * into BLOCK (spin lock block) and SSYS (kernel process) into SYS
340 * (system time) Ideally, all screens would be wider :-)
342 dynamic
.psd_cpu_time
[CP_BLOCK
] += dynamic
.psd_cpu_time
[CP_SWAIT
];
343 dynamic
.psd_cpu_time
[CP_SWAIT
] = 0;
344 dynamic
.psd_cpu_time
[CP_SYS
] += dynamic
.psd_cpu_time
[CP_SSYS
];
345 dynamic
.psd_cpu_time
[CP_SSYS
] = 0;
346 for (i
= 0; i
< PST_MAX_CPUSTATES
; i
++)
347 cp_time
[i
] = dynamic
.psd_cpu_time
[i
];
348 percentages(PST_MAX_CPUSTATES
, cpu_states
, cp_time
, cp_old
, cp_diff
);
349 si
->cpustates
= cpu_states
;
354 memory_stats
[0] = -1;
355 memory_stats
[1] = pagetok (dynamic
.psd_arm
);
356 memory_stats
[2] = pagetok (dynamic
.psd_rm
);
357 memory_stats
[3] = -1;
358 memory_stats
[4] = pagetok (dynamic
.psd_avm
);
359 memory_stats
[5] = pagetok (dynamic
.psd_vm
);
360 memory_stats
[6] = pagetok (dynamic
.psd_free
);
361 si
->memory
= memory_stats
;
364 * If we can get mpid from the kernel, then we will do so now.
365 * Otherwise we'll guess at mpid from the most recently started
366 * process time. Note that this requires us to get the pst array
367 * now rather than in get_process_info(). We rely on
368 * get_system_info() being called before get_system_info() for this
371 for (i
= 0; i
< nproc
; i
++)
373 n
= pstat_getproc (pst
, sizeof (*pst
), nproc
, 0);
375 if (kmem
>= 0 && mpid_offset
> 0)
376 (void) getkval(mpid_offset
, &(si
->last_pid
), sizeof(si
->last_pid
), "mpid");
379 static int last_start_time
= 0;
382 for (i
= 0; i
< n
; i
++)
384 if (last_start_time
<= pst
[i
].pst_start
)
386 last_start_time
= pst
[i
].pst_start
;
387 if (pid
<= pst
[i
].pst_pid
)
388 pid
= pst
[i
].pst_pid
;
396 caddr_t
get_process_info(si
, sel
, compare_index
)
398 struct system_info
*si
;
399 struct process_select
*sel
;
404 int i
, active
, total
;
407 * Eliminate unwanted processes
408 * and tot up all the wanted processes by state
410 for (i
= 0; i
< sizeof (process_states
)/sizeof (process_states
[0]); i
++)
411 process_states
[i
] = 0;
413 for (total
= 0, active
= 0, i
= 0; pst
[i
].pst_pid
>= 0; i
++)
415 int state
= pst
[i
].pst_stat
;
417 process_states
[state
] += 1;
420 if (!sel
->system
&& (pst
[i
].pst_flag
& PS_SYS
))
422 pst
[i
].pst_stat
= -1;
427 * If we are eliminating idle processes, then a process is regarded
428 * as idle if it is in a short term sleep and not using much
429 * CPU, or stopped, or simple dead.
432 && (state
== PS_SLEEP
|| state
== PS_STOP
|| state
== PS_ZOMBIE
)
433 && (state
!= PS_SLEEP
&& pst
[i
].pst_pctcpu
< CPU_IDLE_THRESH
/100.0))
434 pst
[i
].pst_stat
= -1;
436 if (sel
->uid
> 0 && sel
->uid
!= pst
[i
].pst_uid
)
437 pst
[i
].pst_stat
= -1;
439 if (sel
->command
!= NULL
&&
440 strncmp (sel
->command
, pst
[i
].pst_ucomm
, strlen (pst
[i
].pst_ucomm
)) != 0)
441 pst
[i
].pst_stat
= -1;
443 if (pst
[i
].pst_stat
>= 0)
446 si
->procstates
= process_states
;
448 si
->p_active
= active
;
450 qsort ((char *)pst
, i
, sizeof(*pst
), proc_compare
);
452 /* handle is simply an index into the process structures */
454 return (caddr_t
) &handle
;
458 * Find the terminal name associated with a particular
459 * major/minor number pair
461 static char *term_name (term
)
467 if (term
->psd_major
== -1 && term
->psd_minor
== -1)
470 dev
= makedev (term
->psd_major
, term
->psd_minor
);
471 for (i
= 0; i
< nttys
&& ttynames
[i
].name
[0] != '\0'; i
++)
473 if (dev
== ttynames
[i
].dev
)
474 return ttynames
[i
].name
;
479 char *format_next_process(handle
, get_userid
)
482 char *(*get_userid
)();
485 static char fmt
[MAX_COLS
]; /* static area where result is built */
486 char run
[sizeof ("runNN")];
488 struct pst_status
*proc
;
492 register long cputime
;
497 struct timezone timezone
;
503 idx
= *((int *) handle
);
504 while (idx
< nproc
&& pst
[idx
].pst_stat
< 0)
506 if (idx
>= nproc
|| pst
[idx
].pst_stat
< 0)
509 *((int *) handle
) = idx
+1;
511 /* set ucomm for system processes, although we shouldn't need to */
512 if (proc
->pst_ucomm
[0] == '\0')
514 if (proc
->pst_pid
== 0)
515 strcpy (proc
->pst_ucomm
, "Swapper");
516 else if (proc
->pst_pid
== 2)
517 strcpy (proc
->pst_ucomm
, "Pager");
520 size
= proc
->pst_tsize
+ proc
->pst_dsize
+ proc
->pst_ssize
;
522 if (ncpu
> 1 && proc
->pst_stat
== PS_RUN
)
524 sprintf (run
, "run%02d", proc
->pst_procnum
);
527 else if (proc
->pst_stat
== PS_SLEEP
)
529 switch (proc
->pst_pri
+PTIMESHARE
) {
530 case PSWP
: state
= "SWP"; break; /* also PMEM */
531 case PRIRWLOCK
: state
= "RWLOCK"; break;
532 case PRIBETA
: state
= "BETA"; break;
533 case PRIALPHA
: state
= "ALPHA"; break;
534 case PRISYNC
: state
= "SYNC"; break;
535 case PINOD
: state
= "INOD"; break;
536 case PRIBIO
: state
= "BIO"; break;
537 case PLLIO
: state
= "LLIO"; break; /* also PRIUBA */
538 case PZERO
: state
= "ZERO"; break;
539 case PPIPE
: state
= "pipe"; break;
540 case PVFS
: state
= "vfs"; break;
541 case PWAIT
: state
= "wait"; break;
542 case PLOCK
: state
= "lock"; break;
543 case PSLEP
: state
= "slep"; break;
544 case PUSER
: state
= "user"; break;
546 if (proc
->pst_pri
< PZERO
-PTIMESHARE
)
553 state
= state_abbrev
[proc
->pst_stat
];
555 /* format this entry */
558 term_name (&proc
->pst_term
),
560 (*get_userid
)(proc
->pst_uid
),
562 proc
->pst_nice
- NZERO
,
564 format_k(proc
->pst_rssize
),
566 format_time(proc
->pst_utime
+ proc
->pst_stime
),
567 100.0 * proc
->pst_pctcpu
,
568 printable(proc
->pst_ucomm
));
570 /* return the result */
577 * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
578 * "offset" is the byte offset into the kernel for the desired value,
579 * "ptr" points to a buffer into which the value is retrieved,
580 * "size" is the size of the buffer (and the object to retrieve),
581 * "refstr" is a reference string used when printing error meessages,
582 * if "refstr" starts with a '!', then a failure on read will not
583 * be fatal (this may seem like a silly way to do things, but I
584 * really didn't want the overhead of another argument).
588 getkval(offset
, ptr
, size
, refstr
)
590 unsigned long offset
;
596 if (lseek(kmem
, (long)offset
, SEEK_SET
) == -1) {
599 (void) fprintf(stderr
, "%s: lseek to %s: %s\n", KMEM
,
600 refstr
, strerror(errno
));
603 if (read(kmem
, (char *) ptr
, size
) == -1) {
607 (void) fprintf(stderr
, "%s: reading %s: %s\n", KMEM
,
608 refstr
, strerror(errno
));
615 void (*signal(sig
, func
))()
619 struct sigaction act
;
620 struct sigaction oact
;
622 memset (&act
, 0, sizeof (act
));
623 act
.sa_handler
= func
;
625 if (sigaction (sig
, &act
, &oact
) < 0)
627 return oact
.sa_handler
;
631 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
632 * the process does not exist.
633 * It is EXTREMLY IMPORTANT that this function work correctly.
634 * If top runs setuid root (as in SVR4), then this function
635 * is the only thing that stands in the way of a serious
636 * security problem. It validates requests for the "kill"
637 * and "renice" commands.
644 for (i
= 0; i
< nproc
; i
++)
646 if (pst
[i
].pst_pid
== pid
)
647 return pst
[i
].pst_uid
;
653 static get_tty_names (dir
, m
)
657 char name
[MAXPATHLEN
+1];
658 struct dirent
**namelist
;
661 if ((n
= scandir (dir
, &namelist
, NULL
, NULL
)) < 0)
664 if (ttynames
== NULL
)
667 ttynames
= malloc (n
*sizeof (*ttynames
));
672 ttynames
= realloc (ttynames
, nttys
*sizeof (*ttynames
));
675 for (i
= 0; i
< n
; i
++)
678 char *str
= namelist
[i
]->d_name
;
681 sprintf (name
, "%s/%s", dir
, str
);
682 if (stat (name
, &statbuf
) < 0)
686 str
= name
+ sizeof ("/dev");
687 if (S_ISCHR (statbuf
.st_mode
))
689 ttynames
[*m
].dev
= statbuf
.st_rdev
;
690 strncpy (ttynames
[*m
].name
, str
, 8);
691 ttynames
[*m
].name
[9] = '\0';
694 else if (S_ISDIR (statbuf
.st_mode
))
695 get_tty_names (name
, m
);
698 ttynames
[*m
].name
[0] = '\0';